pax_global_header00006660000000000000000000000064151133134460014513gustar00rootroot0000000000000052 comment=43396d4d9f41fdfb7e39e2678f14983c14d710f5 opentelemetry-collector-0.141.0/000077500000000000000000000000001511331344600165365ustar00rootroot00000000000000opentelemetry-collector-0.141.0/.checkapi.yaml000066400000000000000000000002231511331344600212440ustar00rootroot00000000000000ignored_paths: - confmap/doc_test.go excluded_files: - example_*.go - "*_test.go" unkeyed_literal_initialization: enabled: true limit: 6 opentelemetry-collector-0.141.0/.chloggen/000077500000000000000000000000001511331344600204025ustar00rootroot00000000000000opentelemetry-collector-0.141.0/.chloggen/README.md000066400000000000000000000026541511331344600216700ustar00rootroot00000000000000### Changelog folder This repo uses `chloggen` to manage its changelog files. You can find the source code for the tool [here](https://github.com/open-telemetry/opentelemetry-go-build-tools/tree/main/chloggen). Here is a quick explanation of the `config.yaml` file for chloggen: ```yaml # The directory that stores individual changelog entries. # Each entry is stored in a dedicated yaml file. # - 'chloggen new' will copy the 'template_yaml' to this directory as a new entry file. # - 'chloggen validate' will validate that all entry files are valid. # - 'chloggen update' will read and delete all entry files in this directory, and update 'changelog_md'. # Specify as relative path from root of repo. # (Optional) Default: .chloggen entries_dir: .chloggen # This file is used as the input for individual changelog entries. # Specify as relative path from root of repo. # (Optional) Default: .chloggen/TEMPLATE.yaml template_yaml: .chloggen/TEMPLATE.yaml summary_template: .chloggen/summary.tmpl # The CHANGELOG file or files to which 'chloggen update' will write new entries # (Optional) Default filename: CHANGELOG.md change_logs: user: CHANGELOG.md api: CHANGELOG-API.md # The default change_log or change_logs to which an entry should be added. # If 'change_logs' is specified in this file, and no value is specified for 'default_change_logs', # then 'change_logs' MUST be specified in every entry file. default_change_logs: [user] ``` opentelemetry-collector-0.141.0/.chloggen/TEMPLATE.yaml000066400000000000000000000017001511331344600224770ustar00rootroot00000000000000# Use this changelog template to create an entry for release notes. # One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' change_type: # The name of the component, or a single word describing the area of concern, (e.g. receiver/otlp) component: # A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). note: # One or more tracking issues or pull requests related to the change issues: [] # (Optional) One or more lines of additional information to render under the primary note. # These lines will be padded with 2 spaces and then inserted directly into the document. # Use pipe (|) for multiline entries. subtext: # Optional: The change log or logs in which this entry should be included. # e.g. '[user]' or '[user, api]' # Include 'user' if the change is relevant to end users. # Include 'api' if there is a change to a library API. # Default: '[user]' change_logs: [] opentelemetry-collector-0.141.0/.chloggen/config.yaml000066400000000000000000000030071511331344600225330ustar00rootroot00000000000000change_logs: api: CHANGELOG-API.md user: CHANGELOG.md default_change_logs: - user entries_dir: .chloggen template_yaml: .chloggen/TEMPLATE.yaml summary_template: .chloggen/summary.tmpl components: - all - cmd/builder - cmd/mdatagen - connector/forward - connector/sample - consumer/xconsumer - docs/rfcs - exporter/debug - exporter/nop - exporter/otlp - exporter/otlphttp - extension/memory_limiter - extension/xextension - extension/xextension - extension/zpages - pdata/pprofile - pdata/xpdata - pkg/config/configauth - pkg/config/configcompression - pkg/config/configgrpc - pkg/config/confighttp - pkg/config/configmiddleware - pkg/config/confignet - pkg/config/configopaque - pkg/config/configoptional - pkg/config/configretry - pkg/config/configtelemetry - pkg/config/configtls - pkg/confmap - pkg/exporterhelper - pkg/otelcol - pkg/pdata - pkg/processorhelper - pkg/queuebatch - pkg/receiverhelper - pkg/scraper - pkg/scraperhelper - pkg/service - pkg/xconnector - pkg/xexporter - pkg/xexporterhelper - pkg/xprocessor - pkg/xreceiver - pkg/xscraper - processor/batch - processor/memory_limiter - processor/sample - provider/env - provider/file - provider/http - provider/https - provider/yaml - receiver/nop - receiver/otlp - receiver/sample - receiver/sample - scraper/sample - service/graph opentelemetry-collector-0.141.0/.chloggen/summary.tmpl000066400000000000000000000021551511331344600230000ustar00rootroot00000000000000{{- define "entry" -}} - `{{ .Component }}`: {{ .Note }} ( {{- range $i, $issue := .Issues }} {{- if $i }}, {{ end -}} #{{ $issue }} {{- end -}} ) {{- if .SubText }} {{ .SubText | indent 2 }} {{- end }} {{- end }} ## {{ .Version }} {{- if .BreakingChanges }} ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ {{- range $i, $change := .BreakingChanges }} {{- if eq $i 0}} {{end}} {{ template "entry" $change }} {{- end }} {{- end }} {{- if .Deprecations }} ### ๐Ÿšฉ Deprecations ๐Ÿšฉ {{- range $i, $change := .Deprecations }} {{- if eq $i 0}} {{end}} {{ template "entry" $change }} {{- end }} {{- end }} {{- if .NewComponents }} ### ๐Ÿš€ New components ๐Ÿš€ {{- range $i, $change := .NewComponents }} {{- if eq $i 0}} {{end}} {{ template "entry" $change }} {{- end }} {{- end }} {{- if .Enhancements }} ### ๐Ÿ’ก Enhancements ๐Ÿ’ก {{- range $i, $change := .Enhancements }} {{- if eq $i 0}} {{end}} {{ template "entry" $change }} {{- end }} {{- end }} {{- if .BugFixes }} ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ {{- range $i, $change := .BugFixes }} {{- if eq $i 0}} {{end}} {{ template "entry" $change }} {{- end }} {{- end }} opentelemetry-collector-0.141.0/.codecov.yml000066400000000000000000000006231511331344600207620ustar00rootroot00000000000000codecov: branch: main # only use the latest copy on main branch strict_yaml_branch: main coverage: precision: 2 round: down range: "80...100" status: project: default: enabled: yes target: 90% patch: default: enabled: yes target: 95% ignore: - "pdata/internal/data/protogen/**/*" - "**/*.pb.go" - "cmd/mdatagen/third_party/**/*" opentelemetry-collector-0.141.0/.gitattributes000066400000000000000000000005671511331344600214410ustar00rootroot00000000000000# This file is documented at https://git-scm.com/docs/gitattributes. # Linguist-specific attributes are documented at # https://github.com/github/linguist. go.sum linguist-generated=true # Avoid git status and other tools (lint, fmt) reporting whitespace differences # on Windows machines by ensuring that `lf` on text files are not converted to `crlf`. * text=auto eol=lf opentelemetry-collector-0.141.0/.github/000077500000000000000000000000001511331344600200765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/.github/ALLOWLIST000066400000000000000000000012651511331344600213770ustar00rootroot00000000000000# Code generated by githubgen. DO NOT EDIT. ##################################################### # # List of components # waiting on owners to be assigned # ##################################################### # # Learn about CODEOWNERS file format: # https://help.github.com/en/articles/about-code-owners # ## # NOTE: New components MUST have one or more codeowners. Add codeowners to the component metadata.yaml and run make gengithub ## ## COMMON & SHARED components internal/common ## DEPRECATED components # Start deprecated components list # End deprecated components list ## UNMAINTAINED components # Start unmaintained components list # End unmaintained components list opentelemetry-collector-0.141.0/.github/CODEOWNERS000066400000000000000000000126361511331344600215010ustar00rootroot00000000000000# Code generated by githubgen. DO NOT EDIT. ##################################################### # # List of codeowners # ##################################################### # # Learn about CODEOWNERS file format: # https://help.github.com/en/articles/about-code-owners # * @open-telemetry/collector-approvers # Files owned by collector-releases-approvers .github/workflows/prepare-release.yml @open-telemetry/collector-approvers @open-telemetry/collector-releases-approvers .github/workflows/sourcecode-release.yml @open-telemetry/collector-approvers @open-telemetry/collector-releases-approvers .github/workflows/scripts/release-*.sh @open-telemetry/collector-approvers @open-telemetry/collector-releases-approvers # Start components list cmd/builder/ @open-telemetry/collector-approvers cmd/mdatagen/ @open-telemetry/collector-approvers @dmitryax cmd/mdatagen/internal/sampleconnector/ @open-telemetry/collector-approvers cmd/mdatagen/internal/samplefactoryreceiver/ @open-telemetry/collector-approvers @dmitryax cmd/mdatagen/internal/sampleprocessor/ @open-telemetry/collector-approvers cmd/mdatagen/internal/samplereceiver/ @open-telemetry/collector-approvers @dmitryax cmd/mdatagen/internal/samplescraper/ @open-telemetry/collector-approvers @dmitryax confmap/ @open-telemetry/collector-approvers @mx-psi @evan-bradley confmap/provider/envprovider/ @open-telemetry/collector-approvers confmap/provider/fileprovider/ @open-telemetry/collector-approvers confmap/provider/httpprovider/ @open-telemetry/collector-approvers confmap/provider/httpsprovider/ @open-telemetry/collector-approvers confmap/provider/yamlprovider/ @open-telemetry/collector-approvers connector/forwardconnector/ @open-telemetry/collector-approvers connector/xconnector/ @open-telemetry/collector-approvers @mx-psi @dmathieu consumer/xconsumer/ @open-telemetry/collector-approvers @mx-psi @dmathieu docs/rfcs/ @open-telemetry/collector-approvers @codeboten @bogdandrutu @dmitryax @mx-psi exporter/debugexporter/ @open-telemetry/collector-approvers @andrzej-stencel exporter/exporterhelper/ @open-telemetry/collector-approvers @bogdandrutu @dmitryax exporter/exporterhelper/internal/queuebatch/ @open-telemetry/collector-approvers exporter/exporterhelper/xexporterhelper/ @open-telemetry/collector-approvers @mx-psi @dmathieu exporter/nopexporter/ @open-telemetry/collector-approvers @evan-bradley exporter/otlpexporter/ @open-telemetry/collector-approvers exporter/otlphttpexporter/ @open-telemetry/collector-approvers exporter/xexporter/ @open-telemetry/collector-approvers @mx-psi @dmathieu extension/memorylimiterextension/ @open-telemetry/collector-approvers extension/xextension/ @open-telemetry/collector-approvers extension/xextension/storage/ @open-telemetry/collector-approvers @swiatekm extension/zpagesextension/ @open-telemetry/collector-approvers otelcol/ @open-telemetry/collector-approvers pdata/ @open-telemetry/collector-approvers @bogdandrutu @dmitryax pdata/pprofile/ @open-telemetry/collector-approvers @mx-psi @dmathieu pdata/xpdata/ @open-telemetry/collector-approvers processor/batchprocessor/ @open-telemetry/collector-approvers processor/memorylimiterprocessor/ @open-telemetry/collector-approvers processor/processorhelper/ @open-telemetry/collector-approvers processor/xprocessor/ @open-telemetry/collector-approvers @mx-psi @dmathieu receiver/nopreceiver/ @open-telemetry/collector-approvers @evan-bradley receiver/otlpreceiver/ @open-telemetry/collector-approvers receiver/receiverhelper/ @open-telemetry/collector-approvers receiver/xreceiver/ @open-telemetry/collector-approvers @mx-psi @dmathieu scraper/ @open-telemetry/collector-approvers scraper/xscraper @open-telemetry/collector-approvers scraper/scraperhelper/ @open-telemetry/collector-approvers service/ @open-telemetry/collector-approvers service/internal/graph/ @open-telemetry/collector-approvers # End components list ##################################################### # # List of distribution maintainers # ##################################################### # Start distribution list reports/distributions/core.yaml @open-telemetry/collector-approvers reports/distributions/contrib.yaml @open-telemetry/collector-approvers reports/distributions/k8s.yaml @open-telemetry/collector-approvers reports/distributions/otlp.yaml @open-telemetry/collector-approvers # End distribution list ##################################################### # ## UNMAINTAINED components # ##################################################### # Start unmaintained components list # End unmaintained components list opentelemetry-collector-0.141.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001511331344600222615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/.github/ISSUE_TEMPLATE/bug_report.yaml000066400000000000000000000115521511331344600253210ustar00rootroot00000000000000name: Bug report description: Create a report to help us improve labels: ["bug"] body: - type: markdown attributes: value: | Thanks for taking the time to fill out this bug report! Please make sure to fill out the entire form below, providing as much context as you can in order to help us triage and track down your bug as quickly as possible. Before filing a bug, please be sure you have searched through [existing bugs](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Abug) to see if an existing issue covers your bug. - type: dropdown id: component attributes: label: Component(s) description: Which component(s) does your bug report concern? multiple: true options: # NOTE: The list below is autogenerated using `make generate-gh-issue-templates` # Do not manually edit it. # Start components list - cmd/builder - cmd/mdatagen - cmd/mdatagen/internal/sampleconnector - cmd/mdatagen/internal/samplefactoryreceiver - cmd/mdatagen/internal/sampleprocessor - cmd/mdatagen/internal/samplereceiver - cmd/mdatagen/internal/samplescraper - confmap - confmap/provider/envprovider - confmap/provider/fileprovider - confmap/provider/httpprovider - confmap/provider/httpsprovider - confmap/provider/yamlprovider - connector/forward - connector/x - consumer/xconsumer - docs/rfcs - exporter/debug - exporter/exporterhelper - exporter/exporterhelper/internal/queuebatch - exporter/exporterhelper/xexporterhelper - exporter/nop - exporter/otlp - exporter/otlphttp - exporter/x - extension/memorylimiter - extension/x - extension/x/storage - extension/zpages - otelcol - pdata - pdata/pprofile - pdata/xpdata - processor/batch - processor/memorylimiter - processor/processorhelper - processor/x - receiver/nop - receiver/otlp - receiver/receiverhelper - receiver/x - scraper - scraper/scraperhelper - service - service/internal/graph # End components list - type: textarea attributes: label: What happened? description: Please provide as much detail as you reasonably can. value: | **Describe the bug** **Steps to reproduce** **What did you expect to see?** **What did you see instead?** validations: required: true - type: input attributes: label: Collector version description: What version did you use? (e.g., `v0.4.0`, `1eb551b`, etc) validations: required: true - type: textarea attributes: label: Environment information description: Please provide any additional information about your installation. value: | ## Environment OS: (e.g., "Ubuntu 20.04") Compiler(if manually compiled): (e.g., "go 14.2") - type: textarea attributes: label: OpenTelemetry Collector configuration description: Please provide the configuration you are using (e.g. the YAML config file). placeholder: | # Empty Collector config receivers: exporters: processors: extensions: service: pipelines: traces: receivers: [] exporters: [] processors: [] metrics: receivers: [] exporters: [] processors: [] logs: receivers: [] exporters: [] processors: [] render: yaml - type: textarea attributes: label: Log output description: | Please copy and paste any relevant log output. render: shell - type: textarea attributes: label: Additional context description: Any additional information you think may be relevant to this issue. - type: dropdown attributes: label: Tip description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is. options: - [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with ๐Ÿ‘ to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/). default: 0 opentelemetry-collector-0.141.0/.github/ISSUE_TEMPLATE/feature_request.yaml000066400000000000000000000065031511331344600263540ustar00rootroot00000000000000name: Feature request description: Suggest an idea for this project labels: ["feature request"] body: - type: dropdown id: component attributes: label: Component(s) description: Which component(s) does your feature request concern? multiple: true options: # NOTE: The list below is autogenerated using `make generate-gh-issue-templates` # Do not manually edit it. # Start components list - cmd/builder - cmd/mdatagen - cmd/mdatagen/internal/sampleconnector - cmd/mdatagen/internal/samplefactoryreceiver - cmd/mdatagen/internal/sampleprocessor - cmd/mdatagen/internal/samplereceiver - cmd/mdatagen/internal/samplescraper - confmap - confmap/provider/envprovider - confmap/provider/fileprovider - confmap/provider/httpprovider - confmap/provider/httpsprovider - confmap/provider/yamlprovider - connector/forward - connector/x - consumer/xconsumer - docs/rfcs - exporter/debug - exporter/exporterhelper - exporter/exporterhelper/internal/queuebatch - exporter/exporterhelper/xexporterhelper - exporter/nop - exporter/otlp - exporter/otlphttp - exporter/x - extension/memorylimiter - extension/x - extension/x/storage - extension/zpages - otelcol - pdata - pdata/pprofile - pdata/xpdata - processor/batch - processor/memorylimiter - processor/processorhelper - processor/x - receiver/nop - receiver/otlp - receiver/receiverhelper - receiver/x - scraper - scraper/scraperhelper - service - service/internal/graph # End components list - type: textarea attributes: label: Is your feature request related to a problem? Please describe. description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]. We are currently preparing for the upcoming 1.0 GA release. Feature requests that are not aligned with the current roadmap and are not aimed at stabilizing and preparing the Collector for the release will not be prioritized. validations: required: true - type: textarea attributes: label: Describe the solution you'd like description: A clear and concise description of what you want to happen. validations: required: true - type: textarea attributes: label: Describe alternatives you've considered description: A clear and concise description of any alternative solutions or features you've considered. - type: textarea attributes: label: Additional context description: Add any other context or screenshots about the feature request here. - type: dropdown attributes: label: Tip description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is. options: - [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with ๐Ÿ‘ to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/). default: 0 opentelemetry-collector-0.141.0/.github/ISSUE_TEMPLATE/other.yaml000066400000000000000000000050071511331344600242700ustar00rootroot00000000000000name: Other issue description: Create a new issue to help us improve the collector body: - type: dropdown id: component attributes: label: Component(s) description: Which component(s) does your issue concern? multiple: true options: # NOTE: The list below is autogenerated using `make generate-gh-issue-templates` # Do not manually edit it. # Start components list - cmd/builder - cmd/mdatagen - cmd/mdatagen/internal/sampleconnector - cmd/mdatagen/internal/samplefactoryreceiver - cmd/mdatagen/internal/sampleprocessor - cmd/mdatagen/internal/samplereceiver - cmd/mdatagen/internal/samplescraper - confmap - confmap/provider/envprovider - confmap/provider/fileprovider - confmap/provider/httpprovider - confmap/provider/httpsprovider - confmap/provider/yamlprovider - connector/forward - connector/x - consumer/xconsumer - docs/rfcs - exporter/debug - exporter/exporterhelper - exporter/exporterhelper/internal/queuebatch - exporter/exporterhelper/xexporterhelper - exporter/nop - exporter/otlp - exporter/otlphttp - exporter/x - extension/memorylimiter - extension/x - extension/x/storage - extension/zpages - otelcol - pdata - pdata/pprofile - pdata/xpdata - processor/batch - processor/memorylimiter - processor/processorhelper - processor/x - receiver/nop - receiver/otlp - receiver/receiverhelper - receiver/x - scraper - scraper/scraperhelper - service - service/internal/graph # End components list - type: textarea attributes: label: Describe the issue you're reporting description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] validations: required: true - type: dropdown attributes: label: Tip description: This element is static, used to render a helpful sub-heading for end-users and community members to help prioritize issues. Please leave as is. options: - [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with ๐Ÿ‘ to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/). default: 0 opentelemetry-collector-0.141.0/.github/ISSUE_TEMPLATE/stabilization.md000066400000000000000000000030701511331344600254570ustar00rootroot00000000000000--- name: Module stabilization about: Stabilize a module before a 1.0 release title: 'Stabilize module X' labels: 'stabilization' assignees: '' --- Before stabilizing a module, an approver or maintainer must make sure that the following criteria have been met for at least two successive minor version releases (regardless of when this issue was opened): - [ ] No open issues or PRs in the module that would require breaking changes - [ ] No TODOs in the module code that would require breaking changes - [ ] No deprecated symbols in the module - [ ] No symbols marked as experimental in the module - [ ] The module follows the [Coding guidelines](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/coding-guidelines.md) Please also make sure to publicly announce our intent to stabilize the module on: - [ ] The #otel-collector CNCF Slack Channel - [ ] The #opentelemetry CNCF Slack channel - [ ] A Collector SIG meeting (if unable to attend, just add to the agenda) To help other people verify the above criteria, please link to the announcement and other links used to complete the above in a comment on this issue. Once all criteria are met, close this issue by moving this module to the `stable` module set. **Tip**: [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with ๐Ÿ‘ to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/). opentelemetry-collector-0.141.0/.github/ISSUE_TEMPLATE/vote.md000066400000000000000000000053321511331344600235630ustar00rootroot00000000000000--- name: Vote about: Vote to make a decision related to an RFC title: '[Vote] RFC #XXXX:' labels: "rfc:vote-needed" assignees: '' --- A [vote](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/README.md#voting) has been called for RFC #XXXX following the RFC process. ### Stakeholders Any person in the community may vote. Votes of the stakeholders are binding. Stakeholders are encouraged to consider the views from the wider community when casting their vote. As defined in the RFC, there are N stakeholders for this RFC divided as follows: | Stakeholders | As defined on date | Number of people | |-------------------------------------|--------------------|------------------| | @open-telemetry/collector-approvers | yyyy-mm-dd | N | For any stakeholder team, we consider the people that were part of the team at the time the vote is called. ### Voting options | Option | Description | # Votes (stakeholders) | # Votes (total) | |--------|-------------|------------------------|-----------------| | Option 1 | Description of the option | 0 | 0 | ### Result The vote is in progress. A minimum of X votes is required to select an option. ### Vote process Please **leave a comment** with your vote and any additional context you would like to provide. Start your comment with "I vote for **Option N**." and then provide any additional context. ### Related links Include here any links to the RFC, other PRs and resources that help make an informed vote. ### Checklists When starting the vote: - [ ] Announce the vote in the #otel-collector-dev CNCF Slack channel. - [ ] Add an entry to announce the vote in the next Collector SIG meeting. For closing the vote: - [ ] At least five business days have passed since the vote was announced. - [ ] At least one-third of the stakeholders have voted. - [ ] The "Voting options" and "Result" sections have been updated reflecting the votes casted. - [ ] The RFC has been updated reflecting the votes casted. **Tip**: [React](https://github.blog/news-insights/product-news/add-reactions-to-pull-requests-issues-and-comments/) with ๐Ÿ‘ to help prioritize this issue. Please use comments to provide useful context, avoiding `+1` or `me too`, to help us triage it. Learn more [here](https://opentelemetry.io/community/end-user/issue-participation/). opentelemetry-collector-0.141.0/.github/actionlint.yaml000066400000000000000000000046701511331344600231350ustar00rootroot00000000000000self-hosted-runner: labels: [] config-variables: null paths: .github/workflows/**/*.{yml,yaml}: ignore: # SC1070: Suppressing because scripts intentionally contain valid but unusual characters, # Escape characters like `\o` used purposefully, and tested for clarity - '.*shellcheck reported issue in this script: SC1070:.+' # SC1133: ShellCheck suggests optimizing conditional expressions, but these scripts # operate correctly and readability is prioritized in real-world use. This ensures familiarity for contributors. - '.*shellcheck reported issue in this script: SC1133:.+' # SC2086: Ignored because word splitting is intentional in commands like `git diff`, # where simple, predictable paths are passed as arguments. No unintended globbing occurs in this context. - '.*shellcheck reported issue in this script: SC2086:.+' # SC2046: Suppressed because word splitting is desired and necessary in certain scenarios, # PR_HEAD is set by GitHub Actions and paths are fixed/controlled. - '.*shellcheck reported issue in this script: SC2046:.+' # SC2059: Format strings in `printf` are deliberately designed and controlled for specific outputs. # ShellCheckโ€™s safeguard warning is appreciated but not critical in these cases. - '.*shellcheck reported issue in this script: SC2059:.+' # SC2236: Both `! -z` and `-n` achieve the same result, and while `-n` is idiomatic. (Just a style suggestion) # suppressing this warning allows scripts to remain consistent with existing standards. - '.*shellcheck reported issue in this script: SC2236:.+' # SC1001: Escaped characters (like `\o`) are deliberate in certain scripts for expected functionality. # ShellCheckโ€™s flagging of these characters as potential issues isnโ€™t applicable to this use case. - '.*shellcheck reported issue in this script: SC1001:.+' # SC2129: Individual redirections are chosen for simplicity and clarity in the workflows. # combining them is technically efficient, the current approach ensures more readable scripts. - '.*shellcheck reported issue in this script: SC2129:.+' # Runner warnings ignored because scripts are validated against specific configurations # and tested on GitHub Actions, ensuring compatibility. These warnings do not affect functionality. - '.*the runner of ".+" action is too old to run on GitHub Actions.+' opentelemetry-collector-0.141.0/.github/lychee.toml000066400000000000000000000002731511331344600222460ustar00rootroot00000000000000include-fragments = true accept = ["200..=299", "429"] exclude = [ "^http(s)?://localhost", "^http(s)?://example.com" ] # better to be safe and avoid failures max-retries = 6 opentelemetry-collector-0.141.0/.github/pull_request_template.md000066400000000000000000000006611511331344600250420ustar00rootroot00000000000000 #### Description #### Link to tracking issue Fixes # #### Testing #### Documentation opentelemetry-collector-0.141.0/.github/workflows/000077500000000000000000000000001511331344600221335ustar00rootroot00000000000000opentelemetry-collector-0.141.0/.github/workflows/add-labels-and-owners.yml000066400000000000000000000014231511331344600267210ustar00rootroot00000000000000name: 'Add labels and code owners to PR' on: pull_request_target: types: - opened - synchronize - ready_for_review permissions: read-all jobs: add-labels-and-owners: permissions: pull-requests: write runs-on: ubuntu-24.04 if: ${{ github.actor != 'dependabot[bot]' && github.actor != 'renovate[bot]' && github.repository_owner == 'open-telemetry' && github.event.pull_request.draft == false }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run add-codeowners-to-pr.sh run: ./.github/workflows/scripts/add-labels-and-owners.sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: ${{ github.repository }} PR: ${{ github.event.number }} opentelemetry-collector-0.141.0/.github/workflows/add-labels-command.yml000066400000000000000000000013411511331344600262610ustar00rootroot00000000000000name: 'Add Labels' on: issue_comment: types: [created] permissions: read-all jobs: add-labels-command: if: ${{ !github.event.issue.pull_request && startsWith(github.event.comment.body, '/label') && github.repository_owner == 'open-telemetry' }} permissions: issues: write runs-on: ubuntu-24.04 steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run add-labels-command.sh run: ./.github/workflows/scripts/add-labels-command.sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE: ${{ github.event.issue.number }} COMMENT: ${{ github.event.comment.body }} SENDER: ${{ github.event.sender.login }} opentelemetry-collector-0.141.0/.github/workflows/api-compatibility.yml000066400000000000000000000036741511331344600263100ustar00rootroot00000000000000# This GitHub action is used to compare API state snapshots of Main # to Head of the PR in order to validate releases are not breaking # backwards compatibility. # # This GitHub action will fail if there are incompatible changes. # name: "Inform Incompatible PRs" on: pull_request: branches: - main permissions: read-all jobs: Check-Compatibility: runs-on: ubuntu-latest env: BASE_REF: ${{ github.base_ref }} HEAD_REF: ${{ github.head_ref }} steps: - name: Checkout-Main uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ github.base_ref }} path: ${{ github.base_ref }} - name: Checkout-HEAD uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: path: ${{ github.head_ref }} - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} # Generate apidiff states of Main - name: Generate-States run: | cd $BASE_REF make apidiff-build # Compare apidiff states of Main with PR - name: Compare-States env: CI: true COMPARE_OPTS: -d "../${{ github.base_ref }}/internal/data/apidiff" run: | cd $HEAD_REF make apidiff-compare # Fail GitHub Action if there are incompatible changes - name: Check-States env: CI: true COMPARE_OPTS: -d "../${{ github.base_ref }}/internal/data/apidiff" -c run: | cd $HEAD_REF make apidiff-compare opentelemetry-collector-0.141.0/.github/workflows/build-and-test-arm.yml000066400000000000000000000044061511331344600262530ustar00rootroot00000000000000name: build-and-test-arm on: push: branches: [main] tags: - "v[0-9]+.[0-9]+.[0-9]+*" merge_group: types: [checks_requested] pull_request: env: TEST_RESULTS: testbed/tests/results/junit/results.xml # Make sure to exit early if cache segment download times out after 2 minutes. # We limit cache download as a whole to 5 minutes. SEGMENT_DOWNLOAD_TIMEOUT_MINS: 2 permissions: read-all # Do not cancel this workflow on main. See https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/16616 concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true jobs: arm-unittest-matrix: strategy: matrix: os: [ubuntu-22.04-arm, macos-14] if: ${{ github.actor != 'dependabot[bot]' && (contains(github.event.pull_request.labels.*.name, 'Run ARM') || github.event_name == 'push' || github.event_name == 'merge_group') }} runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache timeout-minutes: 5 uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Install dependencies if: steps.go-cache.outputs.cache-hit != 'true' run: make gomoddownload - name: Run Unit Tests run: make -j4 gotest arm-unittest: if: ${{ github.actor != 'dependabot[bot]' && (contains(github.event.pull_request.labels.*.name, 'Run ARM') || github.event_name == 'push' || github.event_name == 'merge_group') }} runs-on: ubuntu-latest needs: [arm-unittest-matrix] steps: - name: Print result run: echo ${{ needs.arm-unittest-matrix.result }} - name: Interpret result run: | if [[ success == ${{ needs.arm-unittest-matrix.result }} ]] then echo "All matrix jobs passed!" else echo "One or more matrix jobs failed." false fi opentelemetry-collector-0.141.0/.github/workflows/build-and-test-windows.yaml000066400000000000000000000057571511331344600273410ustar00rootroot00000000000000name: build-and-test-windows on: push: branches: [main] tags: - "v[0-9]+.[0-9]+.[0-9]+*" merge_group: types: [checks_requested] pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true permissions: read-all jobs: windows-unittest: strategy: fail-fast: false matrix: os: [windows-2022, windows-2025, windows-11-arm] runs-on: ${{ matrix.os }} steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 env: cache-name: cache-go-modules with: path: | ~\go\pkg\mod ~\AppData\Local\go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - name: Ensure required ports in the dynamic range are available run: | & ${{ github.workspace }}\.github\workflows\scripts\win-required-ports.ps1 - name: Run Unit Tests run: make gotest windows-service-test: strategy: fail-fast: false matrix: os: [windows-2022, windows-2025, windows-11-arm] runs-on: ${{ matrix.os }} steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 env: cache-name: cache-go-modules with: path: | ~\go\pkg\mod ~\AppData\Local\go-build key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} - name: Ensure required ports in the dynamic range are available run: | & ${{ github.workspace }}\.github\workflows\scripts\win-required-ports.ps1 - name: Make otelcorecol run: make otelcorecol - name: Install otelcorecol as a service run: | New-Service -Name "otelcorecol" -StartupType "Manual" -BinaryPathName "${PWD}\bin\otelcorecol_windows_$(go env GOARCH) --config ${PWD}\examples\local\otel-config.yaml" eventcreate.exe /t information /id 1 /l application /d "Creating event provider for 'otelcorecol'" /so otelcorecol - name: Test otelcorecol service working-directory: ${{ github.workspace }}/otelcol run: | go test -timeout 90s -run ^TestCollectorAsService$ -v -tags=win32service - name: Remove otelcorecol service if: always() run: | Remove-Service otelcorecol Remove-Item HKLM:\SYSTEM\CurrentControlSet\Services\EventLog\Application\otelcorecol opentelemetry-collector-0.141.0/.github/workflows/build-and-test.yml000066400000000000000000000230671511331344600255020ustar00rootroot00000000000000name: build-and-test on: push: branches: [main] tags: - "v[0-9]+.[0-9]+.[0-9]+*" merge_group: types: [checks_requested] pull_request: permissions: read-all concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true jobs: setup-environment: runs-on: ubuntu-latest steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Install dependencies if: steps.go-cache.outputs.cache-hit != 'true' run: make gomoddownload lint: runs-on: ubuntu-latest needs: [setup-environment] steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: golint run: make -j2 golint - name: goimpi run: make goimpi govulncheck: runs-on: ubuntu-latest timeout-minutes: 30 needs: [setup-environment] steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Run `govulncheck` run: make govulncheck checks: runs-on: ubuntu-latest needs: [setup-environment] steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: stable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: checklicense run: make checklicense - name: misspell run: make misspell - name: checkdoc run: make checkdoc - name: checkapi run: make checkapi - name: Check for go mod dependency changes run: | make gotidy git diff --exit-code || (echo 'go.mod/go.sum deps changes detected, please run "make gotidy" and commit the changes in this PR.' && exit 1) - name: go:porto run: | make goporto git diff --exit-code || (echo 'Porto links are out of date, please run "make goporto" and commit the changes in this PR.' && exit 1) - name: go:generate run: | make gogenerate git diff --exit-code || (echo 'Generated code is out of date, please run "make gogenerate" and commit the changes in this PR.' && exit 1) - name: Generate proto files run: | make genproto git diff --exit-code || (echo 'Generated code is out of date, please run "make genproto" and commit the changes in this PR.' && exit 1) - name: Gen Pdata run: | make genpdata git diff --exit-code || (echo 'Generated code is out of date, please run "make genpdata" and commit the changes in this PR.' && exit 1) - name: Gen otelcorecol run: | make genotelcorecol git diff --exit-code || (echo 'Generated code is out of date, please run "make genotelcorecol" and commit the changes in this PR.' && exit 1) - name: Multimod verify run: make multimod-verify - name: crosslink run: | make crosslink git diff -s --exit-code || (echo 'Replace statements are out of date, please run "make crosslink" and commit the changes in this PR.' && exit 1) unittest-matrix: strategy: matrix: runner: [ubuntu-latest] go-version: ["stable", "oldstable"] runs-on: ${{ matrix.runner }} needs: [setup-environment] steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: ${{ matrix.go-version }} cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Cache Build uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.cache/go-build key: unittest-${{ runner.os }}-${{ matrix.runner }}-go-build-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }} - name: Run Unit Tests run: | make -j4 gotest-with-junit - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: test-results-${{ runner.os }}-${{ matrix.runner }}-${{ matrix.go-version }} path: internal/tools/testresults/ retention-days: 4 unittest: if: always() runs-on: ubuntu-latest needs: [setup-environment, unittest-matrix] steps: - name: Print result run: echo ${{ needs.unittest-matrix.result }} - name: Interpret result run: | if [[ success == ${{ needs.unittest-matrix.result }} ]] then echo "All matrix jobs passed!" else echo "One or more matrix jobs failed." false fi test-coverage: runs-on: ubuntu-latest needs: [setup-environment] steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Cache Build uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.cache/go-build key: coverage-${{ runner.os }}-go-build-${{ hashFiles('**/go.sum') }} - name: Run Unit Tests With Coverage run: make gotest-with-cover - name: Upload coverage report uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # 5.5.1 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} cross-build-collector: needs: [setup-environment] runs-on: ubuntu-latest timeout-minutes: 10 strategy: fail-fast: false matrix: include: # Go 1.15 dropped support for 32-bit binaries # on macOS: https://go.dev/doc/go1.15 #- goos: darwin # goarch: 386 - goos: aix goarch: ppc64 - goos: darwin goarch: amd64 - goos: darwin goarch: arm64 - goos: linux goarch: 386 - goos: linux goarch: amd64 - goos: linux goarch: arm64 - goos: linux goarch: ppc64le - goos: linux goarch: riscv64 - goos: linux goarch: arm goarm: 7 - goos: linux goarch: s390x - goos: windows goarch: 386 - goos: windows goarch: amd64 - goos: windows goarch: arm64 steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Build env: GOOS: ${{matrix.goos}} GOARCH: ${{matrix.goarch}} GOARM: ${{matrix.goarm}} run: | make otelcorecol opentelemetry-collector-0.141.0/.github/workflows/builder-integration-test.yaml000066400000000000000000000022551511331344600277470ustar00rootroot00000000000000name: Builder - Integration tests on: # on changes to the main branch touching the builder push: branches: [main] # on PRs touching the builder pull_request: branches: [main] # once a day at 6:17 AM UTC schedule: - cron: "17 6 * * *" # manual execution workflow_dispatch: merge_group: types: [checks_requested] concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true permissions: read-all jobs: integration-test: name: Integration test runs-on: ubuntu-latest steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Test run: make builder-integration-test opentelemetry-collector-0.141.0/.github/workflows/builder-snapshot.yaml000066400000000000000000000065101511331344600263040ustar00rootroot00000000000000name: Builder - Snapshot build on: push: branches: [main] # on PRs touching the builder pull_request: branches: [main] paths: - "cmd/builder/**" permissions: contents: read env: # renovate: datasource=github-tags depName=goreleaser-pro packageName=goreleaser/goreleaser-pro GORELEASER_PRO_VERSION: v2.11.1 jobs: snapshot: runs-on: ubuntu-24.04 if: ${{ github.repository_owner == 'open-telemetry' }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: path: .core - name: Pull the latest releases repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: path: opentelemetry-collector-releases repository: open-telemetry/opentelemetry-collector-releases - name: Copy release files run: cp -R ./opentelemetry-collector-releases/cmd/builder/. ./.core/cmd/builder/ - uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - uses: anchore/sbom-action/download-syft@fbfd9c6c189226748411491745178e0c2017392d # v0.20.10 - uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0 with: platforms: amd64, arm64,ppc64le - uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: stable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Check GoReleaser uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 with: distribution: goreleaser-pro version: ${{ env.GORELEASER_PRO_VERSION }} args: check --verbose -f .core/cmd/builder/.goreleaser.yaml env: GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Run GoReleaser uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6.4.0 with: distribution: goreleaser-pro version: ${{ env.GORELEASER_PRO_VERSION }} args: --snapshot --clean -f .core/cmd/builder/.goreleaser.yaml --skip sign env: GORELEASER_KEY: ${{ secrets.GORELEASER_KEY }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} COSIGN_YES: false # Only create an issue if the workflows fails on push to main branch - name: File an issue if the workflow failed if: failure() && github.ref == 'refs/heads/main' run: | template=$(cat <<'END' [Link to job log](%s) END ) job_url="$(gh run view ${{ github.run_id }} -R ${{ github.repository }} --json jobs -q '.jobs[] | select(.name == "snapshot") | .url')" body="$(printf "$template" "$job_url")" gh issue create -R ${{ github.repository }} -t 'OCB snapshot workflow failed' -b "$body" -l 'ci-cd' -l 'area:builder' env: GH_TOKEN: ${{ github.token }} opentelemetry-collector-0.141.0/.github/workflows/changelog.yml000066400000000000000000000076601511331344600246160ustar00rootroot00000000000000# This action requires that any PR targeting the main branch should touch at # least one CHANGELOG file. If a CHANGELOG entry is not required, add the "Skip # Changelog" label to disable this action. name: changelog on: pull_request: types: [opened, ready_for_review, synchronize, reopened, labeled, unlabeled, edited] branches: - main merge_group: types: [checks_requested] concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true permissions: read-all jobs: changelog: runs-on: ubuntu-latest if: ${{ github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'dependencies') && !contains(github.event.pull_request.labels.*.name, 'Skip Changelog') && !contains(github.event.pull_request.title, '[chore]') }} env: PR_HEAD: ${{ github.event.pull_request.head.sha }} steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Ensure no changes to the CHANGELOG.md or CHANGELOG-API.md run: | if [[ $(git diff --name-only $(git merge-base origin/main $PR_HEAD) $PR_HEAD ./CHANGELOG*.md) ]] then echo "CHANGELOG.md and CHANGELOG-API.md should not be directly modified." echo "Please add a .yaml file to the ./.chloggen/ directory." echo "See CONTRIBUTING.md for more details." echo "Alternately, add either \"[chore]\" to the title of the pull request or add the \"Skip Changelog\" label if this job should be skipped." false else echo "CHANGELOG.md and CHANGELOG-API.md were not modified." fi - name: Ensure changelog config.yaml is up to date run: | make generate-chloggen-components if [[ $(git diff --name-only) ]]; then echo ".chloggen/config.yaml is out of date. Please run 'make generate-chloggen-components' and commit the changes." false else echo ".chloggen/config.yaml is up to date." fi git checkout $PR_HEAD -- ./.chloggen/config.yaml - name: Ensure ./.chloggen/*.yaml addition(s) run: | if [[ 1 -gt $(git diff --diff-filter=A --name-only $(git merge-base origin/main $PR_HEAD) $PR_HEAD ./.chloggen | grep -c \\.yaml) ]] then echo "No changelog entry was added to the ./.chloggen/ directory." echo "Please add a .yaml file to the ./.chloggen/ directory." echo "See CONTRIBUTING.md for more details." echo "Alternately, add either \"[chore]\" to the title of the pull request or add the \"Skip Changelog\" label if this job should be skipped." false else echo "A changelog entry was added to the ./.chloggen/ directory." fi - name: Validate ./.chloggen/*.yaml changes run: | make chlog-validate \ || { echo "New ./.chloggen/*.yaml file failed validation."; exit 1; } # In order to validate any links in the yaml file, render the config to markdown - name: Render .chloggen changelog entries run: make chlog-preview > changelog_preview.md - name: Link Checker id: lychee uses: lycheeverse/lychee-action@a8c4c7cb88f0c7386610c35eb25108e448569cb0 # v2.7.0 with: args: "--verbose --no-progress ./changelog_preview.md --config .github/lychee.toml" failIfEmpty: false opentelemetry-collector-0.141.0/.github/workflows/check-codeowners.yaml000066400000000000000000000043411511331344600262440ustar00rootroot00000000000000name: codeowners on: push: branches: [main] paths: - ".github/CODEOWNERS" - "**/metadata.yaml" tags: - "v[0-9]+.[0-9]+.[0-9]+*" pull_request_target: paths: - ".github/CODEOWNERS" - "**/metadata.yaml" types: - opened - synchronize - edited - reopened env: # Make sure to exit early if cache segment download times out after 2 minutes. # We limit cache download as a whole to 5 minutes. SEGMENT_DOWNLOAD_TIMEOUT_MINS: 2 # Do not cancel this workflow on main. See https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/16616 concurrency: group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} cancel-in-progress: true permissions: read-all jobs: check-codeowners: timeout-minutes: 30 runs-on: ubuntu-24.04 if: ${{ github.actor != 'dependabot[bot]' && github.repository == 'open-telemetry/opentelemetry-collector' }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 id: go-setup with: go-version: oldstable cache-dependency-path: "**/*.sum" - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 with: ref: ${{github.event.pull_request.head.ref}} repository: ${{github.event.pull_request.head.repo.full_name}} path: pr - uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0 id: otelbot-token with: app-id: ${{ vars.OTELBOT_APP_ID }} private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }} # NOTE: the make command below intentionally uses the Makefile from the # target branch, and not the PR checkout, since it runs with the # pull_request_target event and has elevated permissions. - name: Gen CODEOWNERS run: | GITHUB_TOKEN=${{ steps.otelbot-token.outputs.token }} GITHUBGEN_ARGS="-folder=./pr" make generate-codeowners git diff -s --exit-code || (echo 'Generated code is out of date, please run "make generate-codeowners" or apply this diff and commit the changes in this PR.' && git diff && exit 1) opentelemetry-collector-0.141.0/.github/workflows/check-links.yaml000066400000000000000000000030441511331344600252130ustar00rootroot00000000000000name: check-links on: push: branches: [main] pull_request: merge_group: types: [checks_requested] concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true permissions: read-all jobs: changedfiles: name: changed files runs-on: ubuntu-latest env: PR_HEAD: ${{ github.event.pull_request.head.sha }} outputs: files: ${{ steps.changes.outputs.files }} steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - name: Get changed files id: changes run: | files=$(git diff --name-only --diff-filter=ACMRTUXB $(git merge-base origin/main $PR_HEAD) $PR_HEAD | grep .md$ | xargs) if [ -z "$files" ] && git diff --name-only $(git merge-base origin/main $PR_HEAD) $PR_HEAD | grep -q "package.json"; then files="**/*.md" fi echo "files=$files" >> $GITHUB_OUTPUT check-links: runs-on: ubuntu-latest needs: changedfiles if: ${{needs.changedfiles.outputs.files}} steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - name: Link Checker id: lychee uses: lycheeverse/lychee-action@a8c4c7cb88f0c7386610c35eb25108e448569cb0 # v2.7.0 with: args: "--verbose --no-progress ${{needs.changedfiles.outputs.files}} --config .github/lychee.toml" failIfEmpty: false opentelemetry-collector-0.141.0/.github/workflows/check-merge-freeze.yml000066400000000000000000000020331511331344600263040ustar00rootroot00000000000000name: Merge freeze on: pull_request: types: [ opened, ready_for_review, synchronize, reopened, labeled, unlabeled, enqueued, ] branches: [main] merge_group: types: [checks_requested] permissions: read-all jobs: check-merge-freeze: name: Check # This condition is to avoid blocking the PR causing the freeze in the first place. if: | (!startsWith(github.event.pull_request.title || github.event.merge_group.head_commit.message, '[chore] Prepare release')) || ((github.event.pull_request.user.login || github.event.merge_group.head_commit.author.name) != 'otelbot[bot]') runs-on: ubuntu-latest steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: sparse-checkout: .github/workflows/scripts - run: ./.github/workflows/scripts/check-merge-freeze.sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: open-telemetry/opentelemetry-collector opentelemetry-collector-0.141.0/.github/workflows/codeql-analysis.yml000066400000000000000000000030061511331344600257450ustar00rootroot00000000000000name: "CodeQL Analysis" on: push: branches: [main] pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true permissions: read-all jobs: CodeQL-Build: permissions: actions: read # for github/codeql-action/init to get workflow details contents: read # for actions/checkout to fetch code security-events: write # for github/codeql-action/autobuild to send a status report runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 with: languages: go - name: Autobuild uses: github/codeql-action/autobuild@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 opentelemetry-collector-0.141.0/.github/workflows/contrib-tests.yml000066400000000000000000000061261511331344600254630ustar00rootroot00000000000000name: contrib-tests on: push: branches: [main] tags: - v[0-9]+.[0-9]+.[0-9]+.* pull_request: types: [opened, ready_for_review, synchronize, reopened, labeled, unlabeled] branches: [main] merge_group: types: [checks_requested] concurrency: group: ${{ github.workflow }}-${{ github.ref_name }} cancel-in-progress: true permissions: read-all jobs: contrib-tests-prepare: runs-on: ubuntu-latest if: ${{ !contains(github.event.pull_request.labels.*.name, 'Skip Contrib Tests') }} steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Prepare Contrib Tests run: | contrib_path=/tmp/opentelemetry-collector-contrib git clone --depth=1 https://github.com/open-telemetry/opentelemetry-collector-contrib.git $contrib_path make CONTRIB_PATH=$contrib_path prepare-contrib - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: contrib path: /tmp/opentelemetry-collector-contrib/ include-hidden-files: true contrib-tests-matrix: runs-on: ubuntu-latest needs: [contrib-tests-prepare] if: ${{ !contains(github.event.pull_request.labels.*.name, 'Skip Contrib Tests') }} strategy: fail-fast: false matrix: group: - receiver-0 - receiver-1 - receiver-2 - receiver-3 - processor - exporter-0 - exporter-1 - extension - connector - internal - pkg - cmd-0 - other steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Download contrib uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 with: name: contrib path: /tmp/contrib - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Run tests run: | chmod +x /tmp/contrib/.tools/* make CONTRIB_PATH=/tmp/contrib SKIP_RESTORE_CONTRIB=true GROUP=${{ matrix.group }} check-contrib contrib_tests: runs-on: ubuntu-latest if: ${{ !contains(github.event.pull_request.labels.*.name, 'Skip Contrib Tests') }} needs: [contrib-tests-matrix] steps: - name: Print result run: echo ${{ needs.contrib-tests-matrix.result }} - name: Interpret result run: | if [[ success == ${{ needs.contrib-tests-matrix.result }} ]] then echo "All matrix jobs passed!" else echo "One or more matrix jobs failed." false fi opentelemetry-collector-0.141.0/.github/workflows/fossa.yml000066400000000000000000000006221511331344600237710ustar00rootroot00000000000000name: FOSSA scanning on: push: branches: - main permissions: contents: read jobs: fossa: runs-on: ubuntu-latest steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - uses: fossas/fossa-action@3ebcea1862c6ffbd5cf1b4d0bd6b3fe7bd6f2cac # v1.7.0 with: api-key: ${{secrets.FOSSA_API_KEY}} team: OpenTelemetry opentelemetry-collector-0.141.0/.github/workflows/go-benchmarks.yml000066400000000000000000000021361511331344600254000ustar00rootroot00000000000000name: CodSpeed Benchmarks on: push: branches: - "main" pull_request: workflow_dispatch: jobs: benchmarks: name: Run benchmarks runs-on: ubuntu-latest steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - run: ./.github/workflows/scripts/free-disk-space.sh - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: stable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Run the benchmarks uses: CodSpeedHQ/action@346a2d8a8d9d38909abd0bc3d23f773110f076ad # v4.4.1 with: mode: walltime run: make for-all-target TARGET="timebenchmark" cache-instruments: false opentelemetry-collector-0.141.0/.github/workflows/lint-workflow-files.yml000066400000000000000000000022751511331344600266020ustar00rootroot00000000000000name: Lint GitHub Workflow YAML Files on: push: branches: - main pull_request: paths: - '.github/workflows/*.yml' - '.github/workflows/*.yaml' - '.github/actionlint.yaml' permissions: contents: read jobs: lint: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Set up Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6 with: go-version: stable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Run Actionlint run: | make actionlint - name: Reminder to Address Linting Errors if: failure() run: echo "โš ๏ธ Please address all linting errors before merging this pull request." - name: All linting checks passed if: success() run: echo "โœ… All linting checks passed." opentelemetry-collector-0.141.0/.github/workflows/milestone-add-to-pr.yml000066400000000000000000000020701511331344600264410ustar00rootroot00000000000000# This action adds the "next release" milestone to a pull request # when it is merged name: "Project: Add PR to Milestone" on: pull_request_target: types: - closed permissions: read-all jobs: update-pr: if: github.event.pull_request.merged runs-on: ubuntu-latest permissions: pull-requests: write steps: - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | const milestones = await github.rest.issues.listMilestones({ owner: context.repo.owner, repo: context.repo.repo, state: "open" }) for (const milestone of milestones.data) { if (milestone.title == "next release") { await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, milestone: milestone.number }); return } } opentelemetry-collector-0.141.0/.github/workflows/perf.yml000066400000000000000000000022441511331344600236140ustar00rootroot00000000000000name: Automation - Performance on: push: branches: [main] permissions: read-all jobs: runperf: runs-on: ubuntu-latest steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Run benchmark run: make gobenchmark # Disabling until fine-grained permissions token enabled for the # repository #- name: Store benchmark result # uses: benchmark-action/github-action-benchmark@v1 # with: # tool: 'go' # output-file-path: benchmarks.txt # gh-pages-branch: gh-pages # auto-push: true # github-token: ${{ secrets.GITHUB_TOKEN }} # benchmark-data-dir-path: "docs/dev/bench" opentelemetry-collector-0.141.0/.github/workflows/ping-codeowners-issues.yml000066400000000000000000000011401511331344600272660ustar00rootroot00000000000000name: 'Ping code owners on issues' on: issues: types: [labeled] permissions: read-all jobs: ping-owners: permissions: issues: write runs-on: ubuntu-24.04 if: ${{ github.repository_owner == 'open-telemetry' }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run ping-codeowners-issues.sh run: ./.github/workflows/scripts/ping-codeowners-issues.sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE: ${{ github.event.issue.number }} COMPONENT: ${{ github.event.label.name }} opentelemetry-collector-0.141.0/.github/workflows/ping-codeowners-on-new-issue.yml000066400000000000000000000013401511331344600303060ustar00rootroot00000000000000name: 'Ping code owners on a new issue' on: issues: types: [opened] permissions: read-all jobs: ping-owners-on-new-issue: permissions: issues: write runs-on: ubuntu-24.04 if: ${{ github.repository_owner == 'open-telemetry' }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run ping-codeowners-on-new-issue.sh run: ./.github/workflows/scripts/ping-codeowners-on-new-issue.sh env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ISSUE: ${{ github.event.issue.number }} TITLE: ${{ github.event.issue.title }} BODY: ${{ github.event.issue.body }} OPENER: ${{ github.event.issue.user.login }} opentelemetry-collector-0.141.0/.github/workflows/ping-codeowners-prs.yml000066400000000000000000000015341511331344600265660ustar00rootroot00000000000000name: 'Ping code owners on PRs' on: pull_request_target: types: - labeled - ready_for_review permissions: read-all jobs: ping-owners: permissions: pull-requests: write runs-on: ubuntu-24.04 if: ${{ github.actor != 'dependabot[bot]' && github.actor != 'renovate[bot]' && github.repository_owner == 'open-telemetry' && github.event.pull_request.draft == false }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run ping-codeowners-prs.sh run: ./.github/workflows/scripts/ping-codeowners-prs.sh env: REPO: ${{ github.repository }} AUTHOR: ${{ github.event.pull_request.user.login }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR: ${{ github.event.number }} COMPONENT: ${{ github.event.label.name }} opentelemetry-collector-0.141.0/.github/workflows/prepare-release.yml000066400000000000000000000147521511331344600257430ustar00rootroot00000000000000name: Automation - Prepare Release on: workflow_dispatch: # Determine the version number that will be assigned to the release. During the beta phase, we increment # the minor version number and set the patch number to 0. inputs: candidate-stable: description: Release candidate version (stable, like 1.3.0). Don't include a leading `v`. current-stable: required: true description: Current version (stable, like 1.2.0). Don't include a leading `v`. candidate-beta: description: Release candidate version (beta, like 0.96.0). Don't include `v`. current-beta: required: true description: Current version (beta, like 0.95.1). Don't include `v`. permissions: read-all jobs: validate-versions-format: runs-on: ubuntu-latest steps: - name: Validate version format shell: bash run: | validate_beta_version() { local regex_pattern_beta='^[0-9]+\.[0-9]+\.[0-9]+$' if [[ ! "$1" =~ $regex_pattern_beta ]]; then echo "Invalid $2 version format. For beta, it can be 0.1.0 or higher" exit 1 fi } validate_stable_version() { local regex_pattern_stable='^[1-9][0-9]*\.[0-9]+\.[0-9]+$' if [[ ! "$1" =~ $regex_pattern_stable ]]; then echo "Invalid stable version format for $2. Major version must be greater than 1." exit 1 fi } if [[ ! -z "${{ inputs.candidate-beta }}" ]]; then validate_beta_version "${{ inputs.candidate-beta }}" "candidate-beta" fi validate_beta_version "${{ inputs.current-beta }}" "current-beta" if [[ ! -z "${{ inputs.candidate-stable }}" ]]; then validate_stable_version "${{ inputs.candidate-stable }}" "candidate-stable" fi validate_stable_version "${{ inputs.current-stable }}" "current-stable" if [[ -z "${{ inputs.candidate-beta }}" && -z "${{ inputs.candidate-stable }}" ]]; then echo "Candidate version is not set for beta or stable. Please set a version to proceed." exit 1 fi check-blockers: needs: - validate-versions-format runs-on: ubuntu-latest steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 # Make sure that there are no open issues with release:blocker label in Core. The release has to be delayed until they are resolved. - name: Check blockers in core env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: open-telemetry/opentelemetry-collector run: ./.github/workflows/scripts/release-check-blockers.sh # Make sure that there are no open issues with release:blocker label in Contrib. The release has to be delayed until they are resolved. - name: Check blockers in contrib env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: open-telemetry/opentelemetry-collector-contrib run: ./.github/workflows/scripts/release-check-blockers.sh # Make sure the current main branch build successfully passes (Core). - name: Check build status in core env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: open-telemetry/opentelemetry-collector run: ./.github/workflows/scripts/release-check-build-status.sh # Make sure the current main branch build successfully passes (Contrib). - name: Check build status in contrib env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} REPO: open-telemetry/opentelemetry-collector-contrib run: ./.github/workflows/scripts/release-check-build-status.sh create-release-issue: needs: - check-blockers runs-on: ubuntu-latest permissions: issues: write steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 # To keep track of the progress, it might be helpful to create a tracking issue similar to #6067. You are responsible # for all of the steps under the "Performed by collector release manager" heading. Once the issue is created, you can # create the individual ones by hovering them and clicking the "Convert to issue" button on the right hand side. - name: Create issue for tracking release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} CANDIDATE_BETA: ${{ inputs.candidate-beta }} CANDIDATE_STABLE: ${{ inputs.candidate-stable }} CURRENT_BETA: ${{ inputs.current-beta }} CURRENT_STABLE: ${{ inputs.current-stable }} REPO: open-telemetry/opentelemetry-collector run: ./.github/workflows/scripts/release-create-tracking-issue.sh # Releasing opentelemetry-collector prepare-release: needs: - check-blockers runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: stable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0 id: otelbot-token with: app-id: ${{ vars.OTELBOT_APP_ID }} private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }} # Prepare Core for release. # - Update CHANGELOG.md file, this is done via chloggen # - Run make prepare-release PREVIOUS_VERSION=1.0.0 RELEASE_CANDIDATE=1.1.0 MODSET=stable # - Run make prepare-release PREVIOUS_VERSION=0.52.0 RELEASE_CANDIDATE=0.53.0 MODSET=beta - name: Prepare release for core env: GITHUB_TOKEN: ${{ steps.otelbot-token.outputs.token }} REPO: open-telemetry/opentelemetry-collector CANDIDATE_BETA: ${{ inputs.candidate-beta }} CANDIDATE_STABLE: ${{ inputs.candidate-stable }} CURRENT_BETA: ${{ inputs.current-beta }} CURRENT_STABLE: ${{ inputs.current-stable }} run: ./.github/workflows/scripts/release-prepare-release.sh opentelemetry-collector-0.141.0/.github/workflows/release-branch.yml000066400000000000000000000027241511331344600255360ustar00rootroot00000000000000name: Automation - Release Branch on: push: tags: # Trigger on beta version tags (0.x.x series) to create release branch # This pattern matches: v0.{minor}.{patch} for new releases and bugfix releases - 'v0.[0-9]+.[0-9]+' - 'v0.[0-9]+.[0-9]+-*' # Also support release candidates if needed permissions: contents: read jobs: release-branch: runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout repository uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 - name: Setup Go uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Setup Git config run: | git config --global user.name "otelbot" git config --global user.email "197425009+otelbot@users.noreply.github.com" - name: Run release-branch.sh run: | ./.github/workflows/scripts/release-branch.sh env: UPSTREAM_REMOTE_NAME: "origin" MAIN_BRANCH_NAME: "main" GITHUB_REF: ${{ github.ref }} opentelemetry-collector-0.141.0/.github/workflows/scorecard.yml000066400000000000000000000053421511331344600246270ustar00rootroot00000000000000name: Scorecard supply-chain security on: # For Branch-Protection check. Only the default branch is supported. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection branch_protection_rule: # To guarantee Maintained check is occasionally updated. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained schedule: - cron: '39 1 * * 3' push: branches: [ "main" ] # Declare default permissions as read only. permissions: read-all jobs: analysis: name: Scorecard analysis runs-on: ubuntu-latest permissions: # Needed to upload the results to code-scanning dashboard. security-events: write # Needed to publish results and get a badge (see publish_results below). id-token: write # Uncomment the permissions below if installing in a private repository. # contents: read # actions: read steps: - name: "Checkout code" uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 with: results_file: results.sarif results_format: sarif # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: # - you want to enable the Branch-Protection check on a *public* repository, or # - you are installing Scorecard on a *private* repository # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. # repo_token: ${{ secrets.SCORECARD_TOKEN }} # Public repositories: # - Publish results to OpenSSF REST API for easy access by consumers # - Allows the repository to include the Scorecard badge. # - See https://github.com/ossf/scorecard-action#publishing-results. # For private repositories: # - `publish_results` will always be set to `false`, regardless # of the value entered here. publish_results: true # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 with: name: SARIF file path: results.sarif retention-days: 5 # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@fdbfb4d2750291e159f0156def62b853c2798ca2 # v4.31.5 with: sarif_file: results.sarif opentelemetry-collector-0.141.0/.github/workflows/scripts/000077500000000000000000000000001511331344600236225ustar00rootroot00000000000000opentelemetry-collector-0.141.0/.github/workflows/scripts/add-labels-and-owners.sh000077500000000000000000000143641511331344600302340ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # # Adds code owners without write access as reviewers on a PR. Note that # the code owners must still be a member of the `open-telemetry` # organization. # # Note that since this script is considered a requirement for PRs, # it should never fail. set -euo pipefail if [[ -z "${REPO:-}" || -z "${PR:-}" ]]; then echo "One or more of REPO and PR have not been set, please ensure each is set." exit 0 fi main () { CUR_DIRECTORY=$(dirname "$0") # Reviews may have comments that need to be cleaned up for jq, # so restrict output to only printable characters and ensure escape # sequences are removed. # The latestReviews key only returns the latest review for each reviewer, # cutting out any other reviews. We use that instead of requestedReviews # since we need to get the list of users eligible for requesting another # review. The GitHub CLI does not offer a list of all reviewers, which # is only available through the API. To cut down on API calls to GitHub, # we use the latest reviews to determine which users to filter out. JSON=$(gh pr view "${PR}" --json "files,author,latestReviews" | LC_ALL=C tr -dc '[:print:]' | sed -E 's/\\[a-z]//g') AUTHOR=$(echo -n "${JSON}"| jq -r '.author.login') FILES=$(echo -n "${JSON}"| jq -r '.files[].path') REVIEW_LOGINS=$(echo -n "${JSON}"| jq -r '.latestReviews[].author.login') COMPONENTS=$(bash "${CUR_DIRECTORY}/get-components.sh") REVIEWERS="" LABELS="" declare -A PROCESSED_COMPONENTS declare -A REVIEWED for REVIEWER in ${REVIEW_LOGINS}; do # GitHub adds "app/" in front of user logins. The API docs don't make # it clear what this means or whether it will always be present. The # '/' character isn't a valid character for usernames, so this won't # replace characters within a username. REVIEWED["@${REVIEWER//app\//}"]=true done if [[ -v REVIEWED[@] ]]; then echo "Users that have already reviewed this PR and will not have another review requested:" "${!REVIEWED[@]}" else echo "This PR has not yet been reviewed, all code owners are eligible for a review request" fi RISKY_REGEX=' ^.github/workflows/prepare-release.yml$ |^.github/workflows/scripts/release-prepare-release.sh$ |^Makefile$ |^Makefile.Common$ ' RISKY_REGEX="$(echo "$RISKY_REGEX" | tr -d ' \n')" RISKY_FILES="$(echo "$FILES" | grep -E "$RISKY_REGEX")" if [[ -n "${RISKY_FILES}" ]]; then echo "This PR may affect the release process, as it touches the following files:" \ "$(echo "$RISKY_FILES" | sed -E 's/\n/, /')" LABELS="release:risky-change" else echo "This PR does not have release-affecting changes." fi for COMPONENT in ${COMPONENTS}; do # Files will be in alphabetical order and there are many files to # a component, so loop through files in an inner loop. This allows # us to remove all files for a component from the list so they # won't be checked against the remaining components in the components # list. This provides a meaningful speedup in practice. for FILE in ${FILES}; do MATCH=$(echo -n "${FILE}" | grep -E "^${COMPONENT}" || true) if [[ -z "${MATCH}" ]]; then continue fi # If we match a file with a component we don't need to process the file again. FILES=$(echo -n "${FILES}" | grep -v "${FILE}") if [[ -v PROCESSED_COMPONENTS["${COMPONENT}"] ]]; then continue fi PROCESSED_COMPONENTS["${COMPONENT}"]=true OWNERS=$(COMPONENT="${COMPONENT}" bash "${CUR_DIRECTORY}/get-codeowners.sh") for OWNER in ${OWNERS}; do # Users that leave reviews are removed from the "requested reviewers" # list and are eligible to have another review requested. We only want # to request a review once, so remove them from the list. if [[ -v REVIEWED["${OWNER}"] || "${OWNER}" = "@${AUTHOR}" ]]; then continue fi if [[ -n "${REVIEWERS}" ]]; then REVIEWERS+="," fi REVIEWERS+=$(echo -n "${OWNER}" | sed -E 's/@(.+)/"\1"/') done # Convert the CODEOWNERS entry to a label COMPONENT_NAME=$(echo -n "${COMPONENT}" | sed -E 's%^(.+)/(.+)\1%\1/\2%') if (( "${#COMPONENT_NAME}" > 50 )); then echo "'${COMPONENT_NAME}' exceeds GitHub's 50-character limit on labels, skipping adding label" continue fi if [[ -n "${LABELS}" ]]; then LABELS+="," fi LABELS+="${COMPONENT_NAME}" done done if [[ -n "${LABELS}" ]]; then echo "Adding labels: ${LABELS}" gh pr edit "${PR}" --add-label "${LABELS}" || echo "Failed to add labels" else echo "No labels found" fi # Note that adding the labels above will not trigger any other workflows to # add code owners, so we have to do it here. # # We have to use the GitHub API directly due to an issue with how the CLI # handles PR updates that causes it require access to organization teams, # and the GitHub token doesn't provide that permission. # For more: https://github.com/cli/cli/issues/4844 # # The GitHub API validates that authors are not requested to review, but # accepts duplicate logins and logins that are already reviewers. if [[ -n "${REVIEWERS}" ]]; then echo "Requesting review from ${REVIEWERS}" curl \ -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ "https://api.github.com/repos/${REPO}/pulls/${PR}/requested_reviewers" \ -d "{\"reviewers\":[${REVIEWERS}]}" \ | jq ".message" \ || echo "jq was unable to parse GitHub's response" else echo "No code owners found" fi } # We don't want this workflow to ever fail and block a PR, # so ensure all errors are caught. main || echo "Failed to run $0" opentelemetry-collector-0.141.0/.github/workflows/scripts/add-labels-command.sh000077500000000000000000000047401511331344600275720ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # # set -euo pipefail if [[ -z "${ISSUE:-}" || -z "${COMMENT:-}" || -z "${SENDER:-}" ]]; then echo "At least one of ISSUE, COMMENT, or SENDER has not been set, please ensure each is set." exit 0 fi CUR_DIRECTORY=$(dirname "$0") if [[ ${COMMENT:0:6} != "/label" ]]; then echo "Comment is not a label comment, exiting." exit 0 fi # key: label in comment # value: actual label declare -A COMMON_LABELS COMMON_LABELS["arm64"]="arm64" COMMON_LABELS["good-first-issue"]="good first issue" COMMON_LABELS["help-wanted"]="help wanted" COMMON_LABELS["discussion-needed"]="discussion-needed" COMMON_LABELS["os:macos"]="os:macos" COMMON_LABELS["os:windows"]="os:windows" COMMON_LABELS["waiting-for-author"]="waiting-for-author" COMMON_LABELS["waiting-for-codeowners"]="waiting-for-codeowners" COMMON_LABELS["bug"]="bug" COMMON_LABELS["priority:p0"]="priority:p0" COMMON_LABELS["priority:p1"]="priority:p1" COMMON_LABELS["priority:p2"]="priority:p2" COMMON_LABELS["priority:p3"]="priority:p3" COMMON_LABELS["stale"]="Stale" LABELS=$(echo "${COMMENT}" | sed -E 's%^/label%%') for LABEL_REQ in ${LABELS}; do LABEL=$(echo "${LABEL_REQ}" | sed -E s/^[+-]?//) # Trim newlines from label that would cause matching to fail LABEL=$(echo "${LABEL}" | tr -d '\n') SHOULD_ADD=true if [[ "${LABEL_REQ:0:1}" = "-" ]]; then SHOULD_ADD=false fi if [[ -v COMMON_LABELS["${LABEL}"] ]]; then if [[ ${SHOULD_ADD} = true ]]; then gh issue edit "${ISSUE}" --add-label "${COMMON_LABELS["${LABEL}"]}" else gh issue edit "${ISSUE}" --remove-label "${COMMON_LABELS["${LABEL}"]}" fi continue fi # Grep exits with status code 1 if there are no matches, # so we manually set RESULT to 0 if nothing is found. RESULT=$(grep -c "${LABEL}" .github/CODEOWNERS || true) if [[ ${RESULT} = 0 ]]; then echo "\"${LABEL}\" doesn't correspond to a component, skipping." continue fi if [[ ${SHOULD_ADD} = true ]]; then gh issue edit "${ISSUE}" --add-label "${LABEL}" # Labels added by a GitHub Actions workflow don't trigger other workflows # by design, so we have to manually ping code owners here. COMPONENT="${LABEL}" ISSUE=${ISSUE} SENDER="${SENDER}" bash "${CUR_DIRECTORY}/ping-codeowners-issues.sh" else gh issue edit "${ISSUE}" --remove-label "${LABEL}" fi done opentelemetry-collector-0.141.0/.github/workflows/scripts/check-merge-freeze.sh000077500000000000000000000015101511331344600276060ustar00rootroot00000000000000#!/bin/bash -e # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # Check for [chore] Prepare release PRs in core repo BLOCKERS=$( gh pr list -A "otelbot[bot]" -S "[chore] Prepare release" --json url -q '.[].url' -R "${REPO}" ) # Check for [chore] Update core dependencies PRs in opentelemetry-collector-contrib CONTRIB_REPO="open-telemetry/opentelemetry-collector-contrib" CONTRIB_BLOCKERS=$( gh pr list -A "otelbot[bot]" -S "[chore] Update core dependencies" --json url -q '.[].url' -R "${CONTRIB_REPO}" ) # Combine both blockers BLOCKERS="${BLOCKERS}${BLOCKERS:+ }${CONTRIB_BLOCKERS}" if [ "${BLOCKERS}" != "" ]; then echo "Merging in main is frozen, as there are open release/update PRs: ${BLOCKERS}" echo "If you believe this is no longer true, re-run this job to unblock your PR." exit 1 fi opentelemetry-collector-0.141.0/.github/workflows/scripts/free-disk-space.sh000077500000000000000000000011061511331344600271210ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 echo "Available disk space before:" df -h / # The Android SDK is the biggest culprit for the lack of disk space in CI. # It is installed into /usr/local/lib/android manually (ie. not with apt) by this script: # https://github.com/actions/runner-images/blob/main/images/ubuntu/scripts/build/install-android-sdk.sh # so let's delete the directory manually. echo "Deleting unused Android SDK and tools..." sudo rm -rf /usr/local/lib/android echo "Available disk space after:" df -h / opentelemetry-collector-0.141.0/.github/workflows/scripts/get-codeowners.sh000077500000000000000000000020561511331344600271110ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # # This script checks the GitHub CODEOWNERS file for any code owners # of contrib components and returns a string of the code owners if it # finds them. set -euo pipefail get_component_type() { echo "${COMPONENT}" | cut -f 1 -d '/' } get_codeowners() { # grep arguments explained: # -m 1: Match the first occurrence # ^: Match from the beginning of the line # ${1}: Insert first argument given to this function # [\/]\?: Match 0 or 1 instances of a forward slash # \s: Match any whitespace character (grep -m 1 "^${1}[\/]\?\s" .github/CODEOWNERS || true) | \ sed 's/ */ /g' | \ cut -f3- -d ' ' } if [[ -z "${COMPONENT:-}" ]]; then echo "COMPONENT has not been set, please ensure it is set." exit 1 fi OWNERS="$(get_codeowners "${COMPONENT}")" if [[ -z "${OWNERS:-}" ]]; then COMPONENT_TYPE=$(get_component_type "${COMPONENT}") OWNERS="$(get_codeowners "${COMPONENT}${COMPONENT_TYPE}")" fi echo "${OWNERS}" opentelemetry-collector-0.141.0/.github/workflows/scripts/get-components.sh000077500000000000000000000004551511331344600271270ustar00rootroot00000000000000#!/usr/bin/env sh # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # # Get a list of components within the repository that have some form of ownership # ascribed to them. grep -E '^[A-Za-z0-9/]' .github/CODEOWNERS | \ awk '{ print $1 }' | \ sed -E 's%(.+)/$%\1%' opentelemetry-collector-0.141.0/.github/workflows/scripts/ping-codeowners-issues.sh000077500000000000000000000014711511331344600306000ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # # set -euo pipefail if [[ -z "${COMPONENT:-}" || -z "${ISSUE:-}" ]]; then echo "Either COMPONENT or ISSUE has not been set, please ensure both are set." exit 0 fi CUR_DIRECTORY=$(dirname "$0") OWNERS=$(COMPONENT="${COMPONENT}" bash "${CUR_DIRECTORY}/get-codeowners.sh") if [[ -z "${OWNERS}" ]]; then exit 0 fi gh issue comment "${ISSUE}" --body "Pinging code owners for ${COMPONENT}: ${OWNERS}. See [Adding Labels via Comments](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CONTRIBUTING.md#adding-labels-via-comments) if you do not have permissions to add labels yourself. For example, comment '/label priority:p2 -needs-triage' to set the priority and remove the needs-triage label." opentelemetry-collector-0.141.0/.github/workflows/scripts/ping-codeowners-on-new-issue.sh000077500000000000000000000070711511331344600316200ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # # set -euo pipefail if [[ -z "${ISSUE:-}" || -z "${TITLE:-}" || -z "${BODY:-}" || -z "${OPENER:-}" ]]; then echo "Missing one of ISSUE, TITLE, BODY, or OPENER, please ensure all are set." exit 0 fi LABELS_COMMENT='See [Adding Labels via Comments](https://github.com/open-telemetry/opentelemetry-collector/blob/main/CONTRIBUTING.md#adding-labels-via-comments) if you do not have permissions to add labels yourself.' CUR_DIRECTORY=$(dirname "$0") LABELS="" PING_LINES="" declare -A PINGED_COMPONENTS TITLE_COMPONENT=$(echo "${TITLE}" | (grep -oE "\[.+\]" || true) | sed -E 's/\[(.+)\]/\1/' | sed -E 's%^(.+)/(.+)\1%\1/\2%') COMPONENTS_SECTION_START=$( (echo "${BODY}" | grep -n '### Component(s)' | awk '{ print $1 }' | grep -oE '[0-9]+') || echo '-1' ) BODY_COMPONENTS="" if [[ "${COMPONENTS_SECTION_START}" != '-1' ]]; then BODY_COMPONENTS=$(echo "${BODY}" | sed -n $((COMPONENTS_SECTION_START+2))p) fi if [[ -n "${TITLE_COMPONENT}" && ! ("${TITLE_COMPONENT}" =~ " ") ]]; then CODEOWNERS=$(COMPONENT="${TITLE_COMPONENT}" "${CUR_DIRECTORY}/get-codeowners.sh" || true) if [[ -n "${CODEOWNERS}" ]]; then PING_LINES+="- ${TITLE_COMPONENT}: ${CODEOWNERS}\n" PINGED_COMPONENTS["${TITLE_COMPONENT}"]=1 if (( "${#TITLE_COMPONENT}" <= 50 )); then LABELS+="${TITLE_COMPONENT}" else echo "'${TITLE_COMPONENT}' exceeds GitHub's 50-character limit, skipping adding a label" fi fi fi for COMPONENT in ${BODY_COMPONENTS}; do # Comments are delimited by ', ' and the for loop separates on spaces, so remove the extra comma. COMPONENT=${COMPONENT//,/} CODEOWNERS=$(COMPONENT="${COMPONENT}" "${CUR_DIRECTORY}/get-codeowners.sh" || true) if [[ -n "${CODEOWNERS}" ]]; then if [[ -v PINGED_COMPONENTS["${COMPONENT}"] ]]; then continue fi PING_LINES+="- ${COMPONENT}: ${CODEOWNERS}\n" PINGED_COMPONENTS["${COMPONENT}"]=1 if (( "${#COMPONENT}" > 50 )); then echo "'${COMPONENT}' exceeds GitHub's 50-character limit on labels, skipping adding a label" continue fi if [[ -n "${LABELS}" ]]; then LABELS+="," fi LABELS+="${COMPONENT}" fi done if [[ -v PINGED_COMPONENTS[@] ]]; then echo "The issue was associated with components:" "${!PINGED_COMPONENTS[@]}" else echo "No related components were given" fi if [[ -n "${LABELS}" ]]; then # Notes on this call: # 1. Labels will be deduplicated by the GitHub CLI. # 2. The call to edit the issue will fail if any of the # labels doesn't exist. We can be reasonably sure that # all labels will exist since they come from a known set. echo "Adding the following labels: ${LABELS//,/ /}" gh issue edit "${ISSUE}" --add-label "${LABELS}" || true else echo "No labels were found to add" fi if [[ -n "${PING_LINES}" ]]; then # Notes on this call: # 1. Adding labels above will not trigger the ping-codeowners flow, # since GitHub Actions disallows triggering a workflow from a # workflow, so we have to ping code owners here. # 2. The GitHub CLI only offers multiline strings through file input, # so we provide the comment through stdin. # 3. The PING_LINES variable must be directly put into the echo string # to get the newlines to render correctly, using string formatting # causes the newlines to be interpreted literally. echo -e "Pinging code owners:\n${PING_LINES}" echo -e "Pinging code owners:\n${PING_LINES}\n" "${LABELS_COMMENT}" \ | gh issue comment "${ISSUE}" -F - else echo "No code owners were found to ping" fi opentelemetry-collector-0.141.0/.github/workflows/scripts/ping-codeowners-prs.sh000077500000000000000000000033271511331344600300730ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # set -euo pipefail if [[ -z "${REPO:-}" || -z "${AUTHOR:-}" || -z "${COMPONENT:-}" || -z "${PR:-}" ]]; then echo "At least one of REPO, AUTHOR, COMPONENT, or PR has not been set, please ensure each is set." exit 0 fi CUR_DIRECTORY=$(dirname "$0") main() { OWNERS=$(COMPONENT="${COMPONENT}" bash "${CUR_DIRECTORY}/get-codeowners.sh") REVIEWERS="" if [[ -z "${OWNERS}" ]]; then exit 0 fi for OWNER in ${OWNERS}; do if [[ "${OWNER}" = "@${AUTHOR}" ]]; then continue fi if [[ -n "${REVIEWERS}" ]]; then REVIEWERS+="," fi REVIEWERS+=$(echo "${OWNER}" | sed -E 's/@(.+)/"\1"/') done # We have to use the GitHub API directly due to an issue with how the CLI # handles PR updates that causes it require access to organization teams, # and the GitHub token doesn't provide that permission. # For more: https://github.com/cli/cli/issues/4844 # # The GitHub API validates that authors are not requested to review, but # accepts duplicate logins and logins that are already reviewers. echo "Requesting review from code owners: ${REVIEWERS}" curl \ -X POST \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${GITHUB_TOKEN}" \ "https://api.github.com/repos/${REPO}/pulls/${PR}/requested_reviewers" \ -d "{\"reviewers\":[${REVIEWERS}]}" \ | jq ".message" \ || echo "jq was unable to parse GitHub's response" } # We don't want this workflow to ever fail and block a PR, # so ensure all errors are caught. main || echo "Failed to run $0" opentelemetry-collector-0.141.0/.github/workflows/scripts/release-branch.sh000077500000000000000000000100451511331344600270340ustar00rootroot00000000000000#!/bin/bash -ex # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # --- Configuration --- UPSTREAM_REMOTE_NAME=${UPSTREAM_REMOTE_NAME:-"upstream"} # Your upstream remote name for open-telemetry/opentelemetry-collector MAIN_BRANCH_NAME=${MAIN_BRANCH_NAME:-"main"} LOCAL_MAIN_BRANCH_NAME=${LOCAL_MAIN_BRANCH_NAME:-"${MAIN_BRANCH_NAME}"} # These variables are only used if git user.name and git user.email are not configured GIT_CONFIG_USER_NAME=${GIT_CONFIG_USER_NAME:-"otelbot"} GIT_CONFIG_USER_EMAIL=${GIT_CONFIG_USER_EMAIL:-"197425009+otelbot@users.noreply.github.com"} # --- Extract release information from tag --- if [[ -z "$GITHUB_REF" ]]; then echo "Error: GITHUB_REF environment variable must be provided when running in GitHub Actions." echo "For manual usage: GITHUB_REF=refs/tags/v0.85.0 $0" exit 1 fi # Extract tag name and validate format using regex if [[ ! $GITHUB_REF =~ ^refs/tags/v([0-9]+\.[0-9]+)\.[0-9]+(-.+)?$ ]]; then echo "Error: GITHUB_REF did not match expected format (refs/tags/vX.XX.X)" exit 1 fi # Extract version numbers from regex match VERSION_MAJOR_MINOR=${BASH_REMATCH[1]} RELEASE_SERIES="v${VERSION_MAJOR_MINOR}.x" echo "Release series: ${RELEASE_SERIES}" # --- Use current commit as prepare release commit --- PREPARE_RELEASE_COMMIT_HASH="${GITHUB_SHA:-HEAD}" echo "Using current commit as prepare release commit: ${PREPARE_RELEASE_COMMIT_HASH}" RELEASE_BRANCH_NAME="release/${RELEASE_SERIES}" echo "Automating Release Steps for: ${RELEASE_SERIES}" echo "Release Branch Name: ${RELEASE_BRANCH_NAME}" echo "'Prepare release' commit hash: ${PREPARE_RELEASE_COMMIT_HASH}" echo "Upstream Remote: ${UPSTREAM_REMOTE_NAME}" echo "--------------------------------------------------" # --- Step 4: Checkout main, Pull, Create/Update and Push Release Branch --- echo "" echo "=== Step 4: Preparing and Pushing Release Branch ===" # 1. Checkout main git checkout "${LOCAL_MAIN_BRANCH_NAME}" # 2. Fetch from upstream (updates remote-tracking branches including potential existing release branch) git fetch "${UPSTREAM_REMOTE_NAME}" # 3. Rebase local main with upstream/main git rebase "${UPSTREAM_REMOTE_NAME}/${MAIN_BRANCH_NAME}" echo "'${LOCAL_MAIN_BRANCH_NAME}' branch is now up-to-date." # Verify the commit exists (it should be reachable from main after fetch) if ! git cat-file -e "${PREPARE_RELEASE_COMMIT_HASH}^{commit}" 2>/dev/null; then echo "Error: Provided 'Prepare release' commit hash '${PREPARE_RELEASE_COMMIT_HASH}' not found." exit 1 fi # 4. Handle Release Branch: Check existence, create or switch, and merge/base BRANCH_EXISTS_LOCALLY=$(git branch --list "${RELEASE_BRANCH_NAME}") # Check remote by looking for the remote tracking branch ref after fetch if git rev-parse --verify --quiet "${UPSTREAM_REMOTE_NAME}/${RELEASE_BRANCH_NAME}" > /dev/null 2>&1; then BRANCH_EXISTS_REMOTELY=true fi if [[ -n "$BRANCH_EXISTS_LOCALLY" ]]; then echo "Release branch '${RELEASE_BRANCH_NAME}' found locally." echo "Please delete local release branch using 'git branch -D ${RELEASE_BRANCH_NAME}' and run the script again." exit 1 elif [[ -n "$BRANCH_EXISTS_REMOTELY" ]]; then echo "Release branch '${RELEASE_BRANCH_NAME}' found on remote '${UPSTREAM_REMOTE_NAME}'." echo "Nothing to do, exiting." exit 0 else echo "Release branch '${RELEASE_BRANCH_NAME}' not found locally or on remote." git switch -c "${RELEASE_BRANCH_NAME}" "${PREPARE_RELEASE_COMMIT_HASH}" fi echo "Current branch is now '${RELEASE_BRANCH_NAME}'." git --no-pager log -1 --pretty=oneline # Show the commit at the tip of the release branch # 5. Push the release branch to upstream git push -u "${UPSTREAM_REMOTE_NAME}" "${RELEASE_BRANCH_NAME}" echo "Branch '${RELEASE_BRANCH_NAME}' pushed (or updated) on '${UPSTREAM_REMOTE_NAME}'." echo "Step 4 completed." echo "--------------------------------------------------" echo "" echo "Automation for release branch creation complete." echo "Release branch '${RELEASE_BRANCH_NAME}' has been created from the prepare release commit." echo "Tag-triggered build workflows should now be running for the pushed tags." opentelemetry-collector-0.141.0/.github/workflows/scripts/release-check-blockers.sh000077500000000000000000000004571511331344600304640ustar00rootroot00000000000000#!/bin/bash -ex # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 BLOCKERS=$( gh issue list --search "label:release:blocker" --json url --jq '.[].url' --repo "${REPO}" ) if [ "${BLOCKERS}" != "" ]; then echo "Release blockers in ${REPO} repo: ${BLOCKERS}" exit 1 fi opentelemetry-collector-0.141.0/.github/workflows/scripts/release-check-build-status.sh000077500000000000000000000011371511331344600312740ustar00rootroot00000000000000#!/bin/bash -ex # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 BRANCH=main WORKFLOW=build-and-test RESULT=$(gh run list --branch "${BRANCH}" --json status --jq '[.[] | select(.status != "queued" and .status != "in_progress")][0].status' --workflow "${WORKFLOW}" --repo "${REPO}" ) if [ "${RESULT}" != "completed" ]; then echo "Build status in ${REPO} is not completed: ${RESULT}" gh run list --branch "${BRANCH}" --json status,url --jq '[.[] | select(.status != "queued" and .status != "in_progress")][0].url' --workflow "${WORKFLOW}" --repo "${REPO}" exit 1 fi opentelemetry-collector-0.141.0/.github/workflows/scripts/release-create-tracking-issue.sh000077500000000000000000000024111511331344600317660ustar00rootroot00000000000000#!/bin/bash -ex # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 RELEASE_VERSION=v${CANDIDATE_STABLE}/v${CANDIDATE_BETA} if [ "${CANDIDATE_STABLE}" == "" ]; then RELEASE_VERSION="v${CANDIDATE_BETA}" fi if [ "${CANDIDATE_BETA}" == "" ]; then RELEASE_VERSION="v${CANDIDATE_STABLE}" fi EXISTING_ISSUE=$( gh issue list --search "in:title Release ${RELEASE_VERSION}" --json url --jq '.[].url' --repo "${REPO}" --state open --label release ) if [ "${EXISTING_ISSUE}" != "" ]; then echo "Issue already exists: ${EXISTING_ISSUE}" exit 0 fi gh issue create -a "${GITHUB_ACTOR}" --repo "${REPO}" --label release --title "Release ${RELEASE_VERSION}" --body "Like #4522, but for ${RELEASE_VERSION} **Performed by collector release manager** - [ ] Prepare core release ${RELEASE_VERSION} - [ ] Tag and release core ${RELEASE_VERSION} - [ ] Prepare contrib release v${CANDIDATE_BETA} - [ ] Tag and release contrib v${CANDIDATE_BETA} - [ ] Prepare otelcol-releases v${CANDIDATE_BETA} - [ ] Release binaries and container images v${CANDIDATE_BETA} **Performed by operator maintainers** - [ ] Release the operator v${CANDIDATE_BETA} **Performed by helm chart maintainers** - [ ] Update the opentelemetry-collector helm chart to use v${CANDIDATE_BETA}" opentelemetry-collector-0.141.0/.github/workflows/scripts/release-prepare-release.sh000077500000000000000000000036211511331344600306550ustar00rootroot00000000000000#!/bin/bash -ex # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 if [ "${CANDIDATE_STABLE}" == "" ] && [ "${CANDIDATE_BETA}" == "" ]; then echo "One of CANDIDATE_STABLE or CANDIDATE_BETA must be set" exit 1 fi # Expand CURRENT_STABLE and CURRENT_BETA to escape . character by using [.] CURRENT_STABLE_ESCAPED=${CURRENT_STABLE//./[.]} CURRENT_BETA_ESCAPED=${CURRENT_BETA//./[.]} RELEASE_VERSION=v${CANDIDATE_STABLE}/v${CANDIDATE_BETA} if [ "${CANDIDATE_STABLE}" == "" ]; then RELEASE_VERSION="v${CANDIDATE_BETA}" fi if [ "${CANDIDATE_BETA}" == "" ]; then RELEASE_VERSION="v${CANDIDATE_STABLE}" fi make chlog-update VERSION="${RELEASE_VERSION}" COMMANDS="- make chlog-update VERSION=${RELEASE_VERSION}" git config user.name otelbot git config user.email 197425009+otelbot@users.noreply.github.com BRANCH="prepare-release-prs/${CANDIDATE_BETA}" git checkout -b "${BRANCH}" git add --all git commit -m "Changelog update ${RELEASE_VERSION}" if [ "${CANDIDATE_STABLE}" != "" ]; then make prepare-release PREVIOUS_VERSION="${CURRENT_STABLE_ESCAPED}" RELEASE_CANDIDATE="${CANDIDATE_STABLE}" MODSET=stable COMMANDS+=" - make prepare-release PREVIOUS_VERSION=${CURRENT_STABLE_ESCAPED} RELEASE_CANDIDATE=${CANDIDATE_STABLE} MODSET=stable" fi if [ "${CANDIDATE_BETA}" != "" ]; then make prepare-release PREVIOUS_VERSION="${CURRENT_BETA_ESCAPED}" RELEASE_CANDIDATE="${CANDIDATE_BETA}" MODSET=beta COMMANDS+=" - make prepare-release PREVIOUS_VERSION=${CURRENT_BETA_ESCAPED} RELEASE_CANDIDATE=${CANDIDATE_BETA} MODSET=beta" fi git push --set-upstream origin "${BRANCH}" # Use OpenTelemetryBot account to create PR, allowing workflows to run # The title must match the checks in check-merge-freeze.yml gh pr create --head "$(git branch --show-current)" --title "[chore] Prepare release ${RELEASE_VERSION}" --body " The following commands were run to prepare this release: ${COMMANDS} " opentelemetry-collector-0.141.0/.github/workflows/scripts/win-required-ports.ps1000066400000000000000000000012271511331344600300310ustar00rootroot00000000000000<# .SYNOPSIS This script ensures that the ports required by the default configuration of the collector are available. .DESCRIPTION Certain runs on GitHub Actions sometimes have ports required by the default configuration reserved by other applications via the WinNAT service. #> #Requires -RunAsAdministrator netsh interface ip show excludedportrange protocol=tcp Stop-Service winnat # Only port in the dynamic range that is being, from time to time, reserved by other applications. netsh interface ip add excludedportrange protocol=tcp startport=55679 numberofports=1 Start-Service winnat netsh interface ip show excludedportrange protocol=tcp opentelemetry-collector-0.141.0/.github/workflows/shellcheck.yml000066400000000000000000000006671511331344600247740ustar00rootroot00000000000000name: Shellcheck lint on: push: branches: [main] pull_request: branches: [main] merge_group: types: [checks_requested] permissions: read-all jobs: shellcheck: name: Shellcheck runs-on: ubuntu-latest steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run ShellCheck uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 # 2.0.0 opentelemetry-collector-0.141.0/.github/workflows/sourcecode-release.yaml000066400000000000000000000053651511331344600266010ustar00rootroot00000000000000name: Source Code - Release on: push: tags: - "v*" permissions: contents: read jobs: goreleaser: runs-on: ubuntu-latest permissions: contents: write # Grant write permissions to repository contents issues: write # Grant write permissions to PR milestones steps: - name: Checkout Repo uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: fetch-depth: 0 # Extract title from latest version title in CHANGELOG.md - name: Prepare release title id: release-title run: | echo "title=$(grep -A 2 '' CHANGELOG.md | awk '/##/{print $2}')" >> $GITHUB_OUTPUT - name: Prepare release notes run: | touch release-notes.md echo "### Images and binaries here: https://github.com/open-telemetry/opentelemetry-collector-releases/releases/tag/${{ github.ref_name }}" >> release-notes.md echo "" >> release-notes.md echo "## End User Changelog" >> release-notes.md awk '//,//' CHANGELOG.md > tmp-chlog.md # select changelog of latest version only sed '1,3d' tmp-chlog.md >> release-notes.md # delete first 3 lines of file echo "" >> release-notes.md echo "## API Changelog" >> release-notes.md awk '//,//' CHANGELOG-API.md > tmp-chlog-api.md # select changelog of latest version only sed '1,3d' tmp-chlog-api.md >> release-notes.md # delete first 3 lines of file - name: Create Github Release run: | gh release create ${{ github.ref_name }} -t ${{ steps.release-title.outputs.title }} -F release-notes.md env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: | const milestones = await github.rest.issues.listMilestones({ owner: context.repo.owner, repo: context.repo.repo, state: "open" }) for (const milestone of milestones.data) { if (milestone.title == "next release") { await github.rest.issues.updateMilestone({ owner: context.repo.owner, repo: context.repo.repo, milestone_number: milestone.number, title: "${{ github.ref_name }}" }); await github.rest.issues.createMilestone({ owner: context.repo.owner, repo: context.repo.repo, title: "next release" }); return } } opentelemetry-collector-0.141.0/.github/workflows/spell-check.yaml000066400000000000000000000007731511331344600252200ustar00rootroot00000000000000name: Spell Check on: push: branches: [main] pull_request: permissions: contents: read jobs: spell-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 - name: Run cSpell uses: streetsidesoftware/cspell-action@3294df585d3d639e30f3bc019cb11940b9866e95 # v8.0.0 with: incremental_files_only: false use_cspell_files: true config: '.github/workflows/utils/cspell.json' opentelemetry-collector-0.141.0/.github/workflows/stale-pr.yaml000066400000000000000000000015101511331344600245430ustar00rootroot00000000000000name: "Close stale pull requests" on: schedule: - cron: "12 3 * * *" # arbitrary time not to DDOS GitHub permissions: read-all jobs: stale: permissions: issues: write # for actions/stale to close stale issues pull-requests: write # for actions/stale to close stale PRs runs-on: ubuntu-latest steps: - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-pr-message: "This PR was marked stale due to lack of activity. It will be closed in 14 days." close-pr-message: "Closed as inactive. Feel free to reopen if this PR is still being worked on." days-before-pr-stale: 14 days-before-issue-stale: 730 days-before-pr-close: 14 days-before-issue-close: 30 opentelemetry-collector-0.141.0/.github/workflows/survey-on-merged-pr.yml000066400000000000000000000035431511331344600265120ustar00rootroot00000000000000name: Survey on Merged PR by Non-Member on: pull_request_target: types: [closed] permissions: contents: read env: PR_NUM: ${{ github.event.pull_request.number }} SURVEY_URL: https://docs.google.com/forms/d/e/1FAIpQLSf2FfCsW-DimeWzdQgfl0KDzT2UEAqu69_f7F2BVPSxVae1cQ/viewform?entry.1540511742=open-telemetry/opentelemetry-collector jobs: comment-on-pr: name: Add survey to PR if author is not a member runs-on: ubuntu-latest if: github.event.pull_request.merged == true steps: - uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0 id: otelbot-token with: app-id: ${{ vars.OTELBOT_APP_ID }} private-key: ${{ secrets.OTELBOT_PRIVATE_KEY }} - name: Add survey comment if author is not a member or bot run: | USERNAME="${{ github.event.pull_request.user.login }}" USER_TYPE="${{ github.event.pull_request.user.type }}" ORG="${{ github.repository_owner }}" # Skip if user is a bot if [[ "$USER_TYPE" == "Bot" ]]; then echo "Skipping survey for bot user: $USERNAME" exit 0 fi # Skip if user is an org member if gh api "orgs/$ORG/members/$USERNAME" --silent; then echo "Skipping survey for org member: $USERNAME" exit 0 fi # Add survey comment for external contributor echo "Adding survey comment for external contributor: $USERNAME" gh pr comment ${PR_NUM} --repo ${{ github.repository }} --body "Thank you for your contribution @${USERNAME}! ๐ŸŽ‰ We would like to hear from you about your experience contributing to OpenTelemetry by taking a few minutes to fill out this [survey](${SURVEY_URL})." env: GH_TOKEN: ${{ steps.otelbot-token.outputs.token }}opentelemetry-collector-0.141.0/.github/workflows/tidy-dependencies.yml000066400000000000000000000033131511331344600262530ustar00rootroot00000000000000name: "Project: Tidy" on: pull_request_target: types: [opened, ready_for_review, synchronize, reopened, labeled, unlabeled] branches: - main permissions: read-all jobs: setup-environment: permissions: contents: write # for Git to git push timeout-minutes: 30 runs-on: ubuntu-latest if: ${{ !contains(github.event.pull_request.labels.*.name, 'dependency-major-update') && (github.actor == 'renovate[bot]' || contains(github.event.pull_request.labels.*.name, 'renovatebot')) }} steps: - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 with: ref: ${{ github.head_ref }} - uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 with: go-version: oldstable cache: false - name: Cache Go id: go-cache uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: | ~/go/bin ~/go/pkg/mod key: go-cache-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/go.sum') }} - name: Install dependencies if: steps.go-cache.outputs.cache-hit != 'true' run: make -j2 gomoddownload - name: go mod tidy run: | make gotidy git config user.name otelbot git config user.email 197425009+otelbot@users.noreply.github.com echo "git diff --exit-code || (git add . && git commit -m \"go mod tidy\" && git push)" git diff --exit-code || (git add . && git commit -m "go mod tidy" && git push) - uses: actions-ecosystem/action-remove-labels@2ce5d41b4b6aa8503e285553f75ed56e0a40bae0 # v1.3.0 with: labels: renovatebot opentelemetry-collector-0.141.0/.github/workflows/utils/000077500000000000000000000000001511331344600232735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/.github/workflows/utils/cspell.json000066400000000000000000000253101511331344600254510ustar00rootroot00000000000000{ "version": "0.2", "language": "en", "words": [ "Alolita", "Andrzej", "Anoshin", "Appy", "Autobuild", "Backpressure", "Baeyens", "Bebbington", "Biswal", "Bogdan", "Boten", "CHACHA", "CODEOWNERS", "Chao", "Chrs", "Confmap", "DOLLARSIGN", "Distro", "Dmitrii", "Dockerhub", "Drutu", "Dynatrace", "Excalidraw", "Expvar", "Fanout", "FIPS", "Funcs", "GHSA", "GOARCH", "GOARM", "GOBIN", "GOCMD", "GOMEMLIMIT", "GOPATH", "GOPROXY", "Guiton", "HKLM", "Helmuth", "Hostfeature", "Islamov", "Jaglowski", "Janotti", "Juraci", "Karis", "Keepalive", "Koanf", "Krรถhling", "MODSET", "Makwana", "Mapprovider", "Marshalers", "Marshallers", "Mathieu", "Mirabella", "Najaryan", "Nanos", "OTELBOT", "OTEP", "OTTL", "Olly", "Owais", "Paixรฃo", "Pdata", "Prometheusremotewrite", "Punya", "RCPC", "Rahul", "SASL", "Samplingdecision", "Sharma", "Statefulness", "Stencel", "Strindices", "Tailsampling", "Tigran", "Toulme", "Triagers", "Unconfigured", "Unmarshable", "Unmarshal", "Unmarshalable", "Unmarshaller", "Unmarshallers", "Vihas", "Weng", "Zipkin", "adilhusain", "alibabacloudlogserviceexporter", "alives", "anchore", "andrzej", "apidiff", "atombender", "atoulme", "attributeprocessor", "attributesprocessor", "authextension", "authtest", "autobuild", "backoffs", "backpressure", "ballastextension", "batchprocessor", "bearertokenauthextension", "behaviour", "bogdandrutu", "braydonk", "bucketize", "buildinfo", "buildx", "bwalk", "capabilityconsumer", "certfile", "cgroupv", "checkapi", "checkdoc", "checklicense", "cheung", "chlog", "chloggen", "cmux", "codeboten", "codeowners", "componenterror", "componenthelper", "componentprofiles", "componentstatus", "componenttest", "configauth", "configcheck", "configcompression", "configcompressions", "configerror", "configgrpc", "confighttp", "configloader", "configmapprovider", "configmiddleware", "configmodels", "confignet", "configopaque", "configoptional", "configparser", "configretry", "configrpc", "configsource", "configtelemetry", "configtest", "configtls", "configunmarshaler", "confmap", "confmaptest", "connectorprofiles", "connectortest", "consumerdata", "consumererror", "consumererrorprofiles", "consumerfanout", "consumerhelper", "consumerprofiles", "consumertest", "consumetest", "conv", "cookiejar", "coreinternal", "cpus", "cpuscraper", "crobert", "crosslink", "cumulativetodeltaprocessor", "customname", "dataloss", "datapoints", "debugexporter", "defaultcomponents", "dehaansa", "distro", "distros", "djaglowski", "dmathieu", "dmitryax", "dokey", "envmapprovider", "envprovider", "eventcreate", "exampleexporter", "examplereceiver", "expandconverter", "expandmapconverter", "expandvar", "exporterbatch", "exporterbatcher", "exporterhelper", "exporterhelperprofiles", "exporterprofiles", "exporterqueue", "exportertest", "exporthelper", "expvar", "extensionauth", "extensionauthtest", "extensioncapabilities", "extensionhelper", "extensionmiddleware", "extensionmiddlewaretest", "extensiontest", "extensionz", "fanout", "fanoutconsumer", "featureflags", "featuregate", "featuregates", "featurez", "fieldalignment", "fileexporter", "filemapprovider", "fileprovider", "filterprocessor", "filterset", "florianl", "fluentbit", "fluentforward", "forwardconnector", "fsnotify", "funcs", "gcflags", "genotelcorecol", "genpdata", "genproto", "goarm", "gobenchmark", "godoc", "gofmt", "gogenerate", "goimpi", "golangci", "goldendataset", "goleak", "golint", "gomod", "gomoddownload", "goporto", "goproxy", "goreleaser", "goroutines", "gotest", "gotidy", "govulncheck", "groupbyattrprocessor", "groupbytrace", "groupbytraceprocessor", "grpclb", "guiton", "healthcheck", "healthcheckextension", "healthcheckv", "hostcapabilities", "hostmetrics", "hostmetricsreceiver", "httpclientconfig", "httpprovider", "httpsprovider", "httptest", "illumos", "incorrectclass", "incorrectcomponent", "incorrectstability", "instrgen", "internaldata", "ints", "invalidaggregation", "invalidtype", "iruntime", "jaegerexporter", "jaegerreceiver", "jmacd", "jpkrohling", "jsoniter", "jsonpb", "kafkaexporter", "kafkaexporter's", "kafkareceiver", "keepalive", "koanf", "ldflags", "limitermiddleware", "localhostgate", "loggingexporter", "logstest", "lycheeverse", "mapconverter", "mapstructure", "marshalers", "mdatagen", "mdatagen's", "memorylimiter", "memorylimiterextension", "memorylimiterprocessor", "metadatatest", "metricfamily", "metricreceiver", "metricsexporter", "metricsgenerationprocessor", "metricstransformprocessor", "middleware", "mostynb", "mowies", "muehle", "multiclient", "multimod", "mycert", "myconnector", "myexporter", "myextension", "myorg", "myprocessor", "myreceiver", "myrepo", "mysite", "nonclobbering", "nopexporter", "nopreceiver", "nosuchprocessor", "notls", "obsreceiver", "obsreport", "obsreporttest", "oidcauthextension", "okey", "oldstable", "oltp", "omitempty", "omnition", "opencensus", "opencensusexporter", "opencensusreceiver", "otelbot", "otelcol", "otelcoltest", "otelconf", "otelconftelemetry", "otelcorecol", "otelgrpc", "otelhttp", "otelsvc", "oteltest", "otelzap", "otlpexporter", "otlpgrpc", "otlphttp", "otlphttpexporter", "otlphttpexporter's", "otlphttpreceiver", "otlpjson", "otlpmetrics", "otlpreceiver", "otlptext", "overwritepropertiesconverter", "overwritepropertiesmapconverter", "parserprovider", "pcommon", "pdata", "pdatagen", "pdatagrpc", "perfcounters", "perflib", "pipelineprofiles", "pipelinez", "pjanotti", "plog", "plogotlp", "plogs", "pmetric", "pmetricotlp", "policyevaluation", "pprof", "pprofextension", "pprofile", "pprofiles", "pprofileotlp", "preconfigured", "priya", "probabilisticsamplerprocessor", "processorhelper", "processorhelperprofiles", "processorprofiles", "processortest", "processscraper", "proctelemetry", "prometheusexporter", "prometheusreceiver", "prometheusremotewrite", "prometheusremotewriteexporter", "protogen", "protos", "ptraceotlp", "queuebatch", "receiverhelper", "receiverprofiles", "receivertest", "renovatebot", "resourcedetection", "resourcedetectionprocessor", "resourceprocessor", "resourcetolabel", "retryable", "riscv", "rpcz", "rrschulze", "runperf", "safelist", "samplefactoryreceiver", "samplereceiver", "samplingdecision", "samplingprocessor", "sarama", "sattributes", "sattributesprocessor", "scrapererror", "scraperhelper", "scrapertest", "semconv", "servicetelemetry", "servicetest", "servicez", "sfixed", "shanduur", "sharedcomponent", "sigstore", "someclientid", "someclientsecret", "somevalue", "songy", "spanmetricsconnector", "spanmetricsprocessor", "spanprocessor", "sprocessor", "statusdata", "statusreporting", "statuswatcher", "stdlib", "stencel", "stretchr", "subcomponent", "subcomponents", "subpackages", "swiatekm", "syft", "tailsampling", "tchannel", "telemetrygen", "telemetrytest", "testcomponents", "testconverter", "testdata", "testfunc", "testonly", "testprocessor", "testprovider", "testresults", "testutil", "tlsconfig", "tmpl", "tocstop", "tpmrm", "tracecontext", "traceid", "tracesonmemory", "tracetranslator", "tracez", "transformprocessor", "triager", "triagers", "triaging", "uints", "unixgram", "unixpacket", "unkeyed", "unmarshal", "unmarshalling", "unmarshalls", "unredacted", "unshallow", "unstarted", "userfriendly", "validatable", "vanityurl", "vmmetrics", "withauth", "xconfighttp", "xconfmap", "xconnector", "xconsumer", "xconsumererror", "xexporter", "xexporterhelper", "xextension", "xpdata", "xpipeline", "xprocessor", "xprocessorhelper", "xreceiver", "xscraper", "yamlmapprovider", "yamlprovider", "yamls", "zapcore", "zipkin", "zipkinexporter", "zipkinreceiver", "zipkinv", "zpages", "zpagesextension", "zstd" ], "enableGlobDot": true, "useGitignore": true, "files": ["**/*.{md,yaml,yml}"], "globRoot": "../../..", "ignorePaths": [ ".git/*", ".git/!{COMMIT_EDITMSG,EDITMSG}", ".git/*/**", ".golangci.yml", ".github/**/*" ] } opentelemetry-collector-0.141.0/.gitignore000066400000000000000000000005241511331344600205270ustar00rootroot00000000000000bin/ dist/ /local # GoLand IDEA /.idea/ *.iml # VS Code .vscode/ .devcontainer/ # Emacs *~ \#*\# # Miscellaneous files *.sw[op] *.DS_Store # Coverage coverage/* coverage.txt # Benchmarks **/benchmark.txt benchmarks.txt # Wix *.wixobj *.wixpdb # golang go.work* # npm (used for markdown-link-check) node_modules/* package-lock.json opentelemetry-collector-0.141.0/.golangci.yml000066400000000000000000000222521511331344600211250ustar00rootroot00000000000000formatters: enable: - gofumpt - goimports settings: gofmt: # simplify code: gofmt with `-s` option, true by default simplify: true gofumpt: # Choose whether to use the extra rules extra-rules: true goimports: # put imports beginning with prefix after 3rd-party packages; # it's a comma-separated list of prefixes local-prefixes: - go.opentelemetry.io/collector issues: # Maximum issues count per one linter. max-issues-per-linter: 0 # Maximum count of issues with the same text. max-same-issues: 0 linters: enable: - asasalint - contextcheck - copyloopvar - decorder - depguard - errcheck - errorlint - fatcontext - gocritic - gosec - govet - misspell - modernize - nolintlint - perfsprint - revive - staticcheck - testifylint - thelper - unconvert - unparam - unused - usestdlibvars - usetesting - whitespace exclusions: presets: - std-error-handling # Excluding configuration per-path, per-linter, per-text and per-source rules: [] # Log a warning if an exclusion rule is unused. warn-unused: true # all available settings of specific linters settings: depguard: rules: denied-deps: deny: - pkg: "go.uber.org/atomic" desc: "Use 'sync/atomic' instead of go.uber.org/atomic" - pkg: "github.com/pkg/errors" desc: "Use 'errors' or 'fmt' instead of github.com/pkg/errors" - pkg: "github.com/hashicorp/go-multierror" desc: "Use go.uber.org/multierr instead of github.com/hashicorp/go-multierror" - pkg: "math/rand$" desc: "Use the newer 'math/rand/v2' instead of math/rand" - pkg: "sigs.k8s.io/yaml" desc: "Use 'go.yaml.in/yaml' instead of sigs.k8s.io/yaml" semconv: list-mode: lax files: - "!cmd/mdatagen/**" # Exclude mdatagen deny: - pkg: go.opentelemetry.io/otel/semconv desc: Use go.opentelemetry.io/otel/semconv/v1.37.0 instead. If a newer semconv version has been released, update the depguard rule. allow: - go.opentelemetry.io/otel/semconv/v1.37.0 # Add a different guard rule so that we can ignore tests. ignore-in-test: # Allow in tests for testing pdata or other receivers/exporters that expect OTLP. files: - '!**/*_test.go' deny: - pkg: go.opentelemetry.io/proto desc: Use go.opentelemetry.io/collector/pdata instead gocritic: disabled-checks: - commentedOutCode - deferInLoop - filepathJoin - hugeParam - importShadow - rangeValCopy - unnamedResult - whyNoLint enable-all: true gosec: excludes: - G104 # FIXME - G402 - G404 govet: disable: # We want to order fields according to readability and grouping them by use cases. # This linter does not offer a discernible performance improvement as the structs # defined in this repository are not in the execution hot path. # See https://github.com/open-telemetry/opentelemetry-collector/issues/2789 - fieldalignment enable-all: true # settings per analyzer settings: printf: # analyzer name, run `go tool vet help` to see all analyzers funcs: # run `go tool vet help printf` to see available settings for `printf` analyzer - Infof - Warnf - Errorf - Fatalf misspell: # Correct spellings using locale preferences for US or UK. # Default is to use a neutral variety of English. # Setting locale to US will correct the British spelling of 'colour' to 'color'. locale: US ignore-rules: - cancelled nolintlint: require-specific: true perfsprint: # Optimizes even if it requires an int or uint type cast. int-conversion: true # Optimizes into `err.Error()` even if it is only equivalent for non-nil errors. err-error: true # Optimizes `fmt.Errorf`. errorf: true # Optimizes `fmt.Sprintf` with only one argument. sprintf1: true # Optimizes into strings concatenation. strconcat: true revive: # minimal confidence for issues, default is 0.8 confidence: 0.8 rules: # Blank import should be only in a main or test package, or have a comment justifying it. - name: blank-imports # context.Context() should be the first parameter of a function when provided as argument. - name: context-as-argument # Basic types should not be used as a key in `context.WithValue` - name: context-keys-type # Importing with `.` makes the programs much harder to understand - name: dot-imports - name: early-return arguments: - preserveScope # Empty blocks make code less readable and could be a symptom of a bug or unfinished refactoring. - name: empty-block # for better readability, variables of type `error` must be named with the prefix `err`. - name: error-naming # for better readability, the errors should be last in the list of returned values by a function. - name: error-return # for better readability, error messages should not be capitalized or end with punctuation or a newline. - name: error-strings # report when replacing `errors.New(fmt.Sprintf())` with `fmt.Errorf()` is possible - name: errorf # incrementing an integer variable by 1 is recommended to be done using the `++` operator - name: increment-decrement # highlights redundant else-blocks that can be eliminated from the code - name: indent-error-flow # This rule suggests a shorter way of writing ranges that do not use the second value. - name: range # receiver names in a method should reflect the struct name (p for Person, for example) - name: receiver-naming # redefining built in names (true, false, append, make) can lead to bugs very difficult to detect. - name: redefines-builtin-id # redundant else-blocks that can be eliminated from the code. - name: superfluous-else arguments: - preserveScope # prevent confusing name for variables when using `time` package - name: time-naming # warns when an exported function or method returns a value of an un-exported type. - name: unexported-return - name: unnecessary-stmt # spots and proposes to remove unreachable code. also helps to spot errors - name: unreachable-code # Functions or methods with unused parameters can be a symptom of an unfinished refactoring or a bug. - name: unused-parameter # Since Go 1.18, interface{} has an alias: any. This rule proposes to replace instances of interface{} with any. - name: use-any # report when a variable declaration can be simplified - name: var-declaration # warns when initialism, variable or package naming conventions are not followed. - name: var-naming staticcheck: checks: - all - -ST1000 - -ST1021 - -ST1022 testifylint: enable-all: true thelper: benchmark: begin: false fuzz: begin: false tb: begin: false test: begin: false # output configuration options output: # The formats used to render issues. formats: # Prints issues in a text format with colors, line number, and linter name. text: # Output path can be either `stdout`, `stderr` or path to the file to write to. path: stdout # print linter name in the end of issue text, default is true print-linter-name: true # print lines of code with issue, default is true print-issued-lines: true # Show statistics per linter. show-stats: false # options for analysis running run: # Allow multiple parallel golangci-lint instances running. # If false (default) - golangci-lint acquires file lock on start. allow-parallel-runners: true # default concurrency is a available CPU number concurrency: 4 # by default isn't set. If set we pass it to "go list -mod={option}". From "go help modules": # If invoked with -mod=readonly, the go command is disallowed from the implicit # automatic updating of go.mod described above. Instead, it fails when any changes # to go.mod are needed. This setting is most useful to check that go.mod does # not need updates, such as in a continuous integration and testing system. # If invoked with -mod=vendor, the go command assumes that the vendor # directory holds the correct copies of dependencies and ignores # the dependency descriptions in go.mod. modules-download-mode: readonly # exit code when at least one issue was found, default is 1 issues-exit-code: 1 # include test files or not, default is true tests: true # timeout for analysis, e.g. 30s, 5m, default is 1m timeout: 10m version: "2" opentelemetry-collector-0.141.0/CHANGELOG-API.md000066400000000000000000002304611511331344600207640ustar00rootroot00000000000000 # Go API Changelog This changelog includes only developer-facing changes. If you are looking for user-facing changes, check out [CHANGELOG.md](./CHANGELOG.md). ## v1.47.0/v0.141.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pkg/config/configgrpc`: Replace `component.Host` parameter of ToServer/ToClientConn by map of extensions (#13640) Components must now pass the map obtained from the host's `GetExtensions` method instead of the host itself. Nil may be used in tests where no middleware or authentication extensions are used. - `pkg/config/confighttp`: Replace `component.Host` parameter of ToServer/ToClient by map of extensions (#13640) Components must now pass the map obtained from the host's `GetExtensions` method instead of the host itself. Nil may be used in tests where no middleware or authentication extensions are used. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `pkg/pdata`: Deprecate profile.Duration() and profile.SetDuration() (#14188) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata/pprofile`: Introduce `MergeTo` method (#14091) - `pkg/pdata`: Add profile.DurationNano() and profile.SetDurationNano() (#14188) ## v1.46.0/v0.140.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pdata/pprofile`: Upgrade the OTLP protobuf definitions to version 1.9.0 (#14128) * Drop field `CommentStrindices` in `Profile`. * Rename `Sample` to `Samples` in `Profile`. * Rename `Line` to `Lines` in `Location`. * Remove `AggregationTemporality` field in `ValueType`. See https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v1.9.0 - `pkg/otelcol`: The `otelcol.Factories.Telemetry` field is now required (#14003) Previously if this field was not set, then it would default to an otelconftelemetry factory. Callers of the otelcol package must now set the field explicitly. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pkg/pdata`: Upgrade the OTLP protobuf definitions to version 1.9.0 (#14128) ## v1.45.0/v0.139.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Change type of `configgrpc.ClientConfig.Headers`, `confighttp.ClientConfig.Headers`, and `confighttp.ServerConfig.ResponseHeaders` (#13930) `configopaque.MapList` is a new alternative to `map[string]configopaque.String` which can unmarshal both maps and lists of name/value pairs. For example, if `headers` is a field of type `configopaque.MapList`, then the following YAML configs will unmarshal to the same thing: ```yaml headers: "foo": "bar" headers: - name: "foo" value: "bar" ``` - `pdata/pprofile`: Update `SetFunction` to return the function's ID rather than update the Line (#14016, #14032) - `pdata/pprofile`: Update `SetLink` to return the link's ID rather than update the Sample (#14016, #14031) - `pdata/pprofile`: Update `SetMapping` to return the mapping's ID rather than update the Location (#14016, #14030) - `pkg/otelcol`: Require a telemetry factory to be injected through otelcol.Factories (#4970) otelcol.Factories now has a required Telemetry field, which contains the telemetry factory to be used by the service. Set it to otelconftelemetry.NewFactory() for the existing behavior. - `pkg/pdata`: Remove unused generated code from pprofile (#14073) Experimental package, ok to break since not used. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata/pprofile`: Introduce `SetStack` method (#14007) - `pdata/xpdata`: Add high-level Entity API for managing entities attached to resources (#14042) Introduces `Entity`, `EntitySlice`, and `EntityAttributeMap` types that provide a user-friendly interface for working with resource entities. The new API ensures consistency between entity and resource attributes by sharing the underlying attribute map, and prevents attribute conflicts between entities. This API may eventually replace the generated protobuf-based API for better usability. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `cmd/mdatagen`: Fix mdatagen generated_metrics for connectors (#12402) ## v1.44.0/v0.138.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pkg/xexporterhelper`: Remove definition of Sizer from public API and ability to configure. (#14001) Now that Request has both Items/Bytes sizes no need to allow custom sizers. - `pkg/service`: The `service.Settings` type now requires a `telemetry.Factory` to be provided (#4970) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `pdata/pprofile`: Deprecated `PutAttribute` helper method (#14016, #14041) - `pdata/pprofile`: Deprecated `PutLocation` helper method (#14019) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `all`: Add `keep_alives_enabled` option to ServerConfig to control HTTP keep-alives for all components that create an HTTP server. (#13783) - `pkg/pdata`: Add pcommon.Map helper to add a key to the map if does not exists (#14023) - `pdata/pprofile`: Introduce `Equal` method on the `KeyValueAndUnit` type (#14041) - `pkg/pdata`: Add `RemoveIf` method to primitive slice types (StringSlice, Int64Slice, UInt64Slice, Float64Slice, Int32Slice, ByteSlice) (#14027) - `pdata/pprofile`: Introduce `SetAttribute` helper method (#14016, #14041) - `pdata/pprofile`: Introduce `SetLocation` helper method (#14019) - `pdata/pprofile`: Introduce `Equal` method on the `Stack` type (#13952) ## v1.43.0/v0.137.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pkg/exporterhelper`: Remove all experimental symbols in exporterhelper (#11143) They have all been moved to xexporterhelper ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `all`: service/telemetry.TracesConfig is deprecated (#13904) This type alias has been added to otelconftelemetry.TracesConfig, where the otelconf-based telemetry implementation now lives. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `all`: Mark configoptional as stable (#13403) - `all`: Mark configauth module as 1.0 (#9476) - `pkg/pdata`: Mark featuregate pdata.useCustomProtoEncoding as stable (#13883) ## v1.42.0/v0.136.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Remove deprecated function NewRequestsSizer (#13803) - `pdata/pprofile`: Upgrade the OTLP protobuf definitions to version 1.8.0 (#13758, #13825, #13839) - `pdata/pprofile`: Remove deprecated ProfilesDictionary method (#13858) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `exporterhelper`: Deprecate all experimental symbols in exporterhelper and move them to xexporterhelper (#11143) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configoptional`: Add `GetOrInsertDefault` method to `configoptional.Optional` (#13856) This method inserts a default or zero value into a `None`/`Default` `Optional` before `Get`ting its inner value. - `exporter`: Stabilize exporter module. (#12978) This does not stabilize the exporterhelper module or configuration - `pdata`: Upgrade the OTLP protobuf definitions to version 1.8.0 (#13758) ## v1.41.0/v0.135.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pdata/pprofile`: Remove deprecated AddAttribute method (#13764) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configmiddleware`: Stabilize `configmiddleware` module (#13422) This only stabilizes the configuration interface but does not stabilize the middlewares themselves or the way of implementing them. - `xpdata`: Add experimental MapBuilder struct to optimize pcommon.Map construction (#13617) ## v1.40.0/v0.134.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Split exporterhelper into a separate module (#12985) ## v1.39.0/v0.133.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `configgrpc`: Set `tcp` as the default transport type (#13657) gRPC is generally used with HTTP/2, so this will simplify usage for most components. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `pdata/pprofile`: Deprecate Profiles.ProfilesDictionary in favor of Profiles.Dictionary. (#13644) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Add support for local memory pooling for data objects. (#13678) This is still an early experimental (alpha) feature. Do not recommended to be used production. To enable use "--featuregate=+pdata.useProtoPooling" ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configoptional`: Allow validating nested types (#13579) `configoptional.Optional` now implements `xconfmap.Validator` ## v1.38.0/v0.132.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `componenttest`: Remove `GetFactory` from the host returned by `NewNopHost` (#13577) This method is no longer part of the `component.Host` interface. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Provide an interface `queue_batch.Setting.MergeCtx` so users can control how context values are preserved or combined (#13320) By supplying a custom mergeCtx function, users can control how context values are preserved or combined. The default behavior is to preserve no context values. - `pdata`: Generate Logs/Traces/Metrics/Profiles and p[log|trace|metric|profile]ExportResponse with pdatagen. (#13597) This change brings consistency on how these structs are written and remove JSON marshaling/unmarshaling hand written logic. - `pdata`: Avoid unnecessary buffer copy when JSON marshal fails. (#13598) - `pipeline`: Mark module as stable (#12831) ## v1.37.0/v0.131.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `configgrpc`: Update optional fields to use `configoptional.Optional` field for optional values. (#13252, #13364) Specifically, the following fields have been updated to `configoptional`: - `KeepaliveServerConfig.ServerParameters` (`KeepaliveServerParameters` type) - `KeepaliveServerConfig.EnforcementPolicy` (`KeepaliveEnforcementPolicy` type) - `xexporterhelper`: Remove deprecated NewProfilesExporter function from xexporterhelper package (#13391) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `consumererror`: Add new "Downstream" error marker (#13234) This new error wrapper type indicates that the error returned by a component's `Consume` method is not an internal failure of the component, but instead was passed through from another component further downstream. This is used internally by the new pipeline instrumentation feature to determine the `outcome` of a component call. This wrapper is not intended to be used by components directly. - `pdata/pprofile`: Introduce `Equal` method on the `Function` type (#13222) - `pdata/pprofile`: Introduce `Equal` method on the `Link` type (#13223) - `pdata/pprofile`: Add new helper method `SetFunction` to set a new function on a line. (#13222) - `pdata/pprofile`: Add new helper method `SetLink` to set a new link on a sample. (#13223) - `pdata/pprofile`: Add new helper method `SetString` to set or retrieve the index of a value in the StringTable. (#13225) ## v1.36.1/v0.130.1 No API-only changes in this release. ## v1.36.0/v0.130.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Use configoptional for sending_queue::batch field (#13345) - `configgrpc`: Update optional fields to use `configoptional.Optional` field for optional values. (#13250, #13252) Components using `configgrpc` package may need to update config values. - `confighttp`: Use configoptional.Optional in confighttp (#9478) - `exporterhelper`: Remove sizer map in favor of items/bytes sizers. Request based is automatically supported. (#13262) - `pdata/pprofile`: Remove field Profile.StartTime from pdata/pprofile (#13315) Remove Profile.StartTime from OTel Profiling signal. - `exporterhelper`: Remove deprecated old batcher config (#13003) - `exporter/otlp`: Remove deprecated batcher config from OTLP, use queuebatch (#13339) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `exporterhelper`: Deprecate NewRequestsSizer always supported. (#13262) - `xexporterhelper`: Introduce NewProfiles method and deprecate NewProfilesExporter (#13372) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `consumererror`: Add `Error` type (#7047) This type can contain information about errors that allow components (e.g. exporters) to communicate error information back up the pipeline. - `pdata`: Document that changing pcommon.Map (Remove/removeIf/Put*) invalidates Value references obtained via Get. (#13073) - `cmd/mdatagen`: Add support for optional attribute (#12571) - `exporterhelper`: Add support to configure a different Sizer for the batcher than the queue (#13313) - `pdata`: Add support for the new resource-entity reference API as part of the experimental xpdata package. (#13264) ## v1.35.0/v0.129.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `semconv`: Removing deprecated semconv package (#13071) - `configgrpc,confighttp`: Unify return type of `NewDefault*Config` functions to return a struct instead of a pointer. (#13169) - `exporterhelper`: QueueBatchEncoding interface is changed to support marshaling and unmarshaling of request context. (#13188) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata/pprofile`: Introduce `Equal` method on the `Mapping` type (#13197) - `configoptional`: Make unmarshaling into `None[T]` work the same as unmarshaling into `(*T)(nil)`. (#13168) - `configoptional`: Add a confmap.Marshaler implementation for configoptional.Optional (#13196) - `pdata/pprofile`: Introduce `Equal` methods on the `Line` and `Location` types (#13150) - `pdata/pprofile`: Add new helper method `SetMapping` to set a new mapping on a location. (#13197) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confmap`: Distinguish between empty and nil values when marshaling `confmap.Conf` structs. (#13196) ## v1.34.0/v0.128.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Remove deprecated NewProfilesRequestExporter function from xexporterhelper package (#13157) - `confighttp`: Remove pointer to field `cookies` in confighttp.ClientConfig (#13116) - `otlpreceiver`: Use `configoptional.Optional` to define optional configuration sections in the OTLP receiver. Remove `Unmarshal` method. (#13119) - `confighttp,configgrpc`: Rename `ClientConfig.TLSSetting` and `ServerConfig.TLSSetting` to `ClientConfig.TLS` and `ServerConfig.TLS`. (#13115) - `pdata/pprofile`: Upgrade the OTLP protobuf definitions to version 1.7.0 (#13075) Note that the batcher is temporarily a noop. - `pipeline`: Remove deprecated MustNewID[WithName] (#13139) ### ๐Ÿš€ New components ๐Ÿš€ - `configoptional`: Add a new configoptional module to support optional configuration fields. (#12981) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Introduce `MoveAndAppendTo` methods to the generated primitive slices (#13074) - `pdata`: Upgrade the OTLP protobuf definitions to version 1.7.0 (#13075) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confmap`: Correctly distinguish between `nil` and empty map values on the `ToStringMap` method (#13161) This means that `ToStringMap()` method can now return a nil map if the original value was `nil`. If you were not doing so already, make sure to check for `nil` before writing to the map to avoid panics. - `confighttp`: Make the `NewDefaultServerConfig` function return a nil TLS config by default. (#13129) - The previous default was a TLS config with no certificates, which would fail at runtime. ## v1.33.0/v0.127.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `mdatagen`: Add context parameter for recording event to set traceID and spanID (#12571) - `otlpreceiver`: Use wrapper type for URL paths (#13046) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `pipeline`: Deprecate MustNewID and MustNewIDWithName (#12831) - `pdata/profile`: Replace AddAttribute with the PutAttribute helper method to modify the content of attributable records. (#12798) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `consumer/consumertest`: Add context to sinks (#13039) - `cmd/mdatagen`: Add events in generated documentation (#12571) - `confmap`: Add a `Conf.Delete` method to remove a path from the configuration map. (#13064) - `confmap`: Support running Unmarshal hooks on nil values. (#12981) ## v1.32.0/v0.126.0 ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `configauth`: Deprecate `configauth.Authentication` in favor of `configauth.Config`. (#12875) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `cmd/mdatagen`: Add type definition for events in mdatagen (#12571) - `cmd/mdatagen`: Add functions for processing structured events in mdatagen (#12571) ## v1.31.0/v0.125.0 ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `extensionauthtest`: Deprecate NewErrorClient in favor of NewErrClient. (#12874) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `xextension/storage`: ErrStorageFull error added to xextension/storage contract (#12925) - `pdata`: Add MoveTo to pcommon.Value, only type missing this (#12877) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `pdata`: Fix MoveTo when moving to the same destination (#12887) ## v1.30.0/v0.124.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterbatcher`: Remove deprecated package exporterbatcher (#12780) - `exporterqueue`: Remove deprecated package exporterqueue (#12779) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Add variable for metric name in mdatagen (#12459) Access metric name via `metadata.MetricsInfo..Name` - `client`: Add support for iterating over client metadata keys (#12804) - `service`: Adds the GetFactory interface to the hostcapabilities package (#12789) - `cmd/mdatagen`: Add the foundational changes necessary for supporting logs data in `mdatagen` (#12571) ## v1.29.0/v0.123.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otlpreceiver/otlpexporter/otlphttpexporter`: Avoid using go embedded messages in Config (#12718) - `exporterqueue`: Move Queue interface to internal, disallow alternative implementations (#12680) - `extensionauth, configauth`: Remove deprecated types and functions from `extensionauth` and `configauth` packages. (#12672) This includes: - `extensionauth.NewClient`, - `extensionauth.ClientOption` and all its implementations, - `extensionauth.NewServer`, - `extensionauth.ServerOption` and all its implementations and - `configauth.Authenticator.GetClientAuthenticator`. - `exporterhelper`: Remove deprecated converter types from exporterhelper (#12686) - `exporterbatch`: Remove deprecated fields `min_size_items` and `max_size_items` from batch config. (#12684) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `exporterhelper`: Deprecate BatcherConfig, SizeConfig and WithBatcher in favor of the new QueueBatchConfig. (#12748) - `exporterbatcher`: Deprecated Config, SizeConfig, SizerType, SizerType[Requests|Items|Bytes], NewDefaultConfig. Use alias from exporterhelper. (#12707) - `exporterqueue`: Deprecated Config, NewDefaultConfig, Encoding, ErrQueueFull. Use alias from exporterhelper. (#12706) - `exporterhelper`: Deprecate exporterhelper WithRequestQueue in favor of WithQueueBatch (#12679) - `exporterhelper`: Deprecate `QueueConfig` in favor of `QueueBatchConfig`. (#12746) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `extensionauth`: Mark module as stable (#11006) - `processor`: Mark module as stable. (#12677) - `processorhelper`: Split processorhelper into a separate module. (#12678) ## v1.28.1/v0.122.1 ## v1.28.0/v0.122.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `auth, authtest`: Remove deprecated modules extension/auth and extension/auth/authtest (#12543) Use extension/extensionauth and extension/extensionauth/extensionauthtest instead. - `extensionauth`: Remove deprecated methods from the `Func` types. (#12547) - `extensiontest, connectortest, processortest, receivertest, scrapertest, exportertest`: Remove deprecated `NewNopSettingsWithType` functions, use `NewNopSettings` instead. (#12221) - `extensionauthtest`: Remove the `extensionauthtest.MockClient` struct. (#12567) - Use `extensionauthtest.NewNopClient` to create a client with a noop implementation. - Use `extensionauthtest.NewErrorClient` to create a client that always returns an error. - Implement the `extensionauth` interfaces for custom mock client implementations. - `component/componenttest`: Remove the deprecated componenttest.TestTelemetry in favor of componenttest.Telemetry (#12419) - `exporterhelper`: Remove the Request.Export function in favor of an equivalent request consume func in the New[Traces|Metrics|Logs|Profiles]Request (#12637) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `exporterhelper`: Deprecate per signal converter in favor of generic version (#12631) - `extensionauth`: Deprecate `extensionauth.NewClient` and `extensionauth.NewServer`. (#12574) - Manually implement the interfaces instead. - `configauth`: Deprecate `configauth.Authenticator.GetClientAuthenticator`. (#12574) - Use the per-protocol methods instead. ### ๐Ÿš€ New components ๐Ÿš€ - `receiverhelper`: Split `receiverhelper` into a separate module (#28328) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `cmd/mdatagen`: Add `supportsSignal` func for `Metadata` type in `mdatagen`. (#12640) - `receiver`: Mark module as stable (#12513) - `pdata/pcommon`: Introduce `Equal()` method for comparison equality to `Value`, `ByteSlice`, `Float64Slice`, `Int32Slice`, `Int64Slice`, `StringSlice`, `Uint64Slice`, `Map` and `Slice` (#12594) - `pdata`: Add iterator All method to pdata slices and map types. (#11982) - `pdata/pprofile`: Introduce AddAttribute helper method to modify the content of attributable records (#12206) ## v1.27.0/v0.121.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterqueue`: Remove exporterqueue.Factory in favor of the NewQueue function, and merge configs for memory and persistent. (#12509) As a side effect of this change, no alternative implementation of the queue are supported and the Queue interface will be hidden. - `exporterhelper`: Update MergeSplit function signature to use the new SizeConfig (#12486) - `extension, connector, processor, receiver, exporter, scraper`: Remove deprecated `Create*` methods from `Create*Func` types. (#12305) The `xconnector.CreateMetricsToProfilesFunc.CreateMetricsToProfiles` method has been removed without a deprecation. - `component`: Remove deprecated function and interface `ConfigValidator` and `ValidateConfig`. (#11524) - Use `xconfmap.Validator` and `xconfmap.Validate` instead. - `receiver, scraper, processor, exporter, extension`: Remove deprecated MakeFactoryMap functions in favor of generic implementation (#12222) - `exporterhelper`: Change the signature of the exporterhelper.WithQueueRequest to accept Encoding instead of the Factory. (#12509) - `component/componenttest`: Removing the deprecated `CheckReceiverMetrics` and `CheckReceiverTraces` functions. (#12185) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `componenttest`: Deprecated componenttest.TestTelemetry in favor of componenttest.Telemetry (#12419) - `connector, exporter, extension, processor, receiver, scraper`: Add type parameter to `NewNopSettings` and deprecate `NewNopSettingsWithType` (#12305) - `exporterhelper`: Deprecate MinSizeConfig and MaxSizeItems. (#12486) - `extension/extensionauth`: Deprecate methods on `*Func` types. (#12480) - `extension/auth, extension/auth/authtest`: Deprecate extension/auth and the related test module in favor of extension/extensionauth (#12478) ### ๐Ÿš€ New components ๐Ÿš€ - `service/hostcapabilities`: create `service/hostcapabilities` module (#12296, #12375) Removes getExporters interface in service/internal/graph. Removes getModuleInfos interface in service/internal/graph. Creates interface ExposeExporters in service/hostcapabilities to expose GetExporters function. Creates interface ModuleInfo in service/hostcapabilities to expose GetModuleInfos function. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Adds the config API to support serialized bytes based batching (#3262) - `configauth`: Add the `omitempty` mapstructure tag to struct fields (#12191) This results in unset fields not being rendered when marshaling. - `confighttp`: Add the `omitempty` mapstructure tag to struct fields (#12191) This results in unset fields not being rendered when marshaling. - `otelcol`: Converters are now available in the `components` command. (#11900, #12385) - `extension`: Mark module as stable (#11005) - `pcommon.Map`: preallocate go map in Map.AsRaw() (#12406) - `exporterhelper`: Stabilize exporter.UsePullingBasedExporterQueueBatcher and remove old batch sender (#12425) - `service`: Add the `omitempty` mapstructure tag to struct fields (#12191) This results in unset fields not being rendered when marshaling. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `mdatagen`: Fix broken imports in the generated files. (#12298) - `processor, connector, exporter, receiver`: Explicitly error out at component creation time if there is a type mismatch. (#12305) ## v1.26.0/v0.120.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `configauth`: Remove NewDefaultAuthentication (#12223) The value returned by this function will always cause an error on startup. In `configgrpc.Client/ServerConfig.Auth`, `nil` should be used instead to disable authentication. - `otelcol`: Make the `ConfigProvider` interface a struct (#12297) Calls to `NewConfigProvider` will now return `*ConfigProvider`, but will otherwise work the same as before. - `extension`: Remove `extension.Settings.ModuleInfo` (#12296) - The functionality is now available as an optional, hidden interface on `service`'s implementation of the `Host` - `component`: Remove deprecated field `component.TelemetrySettings.MetricsLevel`. (#11061) - `confighttp`: Add `ToClientOption` type and add it to signature of `ToClient` method. (#12353) - This has no use for now, it may be used in the future. - `mdatagen`: Remove unused not_component config for mdatagen (#12237) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `component/componenttest`: Deprecate CheckReceiverMetrics in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckReceiverMetrics` - `component/componenttest`: Deprecate CheckReceiverTraces in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckReceiverTraces` - `component`: Deprecate `ConfigValidator` and `ValidateConfig` (#11524) Please use `Validator` and `Validate` respectively from `xconfmap`. - `receiver, scraper, processor, exporter, extension`: Deprecate existing MakeFactoryMap functions in favor of generic implementation (#12222) - `extension, connector, processor, receiver, exporter, scraper`: Deprecate `Create*` methods from `Create*Func` types. (#12305) - `extensiontest, connectortest, processortest, receivertest, exportertest, scrapertest`: Deprecate `*test.NewNopSettings` in favor of `*test.NewNopSettingsWithType` (#12305) ### ๐Ÿš€ New components ๐Ÿš€ - `xconfmap`: Create the xconfmap module and add the `Validator` interface and `Validate` function to facilitate config validation (#11524) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configgrpc`: Add the `omitempty` mapstructure tag to struct fields (#12191) This results in unset fields not being rendered when marshaling. - `confignet`: Add the `omitempty` mapstructure tag to struct fields (#12191) This results in unset fields not being rendered when marshaling. - `configtls`: Add the `omitempty` mapstructure tag to struct fields (#12191) This results in unset fields not being rendered when marshaling. - `consumer`: Clarify that data cannot be accessed after Consume* func is called. (#12284) - `pdata/pprofile`: Introduce aggregation temporality constants (#12253) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configgrpc`: Apply configured Headers automatically (#12307) configgrpc now calls metadata.AppendToOutgoingContext automatically in an interceptor. Components that were manually using metadata.NewOutgoingContext as a workaround no longer need to do so, unless they are overwriting or adding header keys. - `configgrpc`: Set Auth to nil in NewDefaultClientConfig/NewDefaultServerConfig (#12223) The value that was used previously would always cause an error on startup. - `exporterqueue`: Fix async queue to propagate cancellation all they way to the queue (#12282) - `otlpreceiver`: Fix OTLP http receiver to correctly set Retry-After (#12367) - `extension`: Explicitly error out at extension creation time if there is a type mismatch. (#12305) ## v1.25.0/v0.119.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Change queue to embed the async consumers. (#12242) - `exporterqueue`: Change Queue interface to return a callback instead of an index (#8122) - `cmd/mdatagen`: Allow passing OTel Metric SDK options to the generated `SetupTelemetry` function. (#12166) - `exporterhelper`: Rename exporter span signal specific attributes (e.g. "sent_spans" / "send_failed_span") to "items.sent" / "items.failed". (#12165) - `component`: Change underlying type for `component.Kind` to be a struct. (#12214) - `extension`: Change `extension.Extension` to be an interface that embeds `component.Component` instead of an alias (#11443) - `component/componenttest`: Remove deprecated `CheckScraperMetrics` functions (#12183) - `scraperhelper`: Remove deprecated ScrapperControllerOption and NewScraperControllerMetrics from scraperhelper. (#12147) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `metadatatest`: Deprecate metadatatest.Telemetry in favor of componenttest.Telemetry (#12218) metadatatest.Telemetry -> componenttest.Telemetry | metadatatest.SetupTelemetry -> componenttest.NewTelemetry | metadatatest.Telemetry.NewSettings -> metadatatest.NewSettings | metadatatest.Telemetry.AssertMetrics -> metadatatest.AssertEqual* | - `component/componenttest`: Deprecate `CheckExporterEnqueue*` functions in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckExporterEnqueue*` functions. - `component/componenttest`: Deprecate CheckExporterLogs in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckExporterLogs` - `component/componenttest`: Deprecate CheckExporterMetricGauge in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckReceiverMetricGauge` - `component/componenttest`: Deprecate CheckExporterMetrics in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckExporterMetrics` - `component/componenttest`: Deprecate CheckExporterTraces in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckExporterTraces` - `component/componenttest`: Deprecate CheckReceiverLogs in componenttest (#12185) Use the `metadatatest.AssertEqualMetric` series of functions instead of `obsreporttest.CheckReceiverLogs` - `mdatagen`: Make registration of callback for async metric always optional. (#12204) Deprecate `metadata.TelemetryBuilder.Init*` and `metadata.With*Callback` in favor of `metadata.TelemetryBuilder.Register*Callback` - `component`: Deprecate `component.TelemetrySettings.MetricsLevel` in favor of using views and 'Enabled' method. (#12159) - Components will temporarily need the service to support using views. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `componenttest`: Add helper to get a metric for componenttest.Telemetry (#12215) - `componenttest`: Extract componenttest.Telemetry as generic struct for telemetry testing (#12151) - `mdatagen`: Generate assert function for each metric in mdatagen (#12179) - `metadatatest`: Generate NewSettings that accepts componenttest.Telemetry (#12216) - `pdata/pprofile`: Add new helper method `FromAttributeIndices` to build a `pcommon.Map` out of `AttributeIndices`. (#12176) - `scraper`: Support logs scraper (#12116) - `component`: Allow `component.ValidateConfig` to recurse through all fields in a config object (#11524) - `component`: Show path to invalid config in errors returned from `component.ValidateConfig` (#12108) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `mdatagen`: All register callbacks to async instruments can now be unregistered by calling `metadata.TelemetryBuilder.Shutdown()` (#12204) - `mdatagen`: Fix bug where Histograms were marked as not supporting temporal aggregation (#12168) ## v1.24.0/v0.118.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterqueue`: Change Queue Size and Capacity to return explicit int64. (#12076) - `receiver/scraperhelper`: Removing the deprecated receiver/scraperhelper package (#12054) - `processortest`: Revert the nop_processor.NewNopSettings change, as it is no longer needed (#11433) - `experimental/storage`: Remove deprecated package/module experimental/storage (#12109) - `mdatagen`: Remove deprecated generated_component_telemetry_test file from being generated and delete it. (#12068) - `receivertest`: Remove deprecated receivertest.NewNopFactoryForType (#12110) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `componenttest`: Deprecate CheckScraperMetrics in componenttest (#12105) Use `metadatatest.AssertMetrics` instead of `obsreporttest.CheckScraperMetrics` - `scraperhelper`: Deprecate `scraperhelper.NewScraperControllerReceiver` and `scraperhelper.ScraperControllerOption`. (#12103) Use `scraperhelper.NewMetricsController` instead of `scraperhelper.NewScraperControllerReceiver` | Use `scraperhelper.ScraperControllerOption` instead of `scraperhelper.ControllerOption` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add capability for memory and persistent queue to block when add items (#12074) - `scraper/scraperhelper`: Add obs_logs for scraper/scraperhelper (#12036) This change adds obs for logs in scraper/scraperhelper, also introduced new metrics for scraping logs. - `mdatagen`: Add scraper component type support to mdatagen (#12092) - `mdatagen`: Add tracing support in metadatatest (#12106) - `exporterhelper`: Change persistent queue to not use sized channel, improve memory usage and simplify sized_channel. (#12060) - `confighttp`: Added support for configuring compression levels. (#10467) A new configuration option called CompressionParams has been added to confighttp. | This allows users to configure the compression levels for the confighttp client. ## v1.23.0/v0.117.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pdata/pprofile`: Remove duplicate Attributes field from profile (#11932) - `connector`: Remove deprecated connectorprofiles module, use xconnector instead. (#11778) - `consumererror`: Remove deprecated consumererrorprofiles module, use xconsumererror instead. (#11778) - `consumer`: Remove deprecated consumerprofiles module, use xconsumer instead. (#11778) - `exporterhelper`: Remove deprecated exporterhelperprofiles module, use xexporterhelper instead. (#11778) - `exporter`: Remove deprecated exporterprofiles module, use xexporter instead. (#11778) - `pipeline`: Remove deprecated pipelineprofiles module, use xpipeline instead. (#11778) - `processorhelper`: Remove deprecated processorhelperprofiles module, use xprocessorhelper instead. (#11778) - `processor`: Remove deprecated processorprofiles module, use xprocessor instead. (#11778) - `receiver`: Remove deprecated receiverprofiles module, use xreceiver instead. (#11778) - `exporterhelper`: Remove Merge function from experimental Request interface (#12012) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `mdatagen`: Deprecate component_test in favor of metadatatest (#11812) - `receivertest`: Deprecate receivertest.NewNopFactoryForType (#11993) - `extension/experimental`: Deprecate extension/experimental in favor of extension/xextension (#12010) - `scraperhelper`: Move scraperhelper under scraper and in a separate module. (#11003) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `scrapertest`: Add scrapertest package in a separate module (#11988) - `pdata`: Upgrade pdata to opentelemetry-proto v1.5.0 (#11932) ## v1.22.0/v0.116.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `component`: Remove deprecated TelemetrySettings.LeveledMeterProvider (#11811) - `scraperhelper`: Remove deprecated scraperhelper.Scraper and helpers (#11803) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `connector`: Deprecate connectorprofiles module in favor of xconnector to allow adding more experimental data types. (#11778) - `consumererror`: Deprecate consumererrorprofiles module in favor of xconsumererror to allow adding more experimental data types. (#11778) - `consumer`: Deprecate consumerprofiles module in favor of xconsumer to allow adding more experimental data types. (#11778) - `exporterhelper`: Deprecate exporterhelperprofiles module in favor of xexporterhelper to allow adding more experimental data types. (#11778) - `exporter`: Deprecate exporterprofiles module in favor of xexporter to allow adding more experimental data types. (#11778) - `pipeline`: Deprecate pipelineprofiles module in favor of xpipeline to allow adding more experimental data types. (#11778) - `processorhelper`: Deprecate processorhelperprofiles module in favor of xprocessorhelper to allow adding more experimental data types. (#11778) - `processor`: Deprecate processorprofiles module in favor of xprocessor to allow adding more experimental data types. (#11778) - `receiver`: Deprecate receiverprofiles module in favor of xreceiver to allow adding more experimental data types. (#11778) - `receiver/scrapererror`: Remove the receiver/scrapererror alias. (#11003) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `receiver/scraperhelper`: Add scraper for logs (#11238) ## v1.21.0/v0.115.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `extension/auth/authtest`: `authtest` is now its own module (#11465, #11705) - `pdata/pprofile`: AttributeTable is now a slice rather than a map (#11706) - `scraperhelper`: Remove deprecated scraperhelper funcs Scraper.ID, NewScraper, AddScraper. (#11710) - `mdatagen`: Remove deprecated LeveledMeter from the generated code (#11696) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `component`: Mark `TelemetrySettings.LeveledMeterProvider` as deprecated (#11697) - `receiver/scraper`: Move receiver/scrapererror package to scraper/scrapererror and deprecate original receiver/scrapererror package. (#11003) - `scraperhelper`: Make Scraper compatible with the new scraper.Metrics (#11682) Deprecate scraperhelper.Scraper in favor of scraper.Metrics ## v1.20.0/v0.114.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `extensiontest`: Make extensiontest into its own module (#11463) - `component`: Make componenttest into its own module (#11464) - `expandconverter`: Remove deprecated expandvar converter (#11672) - `exporter`: Remove deprecated funcs Create[*]Exporter and [*]ExporterStability (#11662) - `exporterhelper`: Remove deprecated NewLogs[Request]Exporter funcs (#11661) - `extension`: Remove deprecated funcs CreateExtension and ExtensionStability (#11663) - `processortest`: Remove deprecated func NewUnhealthyProcessorCreateSettings (#11665) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `component`: Deprecate `TelemetrySettings.LeveledMeterProvider` and undo deprecation of `TelemetrySettings.MeterProvider` (#11061) - `scraperhelper`: Deprecate Scraper.ID func, pass type when register Scraper (#11238) ## v1.19.0/v0.113.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `builder`: Remove deprecated flags from Builder (#11576) Here is the list of flags | --name, --description, --version, --otelcol-version, --go, --module ### ๐Ÿš€ New components ๐Ÿš€ - `processorhelperprofiles`: Add processorhelperprofiles to support profiles signal (#11556) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Add newTelemetrySettings to be generated all the time even for pkg class (#11535) - `debugexporter`: Add profiles support to debug exporter (#11155) - `component`: Add UnmarshalText for StabilityLevel (#11520) ## v1.18.0/v0.112.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: Change Host to not implement GetExportersWithSignal (#11444) Use Host.GetExporters if still needed. - `componentstatus`: Remove deprecated `NewInstanceIDWithPipelineIDs`, `AllPipelineIDsWithPipelineIDs`, and `WithPipelineIDs`. Use `NewInstanceID`, `AllPipelineIDs` and `WithPipelines` instead. (#11363) - `configgrpc`: Removed deprecated `ClientConfig.ToClientConnWithOptions`/`ServerConfig.ToServerWithOptions`. (#11359, #9480) These methods were renamed to `ClientConfig.ToClientConn`/`ServerConfig.ToServer` in v0.111.0. - `connector`: Put connectortest in its own module (#11216) - `exporter`: Disables setting batch option to batch sender directly. (#10368) Removed WithRequestBatchFuncs(BatcherOption) in favor of WithBatchFuncs(Option), where | BatcherOption is a function that operates on batch sender and Option is one that operates | on BaseExporter - `exporter`: Made mergeFunc and mergeSplitFunc required method of exporter.Request (#10368) mergeFunc and mergeSplitFunc used to be part of the configuration pass to the exporter. Now it is changed | to be a method function of request. - `componentprofiles`: Move componentprofiles to pipelineprofiles (#11421) - `processor`: Put processortest in its own module (#11218) - `receivertest`: Removed deprecated `NewNopFactoryForTypeWithSignal`. Use `NewNopFactoryForType` instead. (#11362) - `processor`: Remove deprecated funcs from processor package (#11368) - `receiver`: Remove deprecated funcs from receiver package (#11367) - `processorhelper`: Remove deprecated funcs/types from processorhelper & componenttest (#11302) - `service`: Remove deprecated `pipelines.ConfigWithPipelineID` and `Config.PipelinesWithPipelineID`. Use `pipelines.Config` and `Config.Pipelines` instead. (#11361) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `extension`: Deprecate funcs that repeat extension in name (#11413) Factory.CreateExtension -> Factory.Create | Factory.ExtensionStability -> Factory.Stability - `exporter`: Deprecate funcs that repeat exporter in name (#11370) Factory.Create[Traces|Metrics|Logs|Profiles]Exporter -> Factory.Create[Traces|Metrics|Logs|Profiles] | Factory.[Traces|Metrics|Logs|Profiles]ExporterStability -> Factory.[Traces|Metrics|Logs|Profiles]Stability ### ๐Ÿš€ New components ๐Ÿš€ - `consumererrorprofiles`: Add new module consumererrorprofiles for consumer error profiles. (#11131) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configcompression`: Add support for lz4 compression (#9128) - `otlpexporter`: Add profiles support to OTLP exporter (#11435) - `otlphttpexporter`: Add profiles support to OTLP HTTP exporter (#11450) ## v1.17.0/v0.111.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service/telemetry`: Change default metrics address to "localhost:8888" instead of ":8888" (#11251) This behavior can be disabled by disabling the feature gate 'telemetry.UseLocalHostAsDefaultMetricsAddress'. - `componentprofiles`: Removed deprecated `DataTypeProfiles`. Use `SignalProfiles` instead. (#11312) - `configgrpc`: Replace ToClientConn and ToServer with ToClientConnWithOptions and ToServerWithOptions. (#11271, #9480) `ClientConfig.ToClientConn` and `ServerConfig.ToServer` were deprecated in v0.110.0 in favor of `ClientConfig.ToClientConnWithOptions` and `ServerConfig.ToServerWithOptions` which use a more flexible option type. The original functions are now removed, and the new ones are renamed to the old names. The `WithOptions` names are kept as deprecated aliases for now. - `exporterhelper`: Removed deprecated `QueueTimeout`/`TimeoutSettings` aliases in favor of `QueueConfig`/`TimeoutConfig`. (#11264, #6767) `NewDefaultQueueSettings` and `NewDefaultTimeoutSettings` have been similarly renamed. - `exporterqueue`: Remove deprecated `Settings.DataType`. Use `Settings.Signal` instead. (#11305) - `exportertest`: Remove deprecated `CheckConsumeContractParams.DataType`. Use `CheckConsumeContractParams.Signal` instead. (#11305) - `component`: Removed deprecated `ErrDataTypeIsNotSupported`, `DataType`, `DataTypeTraces`, `DataTypeMetrics`, and `DataTypeLogs`. Use `pipeline.ErrSignalNotSupported`, `pipeline.Signal`, `pipeline.SignalTraces`, `pipeline.SignalMetrics`, and `pipeline.SignalLogs` instead. (#11253) - `pdata/pprofile`: Replace slices of values to slices of pointers for the `Mapping`, `Location`, `Line`, `Function`, `AttributeUnit`, `Link`, `Value`, `Sample` and `Labels` attributes. (#11339) - `receivertest`: Remove deprecated `CheckConsumeContractParams.DataType`. Use `CheckConsumeContractParams.Signal` instead. (#11304) - `scraperhelper`: Remove deprecated function `NewScraperWithComponentType`. (#11294) - `processorhelper`: Remove deprecated funcs form processorhelper.ObsReport (#11289) The "otelcol_processor_dropped_log_records", "otelcol_processor_dropped_log_records" | and "otelcol_processor_dropped_spans" metrics are complete removed, before they were always record with 0 values. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `componentstatus`: Deprecated `NewInstanceIDWithPipelineIDs`, `AllPipelineIDsWithPipelineIDs`, and `WithPipelineIDs`. Use `NewInstanceID`, `AllPipelineIDs`, and `WithPipelines` instead. (#11313) - `processorhelper`: Deprecate unused and empty struct processorhelper.ObsReport (#11293) - `processor`: Deprecate funcs that repeat "processor" in name (#11310) Factory.Create[Traces|Metrics|Logs|Profiles]Processor -> Factory.Create[Traces|Metrics|Logs|Profiles] Factory.[Traces|Metrics|Logs|Profiles]ProcessorStability -> Factory.[Traces|Metrics|Logs|Profiles]Stability - `receiver`: Deprecate funcs that repeat "receiver" in name (#11287) Factory.Create[Traces|Metrics|Logs|Profiles]Receiver -> Factory.Create[Traces|Metrics|Logs|Profiles] Factory.[Traces|Metrics|Logs|Profiles]ReceiverStability -> Factory.[Traces|Metrics|Logs|Profiles]Stability - `receivertest`: Deprecated `NewNopFactoryForTypeWithSignal`. Use `NewNopFactoryForType` instead. (#11304) - `service`: Deprecates `Config.PipelinesWithPipelineID`, `pipelines.ConfigWithPipelineID` and `GetExportersWithSignal` interface implementation. Use `Config.Pipelines`, `pipelines.Config`, and `GetExporters` interface implementation instead. (#11303) ## v1.16.0/v0.110.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otlpexporter`: The `TimeoutSettings` field in `otlpexporter.Config` was renamed to `TimeoutConfig`. (#11132) - `connector`: Change `TracesRouterAndConsumer`, `NewTracesRouter`, `MetricsRouterAndConsumer`, `NewMetricsRouter`, `LogsRouterAndConsumer`, and `NewLogsRouter` to use `pipeline.ID` instead of `component.ID`. (#11204) - `extension`: Remove deprecated extension interfaces. (#11043) They are now available in the `extensioncapabilities` module. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `exporterhelper`: Deprecate TimeoutSettings/QueueSettings in favor of TimeoutConfig/QueueConfig. (#6767) - `configgrpc`: Deprecate `ClientConfig.ToClientConn`/`ServerConfig.ToServer` in favor of `ToClientConnWithOptions`/`ToServerWithOptions` (#9480) Users providing a grpc.DialOption/grpc.ServerOption should now wrap them into a generic option with `WithGrpcDialOption`/`WithGrpcServerOption`. - `componentprofiles`: Deprecates `DataTypeProfiles`. Use `SignalProfiles` instead. (#11204) - `componentstatus`: Deprecates `NewInstanceID`, `AllPipelineIDs`, and `WithPipelines`. Use `NewInstanceIDWithPipelineIDs`, `AllPipelineIDsWithPipelineIDs`, and `WithPipelineIDs` instead. (#11204) - `exporterqueue`: Deprecates `Settings.DataType`. Use `Settings.Signal` instead. (#11204) - `service`: Deprecates `pipelines.Config`. Use `pipelines.ConfigWithPipelineID` instead. (#11204) - `component`: Deprecates `DataType`, `DataTypeTraces`, `DataTypeMetrics`, and `DataTypeLogs`. Use `pipeline.Signal`, `SignalTraces`, `SignalMetrics`, and `SignalLogs` instead. (#11204) - `service`: Deprecates service's implementation of `GetExporters` interface. Use `GetExportersWithSignal` instead. (#11249) - `scraperhelper`: Deprecate NewScraperWithComponentType, should use NewScraper (#11159) ### ๐Ÿš€ New components ๐Ÿš€ - `pipeline`: Adds new `pipeline` module to house the concept of pipeline ID and Signal. (#11209) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Add support to MoveTo for Map, allow avoiding copies (#11175) - `options`: Avoid using private types in public APIs and also protect options to be implemented outside this module. (#11054) - `mdatagen`: Avoid using private types in public APIs and also protect options to be implemented outside this module. (#11040) - `consumertest`: Introduce SampleCount method in ProfilesSink struct. (#11225) - `otlpreceiver`: Support profiles in the OTLP receiver (#11071) ## v1.15.0/v0.109.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `Remove `extensiontest` StatusWatcher helpers`: They were unused. They may be added back on a different module or after `componentstatus` is marked 1.0 (#11044) - `pprofile`: Change Profile ID field from a byte array to a custom data type (#11048) - `connector`: Remove deprecated connector builder (#11019) - `exporter`: Remove deprecated exporter builder (#11019) - `extension`: Remove deprecated extension builder (#11019) - `processor`: Remove deprecated processor builder (#11019) - `receiver`: Remove deprecated receiver builder (#11019) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `configtelemetry`: Deprecating `TelemetrySettings.MeterProvider` in favour of `TelemetrySettings.LeveledMeterProvider` (#10912) - `extension`: Deprecate `extension.ConfigWatcher`, `extension.PipelineWatcher` and `extension.Dependent` in favor of equivalents in the `extensioncapabilities` module. (#11000) - `scraperhelper`: deprecate NewScraper, should use NewScraperWithComponentType (#11082) ### ๐Ÿš€ New components ๐Ÿš€ - `extensioncapabilities`: Create a new module for optional extension capabilities. (#11000) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `connectorprofiles`: Add ProfilesRouterAndConsumer interface, and NewProfilesRouter method. (#11023) - `pprofileotlp`: Introduce grpc service implementation of pprofileotlp (#11048) - `pprofile`: Introduce marshalling and unmarshalling of pprofile data (#11048) - `service`: Support profiles in the service package (#11024) ## v1.14.1/v0.108.1 ## v1.14.0/v0.108.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `extensions`: Remove `StatusWatcher` interface. Use `componentstatus.Watcher` instead. (#10777) - `component`: Removed Status related types and functions. Use `componentstatus` instead. (#10777) - `component`: Remove `ReportStatus` from `TelemetrySettings`. Use `componentstatus.ReportStatus` instead. (#10777) - `componentstatus`: Make componentstatus.InstanceID immutable. (#10494) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `scraperhelper`: deprecate NewObsReport, ObsReport, ObsReportSettings, scrapers should use NewScraperControllerReceiver (#10959) - `mdatagen`: Deprecating generated `Meter` func in favour of `LeveledMeter` (#10939) - `connector`: Deprecate connector.Builder, and move it into an internal package of the service module (#10784) - `exporter`: Deprecate exporter.Builder, and move it into an internal package of the service module (#10783) - `extension`: Deprecate extension.Builder, and move it into an internal package of the service module (#10785) - `processor`: Deprecate processor.Builder, and move it into an internal package of the service module (#10782) - `receiver`: Deprecate receiver.Builder, and move it into an internal package of the service module (#10781) ## v1.13.0/v0.107.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otelcol`: Delete deprecated NewCommandMustSetProvider (#10778) - `component`: Removes the deprecated `Host.GetFactory` method. (#10771) - `otelcoltest`: The `otelcol.LoadConfig` method no longer sets the `expandconverter`. (#10510) - `ocb`: Collectors built with OCB will no longer include the `expandconverter` (#10510) - `exporterhelper`: Delete deprecated `exporterhelper.ObsReport` and `exporterhelper.NewObsReport` (#10779, #10592) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `expandconverter`: Deprecate `expandconverter`. (#10510) ### ๐Ÿš€ New components ๐Ÿš€ - `componentstatus`: Adds new componentstatus module that will soon replace status content in component. (#10730) - `connector/connectorprofiles`: Allow handling profiles in connector. (#10703) - `exporter/exporterprofiles`: Allow handling profiles in exporter. (#10702) - `processor/processorprofiles`: Allow handling profiles in processor. (#10691) - `receiver/receiverprofiles`: Allow handling profiles in receiver. (#10690) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confmap`: Check that providers have a correct scheme when building a confmap.Resolver. (#10786) - `confighttp`: Add `NewDefaultCORSConfig` function to initialize the default `confighttp.CORSConfig` (#9655) ## v0.106.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `configauth`: removing deprecated methods GetServerAuthenticatorContext and GetClientAuthenticatorContext (#9808) - `connector,exporter,receiver,extension,processor`: Remove deprecated funcs/structs (#10423) Remove the following funcs & structs: - connector.CreateSettings -> connector.Settings - connectortest.NewNopCreateSettings -> connectortest.NewNopSettings - exporter.CreateSettings -> exporter.Settings - exportertest.NewNopCreateSettings -> exportertest.NewNopSettings - extension.CreateSettings -> extension.Settings - extensiontest.NewNopCreateSettings -> extensiontest.NewNopSettings - processor.CreateSettings -> processor.Settings - processortest.NewNopCreateSettings -> processortest.NewNopSettings - receiver.CreateSettings -> receiver.Settings - receivertest.NewNopCreateSettings -> receivertest.NewNopSettings - `component/componenttest`: Add optional ...attribute.KeyValue argument to TestTelemetry.CheckExporterMetricGauge. (#10593) - `confighttp`: Auth data type signature has changed (#4806) As part of the linked PR, the `auth` attribute was moved from `configauth.Authentication` to a new `AuthConfig`, which contains a `configauth.Authentication`. For end-users, this is a non-breaking change. For users of the API, create a new AuthConfig using the `configauth.Authentication` instance that was being used before. - `mdatagen`: Remove WithAttributes option from the telemetry builder constructor. (#10608) Attribute sets for async instruments now can be set as options to callback setters and async instruments initializers. This allows each async instrument to have its own attribute set. - `service/extensions`: Adds `Options` to `extensions.New`. (#10728) This is only a breaking change if you are depending on `extensions.New`'s signature. Calls to `extensions.New` are not broken. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `component`: Deprecates Host.GetFactory. (#10709) ### ๐Ÿš€ New components ๐Ÿš€ - `component/componentprofiles`: Add componentprofiles module. (#10525) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter, processor, receiver`: Document factory functions. (#9323) - `component`: Document status enums and New constructors (#9822) - `confighttp, configgrpc`: Remove the experimental comment on `IncludeMetadata` in confighttp and configgrpc (#9381) - `confighttp`: Add `confighttp.NewDefaultServerConfig()` to instantiate the default HTTP server configuration (#9655) - `consumer/consumertest`: Allow testing profiles with consumertest. (#10692) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confmap`: Fix wrong expansion of environment variables escaped with `$$`, e.g. `$${ENV_VAR}` and `$$ENV_VAR`. (#10713) This change fixes the issue where environment variables escaped with $$ were expanded. The collector now converts `$${ENV_VAR}` to `${ENV_VAR}` and `$$ENV_VAR` to `$ENV_VAR` without further expansion. ## v1.12.0/v0.105.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otelcol`: Obtain the Collector's effective config from otelcol.Config (#10139) `otelcol.Collector` will now marshal `confmap.Conf` objects from `otelcol.Config` itself. - `otelcoltest`: Remove deprecated methods `LoadConfigWithSettings` and `LoadConfigAndValidateWithSettings` (#10512) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `configauth`: Deprecated `Authentication.GetClientAuthenticatorContext` and `Authentication.GetServerAuthenticatorContext` (#10578) - `otelcol`: Deprecate `otelcol.ConfmapProvider` (#10139) `otelcol.Collector` will now marshal `confmap.Conf` objects from `otelcol.Config` itself. - `otelcol`: Deprecate `(*otelcol.ConfigProvider).GetConfmap` (#10139) Call `(*confmap.Conf).Marshal(*otelcol.Config)` to get the Collector's configuration. - `exporterhelper`: Deprecate the obsreport API in the exporterhelper package. (#10592) ### ๐Ÿš€ New components ๐Ÿš€ - `consumer/consumerprofiles`: Allow handling profiles in consumer. (#10464) ## v1.11.0/v0.104.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otelcol`: The `otelcol.NewCommand` now requires at least one provider be set. (#10436) - `component/componenttest`: Added additional "inserted" count to `TestTelemetry.CheckProcessor*` methods. (#10353) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `otelcoltest`: Deprecates `LoadConfigWithSettings` and `LoadConfigAndValidateWithSettings`. Use `LoadConfig` and `LoadConfigAndValidate` instead. (#10417) - `otelcol`: The `otelcol.NewCommandMustSetProvider` is deprecated. Use `otelcol.NewCommand` instead. (#10436) ### ๐Ÿš€ New components ๐Ÿš€ - `otelcoltest`: Split off go.opentelemetry.io/collector/otelcol/otelcoltest into its own module (#10417) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata/pprofile`: Add pprofile wrapper to convert proto into pprofile. (#10401) - `pdata/testdata`: Add pdata testdata for profiles. (#10401) ## v1.10.0/v0.103.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `component`: Remove deprecated `component.UnmarshalConfig` (#7102) - `confighttp`: Use `confighttp.ServerConfig` as part of zpagesextension.Config. Previously the extension used `confignet.TCPAddrConfig` (#9368) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `connector`: Deprecate CreateSettings and NewNopCreateSettings (#9428) The following methods are being renamed: - connector.CreateSettings -> connector.Settings - connector.NewNopCreateSettings -> connector.NewNopSettings - `exporter`: Deprecate CreateSettings and NewNopCreateSettings (#9428) The following methods are being renamed: - exporter.CreateSettings -> exporter.Settings - exporter.NewNopCreateSettings -> exporter.NewNopSettings - `extension`: Deprecate CreateSettings and NewNopCreateSettings (#9428) The following methods are being renamed: - extension.CreateSettings -> extension.Settings - extension.NewNopCreateSettings -> extension.NewNopSettings - `processor`: Deprecate CreateSettings and NewNopCreateSettings (#9428) The following methods are being renamed: - processor.CreateSettings -> processor.Settings - processor.NewNopCreateSettings -> processor.NewNopSettings - `receiver`: Deprecate CreateSettings and NewNopCreateSettings (#9428) The following methods are being renamed: - receiver.CreateSettings -> receiver.Settings - receiver.NewNopCreateSettings -> receiver.NewNopSettings - `configauth`: Deprecate `GetClientAuthenticator` and `GetServerAuthenticator`, use `GetClientAuthenticatorContext` and `GetServerAuthenticatorContext` instead. (#9808) - `confighttp`: Deprecate `ClientConfig.CustomRoundTripper` (#8627) Set the `Transport` field on the `*http.Client` object returned from `(ClientConfig).ToClient` instead. - `filter`: Deprecate the `filter.CombinedFilter` struct (#10348) - `otelcol`: Deprecate `otelcol.NewCommand`. Use `otelcol.NewCommandMustProviderSettings` instead. (#10359) - `otelcoltest`: Deprecate `LoadConfig` and `LoadConfigAndValidate`. Use `LoadConfigWithSettings` and `LoadConfigAndValidateWithSettings` instead (#10359) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confmap`: Adds `confmap.Retrieved.AsString` method that returns the configuration value as a string (#9532) - `confmap`: Adds `confmap.NewRetrievedFromYAML` helper to create `confmap.Retrieved` values from YAML bytes (#9532) ## v0.102.1 No API-only changes on this release. **This release addresses [GHSA-c74f-6mfw-mm4v](https://github.com/open-telemetry/opentelemetry-collector/security/advisories/GHSA-c74f-6mfw-mm4v) for `configgrpc`.** ## v1.9.0/v0.102.0 **This release addresses [GHSA-c74f-6mfw-mm4v](https://github.com/open-telemetry/opentelemetry-collector/security/advisories/GHSA-c74f-6mfw-mm4v) for `confighttp`.** ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otelcol`: Remove deprecated `ConfigProvider` field from `CollectorSettings` (#10281) - `exporterhelper`: remove deprecated RequestMarshaler & RequestUnmarshaler types (#10283) - `service`: remove deprecated Telemetry struct and New func (#10285) - `configtls`: remove deprecated LoadTLSConfigContext funcs (#10283) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `component`: Deprecate `component.UnmarshalConfig`, use `(*confmap.Conf).Unmarshal(&intoCfg)` instead. (#7102) - `service/telemetry`: Deprecate telemetry.New in favor of telemetry.NewFactory (#4970) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confmap`: Allow setting a default Provider on a Resolver to use when `${}` syntax is used without a scheme (#10182) - `pdata`: Introduce string and int64 slices to pcommon (#10148) - `pdata`: Introduce generated experimental pdata for profiling signal. (#10195) - `confmap`: Remove top level condition when considering struct as Unmarshalers (#7101) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otelcol`: Update validate command to use the new configuration options (#10203) ## v1.8.0/v0.101.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `confighttp`: Removes deprecated functions `ToClientContext`, `ToListenerContext`, and `ToServerContext`. (#10138) - `confmap`: Deprecate `NewWithSettings` for all Providers and `New` for all Converters (#10134) Use `NewFactory` instead for all affected modules. - `confmap`: Remove deprecated `Providers` and `Converters` from `confmap.ResolverSettings` (#10173) Use `ProviderSettings` and `ConverterSettings` instead. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otelcol`: Add explicit mapstructure tags to main configuration struct (#10152) - `confmap`: Support string-like types as map keys when marshaling (#10137) ## v1.7.0/v0.100.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configgrpc`: Adds `NewDefault*` functions for all the config structs. (#9654) - `exporterqueue`: Expose ErrQueueIsFull so upstream components can retry or apply backpressure. (#10070) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `mdatagen`: Call connectors with routers to be the same as the service graph (#10079) ## v1.6.0/v0.99.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `component`: Removed deprecated function `GetExporters` from `component.Host` interface (#9987) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `confighttp`: deprecate ToClientContext, ToServerContext, ToListenerContext, replaced by ToClient, ToServer, ToListener (#9807) - `configtls`: Deprecates `ClientConfig.LoadTLSConfigContext` and `ServerConfig.LoadTLSConfigContext`, use `ClientConfig.LoadTLSConfig` and `ServerConfig.LoadTLSConfig` instead. (#9945) - `confmap`: Deprecate the `Providers` and `Converters` fields in `confmap.ResolverSettings` (#9516) Use the `ProviderFactories` and `ConverterFactories` fields instead. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configauth`: Adds `NewDefault*` functions for all the config structs. (#9821) - `configtls`: Adds `NewDefault*` functions for all the config structs. (#9658) - `pmetric`: Support metric.metadata in pdata/pmetric (#10006) ## v1.5.0/v0.98.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `component`: Restricts maximum length for `component.Type` to 63 characters. (#9872) - `configgrpc`: Remove deprecated `ToServerContext`, use `ToServer` instead. (#9836) - `configgrpc`: Remove deprecated `SanitizedEndpoint`. (#9836) - `configtls`: Remove Deprecated `TLSSetting`, `TLSClientSetting`, and `TLSServerSetting`. (#9786) - `configtls`: Rename `TLSSetting` to `Config` on `ClientConfig` and `ServerConfig`. (#9786) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `confighttp`: Deprecate `ToClient`,`ToListener`and `ToServer` use `ToClientContext`,`ToListenerContext` and `ToServerContext`instead. (#9807) - `configtls`: Deprecate `ClientConfig.LoadTLSConfig` and `ServerConfig.LoadTLSConfig`, use `ClientConfig.LoadTLSConfigContext` and `ServerConfig.LoadTLSConfigContext` instead. (#9811) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Introduce new module for generating pdata: pdata/testdata (#9886) - `exporterhelper`: Make the `WithBatcher` option available for regular exporter helpers based on OTLP data type. (#8122) Now, `WithBatcher` can be used with both regular exporter helper (e.g. NewTracesExporter) and the request-based exporter helper (e.g. NewTracesRequestExporter). The request-based exporter helpers require `WithRequestBatchFuncs` option providing batching functions. - `confmap`: Creates a logger in the confmap.ProviderSettings and uses it to log when there is a missing or blank environment variable referenced in config. For now the noop logger is used everywhere except tests. (#5615) ## v1.4.0/v0.97.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `configgrpc`: Remove deprecated `ToServer` function. (#9787) - `confignet`: Change `Transport` field from `string` to `TransportType` (#9385) - `component`: Change underlying type of `component.Type` to an opaque struct. (#9208) - `obsreport`: Remove deprecated obsreport/obsreporttest package. (#9724) - `component`: Remove deprecated error `ErrNilNextConsumer` (#9322) - `connector`: Remove `LogsRouter`, `MetricsRouter` and `TracesRouter`. Use `LogsRouterAndConsumer`, `MetricsRouterAndConsumer`, `TracesRouterAndConsumer` respectively instead. (#9095) - `receiver`: Remove deprecated struct `ScraperControllerSettings` and function `NewDefaultScraperControllerSettings` (#6767) - `confmap`: Remove deprecated `provider.New` methods, use `NewWithSettings` moving forward. (#9443) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `configgrpc`: Deprecated `ToServerContext`, use `ToServer` instead. (#9787) - `configgrpc`: Deprecate `SanitizedEndpoint` (#9788) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add experimental batching capabilities to the exporter helper (#8122) - `confignet`: Adds `NewDefault*` functions for all the config structs. (#9656) - `configtls`: Validates TLS min_version and max_version (#9475) Introduces `Validate()` method in TLSSetting. - `exporterhelper`: Invalid exporterhelper options now make the exporter creation error out instead of panicking. (#9717) - `components`: Give NoOp components a unique name (#9637) ## v1.3.0/v0.96.0 ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `configgrpc`: Deprecates `ToServer`. Use `ToServerContext` instead. (#9624) - `component`: deprecate component.ErrNilNextConsumer (#9526) - `configtls`: Rename TLSClientSetting, TLSServerSetting, and TLSSetting based on the naming convention used in other config packages. (#9474) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `receivertest`: add support for metrics in contract checker (#9551) ## v1.2.0/v0.95.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Bump minimum go version to go 1.21 (#9507) - `service/telemetry`: Delete generated_config types, use go.opentelemetry.io/contrib/config types instead (#9546) - `configcompression`: Remove deprecated `configcompression` types, constants and methods. (#9388) - `component`: Remove `host.ReportFatalError` (#6344) - `configgrpc`: Remove deprecated `configgrpc.ServerConfig.ToListener` (#9481) - `confmap`: Remove deprecated `confmap.WithErrorUnused` (#9484) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `confignet`: Deprecate `confignet.NetAddr` and `confignet.TCPAddr` in favor of `confignet.AddrConfig` and `confignet.TCPAddrConfig`. (#9509) - `config/configgrpc`: Deprecate `configgrpc.ClientConfig.SanitizedEndpoint`, `configgrpc.ServerConfig.ToListener` and `configgrpc.ServerConfig.ToListenerContext` (#9481, #9482) - `scraperhelper`: Deprecate ScraperControllerSettings, use ControllerConfig instead (#6767) ## v1.1.0/v0.94.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `confignet`: Remove deprecated `DialContext` and `ListenContext` functions (#9363) - `confmap/converter/expandconverter`: Add `confmap.ConverterSettings` argument to experimental `expandconverter.New` function. (#5615, #9162) - The `confmap.ConverterSettings` struct currently has no fields. It will be used to pass a logger. - `component`: Remove deprecated funcs and types (#9283) - `otlpexporter`: Config struct is moving from embedding the deprecated GRPCClientSettings struct to using ClientConfig instead. (#6767) - `otlphttpexporter`: otlphttpexporter.Config embeds the struct confighttp.ClientConfig instead of confighttp.HTTPClientSettings (#6767) - `otlpreceiver`: HTTPConfig struct is moving from embedding the deprecated ServerSettings struct to using HTTPServerConfig instead. (#6767) - `component`: Validate component.Type at creation and unmarshaling time. (#9208) - A component.Type must start with an ASCII alphabetic character and can only contain ASCII alphanumeric characters and '_'. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `configcompressions`: Deprecate `IsCompressed`. Use `CompressionType.IsCompressed instead` instead. (#9435) - `configcompression`: Deprecate `CompressionType`, use `Type` instead. (#9416) - `confighttp`: Deprecate CORSSettings, use CORSConfig instead (#6767) - `configgrpc`: Deprecate `ToListener` function in favor of `ToListenerContext` (#9389) - `configgrpc`: Deprecate GRPCServerSettings, use ServerConfig instead (#6767) - `confighttp`: Deprecate HTTPClientSettings, use ClientConfig instead (#6767) - `confighttp`: Deprecate HTTPServerSettings, use ServerConfig instead (#6767) - `confmap/provider`: Deprecate .New in favor of .NewWithSettings for all core providers (#5615, #9162) - NewWithSettings now takes an empty confmap.ProviderSettings struct. This will be used to pass a logger in the future. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter/exporterhelper`: Add API for enabling queue in the new exporter helpers. (#7874) The following experimental API is introduced in exporter package: - `exporterhelper.WithRequestQueue`: a new exporter helper option for using a queue. - `exporterqueue.Queue`: an interface for queue implementations. - `exporterqueue.Factory`: a queue factory interface, implementations of this interface are intended to be used with WithRequestQueue option. - `exporterqueue.Settings`: queue factory settings. - `exporterqueue.Config`: common configuration for queue implementations. - `exporterqueue.NewDefaultConfig`: a function for creating a default queue configuration. - `exporterqueue.NewMemoryQueueFactory`: a new factory for creating a memory queue. - `exporterqueue.NewPersistentQueueFactory: a factory for creating a persistent queue. - `featuregate`: Add the `featuregate.ErrAlreadyRegistered` error, which is returned by `featuregate.Registry`'s `Register` when adding a feature gate that is already registered. (#8622) Use `errors.Is` to check for this error. ## v0.93.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `bug_fix`: Implement `encoding.BinaryMarshaler` interface to prevent `configopaque` -> `[]byte` -> `string` conversions from leaking the value (#9279) - `configopaque`: configopaque.String implements `fmt.Stringer` and `fmt.GoStringer`, outputting [REDACTED] when formatted with the %s, %q or %#v verbs` (#9213) This may break applications that rely on the previous behavior of opaque strings with `fmt.Sprintf` to e.g. build URLs or headers. Explicitly cast the opaque string to a string before using it in `fmt.Sprintf` to restore the previous behavior. - `all`: Remove obsolete "// +build" directives (#9304) - `connectortest`: Remove deprecated connectortest router helpers. (#9278) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `obsreporttest`: deprecate test funcs/structs (#8492) The following methods/structs have been moved from obsreporttest to componenttest: - obsreporttest.TestTelemetry -> componenttest.TestTelemetry - obsreporttest.SetupTelemetry -> componenttest.SetupTelemetry - obsreporttest.CheckScraperMetrics -> TestTelemetry.CheckScraperMetrics - obsreporttest.TestTelemetry.TelemetrySettings -> componenttest.TestTelemetry.TelemetrySettings() - `confignet`: Deprecates `DialContext` and `ListenContext` functions. Use `Dial` and `Listen` instead. (#9258) Unlike the previous `Dial` and `Listen` functions, the new `Dial` and `Listen` functions take a `context.Context` like `DialContext` and `ListenContext`. ## v1.0.1/v0.92.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otlpexporter`: Change Config members names to use Config suffix. (#9091) - `component`: Remove deprecated unused TelemetrySettingsBase (#9145) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `confignet`: Deprecates the `Dial` and `Listen` functions in favor of `DialContext` and `ListenContext`. (#9163) - `component`: Deprecate unnecessary type StatusFunc (#9146) ## v0.91.0 ## v1.0.0/v0.90.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Replace converter interface with function in the new experimental exporter helper. (#8122) - `featuregate`: Remove deprecate function `featuregate.NewFlag` (#8727) Use `featuregate.Registry`'s `RegisterFlags` method instead. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `telemetry`: deprecate jsonschema generated types (#15009) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Add ZeroThreshold field to exponentialHistogramDataPoint in pmetric package. (#8802) ## v1.0.0-rcv0018/v0.89.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otelcol`: CollectorSettings.Factories now expects: `func() (Factories, error)` (#8478) - `exporter/exporterhelper`: The experimental Request API is updated. (#7874) - `Request` interface now includes ItemsCount() method. - `RequestItemsCounter` is removed. - The following interfaces are added: - Added an optional interface for handling errors that occur during request processing `RequestErrorHandler`. - Added a function to unmarshal bytes into a Request `RequestUnmarshaler`. - Added a function to marshal a Request into bytes `RequestMarshaler` ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `featuregate`: Deprecate `featuregate.NewFlag` in favor of `featuregate.Registry`'s `RegisterFlags` method (#8727) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `featuregate`: Add validation for feature gates ID, URL and versions. (#8766) Feature gates IDs are now explicitly restricted to ASCII alphanumerics and dots. ## v1.0.0-rcv0017/v0.88.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Add IsReadOnly() method to p[metrics|logs|traces].[Metrics|Logs|Spans] pdata structs allowing to check if the struct is read-only. (#6794) ## v1.0.0-rcv0016/v0.87.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Introduce API to control pdata mutability (#6794) This change introduces new API pdata methods to control the mutability: - p[metric|trace|log].[Metrics|Traces|Logs].MarkReadOnly() - marks the pdata as read-only. Any subsequent mutations will result in a panic. - p[metric|trace|log].[Metrics|Traces|Logs].IsReadOnly() - returns true if the pdata is marked as read-only. Currently, all the data is kept mutable. This API will be used by fanout consumer in the following releases. ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `obsreport`: remove methods/structs deprecated in previous release. (#8492) - `extension`: remove deprecated Configs and Factories (#8631) ## v1.0.0-rcv0015/v0.86.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: remove deprecated service.PipelineConfig (#8485) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `obsreporttest`: deprecate To*CreateSettings funcs in obsreporttest (#8492) The following TestTelemetry methods have been deprecated. Use structs instead: - ToExporterCreateSettings -> exporter.CreateSettings - ToProcessorCreateSettings -> processor.CreateSettings - ToReceiverCreateSettings -> receiver.CreateSettings - `obsreport`: Deprecating `obsreport.Exporter`, `obsreport.ExporterSettings`, `obsreport.NewExporter` (#8492) These deprecated methods/structs have been moved to exporterhelper: - `obsreport.Exporter` -> `exporterhelper.ObsReport` - `obsreport.ExporterSettings` -> `exporterhelper.ObsReportSettings` - `obsreport.NewExporter` -> `exporterhelper.NewObsReport` - `obsreport`: Deprecating `obsreport.BuildProcessorCustomMetricName`, `obsreport.Processor`, `obsreport.ProcessorSettings`, `obsreport.NewProcessor` (#8492) These deprecated methods/structs have been moved to processorhelper: - `obsreport.BuildProcessorCustomMetricName` -> `processorhelper.BuildCustomMetricName` - `obsreport.Processor` -> `processorhelper.ObsReport` - `obsreport.ProcessorSettings` -> `processorhelper.ObsReportSettings` - `obsreport.NewProcessor` -> `processorhelper.NewObsReport` - `obsreport`: Deprecating obsreport scraper and receiver API (#8492) These deprecated methods/structs have been moved to receiverhelper and scraperhelper: - `obsreport.Receiver` -> `receiverhelper.ObsReport` - `obsreport.ReceiverSettings` -> `receiverhelper.ObsReportSettings` - `obsreport.NewReceiver` -> `receiverhelper.NewObsReport` - `obsreport.Scraper` -> `scraperhelper.ObsReport` - `obsreport.ScraperSettings` -> `scraperhelper.ObsReportSettings` - `obsreport.NewScraper` -> `scraperhelper.NewObsReport` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `otelcol`: Splitting otelcol into its own module. (#7924) - `service`: Split service into its own module (#7923) ## v0.85.0 ## v0.84.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter/exporterhelper`: Introduce a new exporter helper that operates over client-provided requests instead of pdata (#7874) The following experimental API is introduced in exporter/exporterhelper package: - `NewLogsRequestExporter`: a new exporter helper for logs. - `NewMetricsRequestExporter`: a new exporter helper for metrics. - `NewTracesRequestExporter`: a new exporter helper for traces. - `Request`: an interface for client-defined requests. - `RequestItemsCounter`: an optional interface for counting the number of items in a Request. - `LogsConverter`: an interface for converting plog.Logs to Request. - `MetricsConverter`: an interface for converting pmetric.Metrics to Request. - `TracesConverter`: an interface for converting ptrace.Traces to Request. All the new APIs are intended to be used by exporters that need to operate over client-provided requests instead of pdata. - `otlpreceiver`: Export HTTPConfig as part of the API for creating the otlpreceiver configuration. (#8175) Changes signature of receiver/otlpreceiver/config.go type httpServerSettings to HTTPConfig. ## v0.83.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Remove go 1.19 support, bump minimum to go 1.20 and add testing for 1.21 (#8207) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `changelog`: Generate separate changelogs for end users and package consumers (#8153) opentelemetry-collector-0.141.0/CHANGELOG.md000066400000000000000000007613731511331344600203700ustar00rootroot00000000000000 # Changelog Starting with version v0.83.0, this changelog includes only user-facing changes. If you are looking for developer-facing changes, check out [CHANGELOG-API.md](./CHANGELOG-API.md). ## v1.47.0/v0.141.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pkg/config/confighttp`: Use configoptional.Optional for confighttp.ClientConfig.Cookies field (#14021) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pkg/config/confighttp`: Setting `compression_algorithms` to an empty list now disables automatic decompression, ignoring Content-Encoding (#14131) - `pkg/service`: Update semantic conventions from internal telemetry to v1.37.0 (#14232) - `pkg/xscraper`: Implement xscraper for Profiles. (#13915) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `pkg/config/configoptional`: Ensure that configoptional.None values resulting from unmarshaling are equivalent to configoptional.Optional zero value. (#14218) ## v1.46.0/v0.140.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `cmd/mdatagen`: `metadata.yaml` now supports an optional `entities` section to organize resource attributes into logical entities with identity and description attributes (#14051) When entities are defined, mdatagen generates `AssociateWith{EntityType}()` methods on ResourceBuilder that associate resources with entity types using the entity refs API. The entities section is backward compatible - existing metadata.yaml files without entities continue to work as before. - `cmd/mdatagen`: Add semconv reference for metrics (#13920) - `connector/forward`: Add support for Profiles to Profiles (#14092) - `exporter/debug`: Disable sending queue by default (#14138) The recently added sending queue configuration in Debug exporter was enabled by default and had a problematic default size of 1. This change disables the sending queue by default. Users can enable and configure the sending queue if needed. - `pkg/config/configoptional`: Mark `configoptional.AddEnabledField` as beta (#14021) - `pkg/otelcol`: This feature has been improved and tested; secure-by-default redacts configopaque values (#12369) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `all`: Ensure service service.instance.id is the same for all the signals when it is autogenerated. (#14140) ## v1.45.0/v0.139.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `cmd/mdatagen`: Make stability.level a required field for metrics (#14070) - `cmd/mdatagen`: Replace `optional` field with `requirement_level` field for attributes in metadata schema (#13913) The `optional` boolean field for attributes has been replaced with a `requirement_level` field that accepts enum values: `required`, `conditionally_required`, `recommended`, or `opt_in`. - `required`: attribute is always included and cannot be excluded - `conditionally_required`: attribute is included by default when certain conditions are met (replaces `optional: true`) - `recommended`: attribute is included by default but can be disabled via configuration (replaces `optional: false`) - `opt_in`: attribute is not included unless explicitly enabled in user config When `requirement_level` is not specified, it defaults to `recommended`. - `pdata/pprofile`: Remove deprecated `PutAttribute` helper method (#14082) - `pdata/pprofile`: Remove deprecated `PutLocation` helper method (#14082) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `all`: Add FIPS and non-FIPS implementations for allowed TLS curves (#13990) - `cmd/builder`: Set CGO_ENABLED=0 by default, add the `cgo_enabled` configuration to enable it. (#10028) - `pkg/config/configgrpc`: Errors of type status.Status returned from an Authenticator extension are being propagated as is to the upstream client. (#14005) - `pkg/config/configoptional`: Adds new `configoptional.AddEnabledField` feature gate that allows users to explicitly disable a `configoptional.Optional` through a new `enabled` field. (#14021) - `pkg/exporterhelper`: Replace usage of gogo proto for persistent queue metadata (#14079) - `pkg/pdata`: Remove usage of gogo proto and generate the structs with pdatagen (#14078) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporter/debug`: add queue configuration (#14101) ## v1.44.0/v0.138.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Remove deprecated type `TracesConfig` (#14036) - `pkg/exporterhelper`: Add default values for `sending_queue::batch` configuration. (#13766) Setting `sending_queue::batch` to an empty value now results in the same setup as the default batch processor configuration. - `all`: Add unified print-config command with mode support (redacted, unredacted), json support (unstable), and validation support. (#11775) This replaces the `print-initial-config` command. See the `service` package README for more details. The original command name `print-initial-config` remains an alias, to be retired with the feature flag. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `all`: Add `keep_alives_enabled` option to ServerConfig to control HTTP keep-alives for all components that create an HTTP server. (#13783) - `pkg/otelcol`: Avoid unnecessary mutex in collector logs, replace by atomic pointer (#14008) - `cmd/mdatagen`: Add lint/ordering validation for metadata.yaml (#13781) - `pdata/xpdata`: Refactor JSON marshaling and unmarshaling to use `pcommon.Value` instead of `AnyValue`. (#13837) - `pkg/exporterhelper`: Expose `MergeCtx` in exporterhelper's queue batch settings` (#13742) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `all`: Fix zstd decoder data corruption due to decoder pooling for all components that create an HTTP server. (#13954) - `pkg/otelcol`: Remove UB when taking internal logs and move them to the final zapcore.Core (#14009) This can happen because of a race on accessing `logsTaken`. - `pkg/confmap`: Fix a potential race condition in confmap by closing the providers first. (#14018) ## v1.43.0/v0.137.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `cmd/mdatagen`: Improve validation for resource attribute `enabled` field in metadata files (#12722) Resource attributes now require an explicit `enabled` field in metadata.yaml files, while regular attributes are prohibited from having this field. This improves validation and prevents configuration errors. - `all`: Changelog entries will now have their component field checked against a list of valid components. (#13924) This will ensure a more standardized changelog format which makes it easier to parse. - `pkg/pdata`: Mark featuregate pdata.useCustomProtoEncoding as stable (#13883) ## v1.42.0/v0.136.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `xpdata`: Add Serialization and Deserialization of AnyValue (#12826) - `debugexporter`: add support for batching (#13791) The default queue size is 1 - `configtls`: Add early validation for TLS server configurations to fail fast when certificates are missing instead of failing at runtime. (#13130, #13245) - `mdatagen`: Expose stability level in generated metric documentation (#13748) - `internal/tools`: Add support for modernize in Makefile (#13796) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otelcol`: Fix a potential deadlock during collector shutdown. (#13740) - `otlpexporter`: fix the validation of unix socket endpoints (#13826) ## v1.41.0/v0.135.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add new `exporter_queue_batch_send_size` and `exporter_queue_batch_send_size_bytes` metrics, showing the size of telemetry batches from the exporter. (#12894) ## v1.40.0/v0.134.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Add custom grpc/encoding that replaces proto and calls into the custom marshal/unmarshal logic in pdata. (#13631) This change should not affect other gRPC calls since it fallbacks to the default grpc/proto encoding if requests are not pdata/otlp requests. - `pdata`: Avoid copying the pcommon.Map when same origin (#13731) This is a very large improvement if using OTTL with map functions since it will avoid a map copy. - `exporterhelper`: Respect `num_consumers` when batching and partitioning are enabled. (#13607) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `pdata`: Correctly parse OTLP payloads containing non-packed repeated primitive fields (#13727, #13730) This bug prevented the Collector from ingesting most Histogram, ExponentialHistogram, and Profile payloads. ## v1.39.0/v0.133.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Increase minimum Go version to 1.24 (#13627) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `otlphttpexporter`: Add `profiles_endpoint` configuration option to allow custom endpoint for profiles data export (#13504) The `profiles_endpoint` configuration follows the same pattern as `traces_endpoint`, `metrics_endpoint`, and `logs_endpoint`. When specified, profiles data will be sent to the custom URL instead of the default `{endpoint}/v1development/profiles`. - `pdata`: Add support for local memory pooling for data objects. (#13678) This is still an early experimental (alpha) feature. Do not recommended to be used production. To enable use "--featuregate=+pdata.useProtoPooling" - `pdata`: Optimize CopyTo messages to avoid any copy when same source and destination (#13680) - `receiverhelper`: New feature flag to make receiverhelper distinguish internal vs. downstream errors using new `otelcol_receiver_failed_x` and `otelcol_receiver_requests` metrics (#12207, #12802) This is a breaking change for the semantics of the otelcol_receiver_refused_metric_points, otelcol_receiver_refused_log_records and otelcol_receiver_refused_spans metrics. These new metrics and semantics are enabled through the `receiverhelper.newReceiverMetrics` feature gate. - `debugexporter`: Add support for entity references in debug exporter output (#13324) - `pdata`: Fix unnecessary allocation of a new state when adding new values to pcommon.Map (#13634) - `service`: Implement refcounting for pipeline data owned memory. (#13631) This feature is protected by `--featuregate=+pdata.useProtoPooling`. - `service`: Add a debug-level log message when a consumer returns an error. (#13357) - `xpdata`: Optimize xpdata/context for persistent queue when only one value for key (#13636) - `otlpreceiver`: Log the listening addresses of the receiver, rather than the configured endpoints. (#13654) - `pdata`: Use the newly added proto marshaler/unmarshaler for the official proto Marshaler/Unmarshaler (#13637) If any problems observed with this consider to disable the featuregate `--feature-gates=-pdata.useCustomProtoEncoding` - `configtls`: Enable X25519MLKEM768 as per draft-ietf-tls-ecdhe-mlkem (#13670) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Prevent uncontrolled goroutines in batcher due to a incorrect worker pool behaviour. (#13689) - `service`: Ensure the insecure configuration is accounted for when normalizing the endpoint. (#13691) - `configoptional`: Allow validating nested types (#13579) `configoptional.Optional` now implements `xconfmap.Validator` - `batchprocessor`: Fix UB in batch processor when trying to read bytes size after adding request to pipeline (#13698) This bug only happens id detailed metrics are enabled and also an async (sending queue enabled) exporter that mutates data is configure. ## v1.38.0/v0.132.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `componentstatus`: Change the signature of the componentstatus.NewEvent to accept multiple options. (#13210) Changes the signature of the component.NewEvent to accept multiple EventBuilderOption, like the new WithAttributes constructor. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `service`: move service.noopTraceProvider feature gate to deprecated stage (#13492) The functionality of the feature gate is available via configuration with the following telemetry settings: ``` service: telemetry: traces: level: none ``` - `mdatagen`: Remove the deletion of `generated_component_telemetry_test.go`. (#12067) This file used to be generated by mdatagen. Starting with 0.122.0, the code deletes that file. It is no longer necessary to delete the file, as code has had time to upgrade to mdatagen and delete the file. - `service`: The `telemetry.disableHighCardinalityMetrics` feature gate is deprecated (#13537) The feature gate is now deprecated since metric views can be configured. The feature gate will be removed in v0.134.0. The metric attributes removed by this feature gate are no longer emitted by the Collector by default, but if needed, you can achieve the same functionality by configuring the following metric views: ```yaml service: telemetry: metrics: level: detailed views: - selector: meter_name: "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" stream: attribute_keys: excluded: ["net.sock.peer.addr", "net.sock.peer.port", "net.sock.peer.name"] - selector: meter_name: "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" stream: attribute_keys: excluded: ["net.host.name", "net.host.port"] ``` Note that this requires setting `service::telemetry::metrics::level: detailed`. If you have a strong use case for using views in combination with a different level, please show your interest in https://github.com/open-telemetry/opentelemetry-collector/issues/10769. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Generate Logs/Traces/Metrics/Profiles and p[log|trace|metric|profile]ExportResponse with pdatagen. (#13597) This change brings consistency on how these structs are written and remove JSON marshaling/unmarshaling hand written logic. - `confighttp`: Add option to configure ForceAttemptHTTP2 to support HTTP/1 specific transport settings. (#13426) - `pdata`: Avoid unnecessary buffer copy when JSON marshal fails. (#13598) - `cmd/mdatagen`: Use a custom host implementation for lifecycle tests (#13589) Use a custom noop host implementation that implements all non-deprecated, publicly-accessible interfaces implemented by the Collector service. - `processorhelper`: Add processor internal duration metric. (#13231) - `pdata`: Improve RemoveIf for slices to not reference anymore the removed memory (#13522) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `pdata`: Fix null pointer access when copying into a slice with larger cap but smaller len. (#13523) - `confighttp`: Fix middleware configuration field name from "middleware" to "middlewares" for consistency with configgrpc (#13444) - `memorylimiterextension, memorylimiterprocessor`: Memory limiter extension and processor shutdown don't throw an error if the component was not started first. (#9687) The components would throw an error if they were shut down before being started. With this change, they will no longer return an error, conforming to the lifecycle of components expected. - `confighttp`: Reuse zstd Reader objects (#11824) ## v1.37.0/v0.131.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `confighttp`: Move `confighttp.framedSnappy` feature gate to beta. (#10584) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter/debug`: Move to alpha stability except profiles (#13487) - `exporterhelper`: Enable `exporter.PersistRequestContext` feature gate by default. (#13437) Request context is now preserved by default when using persistent queues. Note that Auth extensions context is not propagated through the persistent queue. - `pdata`: Use pdatagen to generate marshalJSON without using gogo proto jsonpb. (#13450) - `otlpreceiver`: Remove usage of gogo proto which uses reflect.Value.MethodByName. Removes one source of disabling DCE. (#12747) - `exporterhelper`: Fix metrics split logic to consider metrics description into the size. (#13418) - `service`: New pipeline instrumentation now differentiates internal failures from downstream errors (#13234) With the telemetry.newPipelineTelemetry feature gate enabled, the "received" and "produced" metrics related to a component now distinguish between two types of errors: - "outcome = failure" indicates that the component returned an internal error; - "outcome = refused" indicates that the component successfully emitted data, but returned an error coming from a downstream component processing that data. - `pdata`: Remove usage of text/template from pdata, improves DCE. (#12747) - `architecture`: New Tier 3 platform riscv64 allowing the collector to be built and distributed for this platform. (#13462) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Prevents the exporter for being stuck when telemetry data is bigger than batch.max_size (#12893) - `mdatagen`: Fix import paths for mdatagen component (#13069) - `otlpreceiver`: Error handler correctly fallbacks to content type (#13414) - `pdata/pprofiles`: Fix profiles JSON unmarshal logic for originalPayload. The bytes have to be base64 encoded. (#13483) - `xpdata`: Fix unmarshaling JSON for entities, add e2e tests to avoid this in the future. (#13480) - `service`: Downgrade dependency of prometheus exporter in OTel Go SDK (#13429) This fixes the bug where collector's internal metrics are emitted with an unexpected suffix in their names when users configure the service::telemetry::metrics::readers with Prometheus - `service`: Revert Default internal metrics config now enables `otel_scope_` labels (#12939, #13344) Reverting change temporarily due to prometheus exporter downgrade. This unfortunately re-introduces the bug that instrumentation scope attributes cause errors in Prometheus exporter. See http://github.com/open-telemetry/opentelemetry-collector/issues/12939 for details. - `builder`: Remove undocumented handling of `DIST_*` environment variables replacements (#13335) ## v1.36.1/v0.130.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: Fixes bug where internal metrics are emitted with an unexpected suffix in their names when users configure `service::telemetry::metrics::readers` with Prometheus. (#13449) See more details on https://github.com/open-telemetry/opentelemetry-go/issues/7039 ## v1.36.0/v0.130.0 ### โ— Known Issues โ— - Due to a [bug](https://github.com/open-telemetry/opentelemetry-go/issues/7039) in the prometheus exporter, if you are configuring a prometheus exporter, the collector's internal metrics will be emitted with an unexpected suffix in its name. For example, the metric `otelcol_exporter_sent_spans__spans__total` instead of `otelcol_exporter_sent_spans_total`. The workaround is to manually configure `without_units: true` in your prometheus exporter config ```yaml service: telemetry: metrics: readers: - pull: exporter: prometheus: host: 0.0.0.0 port: 8888 without_units: true ``` If you are using the collector's default Prometheus exporter for exporting internal metrics you are unaffected. ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporter/otlp`: Remove deprecated batcher config from OTLP, use queuebatch (#13339) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Enable items and bytes sizers for persistent queue (#12881) - `exporterhelper`: Refactor persistent storage size backup to always record it. (#12890) - `exporterhelper`: Add support to configure a different Sizer for the batcher than the queue (#13313) - `yaml`: Replaced `sigs.k8s.io/yaml` with `go.yaml.in/yaml` for improved support and long-term maintainability. (#13308) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix exporter.PersistRequestContext feature gate (#13342) - `exporterhelper`: Preserve all metrics metadata when batch splitting. (#13236) Previously, when large batches of metrics were processed, the splitting logic in `metric_batch.go` could cause the `name` field of some metrics to disappear. This fix ensures that all metric fields are properly preserved when `metricRequest` objects are split. - `service`: Default internal metrics config now enables `otel_scope_` labels (#12939, #13344) By default, the Collector exports its internal metrics using a Prometheus exporter from the opentelemetry-go repository. With this change, the Collector no longer sets "without_scope_info" to true in its configuration. This means that all exported metrics will have `otel_scope_name`, `otel_scope_schema_url`, and `otel_scope_version` labels corresponding to the instrumentation scope metadata for that metric. This notably prevents an error when multiple metrics are only distinguished by their instrumentation scopes and end up aliased during export. If this is not desired behavior, a Prometheus exporter can be explicitly configured with this option enabled. ## v1.35.0/v0.129.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Remove deprecated sending_queue::blocking options, use sending_queue::block_on_overflow. (#13211) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Taught mdatagen to print the `go list` stderr output on failures, and to run `go list` where the metadata file is. (#13205) - `service`: Support setting `sampler` and `limits` under `service::telemetry::traces` (#13201) This allows users to enable sampling and set span limits on internal Collector traces using the OpenTelemetry SDK declarative configuration. - `pdata/pprofile`: Add new helper methods `FromLocationIndices` and `PutLocation` to read and modify the content of locations. (#13150) - `exporterhelper`: Preserve request span context and client information in the persistent queue. (#11740, #13220, #13232) It allows internal collector spans and client information to propagate through the persistent queue used by the exporters. The same way as it's done for the in-memory queue. Currently, it is behind the exporter.PersistRequestContext feature gate, which can be enabled by adding `--feature-gates=exporter.PersistRequestContext` to the collector command line. An exporter buffer stored by a previous version of the collector (or by a collector with the feature gate disabled) can be read by a newer collector with the feature enabled. However, the reverse is not supported: a buffer stored by a newer collector with the feature enabled cannot be read by an older collector (or by a collector with the feature gate disabled). ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `pdata`: Fix copying of optional fields when the source is unset. (#13268) - `service`: Only allocate one set of internal log sampling counters (#13014) The case where logs are only exported to stdout was fixed in v0.126.0; this new fix also covers the case where logs are exported through OTLP. ## v1.34.0/v0.128.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service/telemetry`: Mark "telemetry.disableAddressFieldForInternalTelemetry" as stable (#13152) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confighttp`: Update the HTTP server span naming to use the HTTP method and route pattern instead of the path. (#12468) The HTTP server span name will now be formatted as ` `. If a route pattern is not available, it will fall back to ``. - `service`: Use configured loggers to log errors as soon as it is available (#13081) - `service`: Remove stabilized featuregate useOtelWithSDKConfigurationForInternalTelemetry (#13152) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `telemetry`: Add generated resource attributes to the printed log messages. (#13110) If service.name, service.version, or service.instance.id are not specified in the config, they will be generated automatically. This change ensures that these attributes are also included in the printed log messages. - `mdatagen`: Fix generation when there are no events in the metadata. (#13123) - `confmap`: Do not panic on assigning nil maps to non-nil maps (#13117) - `pdata`: Fix event_name skipped when unmarshalling LogRecord from JSON (#13127) ## v1.33.0/v0.127.0 ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `semconv`: Deprecating the semconv package in favour of go.opentelemetry.io/otel/semconv (#13012) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter/debug`: Display resource and scope in `normal` verbosity (#10515) - `service`: Add size metrics defined in Pipeline Component Telemetry RFC (#13032) See [Pipeline Component Telemetry RFC](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/component-universal-telemetry.md) for more details: - `otelcol.receiver.produced.size` - `otelcol.processor.consumed.size` - `otelcol.processor.produced.size` - `otelcol.connector.consumed.size` - `otelcol.connector.produced.size` - `otelcol.exporter.consumed.size` ## v1.32.0/v0.126.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `configauth`: Removes deprecated `configauth.Authentication` and `extensionauthtest.NewErrorClient` (#12992) The following have been removed: - `configauth.Authentication` use `configauth.Config` instead - `extensionauthtest.NewErrorClient` use `extensionauthtest.NewErr` instead ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service`: Replace `go.opentelemetry.io/collector/semconv` usage with `go.opentelemetry.io/otel/semconv` (#12991) - `confmap`: Update the behavior of the confmap.enableMergeAppendOption feature gate to merge only component lists. (#12926) - `service`: Add item count metrics defined in Pipeline Component Telemetry RFC (#12812) See [Pipeline Component Telemetry RFC](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/component-universal-telemetry.md) for more details: - `otelcol.receiver.produced.items` - `otelcol.processor.consumed.items` - `otelcol.processor.produced.items` - `otelcol.connector.consumed.items` - `otelcol.connector.produced.items` - `otelcol.exporter.consumed.items` - `tls`: Add trusted platform module (TPM) support to TLS authentication. (#12801) Now the TLS allows the use of TPM for loading private keys (e.g. in TSS2 format). ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Add validation error for batch config if min_size is greater than queue_size. (#12948) - `telemetry`: Allocate less memory per component when OTLP exporting of logs is disabled (#13014) - `confmap`: Use reflect.DeepEqual to avoid panic when confmap.enableMergeAppendOption feature gate is enabled. (#12932) - `internal telemetry`: Add resource attributes from telemetry.resource to the logger (#12582) Resource attributes from telemetry.resource were not added to the internal console logs. Now, they are added to the logger as part of the "resource" field. - `confighttp and configcompression`: Fix handling of `snappy` content-encoding in a backwards-compatible way (#10584, #12825) The collector used the Snappy compression type of "framed" to handle the HTTP content-encoding "snappy". However, this encoding is typically used to indicate the "block" compression variant of "snappy". This change allows the collector to: - When receiving a request with encoding 'snappy', the server endpoints will peek at the first bytes of the payload to determine if it is "framed" or "block" snappy, and will decompress accordingly. This is a backwards-compatible change. If the feature-gate "confighttp.framedSnappy" is enabled, you'll see new behavior for both client and server: - Client compression type "snappy" will now compress to the "block" variant of snappy instead of "framed". Client compression type "x-snappy-framed" will now compress to the "framed" variant of snappy. - Servers will accept both "snappy" and "x-snappy-framed" as valid content-encodings. - `tlsconfig`: Disable TPM tests on MacOS/Darwin (#12964) ## v1.31.0/v0.125.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: Lowercase values for 'otelcol.component.kind' attributes. (#12865) - `service`: Restrict the `telemetry.newPipelineTelemetry` feature gate to metrics. (#12856, #12933) The "off" state of this feature gate introduced a regression, where the Collector's internal logs were missing component attributes. See issue #12870 for more details on this bug. On the other hand, the "on" state introduced an issue with the Collector's default internal metrics, because the Prometheus exporter does not currently support instrumentation scope attributes. To solve both of these issues, this change turns on the new scope attributes for logs and traces by default regardless of the feature gate. However, the new scope attributes for metrics stay locked behind the feature gate, and will remain off by default until the Prometheus exporter is updated to support scope attributes. Please understand that enabling the `telemetry.newPipelineTelemetry` feature gate may break the export of Collector metrics through, depending on your configuration. Having a `batch` processor in multiple pipelines is a known trigger for this. This comes with a breaking change, where internal logs exported through OTLP will now use instrumentation scope attributes to identify the source component instead of log attributes. This does not affect the Collector's stderr output. See the changelog for v0.123.0 for a more detailed description of the gate's effects. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Add support for attributes for telemetry configuration in metadata. (#12919) - `configmiddleware`: Add extensionmiddleware interface. (#12603, #9591) - `configgrpc`: Add gRPC middleware support. (#12603, #9591) - `confighttp`: Add HTTP middleware support. (#12603, #9591, #7441) - `configmiddleware`: Add configmiddleware struct. (#12603, #9591) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Do not ignore the `num_consumers` setting when batching is enabled. (#12244) - `exporterhelper`: Reject elements larger than the queue capacity (#12847) - `mdatagen`: Add time and plog package imports (#12907) - `confmap`: Maintain nil values when marshaling or unmarshaling nil slices (#11882) Previously, nil slices were converted to empty lists, which are semantically different than a nil slice. This change makes this conversion more consistent when encoding or decoding config, and these values are now maintained. ## v1.30.0/v0.124.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add support for bytes-based batching for profiles in the exporterhelper package. (#3262) - `otelcol`: Enhance config validation using command to capture all validation errors that prevents the collector from starting. (#8721) - `exporterhelper`: Link batcher context to all batched request's span contexts. (#12212, #8122) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confighttp`: Ensure http authentication server failures are handled by the provided error handler (#12666) ## v1.29.0/v0.123.0 ### โ— Known Issues โ— - This version increases memory usage by ~0.5 MB per component in the pipelines because a separate Zap Core logger is initialized for each component. The issue is partially fixed in v0.126.0 for users who write logs to stdout, but do not export logs via OTLP. See https://github.com/open-telemetry/opentelemetry-collector/issues/13014 for more details. ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service/telemetry`: Mark `telemetry.disableAddressFieldForInternalTelemetry` as beta, usage of deprecated service::telemetry::address are ignored (#25115) To restore the previous behavior disable `telemetry.disableAddressFieldForInternalTelemetry` feature gate. - `exporterbatch`: Remove deprecated fields `min_size_items` and `max_size_items` from batch config. (#12684) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `otlpexporter`: Mark BatcherConfig as deprecated, use `sending_queue::batch` instead (#12726) - `exporterhelper`: Deprecate `blocking` in favor of `block_on_overflow`. (#12710) - `exporterhelper`: Deprecate configuring exporter batching separately. Use `sending_queue::batch` instead. (#12772) Moving the batching configuration to `sending_queue::batch` requires setting `sending_queue::sizer` to `items` which means that `sending_queue::queue_size` needs to be also increased by the average batch size number (roughly x5000 for the default batching configuration). See https://github.com/open-telemetry/opentelemetry-collector/tree/main/exporter/exporterhelper#configuration ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add support to configure batching in the sending queue. (#12746) - `exporterhelper`: Add support for wait_for_result, remove disabled_queue (#12742) This has a side effect for users of the experimental BatchConfig with the queue disabled, since not this is | uses only NumCPU() consumers. - `exporterhelper`: Allow exporter memory queue to use different type of sizers. (#12708) - `service`: Add "telemetry.newPipelineTelemetry" feature gate to inject component-identifying attributes in internal telemetry (#12217) With the feature gate enabled, all internal telemetry (metrics/traces/logs) will include some of the following instrumentation scope attributes: - `otelcol.component.kind` - `otelcol.component.id` - `otelcol.pipeline.id` - `otelcol.signal` - `otelcol.signal.output` These attributes are defined in the [Pipeline Component Telemetry RFC](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/component-universal-telemetry.md#attributes), and identify the component instance from which the telemetry originates. They are added automatically without changes to component code. These attributes were already included in internal logs as regular log attributes, starting from v0.120.0. For consistency with other signals, they have been switched to scope attributes (with the exception of logs emitted to standard output), and are now enabled by the feature gate. Please make sure that the exporter / backend endpoint you use has support for instrumentation scope attributes before using this feature. If the internal telemetry is exported to another Collector, a transform processor could be used to turn them into other kinds of attributes if necessary. - `exporterhelper`: Enable support to do batching using `bytes` sizer (#12751) - `service`: Add config key to set metric views used for internal telemetry (#10769) The `service::telemetry::metrics::views` config key can now be used to explicitly set the list of metric views used for internal telemetry, mirroring `meter_provider::views` in the SDK config. This can be used to disable specific internal metrics, among other uses. This key will cause an error if used alongside other features which would normally implicitly create views, such as: - not setting `service::telemetry::metrics::level` to `detailed`; - enabling the `telemetry.disableHighCardinalityMetrics` feature flag. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix order of starting between queue and batch. (#12705) ## v1.28.1/v0.122.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confmap`: Ensure slices with defaults containing struct values are correctly set. (#12661) This reverts the changes made in https://github.com/open-telemetry/opentelemetry-collector/pull/11882. ## v1.28.0/v0.122.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: Batch processor telemetry is no longer emitted at "basic" verbosity level (#7890) According to the guidelines, basic-level telemetry should be reserved for core Collector APIs. Components such as the batch processor should emit telemetry starting from the "normal" level (which is also the default level). Migration: If your Collector telemetry was set to `level: basic` and you want to keep seeing batch processor-related metrics, consider switching to `level: normal` instead. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service`: Add `service.AllowNoPipelines` feature gate to allow starting the Collector without pipelines. (#12613) This can be used to start with only extensions. - `mdatagen`: Delete generated_status.go if the component type doesn't require it. (#12346) - `componenttest`: Improve config struct mapstructure field tag checks (#12590) `remain` tags and `omitempty` tags without a custom field name will now pass validation. - `service`: include component id/type in start error (#10426) - `mdatagen`: Add deprecation date and migration guide fields as part of component metadata (#12359) - `confmap`: Introduce a new feature flag to allow for merging lists instead of discarding the existing ones. (#8394, #8754, #10370) You can enable this option via the command line by running following command: otelcol --config=main.yaml --config=extra_config.yaml --feature-gates=-confmap.enableMergeAppendOption - `zpagesextension`: Add expvar handler to zpages extension. (#11081) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confmap`: Maintain nil values when marshaling or unmarshaling nil slices (#11882) Previously, nil slices were converted to empty lists, which are semantically different than a nil slice. This change makes this conversion more consistent when encoding or decoding config, and these values are now maintained. - `service`: do not attempt to register process metrics if they are disabled (#12098) ## v1.27.0/v0.121.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `confighttp`: Make the client config options `max_idle_conns`, `max_idle_conns_per_host`, `max_conns_per_host`, and `idle_conn_timeout` integers (#9478) All four options can be set to `0` where they were previously set to `null` ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `exporterhelper`: Deprecate `min_size_items` and `max_size_items` in favor of `min_size` and `max_size`. (#12486) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Add `converter` and `provider` module classes (#12467) - `pipeline`: output pipeline name with signal as signal[/name] format in logs. (#12410) - `memorylimiter`: Add support to configure min GC intervals for soft and hard limits. (#12450) - `otlpexporter`: Update the stability level for logs, it has been as stable as traces and metrics for some time. (#12423) - `service`: Create a new subcommand to dump the initial configuration after resolving/merging. (#11479) To use the `print-initial-config` subcommand, invoke the Collector with the subcommand and corresponding feature gate: `otelcol print-initial-config --feature-gates=otelcol.printInitialConfig --config=config.yaml`. Note that the feature gate enabling this flag is currently in alpha stability, and the subcommand may be changed in the future. - `memorylimiterprocessor`: Add support for profiles. (#12453) - `otelcol`: Converters are now available in the `components` command. (#11900, #12385) - `component`: Mark module as stable (#9376) - `confmap`: Surface YAML parsing errors when they happen at the top-level. (#12180) This adds context to some instances of the error "retrieved value (type=string) cannot be used as a Conf", which typically happens because of invalid YAML documents - `pprofile`: Add LinkIndex attribute to the generated Sample type (#12485) - `exporterhelper`: Stabilize exporter.UsePullingBasedExporterQueueBatcher and remove old batch sender (#12425) - `mdatagen`: Update metadata schema with new fields without enforcing them (#12359) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: Fix crash at startup when converting from v0.2.0 to v0.3.0 (#12438) - `service`: fix bug in parsing service::telemetry configuration (#12437) - `exporterhelper`: Fix bug where the error logged when conversion of data fails is always nil (#12510) - `mdatagen`: Adds back missing import for filter when emitting resource attributes (#12455) ## v1.26.0/v0.120.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Added support for go1.24, bumped minimum version to 1.23 (#12370) - `mdatagen`: Removing deprecated generated funcs and a few test funcs as well. (#12304) - `service`: Align component logger attributes with those defined in RFC (#12217) See [Pipeline Component Telemetry RFC](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/component-universal-telemetry.md#attributes) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `otlpreceiver`: Update stability for logs (#12335) - `exporterhelper`: Implement sync disabled queue used when batching is enabled. (#12245) - `exporterhelper`: Enable the new pull-based batcher in exporterhelper (#12291) - `exporterhelper`: Update queue size after the element is done exported (#12399) After this change the active queue size will include elements in the process of being exported. - `otelcol`: Add featuregate command to display information about available features (#11998) The featuregate command allows users to view detailed information about feature gates including their status, stage, and description. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `memorylimiter`: Logger no longer attributes to single signal, pipeline, or component. (#12217) - `otlpreceiver`: Logger no longer attributes to random signal when receiving multiple signals. (#12217) - `exporterhelper`: Fix undefined behavior access to request after send to next component. This causes random memory access. (#12281) - `exporterhelper`: Fix default batcher to correctly call all done callbacks exactly once (#12247) - `otlpreceiver`: Fix OTLP http receiver to correctly set Retry-After (#12367) - `otlphttpexporter`: Fix parsing logic for Retry-After in OTLP http protocol. (#12366) The value of Retry-After field can be either an HTTP-date or delay-seconds and the current logic only parsed delay-seconds. - `cmd/builder`: Ensure unique aliases for modules with same suffix (#12201) ## v1.25.0/v0.119.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Rename exporter span signal specific attributes (e.g. "sent_spans" / "send_failed_span") to "items.sent" / "items.failed". (#12165) - `cmd/mdatagen`: Remove dead field `telemetry::level` (#12144) - `exporterhelper`: Change exporter ID to be a Span level attribute instead on each event. (#12164) This does not have an impact on the level of information emitted, but on the structure of the Span. - `cmd/mdatagen`: Remove `level` field from metrics definition (#12145) This mechanism will be added back once a new views mechanism is implemented. - `service`: Value for telemetry exporter `otlp.protocol` updated from `grpc/protobuf` to `grpc`. (#12337) - `service`: internal metrics exported over Prometheus may differ from previous versions. (#11611) Users who do not customize the Prometheus reader should not be impacted. The change to update the internal telemetry to use [otel-go config](https://pkg.go.dev/go.opentelemetry.io/contrib/config) can cause unexpected behaviour for end users. This change is caused by the default values in `config` being different from what the Collector has used in previous versions. The following changes can occur when users configure their `service::telemetry::metrics::readers`: - the metric name will append a `_total` suffix if `without_type_suffix` is not configured. Set `without_type_suffix` to `true` to disable this. - units will be appended to metric name if `without_units` is not configured. Set `without_units` to `true` to disable this. - a `target_info` metric will be emitted if `without_scope_info` is not configured. Set `without_scope_info` to `true` to disable this. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configtls`: Allow users to mention their preferred curve types for ECDHE handshake (#12174) - `service`: remove custom code and instead use config package to instantiate meter provider. (#11611) - `otelcol`: Adds support for listing config providers in components command's output (#11570) - `general`: Reduce memory allocations when loading configuration and parsing component names (#11964) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix bug that the exporter with new batcher may have been marked as non mutation. (#12239) Only affects users that manually turned on `exporter.UsePullingBasedExporterQueueBatcher` featuregate. - `service`: Preserve URL normalization logic that was present before. (#12254) - `confighttp`: confighttp.ToServer now sets ErrorLog with a default logger backed by Zap (#11820) This change ensures that the http.Server's ErrorLog is correctly set using Zap's logger at the error level, addressing the issue of error logs being printed using a different logger. - `exporterhelper`: Fix context propagation for DisabledBatcher (#12231) - `mdatagen`: apply fieldalignment to generated code (#12125) - `mdatagen`: Fix bug where Histograms were marked as not supporting temporal aggregation (#12168) - `exporterhelper`: Fix MergeSplit issue that ignores the initial message size. (#12257) - `service`: Include validation errors from telemetry.Config when validating the service config (#12100) Previously validation errors were only printed to the console - `service-telemetry`: pass the missing async error channel into service telemetry settings (#11417) ## v1.24.0/v0.118.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add blocking option to control queue behavior when full (#12090) - `debugexporter`: Add EventName to debug exporter for Logs. EventName was added as top-level field in the LogRecord from 1.5.0 of proto definition. (#11966) - `confighttp`: Added support for configuring compression levels. (#10467) A new configuration option called CompressionParams has been added to confighttp. | This allows users to configure the compression levels for the confighttp client. - `exporterhelper`: Change the memory queue implementation to not pre-allocate capacity objects. (#12070) This change improves memory usage of the collector under low utilization and is a prerequisite for supporting different other size limitations (number of items, bytes). ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `mdatagen`: apply fieldalignment to generated code (#12121) - `otelcoltest`: Set `DefaultScheme` to `env` in the test `ConfigProvider` to replicate the default provider used by the Collector. (#12066) ## v1.23.0/v0.117.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otelcol`: Remove warnings when 0.0.0.0 is used (#11713, #8510) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `internal/sharedcomponent`: Fixed bug where sharedcomponent would use too much memory remembering all the previously reported statuses (#11826) ## v1.22.0/v0.116.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pdata/pprofile`: Remove deprecated `Profile.EndTime` and `Profile.SetEndTime` methods. (#11796) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `xconfighttp`: Add WithOtelHTTPOptions to experimental module xconfighttp (#11770) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix memory leak at exporter shutdown (#11401) - `sharedcomponent`: Remove race-condition and cleanup locking (#11819) ## v1.21.0/v0.115.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `otelcol`: Change all logged timestamps to ISO8601. (#10543) This makes log timestamps human-readable (as opposed to epoch seconds in scientific notation), but may break users trying to parse logged lines in the old format. - `pdata/pprofile`: Upgrade pdata to opentelemetry-proto v1.4.0 (#11722) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `scraperhelper`: Deprecate all Scraper helpers in scraperhelper (#11732) Deprecate ScrapeFunc, ScraperOption, WithStart, WithShutdown in favor of equivalent funcs in scraper package. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterqueue`: Introduce a feature gate exporter.UsePullingBasedExporterQueueBatcher to use the new pulling model in exporter queue batching. (#8122, #10368) If both queuing and batching is enabled for exporter, we now use a pulling model instead of a pushing model. num_consumer in queue configuration is now used to specify the maximum number of concurrent workers that are sending out the request. - `service`: label metrics as alpha to communicate their stability (#11729) - `consumer`: Mark consumer as stable. (#9046) - `service`: Add support for ca certificates in telemetry metrics otlp grpc exporter (#11633) Before this change the Certificate value in config was silently ignored. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: ensure OTLP emitted logs respect severity (#11718) - `featuregate`: Fix an unfriendly display message `runtime error` when featuregate is used to display command line usage. (#11651) - `profiles`: Fix iteration over scope profiles while counting the samples. (#11688) ## v1.20.0/v0.114.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `cmd/builder`: Allow for replacing of local Providers and Converters when building custom collector with ocb. (#11649) Use the property `path` under `gomod` to replace an go module with a local folder in builder-config.yaml. Ex: ``` providers: - gomod: module.url/my/custom/provider v1.2.3 path: /path/to/local/provider ``` - `cmd/builder`: Allow configuring `confmap.Converter` components in ocb. (#11582) If no converters are specified, there will be no converters added. Currently, the only published converter is `expandconverter` which is deprecated as of v0.107.0, but can still be added for testing purposes. To configure a custom converter, make sure your converter implements the converter interface and is published as a go module (or replaced locally if not published). You may then use the `converters` key in your OCB build manifest with a list of Go modules (and replaces as necessary) to include your converter. Please note that converters are order-dependent. The confmap will apply converters in order of which they are listed in your manifest if there is more than one. - `all`: shorten time period before removing an unmaintained component from 6 months to 3 months (#11664) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `all`: Updates dialer timeout section documentation in confignet README (#11685) - `scraperhelper`: If the scraper shuts down, do not scrape first. (#11632) When the scraper is shutting down, it currently will scrape at least once. With this change, upon receiving a shutdown order, the receiver's scraperhelper will exit immediately. ## v1.19.0/v0.113.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `internal/fanoutconsumer`: Extract internal/fanoutconsumer as a separate go module (#11441) - `builder`: Remove builder support to build old version, and the otelcol_version config (#11405) User should remove this property from their config, to build older versions use older builders. - `receiver`: Make receivertest into its own module (#11462) - `builder`: Remove deprecated flags from Builder (#11576) Here is the list of flags | --name, --description, --version, --otelcol-version, --go, --module - `internal/sharedcomponent`: Extract internal/sharedcomponent as a separate go module (#11442) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Add otlp as supported distribution (#11527) - `batchprocessor`: Move single shard batcher creation to the constructor (#11594) - `service`: add support for using the otelzap bridge and emit logs using the OTel Go SDK (#10544) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: ensure traces and logs emitted by the otel go SDK use the same resource information (#11578) - `config/configgrpc`: Patch for bug in the grpc-go NewClient that makes the way the hostname is resolved incompatible with the way proxy setting are applied. (#11537) - `builder`: Update builder default providers to latest stable releases (#11566) ## v1.18.0/v0.112.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `consumer/consumererror`: Extract consumer/consumererror as a separate go module (#11440) - `exporter/exportertest`: Put exportertest into its own module (#11461) - `service`: Remove stable gate component.UseLocalHostAsDefaultHost (#11412) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `processortest`: Deprecated 'NewUnhealthyProcessorCreateSettings'. Use NewNopSettings instead. (#11307) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Added generated_package_name config field to support custom generated package name. (#11231) - `mdatagen`: Generate documentation for components with resource attributes only (#10705) - `confighttp`: Adding support for lz4 compression into the project (#9128) - `service`: Hide profiles support behind a feature gate while it remains alpha. (#11477) - `exporterhelper`: Retry sender will fail fast when the context timeout is shorter than the next retry interval. (#11183) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `cmd/builder`: Fix default configuration for builder for httpprovider, httpsprovider, and yamlprovider. (#11357) - `processorhelper`: Fix issue where in/out parameters were not recorded when error was returned from consumer. (#11351) ## v1.17.0/v0.111.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service/telemetry`: Change default metrics address to "localhost:8888" instead of ":8888" (#11251) This behavior can be disabled by disabling the feature gate 'telemetry.UseLocalHostAsDefaultMetricsAddress'. - `loggingexporter`: Removed the deprecated logging exporter. Use the debug exporter instead. (#11037) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `service/telemetry`: Deprecate service::telemetry::metrics::address in favor of service::telemetry::metrics::readers. (#11205) - `processorhelper`: Deprecate BuildProcessorMetricName as it's no longer needed since introduction of mdatagen (#11302) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `ocb`: create docker images for OCB, per https://github.com/open-telemetry/opentelemetry-collector-releases/pull/671 (#5712) Adds standard Docker images for OCB to Dockerhub and GitHub, see hub.docker.com/r/otel/opentelemetry-collector-builder - `confighttp`: Snappy compression to lazy read for memory efficiency (#11177) - `httpsprovider`: Mark the httpsprovider as stable. (#11191) - `httpprovider`: Mark the httpprovider as stable. (#11191) - `yamlprovider`: Mark the yamlprovider as stable. (#11192) - `confmap`: Allow using any YAML structure as a string when loading configuration including time.Time formats (#10659) Previously, fields with time.Time formats could not be used as strings in configurations ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `processorhelper`: Fix data race condition, concurrent writes to the err variable, causes UB (Undefined Behavior) (#11350) - `cmd/builder`: re-adds function to properly set and view version number of OpenTelemetry Collector Builder (ocb) binaries (#11208) - `pdata`: Unmarshal Span and SpanLink flags from JSON (#11267) ## v1.16.0/v0.110.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `processorhelper`: Update incoming/outgoing metrics to a single metric with a `otel.signal` attributes. (#11144) The following metrics were added in the previous version - otelcol_processor_incoming_spans - otelcol_processor_outgoing_spans - otelcol_processor_incoming_metric_points - otelcol_processor_outgoing_metric_points - otelcol_processor_incoming_log_records - otelcol_processor_outgoing_log_records They are being replaced with the following to more closely align with OTEP 259: - otelcol_processor_incoming_items - otelcol_processor_outgoing_items - `processorhelper`: Remove deprecated `[Traces|Metrics|Logs]`Inserted funcs (#11151) - `config`: Mark UseLocalHostAsDefaultHostfeatureGate as stable (#11235) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `processorhelper`: deprecate accepted/refused/dropped metrics (#11201) The following metrics are being deprecated as they were only used in a single processor: - `otelcol_processor_accepted_log_records` - `otelcol_processor_accepted_metric_points` - `otelcol_processor_accepted_spans` - `otelcol_processor_dropped_log_records` - `otelcol_processor_dropped_metric_points` - `otelcol_processor_dropped_spans` - `otelcol_processor_refused_log_records` - `otelcol_processor_refused_metric_points` - `otelcol_processor_refused_spans` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Add support to MoveTo for Map, allow avoiding copies (#11175) - `mdatagen`: Add stability field to telemetry metrics, allowing the generated description to include a stability string. (#11160) - `confignet`: Mark module as Stable. (#9801) - `confmap/provider/envprovider`: Support default values when env var is empty (#5228) - `mdatagen`: mdatagen `validateMetrics()` support validate metrics in `telemetry.metric` (#10925) - `service/telemetry`: Mark useOtelWithSDKConfigurationForInternalTelemetry as stable (#7532) - `mdatagen`: Use cobra for the command, add version flag (#11196) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: Ensure process telemetry is registered when internal telemetry is configured with readers instead of an address. (#11093) - `mdatagen`: Fix incorrect generation of metric tests with boolean attributes. (#11169) - `otelcol`: Fix the Windows Event Log configuration when running the Collector as a Windows service. (#5297, #11051) - `builder`: Honor build_tags in config (#11156) - `builder`: Fix version for providers in the default config (#11123) - `cmd/builder`: Temporarily disable strict versioning checks (#11129, #11152) The strict versioning check may be enabled by default in a future version once all configuration providers are stabilized. - `confmap`: Fix loading config of a component from a different source. (#11154) This issue only affected loading the whole component config, loading parts of a component config from a different source was working correctly. ## v1.15.0/v0.109.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `scraperhelper`: Remove deprecated `ObsReport`, `ObsReportSettings`, `NewObsReport` types/funcs (#11086) - `confmap`: Remove stable `confmap.strictlyTypedInput` gate (#11008) - `confmap`: Removes stable `confmap.unifyEnvVarExpansion` feature gate. (#11007) - `ballastextension`: Removes the deprecated ballastextension (#10671) - `service`: Removes stable `service.disableOpenCensusBridge` feature gate (#11009) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `processorhelper`: These funcs are not used anywhere, marking them deprecated. (#11083) ### ๐Ÿš€ New components ๐Ÿš€ - `extension/experimental/storage`: Move `extension/experimental/storage` into a separate module (#11022) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configtelemetry`: Add guidelines for each level of component telemetry (#10286) - `service`: move `useOtelWithSDKConfigurationForInternalTelemetry` gate to beta (#11091) - `service`: implement a no-op tracer provider that doesn't propagate the context (#11026) The no-op tracer provider supported by the SDK incurs a memory cost of propagating the context no matter what. This is not needed if tracing is not enabled in the Collector. This implementation of the no-op tracer provider removes the need to allocate memory when tracing is disabled. - `envprovider`: Mark module as stable (#10982) - `fileprovider`: Mark module as stable (#10983) - `processor`: Add incoming and outgoing counts for processors using processorhelper. (#10910) Any processor using the processorhelper package (this is most processors) will automatically report incoming and outgoing item counts. The new metrics are: - otelcol_processor_incoming_spans - otelcol_processor_outgoing_spans - otelcol_processor_incoming_metric_points - otelcol_processor_outgoing_metric_points - otelcol_processor_incoming_log_records - otelcol_processor_outgoing_log_records ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configgrpc`: Change the value of max_recv_msg_size_mib from uint64 to int to avoid a case where misconfiguration caused an integer overflow. (#10948) - `exporterqueue`: Fix a bug in persistent queue that Offer can becomes deadlocked when queue is almost full (#11015) ## v1.14.1/v0.108.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `mdatagen`: Fix a missing import in the generated test file (#10969) ## v1.14.0/v0.108.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Added support for go1.23, bumped the minimum version to 1.22 (#10869) - `otelcol`: Remove deprecated `ConfmapProvider` interface. (#10934) - `confmap`: Mark `confmap.strictlyTypedInput` as stable (#10552) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter/otlp`: Add batching option to otlp exporter (#8122) - `builder`: Add a --skip-new-go-module flag to skip creating a module in the output directory. (#9252) - `component`: Add `TelemetrySettings.LeveledMeterProvider` func to replace MetricsLevel in the near future (#10931) - `mdatagen`: Add `LeveledMeter` method to mdatagen (#10933) - `service`: Adds `level` configuration option to `service::telemetry::trace` to allow users to disable the default TracerProvider (#10892) This replaces the feature gate `service.noopTracerProvider` introduced in v0.107.0 - `componentstatus`: Add new Reporter interface to define how to report a status via a `component.Host` implementation (#10852) - `mdatagen`: support using a different github project in mdatagen README issues list (#10484) - `mdatagen`: Updates mdatagen's usage to output a complete command line example, including the metadata.yaml file. (#10886) - `extension`: Add ModuleInfo to extension.Settings to allow extensions to access component go module information. (#10876) - `confmap`: Mark module as stable (#9379) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `batchprocessor`: Update units for internal telemetry (#10652) - `confmap`: Fix bug where an unset env var used with a non-string field resulted in a panic (#10950) - `service`: Fix memory leaks during service package shutdown (#9165) - `mdatagen`: Update generated telemetry template to only include context import when there are async metrics. (#10883) - `mdatagen`: Fixed bug in which setting `SkipLifecycle` & `SkipShutdown` to true would result in a generated file with an unused import `confmaptest` (#10866) - `confmap`: Use string representation for field types where all primitive types are strings. (#10937) - `otelcol`: Preserve internal representation when unmarshaling component configs (#10552) ## v1.13.0/v0.107.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: Remove OpenCensus bridge completely, mark feature gate as stable. (#10414) - `confmap`: Set the `confmap.unifyEnvVarExpansion` feature gate to Stable. Expansion of `$FOO` env vars is no longer supported. Use `${FOO}` or `${env:FOO}` instead. (#10508) - `service`: Remove `otelcol` from Prometheus configuration. This means that any metric that isn't explicitly prefixed with `otelcol_` no longer have that prefix. (#9759) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: export ScopeName in internal/metadata package (#10845) This can be used by components that need to set their scope name manually. Will save component owners from having to store a variable, which may diverge from the scope name used by the component for emitting its own telemetry. - `semconv`: Add v1.26.0 semantic conventions package (#10249, #10829) - `mdatagen`: Expose a setting on tests::host to set up your own host initialization code (#10765) Some receivers require a host that has additional capabilities such as exposing exporters. For those, we can expose a setting that allows them to place a different host in the generated code. - `confmap`: Allow using any YAML structure as a string when loading configuration. (#10800) Previous to this change, slices could not be used as strings in configuration. - `ocb`: migrate build and release of ocb binaries to opentelemetry-collector-releases repository (#10710) ocb binaries will now be released under open-telemetry/opentelemetry-collector-releases tagged as "cmd/builder/vX.XXX.X" - `semconv`: Add semantic conventions version v1.27.0 (#10837) - `client`: Mark module as stable. (#10775) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configtelemetry`: Add 10s read header timeout on the configtelemetry Prometheus HTTP server. (#5699) - `service`: Allow users to disable the tracer provider via the feature gate `service.noopTracerProvider` (#10858) The service is returning an instance of a SDK tracer provider regardless of whether there were any processors configured causing resources to be consumed unnecessarily. - `processorhelper`: Fix processor metrics not being reported initially with 0 values. (#10855) - `service`: Implement the `temporality_preference` setting for internal telemetry exported via OTLP (#10745) - `configauth`: Fix unmarshaling of authentication in HTTP servers. (#10750) - `confmap`: If loading an invalid YAML string through a provider, use it verbatim instead of erroring out. (#10759) This makes the ${env:ENV} syntax closer to how ${ENV} worked before unifying syntaxes. - `component`: Allow component names of up to 1024 characters in length. (#10816) - `confmap`: Remove original string representation if invalid. (#10787) ## v0.106.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configauth`: Fix unmarshaling of authentication in HTTP servers. (#10750) ## v0.106.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: Update all metrics to include `otelcol_` prefix to ensure consistency across OTLP and Prometheus metrics (#9759) This change is marked as a breaking change as anyone that was using OTLP for metrics will see the new prefix which was not present before. Prometheus generated metrics remain unchanged. - `confighttp`: Delete `ClientConfig.CustomRoundTripper` (#8627) Set (*http.Client).Transport on the *http.Client returned from ToClient to configure this. - `confmap`: When passing configuration for a string field using any provider, use the verbatim string representation as the value. (#10605, #10405) This matches the behavior of `${ENV}` syntax prior to the promotion of the `confmap.unifyEnvVarExpansion` feature gate to beta. It changes the behavior of the `${env:ENV}` syntax with escaped strings. - `component`: Adds restrictions on the character set for component.ID name. (#10673) - `processor/memorylimiter`: The memory limiter processor will no longer account for ballast size. (#10696) If you are already using GOMEMLIMIT instead of the ballast extension this does not affect you. - `extension/memorylimiter`: The memory limiter extension will no longer account for ballast size. (#10696) If you are already using GOMEMLIMIT instead of the ballast extension this does not affect you. - `service`: The service will no longer be able to get a ballast size from the deprecated ballast extension. (#10696) If you are already using GOMEMLIMIT instead of the ballast extension this does not affect you. ### ๐Ÿš€ New components ๐Ÿš€ - `client`: Create a new go module `go.opentelemetry.io/collector/client` (#9804) This module contains generic representations of clients connecting to different receivers. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add data_type attribute to `otelcol_exporter_queue_size` metric to report the type of data being processed. (#9943) - `confighttp`: Add option to include query params in auth context (#4806) - `configgrpc`: gRPC auth errors now return gRPC status code UNAUTHENTICATED (16) (#7646) - `httpprovider, httpsprovider`: Validate URIs in HTTP and HTTPS providers before fetching. (#10468) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `processorhelper`: update units for internal telemetry (#10647) - `confmap`: Increase the amount of recursion and URI expansions allowed in a single line (#10712) - `exporterhelper`: There is no guarantee that after the exporterhelper sends the plog/pmetric/ptrace data downstream that the data won't be mutated in some way. (e.g by the batch_sender) This mutation could result in the proceeding call to req.ItemsCount() to provide inaccurate information to be logged. (#10033) - `exporterhelper`: Update units for internal telemetry (#10648) - `receiverhelper`: Update units for internal telemetry (#10650) - `scraperhelper`: Update units for internal telemetry (#10649) - `service`: Use Command/Version to populate service name/version attributes (#10644) ## v1.12.0/v0.105.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: add `service.disableOpenCensusBridge` feature gate which is enabled by default to remove the dependency on OpenCensus (#10414) - `confmap`: Promote `confmap.strictlyTypedInput` feature gate to beta. (#10552) This feature gate changes the following: - Configurations relying on the implicit type casting behaviors listed on [#9532](https://github.com/open-telemetry/opentelemetry-collector/issues/9532) will start to fail. - Configurations using URI expansion (i.e. `field: ${env:ENV}`) for string-typed fields will use the value passed in `ENV` verbatim without intermediate type casting. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configtls`: Mark module as stable. (#9377) - `confmap`: Remove extra closing parenthesis in sub-config error (#10480) - `configgrpc`: Update the default load balancer strategy to round_robin (#10319) To restore the behavior that was previously the default, set `balancer_name` to `pick_first`. - `cmd/builder`: Add go module info the builder generated code. (#10570) - `otelcol`: Add go module to components subcommand. (#10570) - `confmap`: Add explanation to errors related to `confmap.strictlyTypedInput` feature gate. (#9532) - `confmap`: Allow using `map[string]any` values in string interpolation (#10605) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `builder`: provide context when a module in the config is missing its gomod value (#10474) - `confmap`: Fixes issue where confmap could not escape `$$` when `confmap.unifyEnvVarExpansion` is enabled. (#10560) - `mdatagen`: fix generated comp test for extensions and unused imports in templates (#10477) - `otlpreceiver`: Fixes a bug where the otlp receiver's http response was not properly translating grpc error codes to http status codes. (#10574) - `exporterhelper`: Fix incorrect deduplication of otelcol_exporter_queue_size and otelcol_exporter_queue_capacity metrics if multiple exporters are used. (#10444) - `service/telemetry`: Add ability to set service.name for spans emitted by the Collector (#10489) - `internal/localhostgate`: Correctly log info message when `component.UseLocalHostAsDefaultHost` is enabled (#8510) ## v1.11.0/v0.104.0 This release includes 2 very important breaking changes. 1. The `otlpreceiver` will now use `localhost` by default instead of `0.0.0.0`. This may break the receiver in containerized environments like Kubernetes. If you depend on `0.0.0.0` disable the `component.UseLocalHostAsDefaultHost` feature gate or explicitly set the endpoint to `0.0.0.0`. 2. Expansion of BASH-style environment variables, such as `$FOO` will no longer be supported by default. If you depend on this syntax, disable the `confmap.unifyEnvVarExpansion` feature gate, but know that the feature will be removed in the future in favor of `${env:FOO}`. ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `filter`: Remove deprecated `filter.CombinedFilter` (#10348) - `otelcol`: By default, `otelcol.NewCommand` and `otelcol.NewCommandMustSetProvider` will set the `DefaultScheme` to `env`. (#10435) - `expandconverter`: By default expandconverter will now error if it is about to expand `$FOO` syntax. Update configuration to use `${env:FOO}` instead or disable the `confmap.unifyEnvVarExpansion` feature gate. (#10435) - `otlpreceiver`: Switch to `localhost` as the default for all endpoints. (#8510) Disable the `component.UseLocalHostAsDefaultHost` feature gate to temporarily get the previous default. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confighttp`: Add support for cookies in HTTP clients with `cookies::enabled`. (#10175) The method `confighttp.ToClient` will return a client with a `cookiejar.Jar` which will reuse cookies from server responses in subsequent requests. - `exporter/debug`: In `normal` verbosity, display one line of text for each telemetry record (log, data point, span) (#7806) - `exporter/debug`: Add option `use_internal_logger` (#10226) - `configretry`: Mark module as stable. (#10279) - `debugexporter`: Print Span.TraceState() when present. (#10421) Enables viewing sampling threshold information (as by OTEP 235 samplers). - `processorhelper`: Add "inserted" metrics for processors. (#10353) This includes the following metrics for processors: - `processor_inserted_spans` - `processor_inserted_metric_points` - `processor_inserted_log_records` ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otlpexporter`: Update validation to support both dns:// and dns:/// (#10449) - `service`: Fixed a bug that caused otel-collector to fail to start with ipv6 metrics endpoint service telemetry. (#10011) ## v1.10.0/v0.103.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporter/debug`: Disable sampling by default (#9921) To restore the behavior that was previously the default, set `sampling_thereafter` to `500`. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `cmd/builder`: Allow setting `otelcol.CollectorSettings.ResolverSettings.DefaultScheme` via the builder's `conf_resolver.default_uri_scheme` configuration option (#10296) - `mdatagen`: add support for optional internal metrics (#10316) - `otelcol/expandconverter`: Add `confmap.unifyEnvVarExpansion` feature gate to allow enabling Collector/Configuration SIG environment variable expansion rules. (#10391) When enabled, this feature gate will: - Disable expansion of BASH-style env vars (`$FOO`) - `${FOO}` will be expanded as if it was `${env:FOO} See https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/env-vars.md for more details. - `confmap`: Add `confmap.unifyEnvVarExpansion` feature gate to allow enabling Collector/Configuration SIG environment variable expansion rules. (#10259) When enabled, this feature gate will: - Disable expansion of BASH-style env vars (`$FOO`) - `${FOO}` will be expanded as if it was `${env:FOO} See https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/env-vars.md for more details. - `confighttp`: Allow the compression list to be overridden (#10295) Allows Collector administrators to control which compression algorithms to enable for HTTP-based receivers. - `configgrpc`: Revert the zstd compression for gRPC to the third-party library we were using previously. (#10394) We switched back to our compression logic for zstd when a CVE was found on the third-party library we were using. Now that the third-party library has been fixed, we can revert to that one. For end-users, this has no practical effect. The reproducers for the CVE were tested against this patch, confirming we are not reintroducing the bugs. - `confmap`: Adds alpha `confmap.strictlyTypedInput` feature gate that enables strict type checks during configuration resolution (#9532) When enabled, the configuration resolution system will: - Stop doing most kinds of implicit type casting when resolving configuration values - Use the original string representation of configuration values if the ${} syntax is used in inline position - `confighttp`: Use `confighttp.ServerConfig` as part of zpagesextension. See [server configuration](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/confighttp/README.md#server-configuration) options. (#9368) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix potential deadlock in the batch sender (#10315) - `expandconverter`: Fix bug where an warning was logged incorrectly. (#10392) - `exporterhelper`: Fix a bug when the retry and timeout logic was not applied with enabled batching. (#10166) - `exporterhelper`: Fix a bug where an unstarted batch_sender exporter hangs on shutdown (#10306) - `exporterhelper`: Fix small batch due to unfavorable goroutine scheduling in batch sender (#9952) - `confmap`: Fix issue where structs with only yaml tags were not marshaled correctly. (#10282) ## v0.102.1 **This release addresses [GHSA-c74f-6mfw-mm4v](https://github.com/open-telemetry/opentelemetry-collector/security/advisories/GHSA-c74f-6mfw-mm4v) for `configgrpc`.** ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configrpc`: Use own compressors for zstd. Before this change, the zstd compressor we used didn't respect the max message size. This addresses [GHSA-c74f-6mfw-mm4v](https://github.com/open-telemetry/opentelemetry-collector/security/advisories/GHSA-c74f-6mfw-mm4v) for `configgrpc` (#10323) ## v1.9.0/v0.102.0 **This release addresses [GHSA-c74f-6mfw-mm4v](https://github.com/open-telemetry/opentelemetry-collector/security/advisories/GHSA-c74f-6mfw-mm4v) for `confighttp`.** ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `envprovider`: Restricts Environment Variable names. Environment variable names must now be ASCII only and start with a letter or an underscore, and can only contain underscores, letters, or numbers. (#9531) - `confighttp`: Apply MaxRequestBodySize to the result of a decompressed body. This addresses [GHSA-c74f-6mfw-mm4v](https://github.com/open-telemetry/opentelemetry-collector/security/advisories/GHSA-c74f-6mfw-mm4v) for `confighttp` (#10289) When using compressed payloads, the Collector would verify only the size of the compressed payload. This change applies the same restriction to the decompressed content. As a security measure, a limit of 20 MiB was added, which makes this a breaking change. For most clients, this shouldn't be a problem, but if you often have payloads that decompress to more than 20 MiB, you might want to either configure your client to send smaller batches (recommended), or increase the limit using the MaxRequestBodySize option. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: auto-generate utilities to test component telemetry (#19783) - `mdatagen`: support setting an AttributeSet for async instruments (#9674) - `mdatagen`: support using telemetry level in telemetry builder (#10234) This allows components to set the minimum level needed for them to produce telemetry. By default, this is set to configtelemetry.LevelBasic. If the telemetry level is below that minimum level, then the noop meter is used for metrics. - `mdatagen`: add support for bucket boundaries for histograms (#10218) - `releases`: add documentation in how to verify the image signatures using cosign (#9610) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `batchprocessor`: ensure attributes are set on cardinality metadata metric (#9674) - `batchprocessor`: Fixing processor_batch_metadata_cardinality which was broken in v0.101.0 (#10231) - `batchprocessor`: respect telemetry level for all metrics (#10234) - `exporterhelper`: Fix potential deadlocks in BatcherSender shutdown (#10255) ## v1.8.0/v0.101.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: generate documentation for internal telemetry (#10170) - `mdatagen`: add ability to use metadata.yaml to automatically generate instruments for components (#10054) The `telemetry` section in metadata.yaml is used to generate instruments for components to measure telemetry about themselves. - `confmap`: Allow Converters to write logs during startup (#10135) - `otelcol`: Enable logging during configuration resolution (#10056) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `mdatagen`: Run package tests when goleak is skipped (#10125) ## v1.7.0/v0.100.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: The `validate` sub-command no longer validates that each pipeline's type is the same as its component types (#10031) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `semconv`: Add support for v1.25.0 semantic convention (#10072) - `builder`: remove the need to go get a module to address ambiguous import paths (#10015) - `pmetric`: Support parsing metric.metadata from OTLP JSON. (#10026) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix enabled config option for batch sender (#10076) ## v1.6.0/v0.99.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `builder`: Add strict version checking when using the builder. Add the temporary flag `--skip-strict-versioning `for skipping this check. (#9896) Strict version checking will error on major and minor version mismatches between the `otelcol_version` configured and the builder version or versions in the go.mod. This check can be temporarily disabled by using the `--skip-strict-versioning` flag. This flag will be removed in a future minor version. - `telemetry`: Distributed internal metrics across different levels. (#7890) The internal metrics levels are updated along with reported metrics: - The default level is changed from `basic` to `normal`, which can be overridden with `service::telemetry::metrics::level` configuration. - Batch processor metrics are updated to be reported starting from `normal` level: - `processor_batch_batch_send_size` - `processor_batch_metadata_cardinality` - `processor_batch_timeout_trigger_send` - `processor_batch_size_trigger_send` - GRPC/HTTP server and client metrics are updated to be reported starting from `detailed` level: - http.client.* metrics - http.server.* metrics - rpc.server.* metrics - rpc.client.* metrics ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confighttp`: Disable concurrency in zstd compression (#8216) - `cmd/builder`: Allow configuring `confmap.Provider`s in the builder. (#4759) If no providers are specified, the defaults are used. The default providers are: env, file, http, https, and yaml. To configure providers, use the `providers` key in your OCB build manifest with a list of Go modules for your providers. The modules will work the same as other Collector components. - `mdatagen`: enable goleak tests by default via mdatagen (#9959) - `cmd/mdatagen`: support excluding some metrics based on string and regexes in resource_attributes (#9661) - `cmd/mdatagen`: Generate config and factory tests covering their requirements. (#9940) The tests are moved from cmd/builder. - `confmap`: Add `ProviderSettings`, `ConverterSettings`, `ProviderFactories`, and `ConverterFactories` fields to `confmap.ResolverSettings` (#9516) This allows configuring providers and converters, which are instantiated by `NewResolver` using the given factories. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporter/otlp`: Allow DNS scheme to be used in endpoint (#4274) - `service`: fix record sampler configuration (#9968) - `service`: ensure the tracer provider is configured via go.opentelemetry.io/contrib/config (#9967) - `otlphttpexporter`: Fixes a bug that was preventing the otlp http exporter from propagating status. (#9892) - `confmap`: Fix decoding negative configuration values into uints (#9060) ## v1.5.0/v0.98.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: emit internal collector metrics with _ instead of / with OTLP export (#9774) This is addressing an issue w/ the names of the metrics generated by the Collector for its internal metrics. Note that this change only impacts users that emit telemetry using OTLP, which is currently still in experimental support. The prometheus metrics already replaced `/` with `_` and they will do the same with `_`. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Adds unsupported platforms to the README header (#9794) - `confmap`: Clarify the use of embedded structs to make unmarshaling composable (#7101) - `nopexporter`: Promote the nopexporter to beta (#7316) - `nopreceiver`: Promote the nopreceiver to beta (#7316) - `otlpexporter`: Checks for port in the config validation for the otlpexporter (#9505) - `service`: Validate pipeline type against component types (#8007) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configtls`: Fix issue where `IncludeSystemCACertsPool` was not consistently used between `ServerConfig` and `ClientConfig`. (#9835) - `component`: Fix issue where the `components` command wasn't properly printing the component type. (#9856) - `otelcol`: Fix issue where the `validate` command wasn't properly printing valid component type. (#9866) - `receiver/otlp`: Fix bug where the otlp receiver did not properly respond with a retryable error code when possible for http (#9357) ## v1.4.0/v0.97.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `telemetry`: Remove telemetry.useOtelForInternalMetrics stable feature gate (#9752) ### ๐Ÿš€ New components ๐Ÿš€ - `exporter/nop`: Add the `nopexporter` to serve as a placeholder exporter in a pipeline (#7316) This is primarily useful for starting the Collector with only extensions enabled or to test Collector pipeline throughput. - `receiver/nop`: Add the `nopreceiver` to serve as a placeholder receiver in a pipeline (#7316) This is primarily useful for starting the Collector with only extensions enabled. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configtls`: Validates TLS min_version and max_version (#9475) Introduces `Validate()` method in TLSSetting. - `configcompression`: Mark module as Stable. (#9571) - `cmd/mdatagen`: Use go package name for the scope name by default and add an option to provide the scope name in metadata.yaml. (#9693) - `cmd/mdatagen`: Generate the lifecycle tests for components by default. (#9683) It's encouraged to have lifecycle tests for all components enabled, but they can be disabled if needed in metadata.yaml with `skip_lifecycle: true` and `skip_shutdown: true` under `tests` section. - `cmd/mdatagen`: optimize the mdatagen for the case like batchprocessor which use a common struct to implement consumer.Traces, consumer.Metrics, consumer.Logs in the meantime. (#9688) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix persistent queue size backup on reads. (#9740) - `processor/batch`: Prevent starting unnecessary goroutines. (#9739) - `otlphttpexporter`: prevent error on empty response body when content type is application/json (#9666) - `confmap`: confmap honors `Unmarshal` methods on config embedded structs. (#6671) - `otelcol`: Respect telemetry configuration when running as a Windows service (#5300) ## v1.3.0/v0.96.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `configgrpc`: Remove deprecated `GRPCClientSettings`, `GRPCServerSettings`, and `ServerConfig.ToListenerContext`. (#9616) - `confighttp`: Remove deprecated `HTTPClientSettings`, `NewDefaultHTTPClientSettings`, and `CORSSettings`. (#9625) - `confignet`: Removes deprecated `NetAddr` and `TCPAddr` (#9614) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configtls`: Add `include_system_ca_certs_pool` to configtls, allowing to load system certs and additional custom certs. (#7774) - `otelcol`: Add `ConfigProviderSettings` to `CollectorSettings` (#4759) This allows passing a custom list of `confmap.Provider`s to `otelcol.NewCommand`. - `pdata`: Update to OTLP v1.1.0 (#9587) Introduces Span and SpanLink flags. - `confmap`: Update mapstructure to use a maintained fork, github.com/go-viper/mapstructure/v2. (#9634) See https://github.com/mitchellh/mapstructure/issues/349 for context. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configretry`: Allow max_elapsed_time to be set to 0 for indefinite retries (#9641) - `client`: Make `Metadata.Get` thread safe (#9595) ## v1.2.0/v0.95.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: scope name for all generated Meter/Tracer funcs now includes full package name (#9494) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confighttp`: Adds support for Snappy decompression of HTTP requests. (#7632) - `configretry`: Validate `max_elapsed_time`, ensure it is larger than `max_interval` and `initial_interval` respectively. (#9489) - `configopaque`: Mark module as stable (#9167) - `otlphttpexporter`: Add support for json content encoding when exporting telemetry (#6945) - `confmap/converter/expandconverter, confmap/provider/envprovider, confmap/provider/fileprovider, confmap/provider/httpprovider, confmap/provider/httpsprovider, confmap/provider/yamlprovider`: Split confmap.Converter and confmap.Provider implementation packages out of confmap. (#4759, #9460) ## v1.1.0/v0.94.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `receiver/otlp`: Update gRPC code from `codes.InvalidArgument` to `codes.Internal` when a permanent error doesn't contain a gRPC status (#9415) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `configgrpc`: Deprecate GRPCClientSettings, use ClientConfig instead (#6767) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `mdatagen`: Add a generated test that checks the config struct using `componenttest.CheckConfigStruct` (#9438) - `component`: Add `component.UseLocalHostAsDefaultHost` feature gate that changes default endpoints from 0.0.0.0 to localhost (#8510) The only component in this repository affected by this is the OTLP receiver. - `confighttp`: Add support of Host header (#9395) - `mdatagen`: Remove use of ReportFatalError in generated tests (#9439) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: fix opencensus bridge configuration in periodic readers (#9361) - `otlpreceiver`: Fix goroutine leak when GRPC server is started but HTTP server is unsuccessful (#9165) - `otlpexporter`: PartialSuccess is treated as success, logged as warning. (#9243) ## v0.93.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: remove deprecated exporterhelper.RetrySettings and exporterhelper.NewDefaultRetrySettings (#9256) - `configopaque`: configopaque.String implements `fmt.Stringer` and `fmt.GoStringer`, outputting [REDACTED] when formatted with the %s, %q or %#v verbs` (#9213) This may break applications that rely on the previous behavior of opaque strings with `fmt.Sprintf` to e.g. build URLs or headers. Explicitly cast the opaque string to a string before using it in `fmt.Sprintf` to restore the previous behavior. ### ๐Ÿš€ New components ๐Ÿš€ - `extension/memory_limiter`: Introduce a `memory_limiter` extension which receivers can use to reject incoming requests when collector doesn't have enough memory (#8632) The extension has the same configuration interface and behavior as the existing `memory_limiter` processor, which potentially can be deprecated and removed in the future ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `configtls`: add `cipher_suites` to configtls. (#8105) Users can specify a list of cipher suites to pick from. If left blank, a safe default list is used. - `service`: mark `telemetry.useOtelForInternalMetrics` as stable (#816) - `exporters`: Cleanup log messages for export failures (#9219) 1. Ensure an error message is logged every time and only once when data is dropped/rejected due to export failure. 2. Update the wording. Specifically, don't use "dropped" term when an error is reported back to the pipeline. Keep the "dropped" wording for failures happened after the enabled queue. 3. Properly report any error reported by a queue. For example, a persistent storage error must be reported as a storage error, not as "queue overflow". ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configgrpc`: Update dependency to address a potential crash in the grpc instrumentation (#9296) - `otlpreceiver`: Ensure OTLP receiver handles consume errors correctly (#4335) Make sure OTLP receiver returns correct status code and follows the receiver contract (gRPC) - `zpagesextension`: Remove mention of rpcz page from zpages extension (#9328) ## v1.0.1/v0.92.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporters/sending_queue`: Do not re-enqueue failed batches, rely on the retry_on_failure strategy instead. (#8382) The current re-enqueuing behavior is not obvious and cannot be configured. It takes place only for persistent queue and only if `retry_on_failure::enabled=true` even if `retry_on_failure` is a setting for a different backoff retry strategy. This change removes the re-enqueuing behavior. Consider increasing `retry_on_failure::max_elapsed_time` to reduce chances of data loss or set it to 0 to keep retrying until requests succeed. - `confmap`: Make the option `WithErrorUnused` enabled by default when unmarshaling configuration (#7102) The option `WithErrorUnused` is now enabled by default, and a new option `WithIgnoreUnused` is introduced to ignore errors about unused fields. - `status`: Deprecate `ReportComponentStatus` in favor of `ReportStatus`. This new function does not return an error. (#9148) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `connectortest`: Deprecate connectortest.New[Metrics|Logs|Traces]Router in favour of connector.New[Metrics|Logs|Traces]Router (#9095) - `exporterhelper`: Deprecate exporterhelper.RetrySettings in favor of configretry.BackOffConfig (#9091) - `extension/ballast`: Deprecate `memory_ballast` extension. (#8343) Use `GOMEMLIMIT` environment variable instead. - `connector`: Deprecate [Metrics|Logs|Traces]Router in favour of [Metrics|Logs|Traces]RouterAndConsumer (#9095) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporterhelper`: Add RetrySettings validation function (#9089) Validate that time.Duration, multiplier values in configretry are non-negative, and randomization_factor is between 0 and 1 - `service`: Enable `telemetry.useOtelForInternalMetrics` by updating the flag to beta (#7454) The metrics generated should be consistent with the metrics generated previously with OpenCensus. Users can disable the behaviour by setting `--feature-gates -telemetry.useOtelForInternalMetrics` at collector start. - `mdatagen`: move component from contrib to core (#9172) - `semconv`: Generated Semantic conventions 1.22.0. (#8686) - `confignet`: Add `dialer_timeout` config option. (#9066) - `processor/memory_limiter`: Update config validation errors (#9059) - Fix names of the config fields that are validated in the error messages - Move the validation from start to the initialization phrase - `exporterhelper`: Add config Validate for TimeoutSettings (#9104) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `memorylimiterprocessor`: Fixed leaking goroutines from memorylimiterprocessor (#9099) - `cmd/otelcorecol`: Fix the code detecting if the collector is running as a service on Windows. (#7350) Removed the `NO_WINDOWS_SERVICE` environment variable given it is not needed anymore. - `otlpexporter`: remove dependency of otlphttpreceiver on otlpexporter (#6454) ## v0.91.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `statusreporting`: Automates status reporting upon the completion of component.Start(). (#7682) - `service`: add resource attributes as labels to otel metrics to ensures backwards compatibility with OpenCensus metrics. (#9029) - `semconv`: Generated Semantic conventions 1.21. (#9056) - `config/confighttp`: Exposes http/2 transport settings to enable health check and workaround golang http/2 issue https://github.com/golang/go/issues/59690 (#9022) - `cmd/builder`: running builder version on binaries installed with `go install` will output the version specified at the suffix. (#8770) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: fix missed metric aggregations (#9048) This ensures that context cancellation in the exporter doesn't interfere with metric aggregation. The OTel SDK currently returns if there's an error in the context used in `Add`. This means that if there's a cancelled context in an export, the metrics are now recorded. - `service`: Fix bug where MutatesData would not correctly propagate through connectors. (#9053) ## v0.90.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Remove noisy log (#9017) ## v1.0.0/v0.90.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: To remain backwards compatible w/ the metrics generated today, otel generated metrics will be generated without the `_total` suffix (#7454) - `service`: use WithNamespace instead of WrapRegistererWithPrefix (#8988) Using this functionality in the otel prom exporter fixes a bug where the target_info was prefixed as otelcol_target_info previously. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter/debug`: Change default `verbosity` from `normal` to `basic` (#8844) This change has currently no effect, as `basic` and `normal` verbosity share the same behavior. This might change in the future though, with the `normal` verbosity being more verbose than it currently is (see https://github.com/open-telemetry/opentelemetry-collector/issues/7806). This is why we are changing the default to `basic`, which is expected to stay at the current level of verbosity (one line per batch). - `exporterhelper`: Fix shutdown logic in persistent queue to not require consumers to be closed first (#8899) - `confighttp`: Support proxy configuration field in all exporters that support confighttp (#5761) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: Fix invalid write index updates in the persistent queue (#8115) ## v1.0.0-rcv0018/v0.89.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `builder`: remove replace statement in builder template (#8763) - `service/extensions`: Allow extensions to declare dependencies on other extensions and guarantee start/stop/notification order accordingly. (#8732) - `exporterhelper`: Log export errors when retry is not used by the component. (#8791) - `cmd/builder`: Add --verbose flag to log `go` subcommands output that are ran as part of a build (#8715) - `exporterhelper`: Remove internal goroutine loop for persistent queue (#8868) - `exporterhelper`: Simplify usage of storage client, avoid unnecessary allocations (#8830) - `exporterhelper`: Simplify logic in boundedMemoryQueue, use channels len/cap (#8829) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: fix bug with queue size and capacity metrics (#8682) - `obsreporttest`: split handler for otel vs oc test path in TestTelemetry (#8758) - `builder`: Fix featuregate late initialization (#4967) - `service`: Fix connector logger zap kind key (#8878) ## v1.0.0-rcv0017/v0.88.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `fanoutconsumer`: Enable runtime assertions to catch incorrect pdata mutations in the components claiming as non-mutating pdata. (#6794) This change enables the runtime assertions to catch unintentional pdata mutations in components that are claimed as non-mutating pdata. Without these assertions, runtime errors may still occur, but thrown by unrelated components, making it very difficult to troubleshoot. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `exporterhelper`: make enqueue failures available for otel metrics (#8673) - `exporterhelper`: Fix nil pointer dereference when stopping persistent queue after a start encountered an error (#8718) - `cmd/builder`: Fix ocb ignoring `otelcol_version` when set to v0.86.0 or later (#8692) ## v1.0.0-rcv0016/v0.87.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service/telemetry exporter/exporterhelper`: Enable sampling logging by default and apply it to all components. (#8134) The sampled logger configuration can be disabled easily by setting the `service::telemetry::logs::sampling::enabled` to `false`. - `core`: Adds the ability for components to report status and for extensions to subscribe to status events by implementing an optional StatusWatcher interface. (#7682) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `telemetry`: remove workaround to ignore errors when an instrument includes a `/` (#8346) ## v1.0.0-rcv0015/v0.86.0 ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `loggingexporter`: Mark the logging exporter as deprecated, in favour of debug exporter (#7769) ### ๐Ÿš€ New components ๐Ÿš€ - `debugexporter`: Add debug exporter, which replaces the logging exporter (#7769) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `featuregate`: List valid feature gates when failing to load invalid gate (#8505) - `supported platforms`: Add `linux/s390x` architecture to cross build tests in CI (#8213) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `builder`: fix setting `dist.*` keys from env (#8239) - `configtls`: fix incorrect use of fsnotify (#8438) ## v0.85.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `components command`: The "components" command now lists the component's stability levels. (#8289) Note that the format of this output is NOT stable and can change between versions. - `confighttp`: Add option to disable HTTP keep-alives (#8260) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confmap`: fix bugs of unmarshalling slice values (#4001) - `exporterhelper`: Stop logging error messages suggesting user to enable `retry_on_failure` or `sending_queue` when they are not available. (#8369) ## v0.84.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `loggingexporter`: Adds exemplars logging to the logging exporter when `detailed` verbosity level is set. (#7912) - `configgrpc`: Allow any registered gRPC load balancer name to be used. (#8262) - `service`: add OTLP export for internal traces (#8106) - `configgrpc`: Add support for :authority pseudo-header in grpc client (#8228) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otlphttpexporter`: Fix the handling of the HTTP response to ignore responses not encoded as protobuf (#8263) ## v0.83.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `extension`: Add optional `ConfigWatcher` interface (#6596) Extensions implementing this interface will be notified of the Collector's effective config. - `otelcol`: Add optional `ConfmapProvider` interface for Config Providers (#6596) This allows providing the Collector's configuration as a marshaled confmap.Conf object from a ConfigProvider - `service`: Add `CollectorConf` field to `service.Settings` (#6596) This field is intended to be used by the Collector to pass its effective configuration to the service. ## v1.0.0-rcv0014/v0.82.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: Enable configuration of collector telemetry through prometheus reader (#7641) These options are still experimental. To enable them, users must enable both `telemetry.useOtelForInternalMetrics` and `telemetry.useOtelWithSDKConfigurationForInternalTelemetry` feature gates. This change updates `metric_readers` to `readers` to align with the configuration working group. - `service`: Remove experimental `metric_readers.args` and `metric_reader.type` config options. (#7641) These options were experimental and did not have any effect on the configuration of the collector's telemetry. The change aligns the configuration with the latest iteration of the configuration json schema, which may still change in the future. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service`: Add support for exporting internal metrics to the console (#7641) Internal collector metrics can now be exported to the console using the otel-go stdout exporter. - `service`: Add support for `interval` and `timeout` configuration in periodic reader (#7641) - `service`: Add support for span processor configuration for internal traces (#8106) These options are still experimental. To enable them, users must enable both `telemetry.useOtelForInternalMetrics` and `telemetry.useOtelWithSDKConfigurationForInternalTelemetry` feature gates. - `service`: Add support for OTLP export for internal metrics (#7641) Internal collector metrics can now be exported via OTLP using the otel-go otlpgrpc and otlphttp exporters. - `scraperhelper`: Adding optional timeout field to scrapers (#7951) - `otlpreceiver`: Add http url paths per signal config options to otlpreceiver (#7511) - `otlphttpexporter`: Add support for trailing slash in endpoint URL (#8084) URLs like `http://localhost:4318/` will now be treated as if they were `http://localhost:4318` ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `connector`: Fix connector validation (#7892) Validation of connectors was too aggressive such that a connector that was used in any combination of unsupported roles would fail. Instead, validation should pass as long as each use of the connector has a supported corresponding use. ## v0.81.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `service`: Remove 'service.connectors' featuregate (#7952) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `HTTPServerSettings`: Add zstd support to HTTPServerSettings (#7927) This adds ability to decompress zstd-compressed HTTP requests to| all receivers that use HTTPServerSettings. - `cmd/builder`: Add "--skip-generate" option to make builder skip source generation (#7541) - `confighttp`: Add support for additional content decoders via `WithDecoder` server option (#7977) - `connectortest`: Add helpers to aid the construction of `connector.TracesRouter`, `connector.MetricsRouter`, and `connector.LogsRouter` instances to `connectortest`. (#7672) - `confighttp`: Add `response_headers` configuration option on HTTPServerSettings. It allows for additional headers to be attached to each HTTP response sent to the client (#7328) - `otlpreceiver, otlphttpexporter, otlpexporter, configgrpc`: Upgrade github.com/mostynb/go-grpc-compression and switch to nonclobbering imports (#7920) consumers of this library should not have their grpc codecs overridden - `otlphttpexporter`: Treat partial success responses as errors (#6686) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `HTTPServerSettings`: Ensure requests with unsupported Content-Encoding return HTTP 400 Bad Request (#7927) ## v1.0.0-rcv0013/v0.80.0 ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `service`: Deprecate service.PipelineConfig in favor of pipelines.Config. (#7854) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service`: Added dry run flag to validate config file without running collector. (#4671) - `configtls`: Allow TLS Settings to be provided in memory in addition to filepath. (#7313) - `connector`: Updates the way connector nodes are built to always pass a fanoutconsumer to their factory functions. (#7672, #7673) - `otlp`: update otlp protos to v0.20.0 (#7839) - `configauth`: Split config/configauth into its own module (#7895) - `configgrpc, confighttp, config/internal`: Split confighttp, configgrpc, and config/internal into separate modules (#7895) - `confignet`: Split config/confignet into its own module (#7895) - `configopaque`: Split config/configopaque into its own module (#7895) - `configtelemetry`: Split config/configtelemetry into its own module (#7895) - `configtls`: Split config/configtls into its own module (#7895) - `configcompression`: Split config/configcompression into its own module (#7895) - `extension`: Splitting `extension/auth` into separate module (#7054) - `connector`: Split connector into its own module (#7895) - `extension`: split extension module into its own module (#7306) - `processor`: Split the processor into its own go module (#7307) - `confighttp`: Avoid re-creating the compressors for every request. (#7859) - `otlpexporter`: Treat partial success responses as errors (#6686) - `service/pipelines`: Add pipelines.Config to remove duplicate of the pipelines configuration (#7854) ## v0.79.0 ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `component`: Deprecate Host.GetExporters function (#7370) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `otelcol`: Add connectors to output of the `components` command (#7809) - `scraperhelper`: Will start calling scrapers on component start. (#7635) The change allows scrapes to perform their initial scrape on component start and provide an initial delay. This means that scrapes will be delayed by `initial_delay` before first scrape and then run on `collection_interval` for each consecutive interval. - `batchprocessor`: Change multiBatcher to use sync.Map, avoid global lock on fast path (#7714) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `connectors`: When replicating data to connectors, consider whether the next pipeline will mutate data (#7776) ## v0.78.2 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `batchprocessor`: Fix return error for batch processor when consuming Metrics and Logs (#7711) ## v0.78.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `batchprocessor`: Fix start/stop logic for batch processor (#7708) ## v1.0.0-rcv0012/v0.78.0 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `batchprocessor`: Add support for batching by metadata keys. (#4544) - `service`: Add feature gate `telemetry.useOtelWithSDKConfigurationForInternalTelemetry` that will add support for configuring the export of internal telemetry to additional destinations in future releases (#7641) - `forwardconnector`: Promote to beta (#7579) - `featuregate`: Promote `featuregate` to the stable module-set (#7693) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `featuregate`: Fix issue where `StageDeprecated` was not usable (#7586) - `exporterhelper`: Fix persistent storage behaviour with no available space on device (#7198) ## v0.77.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `exporterhelper`: Reduce the default queue size to 1000 from 5000 (#7359) Affects any exporter which enables the queue by default and doesn't set its own default size. For example: otlphttp. - `featuregate`: Remove deprecated `RemovalVersion` and `WithRegisterRemovalVersion` functions. (#7587) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service`: Adds ResourceAttributes map to telemetry settings and thus CreateSettings. (#6599) - `service`: Allows users to disable high cardinality OTLP attributes behind a feature flag. (#7517) - `featuregate`: Finalize purpose of `toVersion`. Allow stable gates to be explicitly set to true, but produce a warning log. (#7626) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `config/confighttp`: Ensure Auth RoundTripper follows compression/header changes (#7574) - `otlpreceiver`: do not reject requests having 'content-type' header with optional parameters (#7452) ## v1.0.0-rcv0011/v0.76.1 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `confmap`: Using an Invalid Scheme in a URI will throw an error. (#7504) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `featuregate`: Deprecate Gate.RemovalVersion and WithRegisterRemovalVersion in favor of ToVersion. (#7043) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `batchprocessor`: Support zero timeout. (#7508) This allows the batchprocessor to limit request sizes without introducing delay in a pipeline, to act only as a splitter. - `service`: use the otel opencensus bridge when telemetry.useOtelForInternalMetrics is enabled (#7483) - `connector`: Mark 'service.connectors' featuregate as stable (#2336) - `featuregate`: Add a new Deprecated stage for feature gates, when features are abandoned. (#7043) - `loggingexporter`: Show more counters in not detailed verbosity (#7461) The logging exporter now shows more counters when the verbosity is not detailed. The following numbers are added: - Number of resource logs - Number of resource spans - Number of resource metrics - Number of data points - `configtls`: Reload mTLS ClientCA certificates on file change (#6524) - `confmap`: Add support for nested URIs. (#7117) - `featuregate`: Add concept of gate lifetime, [fromVersion, toVersion]. (#7043) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `obsreport`: fix issue where send_failed_requests counter was reporting an incorrect value. (#7456) ## v1.0.0-rc9/v0.75.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `featuregate`: Remove deprecated featuregate.FlagValue (#7401) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `provider`: Added userfriendly error on incorrect type. (#7399) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `loggingexporter`: Fix display of bucket boundaries of exponential histograms to correctly reflect inclusive/exclusive bounds. (#7445) - `exporterhelper`: Fix a deadlock in persistent queue initialization (#7400) ## v1.0.0-rc8/v0.74.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `consumererror`: Remove deprecated funcs in consumererror (#7357) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `featuregate`: Deprecate `FlagValue` in favor of `NewFlag`. (#7042) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service`: Enable connectors by default by moving service.connectors featuregate to beta (#7369) ## v0.73.0/v1.0.0-rc7 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `consumererror`: Remove `Get` prefix from methods returning failed signal data (#7048) - `service`: Feature gate `service.graph` is now stable and cannot be disabled. It will be removed in the next version. (#2336) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter`: split exporter into its own module (#7239) - `receiver`: split receiver into its own module (#7174) - `connectors`: Provide connectors with a mechanism to route data to specific pipelines (#7152) - `confmap`: Mark `confmap.expandEnabled` as stable (#7323) ## v1.0.0-rc6/v0.72.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `all`: Remove go 1.18 support, bump minimum to go 1.19 and add testing for 1.20 (#7151) - `pdata`: Remove deprecated `[Metrics|Traces|Logs]MoveTo` methods. (#7165) - `featuregate`: Remove deprecated funcs in featuregate. (#7173) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `semconv`: Generated Semantic conventions 1.17 that now contains the `event` type. (#7170) - `semconv`: Generated Semantic conventions 1.18. (#7168) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `memorylimiterprocessor`: Fix incorrect parsing of cgroups when running Collector with host mount (#6826) - `confmap`: Clear list of old already closed closers. (#7215) ## v1.0.0-rc5/v0.71.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pdata`: Add private method to GrpcServer interface, disallow direct implementation (#6966) - `featuregate`: Remove deprecated GetRegistry (#7011) - `pcommon`: Remove deprecated Map.Sort (#6688) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `featuregate`: Deprecate Registry.List in favor of Registry.VisitAll. (#7041) - `featuregate`: Deprecate Apply in favor of Set (#7018) - `pdata`: Deprecate [Metrics|Logs|Traces].MoveTo methods. (#7091) - `featuregate`: Deprecate RegistryOption in favor of RegisterOption (#7012) - `featuregate`: Deprecate featuregate.Registry.[IsEnabled, RegisterID, MustRegister] (#6998) ### ๐Ÿš€ New components ๐Ÿš€ - `httpsprovider`: Add the httpsprovider. This component allows the collector to fetch configurations from web servers using the HTTPS protocol. (#6683) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `exporter`: Allow configuration of fields, `RandomizationFactor` and `Multiplier`, for exponential backoff algorithm when retry on failure is enabled (#6610) - `connectors`: Add "connectors", a new type of pipeline component (#2336) - Connectors connect pipelines by acting as an exporter in one or more pipelines and simultaneously as a receiver of corresponding data in one or more other pipelines. For example: - The `forward` connector can export data to another pipeline of the same type. This allows you to merge data from multiple pipelines onto a common pipeline. Or, you can replicate data onto multiple pipelines so that it may be processed in different ways and/or exported to different backends. - The `count` connector can count data of any type. Regardless of the type of data that is counted, it emits counts as metrics onto a metrics pipeline. - Connectors are currently disabled by default but can be enabled with the `service.connectors` feature gate. - See the [connectors README](https://github.com/open-telemetry/opentelemetry-collector/blob/main/connector/README.md) for more details on how to use connectors. - `service`: Enable new pipelines implementation using graphs. Controlled by the `service.graph` featuregate. (#2336) - `builder`: added ldflags command option (#6940) - `proctelemetry`: Instrument `proctelemetry.ProcessMetrics` metrics with otel-go (#6886) - `capabilityconsumer`: If the consumer has already the desired capability, don't wrap (#7116) - `confmap`: Add support to resolve embedded uris inside a string, concatenate results. (#6932) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confmap`: Fix bug in confmap validation that allowed the usage of case-insensitive keys in the configurations, despite them failing silently. (#6876) - `logging`: Fix the attribute key used to identify the receiver data type in logging configuration (#7033) ## v1.0.0-RC4/v0.70.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pdata`: Start enforcing grpc server implementation to embed UnimplementedGRPCServer, disallow client implementation (#6966) - `config/configgrpc`: Change configgrpc.GRPCClientSettings.Headers type to map[string]configopaque.String (#6852) Use `configopaque.String(str)` and `string(opaque)` to turn a string opaque/clear. - `pdata`: Remove deprecated pcommon.Value.Equal (#6860) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `pdata`: Deprecate pcommon.Map.Sort(). (#6688) - `featuregate`: Deprecate GetRegistry in favor of GlobalRegistry (#6979) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `builder`: Add remote debug option for otel-collector to builder (#6149) - `connector`: Add Builder (#6867) - `cmd/builder`: Add support for connector configurations (#6789) - `exporter/otlphttp`: Retry only on status code 429/502/503/504 (#6845) - `featuregate`: Reduce contention in featuregate by using sync.Map instead of mutex. (#6980) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `loggingexporter`: Fix undefined symbol errors on building otelcorecol for other platforms than darwin, linux, windows. (#6924) - `otlpexporter`: Fix a dataloss bug in persistent storage when collector shuts down or restarts (#6771) ## v0.69.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `various modules`: Fix issue where some collector modules imported previous version of other modules (#6929) ## v1.0.0-RC3/v0.69.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `component`: Remove deprecated Exporter types (#6880) - `component`: Remove deprecated Extension types (#6865) - `component`: Remove deprecated ProcessorFactoryOptions (#6881) - `component`: Remove deprecated Receiver types (#6882) - `componenttest`: Remove deprecated funcs from componenttest (#6836) - `batchprocessor`: Remove deprecated batchprocessor.MetricViews and batchprocessor.OtelMetricViews (#6861) - `component`: Remove deprecated component.[Factories|MakeProcessorFactoryMap] and componenttest.NewNopFactories (#6835) - `config`: Remove deprecated config.*Settings (#6837) - `obsreporttest`: Remove deprecated obsreporttest.SetupTelemetryWithID (#6861) - `component`: Remove deprecated component [Traces|Metrics|Logs]Processor and ProcessorFactory (#6884) - `service`: Remove deprecated service service.ConfigService and service.ConfigServicePipeline (#6859) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `connector`: Add MakeFactoryMap (#6889) - `semconv`: Add semantic conventions for specification v1.16.0 (#6714) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `config`: use [REDACTED] when marshaling to text a configopaque.String, instead of disclosing secret length. (#6868) ## v1.0.0-RC2/v0.68.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `componenttest`: Move NopFactories to otelcoltest (#6792) - `config/confighttp`: Change confighttp.HTTPClientSettings.Headers type to map[string]configopaque.String (#5653) - `config`: Remove deprecated `component.Config.[ID|SetIDName]`. (#4714) - `configauth`: Remove deprecated funcs/types from `configauth` (#6719) - `component`: Remove deprecated funcs/types from component package (#6769) - `component.[Exporter|Processor|Receiver|Extension]Config` - `component.Unmarshal[Exporter|Processor|Receiver|Extension]Config` - `component.[Exporter|Processor|Receiver|Extension]CreateDefaultConfigFunc` - `component.[Exporter|Receiver|Extension]FactoryOption` - `component.New[Exporter|Receiver|Extension]Factory` - `component.With[Traces|Metrics|Logs][Exporter|Receiver]` - `component.Create[Traces|Metrics|Logs][Exporter|Receiver]Func` - `component.CreateExtensionFunc` - `componenttest`: Remove deprecated componenttest.NewNop*CreateSettings (#6761) - `service`: Remove deprecated `service.[Collector|New|CollectorSettings|ConfigProvider]` (#5564) - `service`: Remove deprecated funcs `service.NewCommand` and `service.NewSvcHandler`. (#5564) - `obsreporttest`: Remove deprecate obsreporttest.Check* (#6720) - `service`: Remove deprecated `service.Config`. (#6774) - `servicetest`: Remove deprecated `servicetest` package. (#5564) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `service`: Deprecate `service.ConfigService` in favor of `service.Config` and `service.ConfigServicePipeline` in favor of `service.PipelineConfig`. (#6787) - `pdata`: Deprecate `pcommon.Value.Equal` method (#6811) - `component`: Deprecate `Processor` related structs and functions in favor of `processor` package (#6709) - `component`: Deprecate component.Factories in favor of otelcol.Factories (#6723) - `config`: Deprecate `config.[Extension|Exporter|Connector|Receiver|Processor]Settings`. (#6718) - `batchprocessor`: Deprecate metric views funcs, for OC and Otel. (#6730) - `obsreporttest`: Deprecate obsreporttest.SetupTelemetryWithID in favor of obsreporttest.SetupTelemetry (#6720) ### ๐Ÿš€ New components ๐Ÿš€ - `forwardconnector`: Add forward connector (#6763) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `components`: Add [receiver|processor|exporter|extension].Builder to help with creating components form a set of configs and factories (#6803) - `configunmarshaler`: Consolidate package into generic implementation (#6801) - `service`: Shutdown internal telemetry with the Service (every time config changes). (#5564) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configgrpc`: Fix todo to add MeterProvider to grpc instrumentation (#4030) - `otlpreceiver`: Fix otlpreceiver transport metrics attribute (#6695) ## v1.0.0-RC1/v0.67.0 We are excited to announce that the `pdata` module is now available as a v1.0.0 release candidate. While breaking changes may still happen in this module before v1.0.0, we believe it is ready for final assessment and validation and hope to make a v1.0.0 release soon. ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `overwritepropertiesconverter`: Remove deprecated package `overwritepropertiesconverter` (#6656) - `pdata`: Change [...Slice|Map].Sort methods to not return any value (#6660) - `featuregate`: remove deprecated functions (#6594) - `featuregate.GetID()` - `featuregate.GetDescription()` - `obsreport`: remove deprecated functions. (#6595) - `obsreport.MustNewExporter` - `obsreport.MustNewProcessor` - `obsreport.MustNewReceiver` - `obsreport.MustNewScraper` - `service`: Remove deprecated `service.State` enum values. (#6605) - `component`: Remove deprecated func/types from component (#6606) - `config`: Remove deprecated config.Pipelines and config.Pipeline (#6664) - `ballastextension`: Remove deprecated `ballastextension.MemoryBallast` type (#6628) - `component`: Remove `Validate()` from component.*Config interfaces and make it optional interface (#6544) - `confmap`: Splitting confmap into its own module (#6185) The import path for the confmap module can now be access directly: - `go.opentelemetry.io/collector/confmap` ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `service`: Deprecate service.[Collector|NewSvcHandler|CollectorSettings|State|NewCommand] in favor of otelcol package" (#6608) - Deprecate `service.Config` in favor of `otelcol.Config`. - Deprecate `service.ConfigProvider` in favor of `otelcol.ConfigProvider`. - Deprecate `service.NewConfigProvider` in favor of `otelcol.NewConfigProvider`. - Deprecate `service.CollectorSettings` in favor of `otelcol.CollectorSettings`. - Deprecate `service.Collector` in favor of `otelcol.Collector`. - Deprecate `service.New` in favor of `otelcol.NewCollector`. - Deprecate `service.State` in favor of `otelcol.State`. - Deprecate `service.NewSvcHandler` in favor of `otelcol.NewSvcHandler`. - Deprecate `service.NewCommand` in favor of `otelcol.NewCommand`. - `obsreporttest`: Deprecate obsreporttest.Check* in favor of TestTelemetry.Check (#6678) - `component`: Deprecate Exporter related types/funcs from component package in favor of exporter package. (#6578) - `component.ExporterCreateSettings` -> `exporter.CreateSettings` - `component.CreateTracesExporterFunc` -> `exporter.CreateTracesFunc` - `component.CreateMetricsExporterFunc` -> `exporter.CreateMetricsFunc` - `component.CreateLogsExporterFunc` -> `exporter.CreateLogsFunc` - `component.ExporterFactory` -> `exporter.Factory` - `component.NewExporterFactory` -> `exporter.NewFactory` - `component.MakeExporterFactoryMap` -> `exporter.MakeFactoryMap` - `componenttest.NewNopExporterCreateSettings` -> `exportertest.NewNopCreateSettings` - `componenttest.NewNopExporterFactory` -> `exportertest.NewNopFactory` - `component`: Change Config to be opaque for otel collector core. (#4714) - Deprecate `component.Config.ID()` in favor of `component.[*]CreateSettings.ID`. - Deprecate `component.Config.SetIDName()`, no replacement needed since ID in settings is public member. - Deprecate `obsreporttest.SetupTelemetry` in favor of `obsreporttest.SetupTelemetryWithID`. - `component`: Deprecate `component.Unmarshal[*]Config` in favor of `component.UnmarshalConfig` (#6613) - `component`: Deprecate Extension related types/funcs from component package in favor of extension package. (#6578) - `component.Extension` -> `extension.Extension` - `component.PipelineWatcher` -> extension.PipelineWatcher - `component.ExtensionCreateSettings` -> `extension.CreateSettings` - `component.CreateExtensionFunc` -> `extension.CreateFunc` - `component.ExtensionFactory` -> `extension.Factory` - `component.NewExtensionFactory` -> `extension.NewFactory` - `component.MakeExtensionFactoryMap` -> `extension.MakeFactoryMap` - `componenttest.NewNopExtensionCreateSettings` -> `extensiontest.NewNopCreateSettings` - `componenttest.NewNopExtensionFactory` -> `extensiontest.NewNopFactory` - `component`: Deprecate `Receiver` related structs and functions in favor of `receiver` package (#6687) - `component`: Deprecate `component.[Exporter|Extension|Processor|Receiver]Config` in favor of `component.Config` (#6578) - `pdata`: Remove deprecated funcs `pdata.[Span|Trace]ID.HexString` (#6627) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `config/configopaque`: Add new `configopaque.String` type alias for opaque strings. (#5653) - `service`: Added components sub command which outputs components in collector distribution. (#4671) - `component`: Define new component type 'connectors' (#6577) - `connector`: Add connector factory (#6611) - `connector`: Add connector types (TracesConnector, MetricsConnector, LogsConnector) (#6689) - `connectortest`: Add connector/connectortest package (#6711) - `component`: Add recursive validation check for configs (#4584) - `service`: Improve config error messages, split Validate functionality (#6665) - `extension/authextension`: Define new authextension package and use new package in collector repo (#6467) - configauth.ClientAuthenticator -> auth.Client - configauth.NewClientAuthenticator -> auth.NewClient - configauth.ClientOption -> auth.ClientOption - configauth.WithClientStart -> auth.WithClientStart - configauth.WithClientShutdown -> auth.WithClientShutdown - configauth.WithClientRoundTripper -> auth.WithClientRoundTripper - configauth.WithPerRPCCredentials -> auth.WithClientPerRPCCredentials - configauth.ServerAuthenticator -> auth.Server - configauth.NewServerAuthenticator -> auth.NewServer - configauth.Option -> auth.ServerOption - configauth.AuthenticateFunc -> auth.ServerAuthenticateFunc - configauth.WithAuthenticate -> auth.WithServerAuthenticate - configauth.WithStart -> auth.WithServerStart - configauth.WithShutdown -> auth.WithServerShutdown - `obsreport`: Instrument `obsreport.Processor` metrics with otel-go (#6607) - `pdata`: Add ability to clear optional fields (#6474) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otlpexporter`: Fix nil panic from otlp exporter in case of errors during Start. (#6633) - `service`: Stop notification for signals before shutdown, increase channel size. (#6522) - `confmap`: Fix support for concatenating envvars with colon (#6580) - `otlpexporter`: Fix a bug that exporter persistent queue is sending duplicate data after restarting. (#6692) ## v0.65.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `featuregate`: Capitalize `featuregate.Stage` string values, remove Stage prefix. (#6490) - `configtelemetry`: Update values returned by `Level.String` and `Level.MarshalText` method. (#6490) - All returned strings are capitalized. - "" is returned for integers that are out of Level enum range. - It also affects `Level.Marshal` output, but it's not a problem because `Unmarshal` method accepts strings in all cases, e.g. "normal", "Normal" and "NORMAL". - `featuregate`: Make impossible to implement RegistryOption outside `featuregate` package (#6532) - `service/telemetry`: Remove unit suffixes from metrics exported by the otel-go prometheus exporter. (#6403) - `obsreport`: `obsreport.New[Receiver|Scraper|Processor|Exporter]` returns error now (#6458) - `configgrpc`: Remove deprecated funcs in `configgrpc`. (#6529) - `configgrpc.GRPCClientSettings.ToDialOptions` - `configgrpc.GRPCServerSettings.ToServerOption` - `config/configtest`: Remove deprecated `configtest` package. (#6542) - `config`: Remove deprecated types and funcs from config. Use `component` package. (#6511) - config.ComponentID - config.Type - config.DataType - config.Receiver - config.UnmarshalReceiver - config.Processor - config.UnmarshalProcessor - config.Exporter - config.UnmarshalExporter - config.Extension - config.UnmarshalExtension - `featuregate`: Remove deprecated funcs and struct members from `featuregate` package (#6523) - featuregate.Gate.ID - featuregate.Gate.Description - featuregate.Gate.Enabled - featuregate.Registry.Register - featuregate.Registry.MustRegister - `experimental`: Remove experimental configsource code. (#6558) - `component`: Update values returned by `StabilityLevel.String` method. (#6490) - All returned strings are capitalized. - "Undefined" is returned only for `StabilityLevelUndefined`. - "" is returned for integers that are out of StabilityLevel enum range. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `pdata`: Deprecate `pcommon.[Span|Trace]ID.HexString` methods. Call `hex.EncodeToString` explicitly instead. (#6514) - `obsreport`: deprecate `obsreport.MustNew[Receiver|Scraper|Processor|Exporter]` in favor of `obsreport.New[Receiver|Scraper|Processor|Exporter]` (#6458) - Deprecate `obsreport.MustNewReceiver()` in favor of `obsreport.NewReceiver()` - Deprecate `obsreport.MustNewScraper()` in favor of `obsreport.NewScraper()` - Deprecate `obsreport.MustNewProcessor()` in favor of `obsreport.NewProcessor()` - Deprecate `obsreport.MustNewExporter()` in favor of `obsreport.NewExporter()` - `component`: Deprecate `component.Receiver`, `component.Processor`, and `component.Exporter`. (#6553) - `featuregate`: Deprecate Get prefix funcs for `featuregate.Gate` (#6528) `featuregate.Gate.GetID` -> `featuregate.Gate.ID` `featuregate.Gate.GetDescription` -> `featuregate.Gate.Description` - `component`: Deprecate `component.Config.Validate` in favor of `component.ValidateConfig` (#6572) - `component`: Deprecate `StabilityLevelInDevelopment` enum const in favor of `StabilityLevelDevelopment`. (#6561) Also rename all mentions of "In development" stability level to "Development". - `service`: Deprecate `service.[Starting|Running|Closing|Closed]` in favor of `service.State[Starting|Running|Closing|Closed]` (#6492) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `component`: `component.Extension` is temporarily set to be an alias of `component.Component` which will be reverted once it's moved to the `extension` package. Change your `component.Host.GetExtensions()` implementation to return `map[ID]component.Component` instead of `map[ID]component.Extension` (#6553) - `pdata`: Return error from `pcommon.[Value|Map|Slice].FromRaw` when unsupported type. (#6579) - `batchprocessor`: instrument the `batch` processor with OpenTelemetry Go SDK (#6423) - `obsreport`: Instrument `obsreport.Scraper` metrics with otel-go (#6460) - `service/collector`: Support SIGHUP configuration reloading (#5966) - `component`: Split component into its own package (#6187) The import path for the component module can now be access directly: - `go.opentelemetry.io/collector/component` - `consumer`: Split consumer into its own package (#6186) The import path for the consumer module can now be accessed directly: - `go.opentelemetry.io/collector/consumer` - `featuregate`: Split featuregate into its own package (#6526) The import path for the featuregate module can now be accessed directly: - `go.opentelemetry.io/collector/featuregate` ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: Disallow duplicate references to processors within a single pipeline (#6540) ## v0.64.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `loggingexporter`: Fix logging exporter to not mutate the data (#6420) ## 0.64.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `config`: Remove already deprecates `config.Service`. (#6395) - `pdata`: Change output of String() method of the following enum types to more a concise form: (#6251) - plog.SeverityNumber - ptrace.SpanKind - ptrace.StatusCode - `config`: Remove already deprecates `config.Config`. (#6394) - `pdata`: Remove deprecated code from pdata (#6417) - `p[trace|metric|log]otlp.[Request|Response]` - `p[trace|metric|log]otlp.New[Request|Response]` - `p[trace|metric|log]otlp.NewRequestFrom[Traces|Metrics|Logs]` - `p[trace|metric|log]otlp.NewClient` - `p[trace|metric|log]New[JSON|Proto][Marshaler|Unmarshaler]` - `extension`: Splitting ballast/zpages extension into their own modules (#6191) The import path for the extension modules can now be accessed directly: - `go.opentelemetry.io/collector/extension/ballastextension` - `go.opentelemetry.io/collector/extension/zpagesextension` If using one of these extensions, modify your Collector builder configuration to use `gomod` directly, such as: - `gomod: go.opentelemetry.io/collector/extension/ballastextension v0.64.0` - `processor`: Splitting batch/memorylimiter processors into their own modules (#6188, #6192, #6193) The import path for the processor modules can now be access directly: - `go.opentelemetry.io/collector/processor/batchprocessor` - `go.opentelemetry.io/collector/processor/memorylimiter` If using this processor, modify your Collector builder configuration to use `gomod` directly, such as: - `gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.64.0` - `otlpreceiver`: Splitting otlp receiver into its own module (#6190) The import path for the OTLP receiver can now be access directly: - `go.opentelemetry.io/collector/receiver/otlpreceiver` If using this receiver, modify your Collector builder configuration to use `gomod` directly, such as: - `gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.64.0` - `confmap`: Remove unused public member `sync.Mutex` from `confmap.Resolver`. (#6489) This is an exception from the deprecation rule since this is not used anywhere and it is very unlikely that is used by external users. ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `config`: Deprecate multiple types and funcs in `config` package (#6422) - config.ComponentID => component.ID - config.Type => component.Type - config.DataType => component.DataType - config.[Traces|Metrics|Logs]DataType => component.DataType[Traces|Metrics|Logs] - config.Receiver => component.ReceiverConfig - config.UnmarshalReceiver => component.UnmarshalReceiverConfig - config.Processor => component.ProcessorConfig - config.UnmarshalProcessor => component.UnmarshalProcessorConfig - config.Exporter => component.ExporterConfig - config.UnmarshalExporter => component.UnmarshalExporterConfig - config.Extension => component.ExtensionConfig - config.UnmarshalExtension => component.UnmarshalExtensionConfig - `obsreport`: deprecate `obsreport.New[Receiver|Scraper|Processor|Exporter]` in favor of `obsreport.MustNew[Receiver|Scraper|Processor|Exporter]` (#6458) - `config/configgrpc`: Provide better helpers for configgrpc, consistent with confighttp (#6441) - Deprecate `GRPCClientSettings.ToDialOptions` in favor of `GRPCClientSettings.ToClientConn`. - Deprecate `GRPCServerSettings.ToServerOption` in favor of `GRPCServerSettings.ToServer`. - `featuregates`: Removing Gates being configurable externally to the Registry (#6167) - Deprecate `Gate.ID` in favour of `Registry.RegisterID` - Deprecate `Gate.Enabled` in favour of `Gate.IsEnabled()` - Deprecate `Gate.Description` in favour of `WithRegisterDescription` to be used with `Registry.RegisterID` - Deprecate `Registry.Register` in favour of `Registry.RegisterID` - Deprecate `Registry.MustRegister` in favour of `Registry.MustRegisterID` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `service/telemetry`: Allow to configure sampling config for logs. (#4554) - `featuregates`: Extend feature gate definition to include support for issue links and expected deprecated version (#6167) - `receiver/otlp`: Add warning when using unspecified (`0.0.0.0`) address on HTTP or gRPC servers (#6151) - `obsreport`: Instrument `obsreport.Exporter` metrics with otel-go (#6346) - `config`: Add validation for empty address [telemetry::metrics::address] (#5661) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `cgroups`: split line into exactly 3 parts while parsing /proc/{pid}/cgroup (#6389) - `cgroups`: Use int64 for cgroup v1 parsing (#6443) ## v0.63.1 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `service`: Fix running collector as a windows service. (#6433) ## v0.63.0 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `pdata`: JSON marshaler emits enums as ints per spec requirements. This may be a breaking change if receivers were not confirming with the spec. (#6338) - `confmap`: Remove deprecated `confmap.Conf.UnmarshalExact` API in 0.62.0 (#6315) - `pdata`: Remove API deprecated in 0.62.0 (#6314) - Remove deprecated `pcommon.NewValueString` - Remove deprecated `pcommon.Map.PutString` - Remove deprecated `plog.SeverityNumberUndefined` - Remove deprecated `p[metric|log|trace]otlp.RegisterServer` - Remove deprecated `pmetric.[Default]?MetricDataPointFlags` - Remove deprecated `pmetric.MetricAggregationTemporality*` - Remove deprecated `pmetric.MetricTypeNone` - Remove deprecated `pmetric.NumberDataPointValueTypeNone` - Remove deprecated `pmetric.ExemplarValueTypeNone` - Remove deprecated `pmetric.[New]?Buckets` - Remove deprecated `pmetric.[New]?ValueAtQuantile` - Remove deprecated `pmetric.[New]?ValueAtQuantileSlice` - Remove deprecated `ptrace.[New]?SpanStatus` - `exporter`: Splitting otlp, otlphttp and logging exporters into their own modules (#6343) The import path for these exporters can now be access directly: - `go.opentelemetry.io/collector/exporter/loggingexporter` - `go.opentelemetry.io/collector/exporter/otlpexporter` - `go.opentelemetry.io/collector/exporter/otlphttpexporter` If using these exporters, modify your Collector builder configuration to use `gomod` directly, such as: - `gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.63.0` ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - `overwritepropertiesconverter`: Deprecate `overwritepropertiesconverter`, only used by non builder distributions. (#6294) - `pdata`: Add `Export` prefix to `p[trace|metric|log]otlp.[Request|Response]` (#6365) - Deprecate `p[trace|metric|log]otlp.[Request|Response]` in favor of `p[trace|metric|log]otlp.Export[Request|Response]` - Deprecate `p[trace|metric|log]otlp.New[Request|Response]` in favor of `p[trace|metric|log]otlp.NewExport[Request|Response]` - Deprecate `p[trace|metric|log]otlp.NewRequestFrom[Traces|Metrics|Logs]` in favor of `p[trace|metric|log]otlp.NewExportRequestFrom[Traces|Metrics|Logs]` - `pdata`: Deprecate `p[trace|metric|log]otlp.NewClient` in favor of `p[trace|metric|log]otlp.NewGRPCClient` (#6350) - `exporter/logging`: Deprecate 'loglevel' in favor of 'verbosity' option (#5878) - `pdata`: Deprecate `New[JSON|Proto][Marshaler|Unmarshaler]` in favor of exposing the underlying structs (#6340) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Introduce partial success fields in ExportResponse. (#5815, #5816, #6365) - `obsreport`: Instrument `obsreport.Receiver` metrics with otel-go (#6222) - `service/telemetry`: Move logging and tracing initialization to service/telemetry (#5564) - `confmap`: Fail fast when a resolver has URIs with unsupported schemes. (#6274) - `service`: Use the same `prometheus.Registry` for the OpenCensus and OpenTelemetry Go prometheus exporters to act as a bridge for internal telemetry (#6297) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `pdata`: Because of wrong deprecation/rename in proto, services still send the fake 1000 proto id. See https://github.com/open-telemetry/opentelemetry-proto/issues/431 (#6342) - `confmap`: When a sub-config implements Unmarshaler, do not reinitialized it unless necessary. (#6392) - `pdata`: Enable enums as ints for otlp messages, switch to jsoniter for responses. (#6345) - `collector`: Fixed collector service not cleaning up if it failed during Start (#6352) ## v0.62.1 Beta - Fix support for new line in config URI location. (#6306) ## v0.62.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Delete deprecated `go.opentelemetry.io/collector/service/featuregate`. (#6178) - Delete deprecated `pmetric.OptionalType`. (#6178) - Delete deprecated `ptrace.Span[Link]?.TraceStateStruct`. (#6178) - Delete deprecated `pcommon.NewValueBytesEmpty`. (#6178) - Delete deprecated `pmetric.MetricDataType`. (#6178) - Delete deprecated `pmetric.Metric.DataType()`. (#6178) - Delete deprecated `pmetric.NumberDataPoint.[Set]?[Int|Double]Val()`. (#6178) - Delete deprecated `pmetric.Exemplar.[Set]?[Int|Double]Val()`. (#6178) - Delete deprecated `p[metric|log|trace]otlp.[Client|Server]`. (#6178) - Delete deprecated pdata Clone methods. (#6178) - Delete deprecated `pcommon.Value` getter/setter methods with `Val` suffix. (#6178) - Delete deprecated `StringVal` and `SetStringVal` methods. (#6178) - Delete deprecated `ValueTypeString` method. (#6178) - Change AggregationTemporality.String to simpler, easier to read. (#6117) - Update `pcommon.ValueType.String` output to string representation of corresponding type identifiers. The following values will be returned: (#6247) - ValueTypeEmpty.String() -> "Empty" - ValueTypeStr.String() -> "Str" - ValueTypeBool.String() -> "Bool" - ValueTypeInt.String() -> "Int" - ValueTypeDouble.String() -> "Double" - ValueTypeMap.String() -> "Map" - ValueTypeSlice.String() -> "Slice" - ValueTypeBytes.String() -> "Bytes" - Rename output of `[MetricType|NumberDataPointValueType|ExemplarValueType].String()` for zero values from `"None"` to `"Empty"` (#6270) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `p[metric|log|trace]otlp.RegisterServer` in favor of `p[metric|log|trace]otlp.RegisterGRPCServer` (#6182) - Deprecate `pcommon.Map.PutString` in favor of `pcommon.Map.PutStr` (#6210) - Deprecate `pcommon.NewValueString` in favor of `pcommon.NewValueStr` (#6209) - Deprecate `pmetric.MetricAggregationTemporality` enum type in favor of `pmetric.AggregationTemporality` (#6253) - Deprecate `confmap.Conf.UnmarshalExact` in favor of `confmap.Conf.Unmarshal(.., WithErrorUnused)` (#6231) - Deprecate `pmetric.[Default]?MetricDataPointFlags` favor of `pmetric.[Default]?DataPointFlags` (#6259) - Deprecate `ptrace.[New]?SpanStatus` favor of `ptrace.[New]?Status` (#6258) - Deprecate `pmetric.[New]?Buckets` in favor of `pmetric.[New]?ExponentialHistogramDataPointBuckets` (#6261) - Deprecate `plog.SeverityNumberUndefined` in favor of `plog.SeverityNumberUnspecified` (#6269) - Deprecate `pmetric.[New]?ValueAtQuantile[Slice]?` in favor of `pmetric.[New]?SummaryDataPointValueAtQuantile[Slice]?` (#6262) - Deprecate enum zero constants ending with `None` (#6270) - Deprecate `pmetric.MetricTypeNone` in favor of `pmetric.MetricTypeEmpty` - Deprecate `pmetric.NumberDataPointValueTypeNone` in favor of `pmetric.NumberDataPointValueTypeEmpty` - Deprecate `pmetric.ExemplarValueTypeNone` in favor of `pmetric.ExemplarValueTypeEmpty` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add config marshaler (#5566) - Add semantic conventions for specification v1.10-v1.13 (#6213) - `receiver/otlp`: Make logs related to gRCPC and HTTP server startup clearer (#6174) - Add prometheus metric prefix to Collector's own telemetry when using OpenTelemetry for internal telemetry (#6223) - `exporter/logging`: Apply consistent rendering of map values (#6244) - Add support in the confmap.Resolver to expand embedded config URIs inside configuration. (#6276) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fixed bug where `telemetryInitializer` is not cleaned up when `newService` errors (#6239) ## v0.61.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Change `ptrace.Span[Link]?.TraceState` signature to match `ptrace.Span[Link]?.TraceStateStruct` (#6085) - Delete deprecated `pmetric.NewMetricDataPointFlagsImmutable` func. (#6097) - Delete deprecated `pmetric.*DataPoint.[Set]FlagsImmutable()` funcs. (#6097) - Delete deprecated `config.Unmarshalable` interface. (#6084) - Delete deprecated `p[metric|log|trace].MarshalerSizer` interfaces (#6083) - Delete deprecated `pcommon.Map.Insert*` funcs. (#6088) - Delete deprecated `pcommon.Map.Upsert*` funcs. (#6088) - Delete deprecated `pcommon.Map.Update*` funcs. (#6088) - Change `pcommon.NewValueBytes` signature to match `pcommon.NewValueBytesEmpty`. (#6088) - Delete deprecated `pcommon.Empty[Trace|Span]ID`. (#6098) - Delete deprecated `pcommon.[Trace|Span]ID.Bytes()`. (#6098) - Delete deprecated `pcommon.New[Trace|Span]ID()`. (#6098) - Delete deprecated `pcommon.Value.SetBytesVal`. (#6088) - Delete deprecated `pmetric.Metric.SetDataType`. (#6095) - Delete deprecated `plog.LogRecord.[Set]FlagStruct` funcs. (#6100) - Delete deprecated `pcommon.ImmutableByteSlice` and `pcommon.NewImmutableByteSlice`. (#6107) - Delete deprecated `pcommon.ImmutableFloat64Slice` and `pcommon.NewImmutableFloat64Slice`. (#6107) - Delete deprecated `pcommon.ImmutableUInt64Slice` and `pcommon.NewImmutableUInt64Slice`. (#6107) - Delete deprecated `*DataPoint.SetBucketCounts` and `*DataPoint.SetExplicitBounds`. (#6108) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `go.opentelemetry.io/collector/service/featuregate` in favor of `go.opentelemetry.io/collector/featuregate`. (#6094) - Deprecate `pmetric.OptionalType`, unused enum type. (#6096) - Deprecate `ptrace.Span[Link]?.TraceStateStruct` in favor of `ptrace.Span[Link]?.TraceState` (#6085) - Deprecate `pcommon.NewValueBytesEmpty` in favor of `pcommon.NewValueBytes` that now has the same signature. (#6105) - Deprecate `pmetric.MetricDataType` and related constants in favor of `pmetric.MetricType`. (#6127) - Deprecate `pmetric.Metric.DataType()` in favor of `pmetric.Metric.Type()`. (#6127) - Deprecate `pmetric.NumberDataPoint.[Set]?[Int|Double]Val()` in favor of `pmetric.NumberDataPoint.[Set]?[Int|Double]Value()`. (#6134) - Deprecate `pmetric.Exemplar.[Set]?[Int|Double]Val()` in favor of `pmetric.Exemplar.[Set]?[Int|Double]Value()`. (#6134) - Deprecate `p[metric|log|trace]otlp.[Client|Server]` in favor of `p[metric|log|trace]otlp.GRPC[Client|Server]` (#6165) - Deprecate pdata Clone methods in favor of CopyTo for consistency with other pdata structs (#6164) - `pmetric.Metrics.Clone` is deprecated in favor of `pmetric.Metrics.CopyTo` - `ptrace.Traces.Clone` is deprecated in favor of `pmetric.Traces.CopyTo` - `plog.Logs.Clone` is deprecated in favor of `plogs.Logs.CopyTo` - Rename all `pcommon.Value` getter/setter methods by removing `Val` suffix. (#6092) - Old methods with `Val` suffix are deprecated. - `StringVal` and `SetStringVal` are deprecated in favor of `Str` and `SetStr` to avoid implementing `fmt.Stringer` interface. - Therefore, `ValueTypeString` is deprecated in favour of `ValueTypeStr` for consistency. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add AppendEmpty and EnsureCapacity method to primitive pdata slices (#6060) - Expose `AsRaw` and `FromRaw` `pcommon.Value` methods (#6090) - Convert `ValueTypeBytes` attributes in logging exporter (#6153) - service.name Resource attribute is added to Collector's own telemetry, defaults to the value of `BuildInfo.Command` and can be overridden in the config (#6152) - Updated how `telemetryInitializer` is created so it's instanced per Collector instance rather than global to the process (#6138) ## v0.60.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Replace deprecated `*DataPoint.Flags()` with `*DataPoint.[Set]FlagsImmutable()`. (#6017) - Remove deprecated `MetricDataPointFlagsStruct` struct and `NewMetricDataPointFlagsStruct` func. (#6017) - Replace deprecated `MetricDataPointFlags` with `MetricDataPointFlagsImmutable`. (#6017) - Replace deprecated `LogRecord.[Set]Flags()` with `LogRecord.[Set]FlagsStruct()`. (#6007) - Remove deprecated components helpers funcs (#6006) - `exporterhelper.New[Traces|Metrics|Logs]ExporterWithContext` - `processorhelper.New[Traces|Metrics|Logs]ProcessorWithCreateSettings` - `component.NewExtensionFactoryWithStabilityLevel` - Remove deprecated `pcommon.InvalidTraceID` and `pcommon.InvalidSpanID` funcs (#6008) - Remove deprecated `pcommon.Map` methods: `Update`, `Upsert`, `InsertNull` (#6019) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate pmetric.Metric.SetDataType, in favor of empty setters for each type. (#5979) - Deprecate `p[metric|log|trace].MarshalerSizer` in favor of `p[metric|log|trace].MarshalSizer`. (#6033) - Deprecate `pcommon.Map.Update+` in favor of `pcommon.Map.Get` + `pcommon.Value.Set+` (#6013) - Deprecate `pcommon.Empty[Trace|Span]ID` in favor of `pcommon.New[Trace|Span]IDEmpty` (#6008) - Deprecate `pcommon.[Trace|Span]ID.Bytes` in favor direct conversion. (#6008) - Deprecate `pcommon.New[Trace|Span]ID` in favor direct conversion. (#6008) - Deprecate `MetricDataPointFlagsImmutable` type. (#6017) - Deprecate `*DataPoint.[Set]FlagsImmutable()` funcs in favor of `*DataPoint.[Set]Flags()`. (#6017) - Deprecate `LogRecord.FlagsStruct()` and `LogRecord.SetFlagsStruct()` in favor of `LogRecord.Flags()` and `LogRecord.SetFlags()`. (#6007) - Deprecate `config.Unmarshallable` in favor of `confmap.Unmarshaler`. (#6031) - Primitive slice wrapper are now mutable (#5971): - `pcommon.ImmutableByteSlice` is deprecated in favor of `pcommon.ByteSlice` - `pcommon.ImmutableFloat64Slice` is deprecated in favor of `pcommon.Float64Slice` - `pcommon.ImmutableUInt64Slice` is deprecated in favor of `pcommon.UInt64Slice` - Temporarily deprecate `pcommon.NewValueBytes` that will be replaced with `pcommon.NewValueBytesEmpty` in 0.60.0 - Deprecate `pcommon.Map.UpsertBytes` in favor of `pcommon.Map.PutEmptyBytes` (#6064) - Deprecate `pcommon.Value.SetBytesVal` in favor of `pcommon.Value.SetEmptyBytesVal` - Deprecate `pcommon.New[Slice|Map]FromRaw` functions in favor of `New[Slice|Map]().FromRaw` (#6045) - Deprecate `pcommon.Map.Insert*` methods (#6051) - Deprecate `pcommon.Map.Upsert*` methods in favor of `pcommon.Map.Put*` (#6064) - Deprecate `ptrace.TraceState` in favor of `pcommon.TraceState`. (#6052) - `ptrace.Span.TraceState` in favor of `ptrace.Span.TraceStateStruct().AsRaw()` - `ptrace.Span.SetTraceState` in favor of `ptrace.Span.TraceStateStruct().FromRaw` - `ptrace.SpanLink.TraceState` in favor of `ptrace.SpanLink.TraceStateStruct().AsRaw()` - `ptrace.SpanLink.SetTraceState` in favor of `ptrace.SpanLink.TraceStateStruct().FromRaw` - `TraceStateStruct` is a temporary name that will be replaced back to `TraceState` in the next release. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add `skip-get-modules` builder flag to support isolated environment executions (#6009) - Skip unnecessary Go binary path validation when the builder is used with `skip-compilation` and `skip-get-modules` flags (#6026) - Make the otlpreceiver support to use jsoniter to unmarshal JSON payloads. (#6040) - Add mapstructure hook function for confmap.Unmarshaler interface (#6029) - Add CopyTo and MoveTo methods to primitive slices (#6044) - Add support to unmarshalls bytes into plogs.Logs with `jsoniter` in jsonUnmarshaler (#6021) - Instead of exiting, `ocb` now generates a default Collector when no build configuration is supplied (#5752) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - otlpjson: Correctly skip unknown JSON value types. (#6038) - Fix reading resource attributes from trace JSON. (#6023) ## v0.59.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated fields/funcs from `service` (#5907) - Remove `ConfigProviderSettings.Location` - Remove `ConfigProviderSettings.MapProviders` - Remove `ConfigProviderSettings.MapConverters` - Remove `featuregate.Registry.MustAppy` - Remove deprecated funcs from `pdata` module. (#5911) - Remove `pmetric.MetricDataPointFlags.String()` - Remove `pmetric.NumberDataPoint.FlagsStruct()` - Remove `pmetric.HistogramDataPoint.FlagsStruct()` - Remove `pmetric.ExponentialHistogramDataPoint.FlagsStruct()` - Remove `pmetric.SummaryDataPoint.FlagsStruct()` - Remove deprecated settings from `obsreport`, `ProcessorSettings.Level` and `ExporterSettings.Level` (#5918) - Replace `processorhelper.New[Traces|Metrics|Logs]Exporter` with `processorhelper.New[Traces|Metrics|Logs]ProcessorWithCreateSettings` definition (#5915) - Replace `exporterhelper.New[Traces|Metrics|Logs]Exporter` with `exporterhelper.New[Traces|Metrics|Logs]ExporterWithContext` definition (#5914) - Replace ``component.NewExtensionFactory`` with `component.NewExtensionFactoryWithStabilityLevel` definition (#5917) - Set TLS 1.2 as default for `min_version` for TLS configuration in case this property is not defined (affects servers). (#5956) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `processorhelper.New[Traces|Metrics|Logs]ProcessorWithCreateSettings` in favor of `processorhelper.New[Traces|Metrics|Logs]Exporter` (#5915) - Deprecates `LogRecord.Flags()` and `LogRecord.SetFlags()` in favor of `LogRecord.FlagsStruct()` and `LogRecord.SetFlagsStruct()`. (#5972) - Deprecate `exporterhelper.New[Traces|Metrics|Logs]ExporterWithContext` in favor of `exporterhelper.New[Traces|Metrics|Logs]Exporter` (#5914) - Deprecate `component.NewExtensionFactoryWithStabilityLevel` in favor of `component.NewExtensionFactory` (#5917) - Deprecate `plog.SeverityNumber[UPPERCASE]` constants (#5927) - Deprecate `pcommon.Map.InsertNull` method (#5955) - Deprecate FlagsStruct types (#5933): - `MetricDataPointFlagsStruct` -> `MetricDataPointFlags` - `NewMetricDataPointFlagsStruct` -> `NewMetricDataPointFlags` - Deprecate builder distribution flags, use configuration. (#5946) - Enforce naming conventions for Invalid[Trace|Span]ID: (#5969) - Deprecate funcs `pcommon.InvalidTraceID` and `pcommon.InvalidSpanID` in favor of vars `pcommon.EmptyTraceID` and `pcommon.EmptySpanID` - Deprecate `Update` and `Upsert` methods of `pcommon.Map` (#5975) - Deprecated the current MetricDataPointFlags API. The new API provides functions to check and set Flags. (#5999) - `NumberDataPoint.Flags` -> `NumberDataPoint.FlagsImmutable` - `HistogramDataPoint.Flags` -> `HistogramDataPoint.FlagsImmutable` - `ExponentialHistogramDataPoint.Flags` -> `ExponentialHistogramDataPoint.FlagsImmutable` - `SummaryDataPoint.Flags` -> `SummaryDataPoint.FlagsImmutable` - `MetricDataPointFlags` -> `MetricDataPointFlagsImmutable` - `NewMetricDataPointFlags` -> `MetricDataPointFlagsImmutable` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Added `MarshalerSizer` interface to `ptrace`, `plog`, and `pmetric` packages. `NewProtoMarshaler` now returns a `MarshalerSizer` (#5929) - Add support to unmarshalls bytes into pmetric.Metrics with `jsoniter` in jsonUnmarshaler(#5433) - Add httpprovider to allow loading config files stored in HTTP (#5810) - Added `service.telemetry.traces.propagators` configuration to set propagators for collector's internal spans. (#5572) - Remove unnecessary duplicate code and allocations for reading enums in JSON. (#5928) - Add "dist.build_tags" configuration option to support passing go build flags to builder. (#5659) - Add an AsRaw func on the flags, lots of places to encode these flags. (#5934) - Change pdata generated types to use type definition instead of aliases. (#5936) - Improves documentation, and makes code easier to read/understand. - Log `InstrumentationScope` attributes in `loggingexporter` (#5976) - Add `UpsertEmpty`, `UpsertEmptyMap` and `UpsertEmptySlice` methods to `pcommon.Map` (#5975) - Add `SetEmptyMapVal` and `SetEmptySliceVal` methods to `pcommon.Value` (#5975) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix reading scope attributes for trace JSON, remove duplicate code. (#5930) - otlpjson/trace: skip unknown fields instead of error. (#5931) - Fix bug in setting the correct collector state after a configuration change event. (#5830) - Fix json trace unmarshalling for numbers (#5924): - Accept both string and number for float64. - Accept both string and number for int32/uint32. - Read uint64 numbers without converting from int64. - Fix persistent storage client not closing when shutting down (#6003) ## v0.58.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove the InstrumentationLibrary to Scope translation (part of transition to OTLP 0.19). (#5819) - This has a side effect that when sending JSON encoded telemetry using OTLP proto <= 0.15.0, telemetry will be dropped. - Require the storage to be explicitly set for the (experimental) persistent queue (#5784) - Remove deprecated `confighttp.HTTPClientSettings.ToClientWithHost` (#5803) - Remove deprecated component stability helpers (#5802): - `component.WithTracesExporterAndStabilityLevel` - `component.WithMetricsExporterAndStabilityLevel` - `component.WithLogsExporterAndStabilityLevel` - `component.WithTracesReceiverAndStabilityLevel` - `component.WithMetricsReceiverAndStabilityLevel` - `component.WithLogsReceiverAndStabilityLevel` - `component.WithTracesProcessorAndStabilityLevel` - `component.WithMetricsProcessorAndStabilityLevel` - `component.WithLogsProcessorAndStabilityLevel` - ABI breaking change: `featuregate.Registry.Apply` returns error now. - Update minimum go version to 1.18 (#5795) - Remove deprecated `Flags` API from pdata (#5814) - Change `confmap.Provider` to return pointer to `Retrieved` (#5839) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate duplicate settings in service.ConfigProvider, embed ResolverSettings (#5843) - Deprecate `featuregate.Registry.MustApply` in favor of `featuregate.Registry.Apply`. (#5801) - Deprecate the `component.Factory.StabilityLevel(config.DataType)` in favor of Stability per component (#5762): - `component.ExporterFactory.TracesExporterStability` - `component.ExporterFactory.MetricsExporterStability` - `component.ExporterFactory.LogsExporterStability` - `component.ProcessorFactory.TracesProcessorStability` - `component.ProcessorFactory.MetricsProcessorStability` - `component.ProcessorFactory.LogsProcessorStability` - `component.ReceiverFactory.TracesReceiverStability` - `component.ReceiverFactory.MetricsReceiverStability` - `component.ReceiverFactory.LogsReceiverStability` - Deprecate `obsreport.ProcessorSettings.Level` and `obsreport.ExporterSettings.Level`, use MetricsLevel from CreateSettings (#5824) - Deprecate `processorhelper.New[Traces|Metrics|Logs]Processor` in favor of `processorhelper.New[Traces|Metrics|Logs]ProcessorWithCreateSettings` (#5833) - Deprecate MetricDataPointFlags.String(), no other pdata flags have this method (#5868) - Deprecates `FlagsStruct` in favor of `Flags` (#5842) - `FlagsStruct` -> `Flags` - Deprecate `exporterhelper.New[Traces|Metrics|Logs]Exporter` in favor of `exporterhelper.New[Traces|Metrics|Logs]ExporterWithContext` (#5834) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Enable persistent queue in the build by default (#5828) - Bump to opentelemetry-proto v0.19.0. (#5823) - Expose `Scope.Attributes` in pdata (#5826) - Remove unnecessary limitation on `pcommon.Value.Equal` that slices have only primitive values. (#5865) - Add support to handle 404, 405 http error code as permanent errors in OTLP exporter (#5827) - Enforce scheme name restrictions to all `confmap.Provider` implementations. (#5861) ## v0.57.2 Beta See the changelog for v0.57.0. ## v0.57.1 Beta This was a failed release. ## v0.57.0 Beta There isn't a valid core binary for this release. Use v0.57.2 instead. ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated funcs/types from service related to `Config` (#5755) - Change`confighttp.ToClient` to accept a `component.Host` (#5737) - Remove deprecated funcs from pdata related to mutable slices (#5754) - Change the following deprecated component functions to ensure a stability level is set: - `component.WithTracesExporter` - `component.WithMetricsExporter` - `component.WithLogsExporter` - `component.WithTracesReceiver` - `component.WithMetricsReceiver` - `component.WithLogsReceiver` - `component.WithTracesProcessor` - `component.WithMetricsProcessor` - `component.WithLogsProcessor` ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecated the current Flag API. The new API provides functions to check and set Flags (#5790) (#5602): - `NumberDataPoint.Flags` -> `NumberDataPoint.FlagsStruct` - `NumberDataPoint.SetFlags` -> `NumberDataPoint.FlagsStruct` - `HistogramDataPoint.Flags` -> `HistogramDataPoint.FlagsStruct` - `HistogramDataPoint.SetFlags` -> `HistogramDataPoint.FlagsStruct` - `ExponentialHistogramDataPoint.Flags` -> `ExponentialHistogramDataPoint.FlagsStruct` - `ExponentialHistogramDataPoint.SetFlags` -> `ExponentialHistogramDataPoint.FlagsStruct` - `SummaryDataPoint.Flags` -> `SummaryDataPoint.FlagsStruct` - `SummaryDataPoint.SetFlags` -> `SummaryDataPoint.FlagsStruct` - `MetricDataPointFlags` -> `MetricDataPointFlagsStruct` - `NewMetricDataPointFlags` -> `NewMetricDataPointFlagsStruct` - `MetricDataPointFlagsNone` -> `MetricDataPointFlagsStruct.NoRecordedValue` - `MetricDataPointFlagNoRecordedValue` -> `MetricDataPointFlagsStruct.NoRecordedValue` - `MetricDataPointFlag` - Deprecate the following component functions added to ensure a stability level is set: - `component.WithTracesExporterAndStabilityLevel` -> `component.WithTracesExporter` - `component.WithMetricsExporterAndStabilityLevel` -> `component.WithMetricsExporter` - `component.WithLogsExporterAndStabilityLevel` -> `component.WithLogsExporter` - `component.WithTracesReceiverAndStabilityLevel` -> `component.WithTracesReceiver` - `component.WithMetricsReceiverAndStabilityLevel` -> `component.WithMetricsReceiver` - `component.WithLogsReceiverAndStabilityLevel` -> `component.WithLogsReceiver` - `component.WithTracesProcessorAndStabilityLevel` -> `component.WithTracesProcessor` - `component.WithMetricsProcessorAndStabilityLevel` -> `component.WithMetricsProcessor` - `component.WithLogsProcessorAndStabilityLevel` -> `component.WithLogsProcessor` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Make the in-memory and persistent queues more consistent (#5764) - `ocb` now exits with an error if it fails to load the build configuration. (#5731) - Deprecate `HTTPClientSettings.ToClientWithHost` (#5737) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix bug in ocb where flags did not take precedence. (#5726) ## v0.56.0 Beta ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add `linux-ppc64le` architecture to cross build tests in CI (#5645) - `client`: perform case insensitive lookups in case the requested metadata value isn't found (#5646) - `loggingexporter`: Decouple `loglevel` field from level of logged messages (#5678) - Expose `pcommon.NewSliceFromRaw` function (#5679) - `loggingexporter`: create the exporter's logger from the service's logger (#5677) - Add `otelcol_exporter_queue_capacity` metrics show the collector's exporter queue capacity (#5475) - Add support to handle 402, 413, 414, 431 http error code as permanent errors in OTLP exporter (#5685) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix Collector panic when disabling telemetry metrics (#5642) - Fix Collector panic when featuregate value is empty (#5663) - Fix confighttp.compression panic due to nil request.Body. (#5628) ## v0.55.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated `config.ServiceTelemetry` (#5565) - Remove deprecated `config.ServiceTelemetryLogs` (#5565) - Remove deprecated `config.ServiceTelemetryMetrics` (#5565) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `service.ConfigServiceTelemetry`, `service.ConfigServiceTelemetryLogs`, and `service.ConfigServiceTelemetryMetrics` (#5565) - Deprecate the following component functions to ensure a stability level is set (#5580): - `component.WithTracesExporter` -> `component.WithTracesExporterAndStabilityLevel` - `component.WithMetricsExporter` -> `component.WithMetricsExporterAndStabilityLevel` - `component.WithLogsExporter` -> `component.WithLogsExporterAndStabilityLevel` - `component.WithTracesReceiver` -> `component.WithTracesReceiverAndStabilityLevel` - `component.WithMetricsReceiver` -> `component.WithMetricsReceiverAndStabilityLevel` - `component.WithLogsReceiver` -> `component.WithLogsReceiverAndStabilityLevel` - `component.WithTracesProcessor` -> `component.WithTracesProcessorAndStabilityLevel` - `component.WithMetricsProcessor` -> `component.WithMetricsProcessorAndStabilityLevel` - `component.WithLogsProcessor` -> `component.WithLogsProcessorAndStabilityLevel` - Deprecate `Registry.Apply` in `service.featuregate` (#5660) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Components stability levels are now logged. By default components which haven't defined their stability levels, or which are unmaintained, deprecated or in development will log a message. (#5580) - `exporter/logging`: Skip "bad file descriptor" sync errors (#5585) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix initialization of the OpenTelemetry MetricProvider. (#5571) - Set log level for `undefined` stability level to debug. (#5635) ## v0.54.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated `GetLogger`. (#5504) - Remove deprecated `configtest.LoadConfigMap` (#5505) - Remove deprecated `config.Map` (#5505) - Remove deprecated `config.MapProvider` (#5505) - Remove deprecated `config.MapConverter` (#5505) - Remove deprecated `config.Received` (#5505) - Remove deprecated `config.CloseFunc` (#5505) - Deprecated `pcommon.Value.NewValueBytes` is brought back taking `pcommon.ImmutableByteSlice` as an argument instead of `[]byte` (#5299) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Use immutable slices for primitive types slices to restrict mutations. (#5299) - `Value.NewValueMBytes` func is deprecated in favor of `Value.NewValueBytes` func that takes `ImmutableByteSlice` instead of `[]byte` - `Value.SetMBytesVal` func is deprecated in favor of `Value.SetBytesVal` func that takes `pcommon.ImmutableByteSlice` instead of []byte. - `Value.BytesVal` func is deprecated in favor of `Value.BytesVal` func that returns `pcommon.ImmutableByteSlice` instead of []byte. - `.SetMBucketCounts` funcs are deprecated in favor of `.SetBucketCounts` funcs that take `pcommon.ImmutableUInt64Slice` instead of []uint64. - `.MBucketCounts` funcs are deprecated in favor of `.BucketCounts` funcs that return `pcommon.ImmutableUInt64Slice` instead of []uint64. - `HistogramDataPoint.SetMExplicitBounds` func is deprecated in favor of `HistogramDataPoint.SetExplicitBounds` func that takes `pcommon.ImmutableFloat64Slice` instead of []float64. - `HistogramDataPoint.MExplicitBounds` func func is deprecated in favor of `HistogramDataPoint.ExplicitBounds` returns `pcommon.ImmutableFloat64Slice` instead of []float64. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Deprecate `HTTPClientSettings.ToClient` in favor of `HTTPClientSettings.ToClientWithHost` (#5584) - Use OpenCensus `metric` package for process metrics instead of `stats` package (#5486) - Update OTLP to v0.18.0 (#5530) - Log histogram min/max fields with `logging` exporter (#5520) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Update sum field of exponential histograms to make it optional (#5530) - Remove redundant extension shutdown call (#5532) - Refactor pipelines builder, fix some issues (#5512) - Unconfigured receivers are not identified, this was not a real problem in final binaries since the validation of the config catch this. - Allow configurations to contain "unused" receivers. Receivers that are configured but not used in any pipeline, this was possible already for exporters and processors. - Remove the enforcement/check that Receiver factories create the same instance for the same config. ## v0.53.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated `componenterror` package. (#5420) - Remove deprecated `config.MapConverterFunc`. (#5419) - Remove `AddCollectorVersionTag`, enabled for long time already. (#5471) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Move `config.Map` to its own package `confmap` which does not depend on any component concept (#5237) - `config.Map` -> `confmap.ConfMap` - `config.MapProvider` -> `confmap.Provider` - `config.Received` -> `confmap.Received` - `config.NewReceivedFromMap` -> `confmap.NewReceived` - `config.CloseFunc` -> `confmap.CloseFunc` - `config.ChangeEvent` -> `confmap.ChangeEvent` - `config.MapConverter` -> `confmap.Converter` - Package `envmapprovider` -> `envprovider` - Package `filemapprovider` -> `fileprovider` - Package `yamlmapprovider` -> `yamlprovider` - Package `expandmapconverter` -> `expandconverter` - Package `filemapprovider` -> `fileprovider` - Package `overwritepropertiesmapconverter` -> `overwritepropertiesconverter` - Deprecate `component.ExtensionDefaultConfigFunc` in favor of `component.ExtensionCreateDefaultConfigFunc` (#5451) - Deprecate `confmap.Received.AsMap` in favor of `confmap.Received.AsConf` (#5465) - Deprecate `confmap.Conf.Set`, not used anywhere for the moment (#5485) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Move `service.mapResolver` to `confmap.Resolver` (#5444) - Add `linux-arm` architecture to cross build tests in CI (#5472) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fixes the "service.version" label value for internal metrics, always was "latest" in core/contrib distros. (#5449). - Send correct batch stats when SendBatchMaxSize is set (#5385) - TLS `MinVersion` and `MaxVersion` defaults will be handled by `crypto/tls` (#5480) ## v0.52.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove `configunmarshaler.Unmarshaler` interface, per deprecation comment (#5348) - Remove deprecated pdata funcs/structs from v0.50.0 (#5345) - Remove deprecated pdata getters and setters of primitive slice values: `Value.BytesVal`, `Value.SetBytesVal`, `Value.UpdateBytes`, `Value.InsertBytes`, `Value.UpsertBytes`, `.BucketCounts`, `.SetBucketCounts`, `HistogramDataPoint.ExplicitBounds`, `HistogramDataPoint.SetExplicitBounds` (#5347) - Remove deprecated featuregate funcs/structs from v0.50.0 (#5346) - Remove access to deprecated members of the config.Retrieved struct (#5363) - Replace usage of `config.MapConverterFunc` with `config.MapConverter` (#5382) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `config.Config` and `config.Service`, use `service.Config*` (#4608) - Deprecate `componenterror` package, move everything to `component` (#5383) - `pcommon.Value.NewValueBytes` is deprecated in favor of `Value.NewValueMBytes` in preparation of migration to immutable slices (#5367) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Update OTLP to v0.17.0 (#5335) - Add optional min/max fields to histograms (#5399) - User-defined Resource attributes can be specified under `service.telemetry.resource` configuration key and will be included as metric labels for own telemetry. If `service.instance.id` is not specified it will be auto-generated. Previously `service.instance.id` was always auto-generated, so the default of the new behavior matches the old behavior. (#5402) ## v0.51.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated model module, everything is available in `pdata` and `semconv`. (#5281) - Old versions of the module are still available, but no new versions will be released. - Remove deprecated LogRecord.Name field. (#5202) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - In preparation of migration to immutable slices for primitive type items, the following methods are renamed (#5344) - `Value.BytesVal` func is deprecated in favor of `Value.MBytesVal`. - `Value.SetBytesVal` func is deprecated in favor of `Value.SetMBytesVal`. - `Value.UpdateBytes` func is deprecated in favor of `Value.UpdateMBytes`. - `Value.InsertBytes` func is deprecated in favor of `Value.InsertMBytes`. - `Value.UpsertBytes` func is deprecated in favor of `Value.UpsertMBytes`. - `.BucketCounts` funcs are deprecated in favor of `.MBucketCounts`. - `.SetBucketCounts` funcs are deprecated in favor of `.SetMBucketCounts`. - `HistogramDataPoint.ExplicitBounds` func is deprecated in favor of `HistogramDataPoint.MExplicitBounds`. - `HistogramDataPoint.SetExplicitBounds` func is deprecated in favor of `HistogramDataPoint.SetMExplicitBounds`. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `pdata`: Expose `pcommon.NewSliceFromRaw` and `pcommon.Slice.AsRaw` functions (#5311) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix Windows Event Logs ignoring user-specified logging options (#5298) ## v0.50.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove pdata deprecated funcs from 2 versions (v0.48.0) ago. (#5219) - Remove non pdata deprecated funcs/structs (#5220) - `pmetric.Exemplar.ValueType()` now returns new type `ExemplarValueType` (#5233) - Remove deprecated `Delete` pdata func in favor of `pdata.Remove` from (v0.47.0). (#5307) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `configunmarshaler` package, move it to internal (#5151) - Deprecate all API in `model/semconv`. The package is moved to a new `semconv` module (#5196) - Deprecate access to `config.Retrieved` fields, use the newly added funcs to interact with the internal fields (#5198) - Deprecate `potlp.Request.Set` (#5234) - `plogotlp.Request.SetLogs` func is deprecated in favor of `plogotlp.NewRequestFromLogs` - `pmetricotlp.Request.SetMetrics` func is deprecated in favor of `pmetricotlp.NewRequestFromMetrics` - `ptraceotlp.Request.SetTraces` func is deprecated in favor of `ptraceotlp.NewRequestFromTraces` - `pmetric.NumberDataPoint.ValueType()` now returns new type `NumberDataPointValueType` (#5233) - `pmetric.MetricValueType` is deprecated in favor of `NumberDataPointValueType` - `pmetric.MetricValueTypeNone` is deprecated in favor of `NumberDataPointValueTypeNone` - `pmetric.MetricValueTypeInt` is deprecated in favor of `NumberDataPointValueTypeInt` - `pmetric.MetricValueTypeDouble` is deprecated in favor of `NumberDataPointValueTypeDouble` - Deprecate `plog.LogRecord.SetName()` function (#5230) - Deprecate global `featuregate` funcs in favor of `GetRegistry` and a public `Registry` type (#5160) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add `jsoniter` Unmarshaller (#4817) - Extend config.Map.Unmarshal hook to check map key string to any TextUnmarshaler not only ComponentID (#5244) - Collector will no longer print error with stack trace when the collector is shutdown due to a context cancel. (#5258) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix translation from otlp.Request to pdata representation, changes to the returned pdata not all reflected to the otlp.Request (#5197) - `exporterhelper` now properly consumes any remaining items on stop (#5203) - `pdata`: Fix copying of `Value` with `ValueTypeBytes` type (#5267) - `pdata`: Fix copying of metric fields of primitive items slice type (#5271) ## v0.49.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated structs/funcs from previous versions (#5131) - Do not set TraceProvider to global otel (#5138) - Remove deprecated funcs from otlpgrpc (#5144) - Add Scheme to MapProvider interface (#5068) - Do not set MeterProvider to global otel (#5146) - Make `InstrumentationLibraryToScope` helper functions unexported (#5164) - Remove Log's "ShortName" from logging exporter output (#5172) - `exporter/otlp`: Retry RESOURCE_EXHAUSTED only if the server returns RetryInfo (#5147) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - All pdata related APIs from model (model/pdata, model/otlp and model/otlpgrpc) are deprecated in favor of packages in the new pdata module separated by telemetry signal type (#5168) - `model/pdata`, `model/otlp` -> `pdata/pcommon`, `pdata/plog`, `pdata/pmetric`, `pdata/ptrace` - `model/otlpgrpc` -> `pdata/plog/plogotlp`, `pdata/pmetric/pmetricotlp`, `pdata/ptrace/ptraceotlp` - Deprecate configmapprovider package, replace with mapconverter (#5167) - Deprecate `service.MustNewConfigProvider` and `service.MustNewDefaultConfigProvider`in favor of `service.NewConfigProvider` (#4936) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - OTLP HTTP receiver will use HTTP/2 over TLS if client supports it (#5109) - Add `ObservedTimestamp` field to `pdata.LogRecord` (#5171) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Setup the correct meter provider if telemetry.useOtelForInternalMetrics featuregate enabled (#5146) - Fix pdata.Value.asRaw() to correctly return elements of Slice and Map type (#5153) - Update pdata.Slice.asRaw() to return raw representation of Slice and Map elements (#5157) - The codepath through the OTLP receiver for gRPC was not translating the InstrumentationLibrary* to Scope* (#5189) ## v0.48.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated `consumerhelper` package (#5028) - Remove pdata `InternalRep` deprecated funcs (#5018) - Remove service/defaultcomponents deprecated package (#5019) - Remove deprecated UseOpenTelemetryForInternalMetrics (#5026) - Change outcome of `pdata.Value.MapVal()` and `pdata.Value.SliceVal()` functions misuse. In case of type mismatch, they now return an invalid zero-initialized instance instead of a detached collection (#5034) - OTLP JSON field changes following upgrade to OTLP v0.15.0: - "instrumentationLibraryLogs" is now "scopeLogs" - "instrumentationLibraryMetrics" is now "scopeMetrics" - "instrumentationLibrarySpans" is now "scopeSpans" - "instrumentationLibrary" is now "scope" - AsString for pdata.Value now returns the JSON-encoded string of floats. (#4934) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Move MapProvider to config, split providers in their own package (#5030) - API related to `pdata.AttributeValue` is deprecated in favor of `pdata.Value` (#4978) - `pdata.AttributeValue` struct is deprecated in favor of `pdata.Value` - `pdata.AttributeValueType` type is deprecated in favor of `pdata.ValueType` - `pdata.AttributeValueType...` constants are deprecated in favor of `pdata.ValueType...` - `pdata.NewAttributeValue...` funcs are deprecated in favor of `pdata.NewValue...` - Deprecate featureflags.FlagValue.SetSlice, unnecessary public (#5053) - Remove "Attribute" part from common pdata collections names (#5001) - Deprecate `pdata.AttributeMap` struct in favor of `pdata.Map` - Deprecate `pdata.NewAttributeMap` func in favor of `pdata.NewMap` - Deprecate `pdata.NewAttributeMapFromMap` func in favor of `pdata.NewMapFromRaw` - Deprecate `pdata.AttributeValueSlice` struct in favor of `pdata.Slice` - Deprecate `pdata.NewAttributeValueSlice` func in favor of `pdata.NewSlice` - Deprecate LogRecord.Name(), it was deprecated in the data model (#5054) - Rename `Array` type of `pdata.Value` to `Slice` (#5066) - Deprecate `pdata.AttributeValueTypeArray` type in favor of `pdata.ValueTypeSlice` - Deprecate `pdata.NewAttributeValueArray` func in favor of `pdata.NewValueSlice` - Deprecate global flag in `featuregates` (#5060) - Deprecate last funcs/structs in componenthelper (#5069) - Change structs in otlpgrpc to follow standard go encoding interfaces (#5062) - Deprecate `UnmarshalJSON[Traces|Metrics|Logs][Request|Response]` in favor of `UnmarshalJSON`. - Deprecate `[Traces|Metrics|Logs][Request|Response].Marshal` in favor of `MarshalProto`. - Deprecate `UnmarshalJSON[Traces|Metrics|Logs][Request|Response]` in favor of `UnmarshalProto`. - Deprecating following pdata methods/types following OTLP v0.15.0 upgrade (#5076): - InstrumentationLibrary is now InstrumentationScope - NewInstrumentationLibrary is now NewInstrumentationScope - InstrumentationLibraryLogsSlice is now ScopeLogsSlice - NewInstrumentationLibraryLogsSlice is now NewScopeLogsSlice - InstrumentationLibraryLogs is now ScopeLogs - NewInstrumentationLibraryLogs is now NewScopeLogs - InstrumentationLibraryMetricsSlice is now ScopeMetricsSlice - NewInstrumentationLibraryMetricsSlice is now NewScopeMetricsSlice - InstrumentationLibraryMetrics is now ScopeMetrics - NewInstrumentationLibraryMetrics is now NewScopeMetrics - InstrumentationLibrarySpansSlice is now ScopeSpansSlice - NewInstrumentationLibrarySpansSlice is now NewScopeSpansSlice - InstrumentationLibrarySpans is now ScopeSpans - NewInstrumentationLibrarySpans is now NewScopeSpans ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add semconv definitions for v1.9.0 (#5090) - Change outcome of `pdata.Metric.()` functions misuse. In case of type mismatch, they don't panic right away but return an invalid zero-initialized instance for consistency with other OneOf field accessors (#5035) - Update OTLP to v0.15.0 (#5064) - Adding support for transition from older versions of OTLP to OTLP v0.15.0 (#5085) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Add missing files for semconv definitions v1.7.0 and v1.8.0 (#5091) - The `featuregates` were not configured from the "--feature-gates" flag on windows service (#5060) - Fix Semantic Convention Schema URL definition for 1.5.0 and 1.6.1 versions (#5103) ## v0.47.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove `Type` funcs in pdata (#4933) - Remove all deprecated funcs/structs from v0.46.0 (#4995) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - pdata: deprecate funcs working with InternalRep (#4957) - Deprecate `pdata.AttributeMap.Delete` in favor of `pdata.AttributeMap.Remove` (#4914) - Deprecate consumerhelper, move helpers to consumer (#5006) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add `pdata.AttributeMap.RemoveIf`, which is a more performant way to remove multiple keys (#4914) - Add `pipeline` key with pipeline identifier to processor loggers (#4968) - Add a new yaml provider, allows providing yaml bytes (#4998) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Collector `Run` will now exit when a context cancels (#4954) - Add missing droppedAttributesCount to pdata generated resource (#4979) - Collector `Run` will now set state to `Closed` if startup fails (#4974) ## v0.46.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Change otel collector to enable open telemetry metrics through feature gate instead of a constant (#4912) - Remove support for legacy otlp/http port. (#4916) - Remove deprecated funcs in pdata (#4809) - Remove deprecated Retrieve funcs/calls (#4922) - Remove deprecated NewConfigProvider funcs (#4937) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecated funcs `config.DefaultConfig`, `confighttp.DefaultHTTPSettings`, `exporterhelper.DefaultTimeoutSettings`, `exporthelper.DefaultQueueSettings`, `exporterhelper.DefaultRetrySettings`, `testcomponents.DefaultFactories`, and `scraperhelper.DefaultScraperControllerSettings` in favour for their `NewDefault` method to adhere to contribution guidelines (#4865) - Deprecated funcs `componenthelper.StartFunc`, `componenthelper.ShutdownFunc` in favour of `component.StartFunc` and `component.ShutdownFunc` (#4803) - Move helpers from extensionhelper to component (#4805) - Deprecated `extensionhelper.CreateDefaultConfig` in favour of `component.ExtensionDefaultConfigFunc` - Deprecated `extensionhelper.CreateServiceExtension` in favour of `component.CreateExtensionFunc` - Deprecated `extensionhelper.NewFactory` in favour of `component.NewExtensionFactory` - Move helpers from processorhelper to component (#4889) - Deprecated `processorhelper.CreateDefaultConfig` in favour of `component.ProcessorDefaultConfigFunc` - Deprecated `processorhelper.WithTraces` in favour of `component.WithTracesProcessor` - Deprecated `processorhelper.WithMetrics` in favour of `component.WithMetricsProcessor` - Deprecated `processorhelper.WithLogs` in favour of `component.WithLogsProcessor` - Deprecated `processorhelper.NewFactory` in favour of `component.NewProcessorFactory` - Move helpers from exporterhelper to component (#4899) - Deprecated `exporterhelper.CreateDefaultConfig` in favour of `component.ExporterDefaultConfigFunc` - Deprecated `exporterhelper.WithTraces` in favour of `component.WithTracesExporter` - Deprecated `exporterhelper.WithMetrics` in favour of `component.WithMetricsExporter` - Deprecated `exporterhelper.WithLogs` in favour of `component.WithLogsExporter` - Deprecated `exporterhelper.NewFactory` in favour of `component.NewExporterFactory` - Move helpers from receiverhelper to component (#4891) - Deprecated `receiverhelper.CreateDefaultConfig` in favour of `component.ReceiverDefaultConfigFunc` - Deprecated `receiverhelper.WithTraces` in favour of `component.WithTracesReceiver` - Deprecated `receiverhelper.WithMetrics` in favour of `component.WithMetricsReceiver` - Deprecated `receiverhelper.WithLogs` in favour of `component.WithLogsReceiver` - Deprecated `receiverhelper.NewFactory` in favour of `component.NewReceiverFactory` ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add validation to check at least one endpoint is specified in otlphttpexporter's configuration (#4860) - Implement default client authenticators (#4837) ## ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Initialized logger with collector to avoid potential race condition panic on `Shutdown` (#4827) - In addition to traces, now logs and metrics processors will start the memory limiter. Added thread-safe logic so only the first processor can launch the `checkMemLimits` go-routine and the last processor that calls shutdown to terminate it; this is done per memory limiter instance. Added memory limiter factory to cache initiated object and be reused by similar config. This guarantees a single running `checkMemLimits` per config (#4886) - Resolved race condition in collector when calling `Shutdown` (#4878) ## v0.45.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated funcs in configtelemetry (#4808) - `otlphttp` and `otlp` exporters enable gzip compression by default (#4632) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `service/defaultcomponents` go package (#4622) - Deprecate `pdata.NumberDataPoint.Type()` and `pdata.Exemplar.Type()` in favor of `NumberDataPoint.ValueType()` and `Exemplar.ValueType()` (#4850) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Reject invalid queue size exporterhelper (#4799) - Transform configmapprovider.Retrieved interface to a struct (#4789) - Added feature gate summary to zpages extension (#4834) - Add support for reloading TLS certificates (#4737) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `confighttp`: Allow CORS requests with configured auth (#4869) ## v0.44.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Updated to OTLP 0.12.0. Deprecated traces and metrics messages that existed in 0.11.0 are no longer converted to the messages and fields that replaced the deprecated ones. Received deprecated messages and fields will be now ignored. In OTLP/JSON in the instrumentationLibraryLogs object the "logs" field is now named "logRecords" (#4724) - Deprecate `service.NewWindowsService`, add `service.NewSvcHandler` (#4783). ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `service.NewConfigProvider`, and a new version `service.MustNewConfigProvider` (#4734). ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Invalid requests now return an appropriate unsupported (`405`) or method not allowed (`415`) response (#4735) - `client.Info`: Add Host property for Metadata (#4736) ## v0.43.1 Beta ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - ExpandStringValues function support to map[string]interface{} (#4748) ## v0.43.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Change configmapprovider.Provider to accept a location for retrieve (#4657) - Change Properties Provider to be a Converter (#4666) - Define a type `WatcherFunc` for onChange func instead of func pointer (#4656) - Remove deprecated `configtest.LoadConfig` and `configtest.LoadConfigAndValidate` (#4659) - Move service.ConfigMapConverterFunc to config.MapConverterFunc (#4673) - Add context to config.MapConverterFunc (#4678) - Builder: the skip compilation should only be supplied as a CLI flag. Previously, it was possible to specify that in the YAML file, contrary to the original intention (#4645) - Builder: Remove deprecated config option module::core (#4693) - Remove deprecate flags --metrics-level and --metrics-addr (#4695) - Usages of `--metrics-level={VALUE}` can be replaced by `--set=service.telemetry.metrics.level={VALUE}`; - Usages of `--metrics-addr={VALUE}` can be replaced by `--set=service.telemetry.metrics.address={VALUE}`; - Updated confighttp `ToClient` to support passing telemetry settings for instrumenting otlphttp exporter(#4449) - Remove support to some arches and platforms from `ocb` (opentelemetry-collector-builder) (#4710) - Remove deprecated legacy path ("v1/trace") support for otlp http receiver (#4720) - Change the `service.NewDefaultConfigProvider` to accept a slice of location strings (#4727). ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `configtelemetry.Level.Set()` (#4700) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Ensure Windows path (e.g: C:) is recognized as a file path (#4726) - Fix structured logging issue for windows service (#4686) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Expose experimental API `configmapprovider.NewExpandConverter()` (#4672) - `service.NewConfigProvider`: copy slice argument, disallow changes from caller to the input slice (#4729) - `confighttp` and `configgrpc`: New config option `include_metadata` to persist request metadata/headers in `client.Info.Metadata` (experimental) (#4547) - Remove expand cases that cannot happen with config.Map (#4649) - Add `max_request_body_size` to confighttp.HTTPServerSettings (#4677) - Move `compression.go` into `confighttp.go` to internalize functions in `compression.go` file. (#4651) - create `configcompression` package to manage compression methods in `confighttp` and `configgrpc` - Add support for cgroupv2 memory limit (#4654) - Enable end users to provide multiple files for config location (#4727) ## v0.42.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove `configmapprovider.NewInMemory()` (#4507) - Disallow direct implementation of `configmapprovider.Retrieved` (#4577) - `configauth`: remove interceptor functions from the ServerAuthenticator interface (#4583) - Replace ConfigMapProvider and ConfigUnmarshaler in collector settings by one simpler ConfigProvider (#4590) - Remove deprecated consumererror.Combine (#4597) - Remove `configmapprovider.NewDefault`, `configmapprovider.NewExpand`, `configmapprovider.NewMerge` (#4600) - The merge functionality is now embedded into `service.NewConfigProvider` (#4637). - Move `configtest.LoadConfig` and `configtest.LoadConfigAndValidate` to `servicetest` (#4606) - Builder: Remove deprecated `include-core` flag (#4616) - Collector telemetry level must now be accessed through an atomic function. (#4549) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `confighttp`: add client-side compression support. (#4441) - Each exporter should remove `compression` field if they have and should use `confighttp.HTTPClientSettings` - Allow more zap logger configs: `disable_caller`, `disable_stacktrace`, `output_paths`, `error_output_paths`, `initial_fields` (#1048) - Allow the custom zap logger encoding (#4532) - Collector self-metrics may now be configured through the configuration file. (#4069) - CLI flags for configuring self-metrics are deprecated and will be removed in a future release. - `service.telemetry.metrics.level` and `service.telemetry.metrics.address` should be used to configure collector self-metrics. - `configauth`: add helpers to create new server authenticators. (#4558) - Refactor `configgrpc` for compression methods (#4624) - Add an option to allow `config.Map` conversion in the `service.ConfigProvider` (#4634) - Added support to expose gRPC framework's logs as part of collector logs (#4501) - Builder: Enable unmarshal exact to help finding hard to find typos #4644 ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix merge config map provider to close the watchers (#4570) - Fix expand map provider to call close on the base provider (#4571) - Fix correct the value of `otelcol_exporter_send_failed_requests` (#4629) - `otlp` receiver: Fix legacy port cfg value override and HTTP server starting bug (#4631) ## v0.41.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove reference to `defaultcomponents` in core and deprecate `include_core` flag (#4087) - Remove `config.NewConfigMapFrom[File|Buffer]`, add testonly version (#4502) - `configtls`: TLS 1.2 is the new default minimum version (#4503) - `confighttp`: `ToServer` now accepts a `component.Host`, in line with gRPC's counterpart (#4514) - CORS configuration for OTLP/HTTP receivers has been moved into a `cors:` block, instead of individual `cors_allowed_origins` and `cors_allowed_headers` settings (#4492) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - OTLP/HTTP receivers now support setting the `Access-Control-Max-Age` header for CORS caching. (#4492) - `client.Info` pre-populated for all receivers using common helpers like `confighttp` and `configgrpc` (#4423) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix handling of corrupted records by persistent buffer (experimental) (#4475) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Extending the contribution guide to help clarify what is acceptable defaults and recommendations. ## v0.40.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Package `client` refactored (#4416) and auth data included in it (#4422). Final PR to be merged in the next release (#4423) - Remove `pdata.AttributeMap.InitFromMap` (#4429) - Updated configgrpc `ToDialOptions` to support passing providers to instrumentation library (#4451) - Make state information propagation non-blocking on the collector (#4460) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add semconv 1.7.0 and 1.8.0 (#4452) - Added `feature-gates` CLI flag for controlling feature gate state. (#4368) - Add a default user-agent header to the OTLP/gRPC and OTLP/HTTP exporters containing collector build information (#3970) ## v0.39.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated config (already no-op) `ballast_size_mib` in memorylimiterprocessor (#4365) - Remove `config.Receivers`, `config.Exporters`, `config.Processors`, and `config.Extensions`. Use map directly (#4344) - Remove `component.BaseProcessorFactory`, use `processorhelper.NewFactory` instead (#4175) - Force usage of `exporterhelper.NewFactory` to implement `component.ExporterFactory` (#4338) - Force usage of `receiverhelper.NewFactory` to implement `component.ReceiverFactory` (#4338) - Force usage of `extensionhelper.NewFactory` to implement `component.ExtensionFactory` (#4338) - Move `service/parserprovider` package to `config/configmapprovider` (#4206) - Rename `MapProvider` interface to `Provider` - Remove `MapProvider` from helper names - Renamed slice-valued `pdata` types and functions for consistency. (#4325) - Rename `pdata.AnyValueArray` to `pdata.AttributeValueSlice` - Rename `ArrayVal()` to `SliceVal()` - Rename `SetArrayVal()` to `SetSliceVal()` - Remove `config.Pipeline.Name` (#4326) - Rename `config.Mapprovider` as `configmapprovider.Provider` (#4337) - Move `config.WatchableRetrieved` and `config.Retrieved` interfaces to `config/configmapprovider` package (#4337) - Remove `config.Pipeline.InputDataType` (#4343) - otlpexporter: Do not retry on PermissionDenied and Unauthenticated (#4349) - Enable configuring collector metrics through service config file. (#4069) - New `service::telemetry::metrics` structure added to configuration - Existing metrics configuration CLI flags are deprecated and to be removed in the future. - `--metrics-prefix` is no longer operative; the prefix is determined by the value of `service.buildInfo.Command`. - `--add-instance-id` is no longer operative; an instance ID will always be added. - Remove deprecated funcs `consumererror.As[Traces|Metrics|Logs]` (#4364) - Remove support to expand env variables in default configs (#4366) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Supports more compression methods(`snappy` and `zstd`) for configgrpc, in addition to current `gzip` (#4088) - Moved the OpenTelemetry Collector Builder to core (#4307) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix AggregationTemporality and IsMonotonic when metric descriptors are split in the batch processor (#4389) ## v0.38.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Removed `configauth.HTTPClientAuthenticator` and `configauth.GRPCClientAuthenticator` in favor of `configauth.ClientAuthenticator`. (#4255) - Rename `parserprovider.MapProvider` as `config.MapProvider`. (#4178) - Rename `parserprovider.Watchable` as `config.WatchableMapProvider`. (#4178) - Remove deprecated no-op flags to setup Collector's logging "--log-level", "--log-profile", "--log-format". (#4213) - Move `cmd/pdatagen` as internal package `model/internal/cmd/pdatagen`. (#4243) - Use directly the ComponentID in configauth. (#4238) - Refactor configauth, getters use the map instead of iteration. (#4234) - Change scraperhelper to follow the recommended append model for pdata. (#4202) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Update proto to 0.11.0. (#4209) - Change pdata to use the newly added [Traces|Metrics|Logs]Data. (#4214) - Add ExponentialHistogram field to pdata. (#4219) - Make sure otlphttp exporter tests include TraceID and SpanID. (#4268) - Use multimod tool in release process. (#4229) - Change queue metrics to use opencensus metrics instead of stats, close to otel-go. (#4220) - Make receiver data delivery guarantees explicit (#4262) - Simplify unmarshal logic by adding more supported hooks. (#4237) - Add unmarshaler for otlpgrpc.[*]Request and otlpgrpc.[*]Response (#4215) ## v0.37.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Move `configcheck.ValidateConfigFromFactories` as internal function in service package (#3876) - Rename `configparser.Parser` as `config.Map` (#4075) - Rename `component.DefaultBuildInfo()` to `component.NewDefaultBuildInfo()` (#4129) - Rename `consumererror.Permanent` to `consumererror.NewPermanent` (#4118) - Rename `config.NewID` to `config.NewComponentID` and `config.NewIDFromString` to `config.NewComponentIDFromString` (#4137) - Rename `config.NewIDWithName` to `config.NewComponentIDWithName` (#4151) - Move `extension/storage` to `extension/experimental/storage` (#4082) - Rename `obsreporttest.SetupRecordedMetricsTest()` to `obsreporttest.SetupTelemetry()` and `obsreporttest.TestTelemetrySettings` to `obsreporttest.TestTelemetry` (#4157) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add Gen dependabot into CI (#4083) - Update OTLP to v0.10.0 (#4045). - Add Flags field to NumberDataPoint, HistogramDataPoint, SummaryDataPoint (#4081). - Add feature gate library (#4108) - Add version to the internal telemetry metrics (#4140) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix panic when not using `service.NewCommand` (#4139) ## v0.36.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated pdata.AttributeMapToMap (#3994) - Move ValidateConfig from configcheck to configtest (#3956) - Remove `mem-ballast-size-mib`, already deprecated and no-op (#4005) - Remove `semconv.AttributeMessageType` (#4020) - Remove `semconv.AttributeHTTPStatusText` (#4015) - Remove squash on `configtls.TLSClientSetting` and move TLS client configs under `tls` (#4063) - Rename TLS server config `*configtls.TLSServerSetting` from `tls_settings` to `tls` (#4063) - Split `service.Collector` from the `cobra.Command` (#4074) - Rename `memorylimiter` to `memorylimiterprocessor` (#4064) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Create new semconv package for v1.6.1 (#3948) - Add AttributeValueBytes support to AsString (#4002) - Add AttributeValueTypeBytes support to AttributeMap.AsRaw (#4003) - Add MeterProvider to TelemetrySettings (#4031) - Add configuration to setup collector logs via config file. (#4009) ## v0.35.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove the legacy gRPC port(`55680`) support in OTLP receiver (#3966) - Rename configparser.Parser to configparser.ConfigMap (#3964) - Remove obsreport.ScraperContext, embed into StartMetricsOp (#3969) - Remove dependency on deprecated go.opentelemetry.io/otel/oteltest (#3979) - Remove deprecated pdata.AttributeValueToString (#3953) - Remove deprecated pdata.TimestampFromTime. Closes: #3925 (#3935) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add TelemetryCreateSettings (#3984) - Only initialize collector telemetry once (#3918) - Add trace context info to LogRecord log (#3959) - Add new view for AWS ECS health check extension. (#3776) ## v0.34.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Artifacts are no longer published in this repository, check [here](https://github.com/open-telemetry/opentelemetry-collector-releases) (#3941) - Remove deprecated `tracetranslator.AttributeValueToString` and `tracetranslator.AttributeMapToMap` (#3873) - Change semantic conventions for status (code, msg) as per specifications (#3872) - Move `fileexporter` to contrib (#3474) - Move `jaegerexporter` to contrib (#3474) - Move `kafkaexporter` to contrib (#3474) - Move `opencensusexporter` to contrib (#3474) - Move `prometheusexporter` to contrib (#3474) - Move `prometheusremotewriteexporter` to contrib (#3474) - Move `zipkinexporter` to contrib (#3474) - Move `attributeprocessor` to contrib (#3474) - Move `filterprocessor` to contrib (#3474) - Move `probabilisticsamplerprocessor` to contrib (#3474) - Move `resourceprocessor` to contrib (#3474) - Move `spanprocessor` to contrib (#3474) - Move `hostmetricsreceiver` to contrib (#3474) - Move `jaegerreceiver` to contrib (#3474) - Move `kafkareceiver` to contrib (#3474) - Move `opencensusreceiver` to contrib (#3474) - Move `prometheusreceiver` to contrib (#3474) - Move `zipkinreceiver` to contrib (#3474) - Move `bearertokenauthextension` to contrib (#3474) - Move `healthcheckextension` to contrib (#3474) - Move `oidcauthextension` to contrib (#3474) - Move `pprofextension` to contrib (#3474) - Move `translator/internaldata` to contrib (#3474) - Move `translator/trace/jaeger` to contrib (#3474) - Move `translator/trace/zipkin` to contrib (#3474) - Move `testbed` to contrib (#3474) - Move `exporter/exporterhelper/resource_to_telemetry` to contrib (#3474) - Move `processor/processorhelper/attraction` to contrib (#3474) - Move `translator/conventions` to `model/semconv` (#3901) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Add `pdata.NewTimestampFromTime`, deprecate `pdata.TimestampFromTime` (#3868) - Add `pdata.NewAttributeMapFromMap`, deprecate `pdata.AttributeMap.InitFromMap` (#3936) ## v0.33.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename `configloader` interface to `configunmarshaler` (#3774) - Remove `LabelsMap` from all the metrics points (#3706) - Update generated K8S attribute labels to fix capitalization (#3823) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Collector has now full support for metrics proto v0.9.0. ## v0.32.0 Beta This release is marked as "bad" since the metrics pipelines will produce bad data. - See https://github.com/open-telemetry/opentelemetry-collector/issues/3824 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename `CustomUnmarshable` interface to `Unmarshallable` (#3774) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Change default OTLP/HTTP port number from 55681 to 4318 (#3743) - Update OTLP proto to v0.9.0 (#3740) - Remove `SetValue`/`Value` func for `NumberDataPoint`/`Exemplar` (#3730) - Remove `IntGauge`/`IntSum`from pdata (#3731) - Remove `IntDataPoint` from pdata (#3735) - Add support for `Bytes` attribute type (#3756) - Add `SchemaUrl` field (#3759) - Add `Attributes` to `NumberDataPoint`, `HistogramDataPoint`, `SummaryDataPoint` (#3761) - `conventions` translator: Replace with conventions generated from spec v1.5.0 (#3494) - `prometheus` receiver: Add `ToMetricPdata` method (#3695) - Make configsource `Watchable` an optional interface (#3792) - `obsreport` exporter: Change to accept `ExporterCreateSettings` (#3789) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `configgrpc`: Use chained interceptors in the gRPC server (#3744) - `prometheus` receiver: Use actual interval startTimeMs for cumulative types (#3694) - `jaeger` translator: Fix bug that could generate empty proto spans (#3808) ## v0.31.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove Resize() from pdata slice APIs (#3675) - Remove the ballast allocation when `mem-ballast-size-mib` is set in command line (#3626) - Use `ballast extension` to set memory ballast instead. - Rename `DoubleDataPoint` to `NumberDataPoint` (#3633) - Remove `IntHistogram` (#3676) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Update to OTLP 0.8.0: - Translate `IntHistogram` to `Histogram` in `otlp_wrappers` (#3676) - Translate `IntGauge` to `Gauge` in `otlp_wrappers` (#3619) - Translate `IntSum` to `Sum` in `otlp_wrappers` (#3621) - Update `NumberDataPoint` to support `DoubleVal` and `IntVal` (#3689) - Update `Exemplar` to use `oneOfPrimitiveValue` (#3699) - Remove `IntExemplar` and `IntExemplarSlice` from `pdata` (#3705) - Mark `IntGauge`/`IntSum`/`IntDataPoint` as deprecated (#3707) - Remove `IntGauge`/`IntSum` from `batchprocessor` (#3718) - `prometheusremotewrite` exporter: Convert to new Number metrics (#3714) - `prometheus` receiver: Convert to new Number metrics (#3716) - `prometheus` exporter: Convert to new Number metrics (#3709) - `hostmetrics` receiver: Convert to new Number metrics (#3710) - `opencensus`: Convert to new Number metrics (#3708) - `scraperhelper` receiver: Convert to new Number metrics (#3717) - `testbed`: Convert to new Number metrics (#3719) - `exporterhelper`: Convert `resourcetolabel` to new Number metrics (#3723) - `configauth`: Prepare auth API to return a context (#3618) - `pdata`: - Implement `Equal()` for map-valued `AttributeValues` (#3612) - Add `[Type]Slice.Sort(func)` to sort slices (#3671) - `memorylimiter`: - Add validation on ballast size between `memorylimiter` and `ballastextension` (#3532) - Access Ballast extension via `Host.GetExtensions` (#3634) - `prometheusremotewrite` exporter: Add a WAL implementation without wiring up (#3597) - `prometheus` receiver: Add `metricGroup.toDistributionPoint` pdata conversion (#3667) - Use `ComponentID` as identifier instead of config (#3696) - `zpages`: Move config validation from factory to `Validate` (#3697) - Enable `tracez` z-pages from otel-go, disable opencensus (#3698) - Convert temporality and monotonicity for deprecated sums (#3729) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otlpexporter`: Allow endpoint to be configured with a scheme of `http` or `https` (#3575) - Handle errors when reloading the collector service (#3615) - Do not report fatal error when `cmux.ErrServerClosed` (#3703) - Fix bool attribute equality in `pdata` (#3688) ## v0.30.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename `pdata.DoubleSum` to `pdata.Sum` (#3583) - Rename `pdata.DoubleGauge` to `pdata.Gauge` (#3599) - Migrated `pdata` to a dedicated package (#3483) - Change Marshaler/Unmarshaler to be consistent with other interfaces (#3502) - Remove consumer/simple package (#3438) - Remove unnecessary interfaces from pdata (#3506) - zipkinv1 implement directly Unmarshaler interface (#3504) - zipkinv2 implement directly Marshaler/Unmarshaler interface (#3505) - Change exporterhelper to accept ExporterCreateSettings instead of just logger (#3569) - Use Func pattern in processorhelper, consistent with others (#3570) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate Resize() from pdata slice APIs (#3573) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Update OTLP to v0.8.0 (#3572) - Migrate from OpenCensus to OpenTelemetry for internal tracing (#3567) - Move internal/pdatagrpc to model/otlpgrpc (#3507) - Move internal/otlp to model/otlp (#3508) - Create http Server via Config, enable cors and decompression (#3513) - Allow users to set min and max TLS versions (#3591) - Support setting ballast size in percentage of total Mem in ballast extension (#3456) - Publish go.opentelemetry.io/collector/model as a separate module (#3530) - Pass a TracerProvider via construct settings to all the components (#3592) - Make graceful shutdown optional (#3577) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `scraperhelper`: Include the scraper name in log messages (#3487) - `scraperhelper`: fix case when returned pdata is empty (#3520) - Record the correct number of points not metrics in Kafka receiver (#3553) - Validate the Prometheus configuration (#3589) ## v0.29.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename `service.Application` to `service.Collector` (#3268) - Provide case sensitivity in config yaml mappings by using Koanf instead of Viper (#3337) - Move zipkin constants to an internal package (#3431) - Disallow renaming metrics using metric relabel configs (#3410) - Move cgroup and iruntime utils from memory_limiter to internal folder (#3448) - Move model pdata interfaces to pdata, expose them publicly (#3455) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Change obsreport helpers for scraper to use the same pattern as Processor/Exporter (#3327) - Convert `otlptext` to implement Marshaler interfaces (#3366) - Add encoder/decoder and marshaler/unmarshaler for OTLP protobuf (#3401) - Use the new marshaler/unmarshaler in `kafka` exporter (#3403) - Convert `zipkinv2` to to/from translator interfaces (#3409) - `zipkinv1`: Move to translator and encoders interfaces (#3419) - Use the new marshaler/unmarshaler in `kafka` receiver #3402 - Change `oltp` receiver to use the new unmarshaler, avoid grpc-gateway dependency (#3406) - Use the new Marshaler in the `otlphttp` exporter (#3433) - Add grpc response struct for all signals instead of returning interface in `otlp` receiver/exporter (#3437) - `zipkinv2`: Add encoders, decoders, marshalers (#3426) - `scrapererror` receiver: Return concrete error type (#3360) - `kafka` receiver: Add metrics support (#3452) - `prometheus` receiver: - Add store to track stale metrics (#3414) - Add `up` and `scrape_xxxx` internal metrics (#3116) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `prometheus` receiver: - Reject datapoints with duplicate label keys (#3408) - Scrapers are not stopped when receiver is shutdown (#3450) - `prometheusremotewrite` exporter: Adjust default retry settings (#3416) - `hostmetrics` receiver: Fix missing startTimestamp for `processes` scraper (#3461) ## v0.28.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove unused logstest package (#3222) - Introduce `AppSettings` instead of `Parameters` (#3163) - Remove unused testutil.TempSocketName (#3291) - Move BigEndian helper functions in `tracetranslator` to an internal package.(#3298) - Rename `configtest.LoadConfigFile` to `configtest.LoadConfigAndValidate` (#3306) - Replace `ExtensionCreateParams` with `ExtensionCreateSettings` (#3294) - Replace `ProcessorCreateParams` with `ProcessorCreateSettings`. (#3181) - Replace `ExporterCreateParams` with `ExporterCreateSettings` (#3164) - Replace `ReceiverCreateParams` with `ReceiverCreateSettings`. (#3167) - Change `batchprocessor` logic to limit data points rather than metrics (#3141) - Rename `PrwExporter` to `PRWExporter` and `NewPrwExporter` to `NewPRWExporter` (#3246) - Avoid exposing OpenCensus reference in public APIs (#3253) - Move `config.Parser` to `configparser.Parser` (#3304) - Remove deprecated funcs inside the obsreceiver (#3314) - Remove `obsreport.GRPCServerWithObservabilityEnabled`, enable observability in config (#3315) - Remove `obsreport.ProcessorMetricViews`, use `BuildProcessorCustomMetricName` where needed (#3316) - Remove "Receive" from `obsreport.Receiver` funcs (#3326) - Remove "Export" from `obsreport.Exporter` funcs (#3333) - Hide unnecessary public struct `obsreport.StartReceiveOptions` (#3353) - Avoid exposing internal implementation public in OC/OTEL receivers (#3355) - Updated configgrpc `ToDialOptions` and confighttp `ToClient` apis to take extensions configuration map (#3340) - Remove `GenerateSequentialTraceID` and `GenerateSequentialSpanIDin` functions in testbed (#3390) - Change "grpc" to "GRPC" in configauth function/type names (#3285) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add `doc.go` files to the consumer package and its subpackages (#3270) - Improve documentation of consumer package and subpackages (#3269, #3361) - Automate triggering of doc-update on release (#3234) - Enable Dependabot for Github Actions (#3312) - Remove the proto dependency in `goldendataset` for traces (#3322) - Add telemetry for dropped data due to exporter sending queue overflow (#3328) - Add initial implementation of `pdatagrpc` (#3231) - Change receiver obsreport helpers pattern to match the Processor/Exporter (#3227) - Add model translation and encoding interfaces (#3200) - Add otlpjson as a serializer implementation (#3238) - `prometheus` receiver: - Add `createNodeAndResourcePdata` for Prometheus->OTLP pdata (#3139) - Direct metricfamily Prometheus->OTLP (#3145) - Add `componenttest.NewNop*CreateSettings` to simplify tests (#3375) - Add support for markdown generation (#3100) - Refactor components for the Client Authentication Extensions (#3287) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Use dedicated `zapcore.Core` for Windows service (#3147) - Hook up start and shutdown functions in fileexporter (#3260) - Fix oc to pdata translation for sum non-monotonic cumulative (#3272) - Fix `timeseriesSignature` in prometheus receiver (#3310) ## v0.27.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Change `Marshal` signatures in kafkaexporter's Marshalers to directly convert pdata to `sarama.ProducerMessage` (#3162) - Remove `tracetranslator.DetermineValueType`, only used internally by Zipkin (#3114) - Remove OpenCensus conventions, should not be used (#3113) - Remove Zipkin specific translation constants, move to internal (#3112) - Remove `tracetranslator.TagHTTPStatusCode`, use `conventions.AttributeHTTPStatusCode` (#3111) - Remove OpenCensus status constants and transformation (#3110) - Remove `tracetranslator.AttributeArrayToSlice`, not used in core or contrib (#3109) - Remove `internaldata.MetricsData`, same APIs as for traces (#3156) - Rename `config.IDFromString` to `NewIDFromString`, remove `MustIDFromString` (#3177) - Move consumerfanout package to internal (#3207) - Canonicalize enum names in pdata. Fix usage of uppercase names (#3208) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Use `config.ComponentID` for obsreport receiver/scraper (#3098) - Add initial implementation of the consumerhelper (#3146) - Add Collector version to Prometheus Remote Write Exporter user-agent header (#3094) - Refactor processorhelper to use consumerhelper, split by signal type (#3180) - Use consumerhelper for exporterhelper, add WithCapabilities (#3186) - Set capabilities for all core exporters, remove unnecessary funcs (#3190) - Add an internal sharedcomponent to be shared by receivers with shared resources (#3198) - Allow users to configure the Prometheus remote write queue (#3046) - Mark internaldata traces translation as deprecated for external usage (#3176) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix Prometheus receiver metric start time and reset determination logic. (#3047) - The receiver will no longer drop the first sample for `counter`, `summary`, and `histogram` metrics. - The Prometheus remote write exporter will no longer force `counter` metrics to have a `_total` suffix. (#2993) - Remove locking from jaeger receiver start and stop processes (#3070) - Fix batch processor metrics reorder, improve performance (#3034) - Fix batch processor traces reorder, improve performance (#3107) - Fix batch processor logs reorder, improve performance (#3125) - Avoid one unnecessary allocation in grpc OTLP exporter (#3122) - `batch` processor: Validate that batch config max size is greater than send size (#3126) - Add capabilities to consumer, remove from processor (#2770) - Remove internal protos usage in Prometheusremotewrite exporter (#3184) - `prometheus` receiver: Honor Prometheus external labels (#3127) - Validate that remote write queue settings are not negative (#3213) ## v0.26.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Change `With*Unmarshallers` signatures in Kafka exporter/receiver (#2973) - Rename `marshall` to `marshal` in all the occurrences (#2977) - Remove `componenterror.ErrAlreadyStarted` and `componenterror.ErrAlreadyStopped`, components should not protect against this, Service will start/stop once. - Rename `ApplicationStartInfo` to `BuildInfo` - Rename `ApplicationStartInfo.ExeName` to `BuildInfo.Command` - Rename `ApplicationStartInfo.LongName` to `BuildInfo.Description` ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Add AppendEmpty and deprecate Append for slices (#2970) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `kafka` exporter: Add logs support (#2943) - Update mdatagen to create factories of init instead of new (#2978) - `zipkin` receiver: Reduce the judgment of zipkin v1 version (#2990) - Custom authenticator logic to accept a `component.Host` which will extract the authenticator to use based on a new authenticator name property (#2767) - `prometheusremotewrite` exporter: Add `resource_to_telemetry_conversion` config option (#3031) - `logging` exporter: Extract OTLP text logging (#3082) - Format timestamps as strings instead of int in otlptext output (#3088) - Add darwin arm64 build (#3090) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix Jaeger receiver to honor TLS Settings (#2866) - `zipkin` translator: Handle missing starttime case for zipkin json v2 format spans (#2506) - `prometheus` exporter: Fix OTEL resource label drops (#2899) - `prometheusremotewrite` exporter: - Enable the queue internally (#2974) - Don't drop instance and job labels (#2979) - `jaeger` receiver: Wait for server goroutines exit on shutdown (#2985) - `logging` exporter: Ignore invalid handle on close (#2994) - Fix service zpages (#2996) - `batch` processor: Fix to avoid reordering and send max size (#3029) ## v0.25.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename ForEach (in pdata) with Range to be consistent with sync.Map (#2931) - Rename `componenthelper.Start` to `componenthelper.StartFunc` (#2880) - Rename `componenthelper.Stop` to `componenthelper.StopFunc` (#2880) - Remove `exporterhelper.WithCustomUnmarshaler`, `processorhelper.WithCustomUnmarshaler`, `receiverhelper.WithCustomUnmarshaler`, `extensionhelper.WithCustomUnmarshaler`, implement `config.CustomUnmarshaler` interface instead (#2867) - Remove `component.CustomUnmarshaler` implement `config.CustomUnmarshaler` interface instead (#2867) - Remove `testutil.HostPortFromAddr`, users can write their own parsing helper (#2919) - Remove `configparser.DecodeTypeAndName`, use `config.IDFromString` (#2869) - Remove `config.NewViper`, users should use `config.NewParser` (#2917) - Remove `testutil.WaitFor`, use `testify.Eventually` helper if needed (#2920) - Remove testutil.WaitForPort, users can use testify.Eventually (#2926) - Rename `processorhelper.NewTraceProcessor` to `processorhelper.NewTracesProcessor` (#2935) - Rename `exporterhelper.NewTraceExporter` to `exporterhelper.NewTracesExporter` (#2937) - Remove InitEmptyWithCapacity, add EnsureCapacity and Clear (#2845) - Rename traces methods/objects to include Traces in Kafka receiver (#2966) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add `validatable` interface with `Validate()` to all `config.` (#2898) - add the empty `Validate()` implementation for all component configs - **Experimental**: Add a config source manager that wraps the interaction with config sources (#2857, #2903, #2948) - `kafka` exporter: Key jaeger messages on traceid (#2855) - `scraperhelper`: Don't try to count metrics if scraper returns an error (#2902) - Extract ConfigFactory in a ParserProvider interface (#2868) - `prometheus` exporter: Allows Summary metrics to be exported to Prometheus (#2900) - `prometheus` receiver: Optimize `dpgSignature` function (#2945) - `kafka` receiver: Add logs support (#2944) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `prometheus` receiver: - Treat Summary and Histogram metrics without "\_sum" counter as valid metric (#2812) - Add `job` and `instance` as well-known labels (#2897) - `prometheusremotewrite` exporter: - Sort Sample by Timestamp to avoid out of order errors (#2941) - Remove incompatible queued retry (#2951) - `kafka` receiver: Fix data race with batchprocessor (#2957) - `jaeger` receiver: Jaeger agent should not report ErrServerClosed (#2965) ## v0.24.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove legacy internal metrics for memorylimiter processor, `spans_dropped` and `trace_batches_dropped` (#2841) - For `spans_dropped` use `processor/refused_spans` with `processor=memorylimiter` - Rename pdata._.[Start|End]Time to pdata._.[Start|End]Timestamp (#2847) - Rename pdata.DoubleExemplar to pdata.Exemplar (#2804) - Rename pdata.DoubleHistogram to pdata.Histogram (#2797) - Rename pdata.DoubleSummary to pdata.Summary (#2774) - Refactor `consumererror` package (#2768) - Remove `PartialError` type in favor of signal-specific types - Rename `CombineErrors()` to `Combine()` - Refactor `componenthelper` package (#2778) - Remove `ComponentSettings` and `DefaultComponentSettings()` - Rename `NewComponent()` to `New()` - obsReport.NewExporter accepts a settings struct (#2668) - Remove ErrorWaitingHost from `componenttest` (#2582) - Move `config.Load` to `configparser.Load` (#2796) - Remove `configtest.NewViperFromYamlFile()`, use `config.Parser.NewParserFromFile()` (#2806) - Remove `config.ViperSubExact()`, use `config.Parser.Sub()` (#2806) - Update LoadReceiver signature to remove unused params (#2823) - Move `configerror.ErrDataTypeIsNotSupported` to `componenterror.ErrDataTypeIsNotSupported` (#2886) - Rename`CreateTraceExporter` type to `CreateTracesExporter` in `exporterhelper` (#2779) - Move `fluentbit` extension to contrib (#2795) - Move `configmodels` to `config` (#2808) - Move `fluentforward` receiver to contrib (#2723) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate `consumetest.New[${SIGNAL}]Nop` in favor of `consumetest.NewNop` (#2878) - Deprecate `consumetest.New[${SIGNAL}]Err` in favor of `consumetest.NewErr` (#2878) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `batch` processor: - Support max batch size for logs (#2736) - Use `Endpoint` for health check extension (#2782) - Use `confignet.TCPAddr` for `pprof` and `zpages` extensions (#2829) - Add watcher to values retrieved via config sources (#2803) - Updates for cloud semantic conventions (#2809) - `cloud.infrastructure_service` -> `cloud.platform` - `cloud.zone` -> `cloud.availability_zone` - Add systemd environment file for deb/rpm packages (#2822) - Add validate interface in `configmodels` to force each component do configuration validation (#2802, #2856) - Add `aws.ecs.task.revision` to semantic conventions list (#2816) - Set unprivileged user to container image (#2838) - Add New funcs for extension, exporter, processor config settings (#2872) - Report metric about current size of the exporter retry queue (#2858) - Allow adding new signals in `ProcessorFactory` by forcing everyone to embed `BaseProcessorFactory` (#2885) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `pdata.TracesFromOtlpProtoBytes`: Fixes to handle backwards compatibility changes in proto (#2798) - `jaeger` receiver: Escape user input used in output (#2815) - `prometheus` exporter: Ensure same time is used for updated time (#2745) - `prometheusremotewrite` exporter: Close HTTP response body (#2875) ## v0.23.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Move fanout consumers to fanoutconsumer package (#2615) - Rename ExporterObsReport to Exporter (#2658) - Rename ProcessorObsReport to Processor (#2657) - Remove ValidateConfig and add Validate on the Config struct (#2665) - Rename pdata Size to OtlpProtoSize (#2726) - Rename [Traces|Metrics|Logs]Consumer to [Traces|Metrics|Logs] (#2761) - Remove public access for `componenttest.Example*` components: - Users of these structs for testing configs should use the newly added `componenttest.Nop*` (update all components name in the config `example*` -> `nop` and use `componenttest.NopComponents()`). - Users of these structs for sink like behavior should use `consumertest.*Sink`. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `hostmetrics` receiver: List labels along with respective metrics in metadata (#2662) - `exporter` helper: Remove obsreport.ExporterContext, always add exporter name as a tag to the metrics (#2682) - `jaeger` exporter: Change to not use internal data (#2698) - `kafka` receiver: Change to not use internal data (#2697) - `zipkin` receiver: Change to not use internal data (#2699) - `kafka` exporter: Change to not use internal data (#2696) - Ensure that extensions can be created and started multiple times (#2679) - Use otlp request in logs wrapper, hide members in the wrapper (#2692) - Add MetricsWrapper to disallow access to internal representation (#2693) - Add TracesWrapper to disallow access to internal representation (#2721) - Allow multiple OTLP receivers to be created (#2743) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `prometheus` exporter: Fix to work with standard labels that follow the naming convention of using periods instead of underscores (#2707) - Propagate name and transport for `prometheus` receiver and exporter (#2680) - `zipkin` receiver: Ensure shutdown correctness (#2765) ## v0.22.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename ServiceExtension to just Extension (#2581) - Remove `consumerdata.TraceData` (#2551) - Move `consumerdata.MetricsData` to `internaldata.MetricsData` (#2512) - Remove custom OpenCensus sematic conventions that have equivalent in otel (#2552) - Move ScrapeErrors and PartialScrapeError to `scrapererror` (#2580) - Remove support for deprecated unmarshaler `CustomUnmarshaler`, only `Unmarshal` is supported (#2591) - Remove deprecated componenterror.CombineErrors (#2598) - Rename `pdata.TimestampUnixNanos` to `pdata.Timestamp` (#2549) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `prometheus` exporter: Re-implement on top of `github.com/prometheus/client_golang/prometheus` and add `metric_expiration` option - `logging` exporter: Add support for AttributeMap (#2609) - Add semantic conventions for instrumentation library (#2602) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otlp` receiver: Fix `Shutdown()` bug (#2564) - `batch` processor: Fix Shutdown behavior (#2537) - `logging` exporter: Fix handling the loop for empty attributes (#2610) - `prometheusremotewrite` exporter: Fix counter name check (#2613) ## v0.21.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated function `IsValid` from trace/span ID (#2522) - Remove accessors for deprecated status code (#2521) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `otlphttp` exporter: Add `compression` option for gzip encoding of outgoing http requests (#2502) - Add `ScrapeErrors` struct to `consumererror` to simplify errors usage (#2414) - Add `cors_allowed_headers` option to `confighttp` (#2454) - Add SASL/SCRAM authentication mechanism on `kafka` receiver and exporter (#2503) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `otlp` receiver: Sets the correct deprecated status code before sending data to the pipeline (#2521) - Fix `IsPermanent` to account for wrapped errors (#2455) - `otlp` exporter: Preserve original error messages (#2459) ## v0.20.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename `samplingprocessor/probabilisticsamplerprocessor` to `probabilisticsamplerprocessor` (#2392) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `hostmetrics` receiver: Refactor to use metrics metadata utilities (#2405, #2406, #2421) - Add k8s.node semantic conventions (#2425) ## v0.19.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove deprecated `queued_retry` processor - Remove deprecated configs from `resource` processor: `type` (set "opencensus.type" key in "attributes.upsert" map instead) and `labels` (use "attributes.upsert" instead). ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `hostmetrics` receiver: Refactor load metrics to use generated metrics (#2375) - Add uptime to the servicez debug page (#2385) - Add new semantic conventions for AWS (#2365) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `jaeger` exporter: Improve connection state logging (#2239) - `pdatagen`: Fix slice of values generated code (#2403) - `filterset` processor: Avoid returning always nil error in strict filterset (#2399) ## v0.18.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename host metrics according to metrics spec and rename `swap` scraper to `paging` (#2311) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add check for `NO_WINDOWS_SERVICE` environment variable to force interactive mode on Windows (#2272) - `hostmetrics` receiver: Add `disk/weighted_io_time` metric (Linux only) (#2312) - `opencensus` exporter: Add queue-retry (#2307) - `filter` processor: Filter metrics using resource attributes (#2251) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `fluentforward` receiver: Fix string conversions (#2314) - Fix zipkinv2 translation error tag handling (#2253) ## v0.17.0 Beta ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Default config environment variable expansion (#2231) - `prometheusremotewrite` exporter: Add batched exports (#2249) - `memorylimiter` processor: Introduce soft and hard limits (#2250) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix nits in pdata usage (#2235) - Convert status to not be a pointer in the Span (#2242) - Report the error from `pprof.StartCPUProfile` (#2263) - Rename `service.Application.SignalTestComplete` to `Shutdown` (#2277) ## v0.16.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename Push functions to be consistent across signals in `exporterhelper` (#2203) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Change default OTLP/gRPC port number to 4317, also continue receiving on legacy port 55680 during transition period (#2104). - `kafka` exporter: Add support for exporting metrics as otlp Protobuf. (#1966) - Move scraper helpers to its own `scraperhelper` package (#2185) - Add `componenthelper` package to help build components (#2186) - Remove usage of custom init/stop in `scraper` and use start/shutdown from `component` (#2193) - Add more trace annotations, so zpages are more useful to determine failures (#2206) - Add support to skip TLS verification (#2202) - Expose non-nullable metric types (#2208) - Expose non-nullable elements from slices of pointers (#2200) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Change InstrumentationLibrary to be non-nullable (#2196) - Add support for slices to non-pointers, use non-nullable AnyValue (#2192) - Fix `--set` flag to work with `{}` in configs (#2162) ## v0.15.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Remove legacy metrics, they were marked as legacy for ~12 months #2105 ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Implement conversion between OpenCensus and OpenTelemetry Summary Metric (#2048) - Add ability to generate non nullable messages (#2005) - Implement Summary Metric in Prometheus RemoteWrite Exporter (#2083) - Add `resource_to_telemetry_conversion` to exporter helper expose exporter settings (#2060) - Add `CustomRoundTripper` function to httpclientconfig (#2085) - Allow for more logging options to be passed to `service` (#2132) - Add config parameters for `jaeger` receiver (#2068) - Map unset status code for `jaeger` translator as per spec (#2134) - Add more trace annotations to the queue-retry logic (#2136) - Add config settings for component telemetry (#2148) - Use net.SplitHostPort for IPv6 support in `prometheus` receiver (#2154) - Add --log-format command line option (default to "console") #2177. ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `logging` exporter: Add Logging for Summary Datapoint (#2084) - `hostmetrics` receiver: use correct TCP state labels on Unix systems (#2087) - Fix otlp_log receiver wrong use of trace measurement (#2117) - Fix "process/memory/rss" metric units (#2112) - Fix "process/cpu_seconds" metrics (#2113) - Add check for nil logger in exporterhelper functions (#2141) - `prometheus` receiver: - Upgrade Prometheus version to fix race condition (#2121) - Fix the scraper/discover manager coordination (#2089) - Fix panic when adjusting buckets (#2168) ## v0.14.0 Beta ### ๐Ÿš€ New components ๐Ÿš€ - `otlphttp` exporter which implements OTLP over HTTP protocol. ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename consumer.TraceConsumer to consumer.TracesConsumer #1974 - Rename component.TraceReceiver to component.TracesReceiver #1975 - Rename component.TraceProcessor to component.TracesProcessor #1976 - Rename component.TraceExporter to component.TracesExporter #1975 - Move `tailsampling` processor to contrib (#2012) - Remove NewAttributeValueSlice (#2028) and mark NewAttributeValue as deprecated (#2022) - Remove pdata.StringValue (#2021) - Remove pdata.InitFromAttributeMap, use CopyTo if needed (#2042) - Remove SetMapVal and SetArrayVal for pdata.AttributeValue (#2039) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate NopExporter, add NopConsumer (#1972) - Deprecate SinkExporter, add SinkConsumer (#1973) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `zipkin` exporter: Add queue retry to zipkin (#1971) - `prometheus` exporter: Add `send_timestamps` option (#1951) - `filter` processor: Add `expr` pdata.Metric filtering support (#1940, #1996) - `attribute` processor: Add log support (#1934) - `logging` exporter: Add index for histogram buckets count (#2009) - `otlphttp` exporter: Add correct handling of server error responses (#2016) - `prometheusremotewrite` exporter: - Add user agent header to outgoing http request (#2000) - Convert histograms to cumulative (#2049) - Return permanent errors (#2053) - Add external labels (#2044) - `hostmetrics` receiver: Use scraper controller (#1949) - Change Span/Trace ID to be byte array (#2001) - Add `simple` metrics helper to facilitate building pdata.Metrics in receivers (#1540) - Improve diagnostic logging for exporters (#2020) - Add obsreport to receiverhelper scrapers (#1961) - Update OTLP to 0.6.0 and use the new Span Status code (#2031) - Add support of partial requests for logs and metrics to the exporterhelper (#2059) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `logging` exporter: Added array serialization (#1994) - `zipkin` receiver: Allow receiver to parse string tags (#1893) - `batch` processor: Fix shutdown race (#1967) - Guard for nil data points (#2055) ## v0.13.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Host metric `system.disk.time` renamed to `system.disk.operation_time` (#1887) - Use consumer for sender interface, remove unnecessary receiver address from Runner (#1941) - Enable sending queue by default in all exporters configured to use it (#1924) - Removed `groupbytraceprocessor` (#1891) - Remove ability to configure collection interval per scraper (#1947) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Host Metrics receiver now reports both `system.disk.io_time` and `system.disk.operation_time` (#1887) - Match spans against the instrumentation library and resource attributes (#928) - Add `receiverhelper` for creating flexible "scraper" metrics receiver (#1886, #1890, #1945, #1946) - Migrate `tailsampling` processor to new OTLP-based internal data model and add Composite Sampler (#1894) - Metadata Generator: Change Metrics fields to implement an interface with new methods (#1912) - Add unmarshalling for `pdata.Traces` (#1948) - Add debug-level message on error for `jaeger` exporter (#1964) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix bug where the service does not correctly start/stop the log exporters (#1943) - Fix Queued Retry Unusable without Batch Processor (#1813) - (#1930) - `prometheus` receiver: Log error message when `process_start_time_seconds` gauge is missing (#1921) - Fix trace jaeger conversion to internal traces zero time bug (#1957) - Fix panic in otlp traces to zipkin (#1963) - Fix OTLP/HTTP receiver's path to be /v1/traces (#1979) ## v0.12.0 Beta ### ๐Ÿš€ New components ๐Ÿš€ - `configauth` package with the auth settings that can be used by receivers (#1807, #1808, #1809, #1810) - `perfcounters` package that uses perflib for host metrics receiver (#1835, #1836, #1868, #1869, #1870) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Remove `queued_retry` and enable `otlp` metrics receiver in default config (#1823, #1838) - Add `limit_percentage` and `spike_limit_percentage` options to `memorylimiter` processor (#1622) - `hostmetrics` receiver: - Collect additional labels from partitions in the filesystems scraper (#1858) - Add filters for mount point and filesystem type (#1866) - Add cloud.provider semantic conventions (#1865) - `attribute` processor: Add log support (#1783) - Introduce SpanID data type, not yet used in Protobuf messages ($1854, #1855) - Enable `otlp` trace by default in the released docker image (#1883) - `tailsampling` processor: Combine batches of spans into a single batch (#1864) - `filter` processor: Update to use pdata (#1885) - Allow MSI upgrades (#1914) ### ๐Ÿšฉ Deprecations ๐Ÿšฉ - Deprecate OpenCensus-based internal data structures (#1843) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - `prometheus` receiver: Print a more informative message about 'up' metric value (#1826) - Use custom data type and custom JSON serialization for traceid (#1840) - Skip creation of redundant nil resource in translation from OC if there are no combined metrics (#1803) - `tailsampling` processor: Only send to next consumer once (#1735) - Report Windows pagefile usage in bytes (#1837) - Fix issue where Prometheus SD config cannot be parsed (#1877) ## v0.11.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Rename service.Start() to Run() since it's a blocking call - Fix slice Append to accept by value the element in pdata - Change CreateTraceProcessor and CreateMetricsProcessor to use the same parameter order as receivers/logs processor and exporters. - Prevent accidental use of LogsToOtlp and LogsFromOtlp and the OTLP data structs (#1703) - Remove SetType from configmodels, ensure all registered factories set the type in config (#1798) - Move process telemetry to service/internal (#1794) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Add map and array attribute value type support (#1656) - Add authentication support to kafka (#1632) - Implement InstrumentationLibrary translation to jaeger (#1645) - Add public functions to export pdata to ExportXServicesRequest Protobuf bytes (#1741) - Expose telemetry level in the configtelemetry (#1796) - Add configauth package (#1807) - Add config to docker image (#1792) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Use zap int argument for int values instead of conversion (#1779) - Add support for gzip encoded payload in OTLP/HTTP receiver (#1581) - Return proto status for OTLP receiver when failed (#1788) ## v0.10.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - **Update OTLP to v0.5.0, incompatible metrics protocol.** - Remove support for propagating summary metrics in OtelCollector. - This is a temporary change, and will affect mostly OpenCensus users who use metrics. ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Support zipkin proto in `kafka` receiver (#1646) - Prometheus Remote Write Exporter supporting Cortex (#1577, #1643) - Add deployment environment semantic convention (#1722) - Add logs support to `batch` and `resource` processors (#1723, #1729) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Identify config error when expected map is other value type (#1641) - Fix Kafka receiver closing ready channel multiple times (#1696) - Fix a panic issue while processing Zipkin spans with an empty service name (#1742) - Zipkin Receiver: Always set the endtime (#1750) ## v0.9.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - **Remove old base factories**: - `ReceiverFactoryBase` (#1583) - `ProcessorFactoryBase` (#1596) - `ExporterFactoryBase` (#1630) - Remove logs factories and merge with normal factories (#1569) - Remove `reconnection_delay` from OpenCensus exporter (#1516) - Remove `ConsumerOld` interfaces (#1631) ### ๐Ÿš€ New components ๐Ÿš€ - `prometheusremotewrite` exporter: Send metrics data in Prometheus TimeSeries format to Cortex or any Prometheus (#1544) - `kafka` receiver: Receive traces from Kafka (#1410) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `kafka` exporter: Enable queueing, retry, timeout (#1455) - Add `Headers` field in HTTPClientSettings (#1552) - Change OpenCensus receiver (#1556) and exporter (#1571) to the new interfaces - Add semantic attribute for `telemetry.auto.version` (#1578) - Add uptime and RSS memory self-observability metrics (#1549) - Support conversion for OpenCensus `SameProcessAsParentSpan` (#1629) - Access application version in components (#1559) - Make Kafka payload encoding configurable (#1584) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Stop further processing if `filterprocessor` filters all data (#1500) - `processscraper`: Use same scrape time for all data points coming from same process (#1539) - Ensure that time conversion for 0 returns nil timestamps or Time where IsZero returns true (#1550) - Fix multiple exporters panic (#1563) - Allow `attribute` processor for external use (#1574) - Do not duplicate filesystem metrics for devices with many mount points (#1617) ## v0.8.0 Beta ### ๐Ÿš€ New components ๐Ÿš€ - `groupbytrace` processor that waits for a trace to be completed (#1362) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Migrate `zipkin` receiver/exporter to the new interfaces (#1484) - Migrate `prometheus` receiver/exporter to the new interfaces (#1477, #1515) - Add new FactoryUnmarshaler support to all components, deprecate old way (#1468) - Update `fileexporter` to write data in OTLP (#1488) - Add extension factory helper (#1485) - Host scrapers: Use same scrape time for all data points coming from same source (#1473) - Make logs SeverityNumber publicly available (#1496) - Add recently included conventions for k8s and container resources (#1519) - Add new config StartTimeMetricRegex to `prometheus` receiver (#1511) - Convert Zipkin receiver and exporter to use OTLP (#1446) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Infer OpenCensus resource type based on OpenTelemetry's semantic conventions (#1462) - Fix log adapter in `prometheus` receiver (#1493) - Avoid frequent errors for process telemetry on Windows (#1487) ## v0.7.0 Beta ### ๐Ÿš€ New components ๐Ÿš€ - Receivers - `fluentforward` runs a TCP server that accepts events via the [Fluent Forward protocol](https://github.com/fluent/fluentd/wiki/Forward-Protocol-Specification-v1) (#1173) - Exporters - `kafka` exports traces to Kafka (#1439) - Extensions - **Experimental** `fluentbit` facilitates running a FluentBit subprocess of the collector (#1381) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Updated `golang/protobuf` from v1.3.5 to v1.4.2 (#1308) - Updated `opencensus-proto` from v0.2.1 to v0.3.0 (#1308) - Added round_robin `balancer_name` as an option to gRPC client settings (#1353) - `hostmetrics` receiver - Switch to using perf counters to get disk io metrics on Windows (#1340) - Add device filter for file system (#1379) and disk (#1378) scrapers - Record process physical & virtual memory stats separately (#1403) - Scrape system.disk.time on Windows (#1408) - Add disk.pending_operations metric (#1428) - Add network interface label to network metrics (#1377) - Add `exporterhelper` (#1351) and `processorhelper` (#1359) factories - Update OTLP to latest version (#1384) - Disable timeout, retry on failure and sending queue for `logging` exporter (#1400) - Add support for retry and sending queue for `jaeger` exporter (#1401) - Add batch size bytes metric to `batch` processor (#1270) - `otlp` receiver: Add Log Support (#1444) - Allow to configure read/write buffer sizes for http Client (#1447) - Update DB conventions to latest and add exception conventions (#1452) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fix `resource` processor for old metrics (#1412) - `jaeger` receiver: Do not try to stop if failed to start. Collector service will do that (#1434) ## v0.6.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - Renamed the metrics generated by `hostmetrics` receiver to match the (currently still pending) OpenTelemetry system metric conventions (#1261) (#1269) - Removed `vmmetrics` receiver (#1282) - Removed `cpu` scraper `report_per_cpu` config option (#1326) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - Added disk merged (#1267) and process count (#1268) metrics to `hostmetrics` - Log metric data points in `logging` exporter (#1258) - Changed the `batch` processor to not ignore the errors returned by the exporters (#1259) - Build and publish MSI (#1153) and DEB/RPM packages (#1278, #1335) - Added batch size metric to `batch` processor (#1241) - Added log support for `memorylimiter` processor (#1291) and `logging` exporter (#1298) - Always add tags for `observability`, other metrics may use them (#1312) - Added metrics support (#1313) and allow partial retries in `queued_retry` processor (#1297) - Update `resource` processor: introduce `attributes` config parameter to specify actions on attributes similar to `attributes` processor, old config interface is deprecated (#1315) - Update memory state labels for non-Linux OSs (#1325) - Ensure tcp connection value is provided for all states, even when count is 0 (#1329) - Set `batch` processor channel size to num cpus (#1330) - Add `send_batch_max_size` config parameter to `batch` processor enforcing hard limit on batch size (#1310) - Add support for including a per-RPC authentication to gRPC settings (#1250) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Fixed OTLP waitForReady, not set from config (#1254) - Fixed all translation diffs between OTLP and Jaeger (#1222) - Disabled `process` scraper for any non Linux/Windows OS (#1328) ## v0.5.0 Beta ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - **Update OTLP to v0.4.0 (#1142)**: Collector will be incompatible with any other sender or receiver of OTLP protocol of different versions - Make "--new-metrics" command line flag the default (#1148) - Change `endpoint` to `url` in Zipkin exporter config (#1186) - Change `tls_credentials` to `tls_settings` in Jaeger receiver config (#1233) - OTLP receiver config change for `protocols` to support mTLS (#1223) - Remove `export_resource_labels` flag from Zipkin exporter (#1163) ### ๐Ÿš€ New components ๐Ÿš€ - Receivers - Added process scraper to the `hostmetrics` receiver (#1047) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - otlpexporter: send configured headers in request (#1130) - Enable Collector to be run as a Windows service (#1120) - Add config for HttpServer (#1196) - Allow cors in HTTPServerSettings (#1211) - Add a generic grpc server settings config, cleanup client config (#1183) - Rely on gRPC to batch and loadbalance between connections instead of custom logic (#1212) - Allow to tune the read/write buffers for gRPC clients (#1213) - Allow to tune the read/write buffers for gRPC server (#1218) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Handle overlapping metrics from different jobs in prometheus exporter (#1096) - Fix handling of SpanKind INTERNAL in OTLP OC translation (#1143) - Unify zipkin v1 and v2 annotation/tag parsing logic (#1002) - mTLS: Add support to configure client CA and enforce ClientAuth (#1185) - Fixed untyped Prometheus receiver bug (#1194) - Do not embed ProtocolServerSettings in gRPC (#1210) - Add Context to the missing CreateMetricsReceiver method (#1216) ## v0.4.0 Beta Released 2020-06-16 ### ๐Ÿ›‘ Breaking changes ๐Ÿ›‘ - `isEnabled` configuration option removed (#909) - `thrift_tchannel` protocol moved from `jaeger` receiver to `jaeger_legacy` in contrib (#636) ### โš ๏ธ Major changes โš ๏ธ - Switch from `localhost` to `0.0.0.0` by default for all receivers (#1006) - Internal API Changes (only impacts contributors) - Add context to `Start` and `Stop` methods in the component (#790) - Rename `AttributeValue` and `AttributeMap` method names (#781) (other breaking changes in the internal trace data types) - Change entire repo to use the new vanityurl go.opentelemetry.io/collector (#977) ### ๐Ÿš€ New components ๐Ÿš€ - Receivers - `hostmetrics` receiver with CPU (#862), disk (#921), load (#974), filesystem (#926), memory (#911), network (#930), and virtual memory (#989) support - Processors - `batch` for batching received metrics (#1060) - `filter` for filtering (dropping) received metrics (#1001) ### ๐Ÿ’ก Enhancements ๐Ÿ’ก - `otlp` receiver implement HTTP X-Protobuf (#1021) - Exporters: Support mTLS in gRPC exporters (#927) - Extensions: Add `zpages` for service (servicez, pipelinez, extensions) (#894) ### ๐Ÿงฐ Bug fixes ๐Ÿงฐ - Add missing logging for metrics at `debug` level (#1108) - Fix setting internal status code in `jaeger` receivers (#1105) - `zipkin` export fails on span without timestamp when used with `queued_retry` (#1068) - Fix `zipkin` receiver status code conversion (#996) - Remove extra send/receive annotations with using `zipkin` v1 (#960) - Fix resource attribute mutation bug when exporting in `jaeger` proto (#907) - Fix metric/spans count, add tests for nil entries in the slices (#787) ### ๐Ÿงฉ Components ๐Ÿงฉ #### Traces | Receivers | Processors | Exporters | |:----------:|:--------------:|:----------:| | Jaeger | Attributes | File | | OpenCensus | Batch | Jaeger | | OTLP | Memory Limiter | Logging | | Zipkin | Queued Retry | OpenCensus | | | Resource | OTLP | | | Sampling | Zipkin | | | Span | | #### Metrics | Receivers | Processors | Exporters | |:-----------:|:--------------:|:----------:| | HostMetrics | Batch | File | | OpenCensus | Filter | Logging | | OTLP | Memory Limiter | OpenCensus | | Prometheus | | OTLP | | VM Metrics | | Prometheus | #### Extensions - Health Check - Performance Profiler - zPages ## v0.3.0 Beta Released 2020-03-30 ### Breaking changes - Make prometheus receiver config loading strict. #697 Prometheus receiver will now fail fast if the config contains unused keys in it. ### Changes and fixes - Enable best effort serve by default of Prometheus Exporter (https://github.com/orijtech/prometheus-go-metrics-exporter/pull/6) - Fix null pointer exception in the logging exporter #743 - Remove unnecessary condition to have at least one processor #744 ### Components | Receivers / Exporters | Processors | Extensions | |:---------------------:|:--------------:|:--------------------:| | Jaeger | Attributes | Health Check | | OpenCensus | Batch | Performance Profiler | | OpenTelemetry | Memory Limiter | zPages | | Zipkin | Queued Retry | | | | Resource | | | | Sampling | | | | Span | | ## v0.2.8 Alpha Alpha v0.2.8 of OpenTelemetry Collector - Implemented OTLP receiver and exporter. - Added ability to pass config to the service programmatically (useful for custom builds). - Improved own metrics / observability. - Refactored component and factory interface definitions (breaking change #683) ## v0.2.7 Alpha Alpha v0.2.7 of OpenTelemetry Collector - Improved error handling on shutdown - Partial implementation of new metrics (new obsreport package) - Include resource labels for Zipkin exporter - New `HASH` action to attribute processor ## v0.2.6 Alpha Alpha v0.2.6 of OpenTelemetry Collector. - Update metrics prefix to `otelcol` and expose command line argument to modify the prefix value. - Extend Span processor to have include/exclude span logic. - Batch dropped span now emits zero when no spans are dropped. ## v0.2.5 Alpha Alpha v0.2.5 of OpenTelemetry Collector. - Regexp-based filtering of spans based on service names. - Ability to choose strict or regexp matching for include/exclude filters. ## v0.2.4 Alpha Alpha v0.2.4 of OpenTelemetry Collector. - Regexp-based filtering of span names. - Ability to extract attributes from span names and rename span. - File exporter for debugging. - Span processor is now enabled by default. ## v0.2.3 Alpha Alpha v0.2.3 of OpenTelemetry Collector. Changes: 21a70d6 Add a memory limiter processor (#498) 9778b16 Refactor Jaeger Receiver config (#490) ec4ad0c Remove workers from OpenCensus receiver implementation (#497) 4e01fa3 Update k8s config to use opentelemetry docker image and configuration (#459) ## v0.2.2 Alpha Alpha v0.2.2 of OpenTelemetry Collector. Main changes visible to users since previous release: - Improved Testbed and added more E2E tests. - Made component interfaces more uniform (this is a breaking change). Note: v0.2.1 never existed and is skipped since it was tainted in some dependencies. ## v0.2.0 Alpha Alpha v0.2 of OpenTelemetry Collector. Docker image: omnition/opentelemetry-collector:v0.2.0 (we are working on getting this under an OpenTelemetry org) Main changes visible to users since previous release: - Rename from `service` to `collector`, the binary is now named `otelcol` - Configuration reorganized and using strict mode - Concurrency issues for pipelines transforming data addressed Commits: ```terminal 0e505d5 Refactor config: pipelines now under service (#376) 402b80c Add Capabilities to Processor and use for Fanout cloning decision (#374) b27d824 Use strict mode to read config (#375) d769eb5 Fix concurrency handling when data is fanned out (#367) dc6b290 Rename all github paths from opentelemetry-service to opentelemetry-collector (#371) d038801 Rename otelsvc to otelcol (#365) c264e0e Add Include/Exclude logic for Attributes Processor (#363) 8ce427a Pin a commit for Prometheus dependency in go.mod (#364) 2393774 Bump Jaeger version to 1.14.0 (latest) (#349) 63362d5 Update testbed modules (#360) c0e2a27 Change dashes to underscores to separate words in config files (#357) 7609eaa Rename OpenTelemetry Service to Collector in docs and comments (#354) bc5b299 Add common gRPC configuration settings (#340) b38505c Remove network access popups on macos (#348) f7727d1 Fixed loop variable pointer bug in jaeger translator (#341) 958beed Ensure that ConsumeMetricsData() is not passed empty metrics in the Prometheus receiver (#345) 0be295f Change log statement in Prometheus receiver from info to debug. (#344) d205393 Add Owais to codeowners (#339) 8fa6afe Translate OC resource labels to Jaeger process tags (#325) ``` ## v0.0.2 Alpha Alpha release of OpenTelemetry Service. Docker image: omnition/opentelemetry-service:v0.0.2 (we are working on getting this under an OpenTelemetry org) Main changes visible to users since previous release: ```terminal 8fa6afe Translate OC resource labels to Jaeger process tags (#325) 047b0f3 Allow environment variables in config (#334) 96c24a3 Add exclude/include spans option to attributes processor (#311) 4db0414 Allow metric processors to be specified in pipelines (#332) c277569 Add observability instrumentation for Prometheus receiver (#327) f47aa79 Add common configuration for receiver tls (#288) a493765 Refactor extensions to new config format (#310) 41a7afa Add Span Processor logic 97a71b3 Use full name for the metrics and spans created for observability (#316) fed4ed2 Add support to record metrics for metricsexporter (#315) 5edca32 Add include_filter configuration to prometheus receiver (#298) 0068d0a Passthrough CORS allowed origins (#260) ``` ## v0.0.1 Alpha This is the first alpha release of OpenTelemetry Service. Docker image: omnition/opentelemetry-service:v0.0.1 [v0.3.0]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.10...v0.3.0 [v0.2.10]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.8...v0.2.10 [v0.2.8]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.7...v0.2.8 [v0.2.7]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.6...v0.2.7 [v0.2.6]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.5...v0.2.6 [v0.2.5]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.4...v0.2.5 [v0.2.4]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.3...v0.2.4 [v0.2.3]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.2...v0.2.3 [v0.2.2]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.2.0...v0.2.2 [v0.2.0]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.0.2...v0.2.0 [v0.0.2]: https://github.com/open-telemetry/opentelemetry-collector/compare/v0.0.1...v0.0.2 [v0.0.1]: https://github.com/open-telemetry/opentelemetry-collector/tree/v0.0.1 opentelemetry-collector-0.141.0/CONTRIBUTING.md000066400000000000000000000525101511331344600207720ustar00rootroot00000000000000# Contributing Guide We'd love your help! Please join our weekly [SIG meeting](https://github.com/open-telemetry/community#special-interest-groups). ## Target audiences The OpenTelemetry Collector has three main target audiences: 1. *End-users*, aiming to use an OpenTelemetry Collector binary. 1. *Component developers*, consuming the Go APIs to create components compatible with the OpenTelemetry Collector Builder. 1. *Collector library users*, consuming other Go APIs exposed by the opentelemetry-collector repository, for example to build custom distributions or other projects building on top of the Collector Go APIs. When the needs of these audiences conflict, end-users should be prioritized, followed by component developers, and finally Collector library users. ### End-users End-users are the target audience for our binary distributions, as made available via the [opentelemetry-collector-releases](https://github.com/open-telemetry/opentelemetry-collector-releases) repository, as well as distributions created using the [OpenTelemetry Collector Builder](https://github.com/open-telemetry/opentelemetry-collector/tree/main/cmd/builder). To them, stability in the behavior is important, be it runtime, configuration, or [internal telemetry](https://opentelemetry.io/docs/collector/internal-telemetry/). They are more numerous and harder to get in touch with, making our changes to the Collector more disruptive to them than to other audiences. As a general rule, whenever you are developing OpenTelemetry Collector components (extensions, receivers, processors, exporters, connectors), you should have end-users' interests in mind. Similarly, changes to code within packages like `config` will have an impact on this audience. Make sure to cause minimal disruption when doing changes here. ### Component developers Component developers create new extensions, receivers, processors, exporters, and connectors to be used with the OpenTelemetry Collector. They are the primary audience for the opentelemetry-collector repository's public Go API. A significant part of them will contribute to opentelemetry-collector-contrib. In addition to the end-user aspect mentioned above, this audience also cares about Go API compatibility of Go modules such as the ones in the `pdata`, `component`, `consumer`, `confmap`, `exporterhelper`, `config*` modules and others, even though such changes wouldn't cause any impact to end-users. See the [Breaking changes](docs/coding-guidelines.md#breaking-changes) section in the coding guidelines for more information on how to perform changes affecting this audience. ### Collector library users A third audience uses the OpenTelemetry Collector as a library to build their own distributions or other projects based on the Collector. This audience is the main consumer of modules such as `service` or `otelcol`. They also share the same concerns as component developers regarding Go API compatibility and are likewise interested in behavior stability. These are our most advanced users and are the most equipped to deal with disruptive changes. ## How to structure PRs to get expedient reviews? We recommend that any PR (unless it is trivial) to be smaller than 500 lines (excluding go mod/sum changes) in order to help reviewers to do a thorough and reasonably fast reviews. ### When adding a new component Components refer to connectors, exporters, extensions, processors, and receivers. The key criteria for implementing a component is to: * Implement the `component.Component` interface * Provide a configuration structure which defines the configuration of the component * Provide the implementation that performs the component operation For more details on components, see the [Adding New Components](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#adding-new-components) document and the tutorial [Building a Trace Receiver](https://opentelemetry.io/docs/collector/trace-receiver/) which provides a detailed example of building a component. When adding a new component to the OpenTelemetry Collector, ensure that any configuration structs used by the component include fields with the `configopaque.String` type for sensitive data. This ensures that the data is masked when serialized to prevent accidental exposure. When submitting a component to the community, consider breaking it down into separate PRs as follows: * **First PR** should include the overall structure of the new component: * Readme, configuration, and factory implementation should usually use the helper factory structs. * This PR is usually trivial to review, so the size limit does not apply to it. * The component should use [`In Development` Stability](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development) in its README. * **Second PR** should include the concrete implementation of the component. If the size of this PR is larger than the recommended size consider splitting it into multiple PRs. * **Last PR** should mark the new component as `Alpha` stability and add it to the `otelcorecol` binary by updating the `otelcorecol/components.go` file. The component must be enabled only after sufficient testing and only when it meets [`Alpha` stability requirements.](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha) * Once a new component has been added to the executable, please add the component to the [OpenTelemetry.io registry](https://github.com/open-telemetry/opentelemetry.io#adding-a-project-to-the-opentelemetry-registry). * intra-repository `replace` statements in `go.mod` files can be automatically inserted by running `make crosslink`. For more information on the `crosslink` tool see the README [here](https://github.com/open-telemetry/opentelemetry-go-build-tools/tree/main/crosslink). ### Refactoring Work Any refactoring work must be split in its own PR that does not include any behavior changes. It is important to do this to avoid hidden changes in large and trivial refactoring PRs. ## Report a bug or request a feature Reporting bugs is an important contribution. Please make sure to include: * Expected and actual behavior * The OpenTelemetry version you are running * If possible, steps to reproduce ### Adding Labels via Comments In order to facilitate proper label usage and to empower Code Owners, you are able to add labels to issues via comments. To add a label through a comment, post a new comment on an issue starting with `/label`, followed by a space-separated list of your desired labels. Supported labels come from the table below, or correspond to a component defined in the [CODEOWNERS file](.github/CODEOWNERS). The following general labels are supported: | Label | Label in Comment | |--------------------------|--------------------------| | `arm64` | `arm64` | | `good first issue` | `good-first-issue` | | `help wanted` | `help-wanted` | | `discussion needed` | `discussion-needed` | | `os:macos` | `os:macos` | | `os:windows` | `os:windows` | | `waiting for author` | `waiting-for-author` | | `waiting-for-codeowners` | `waiting-for-codeowners` | | `bug` | `bug` | | `priority:p0` | `priority:p0` | | `priority:p1` | `priority:p1` | | `priority:p2` | `priority:p2` | | `priority:p3` | `priority:p3` | | `Stale` | `stale` | To delete a label, prepend the label with `-`. Note that you must make a new comment to modify labels; you cannot edit an existing comment. Example label comment: ``` /label help-wanted -arm64 ``` ## How to contribute ### Before you start Please read the project contribution [guide](https://github.com/open-telemetry/community/tree/main/guides/contributor) for general practices for the OpenTelemetry project. Select a good issue from the links below (ordered by difficulty/complexity): * [Good First Issue](https://github.com/open-telemetry/opentelemetry-collector/issues?utf8=%E2%9C%93&q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) * [Help Wanted](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) Comment on the issue that you want to work on so we can assign it to you and clarify anything related to it. If you would like to work on something that is not listed as an issue (e.g. a new feature or enhancement) please first read our [vision](docs/vision.md) to make sure your proposal aligns with the goals of the Collector, then create an issue and describe your proposal. It is best to do this in advance so that maintainers can decide if the proposal is a good fit for this repository. This will help avoid situations when you spend significant time on something that maintainers may decide this repo is not the right place for. If you're new to the Collector, the [internal architecture](docs/internal-architecture.md) documentation may be helpful. Follow the instructions below to create your PR. ### Fork In the interest of keeping this repository clean and manageable, you should work from a fork. To create a fork, click the 'Fork' button at the top of the repository, then clone the fork locally using `git clone git@github.com:USERNAME/opentelemetry-collector.git`. You should also add this repository as an "upstream" repo to your local copy, in order to keep it up to date. You can add this as a remote like so: `git remote add upstream https://github.com/open-telemetry/opentelemetry-collector.git` Verify that the upstream exists: `git remote -v` To update your fork, fetch the upstream repo's branches and commits, then merge your `main` with upstream's `main`: ``` git fetch upstream git checkout main git merge upstream/main ``` Remember to always work in a branch of your local copy, as you might otherwise have to contend with conflicts in `main`. Please also see [GitHub workflow](https://github.com/open-telemetry/community/blob/main/guides/contributor/processes.md#github-workflow) section of the general project contributing guide. ## Required Tools Working with the project sources requires the following tools: 1. [git](https://git-scm.com/) 2. [go](https://golang.org/) (version 1.24 and up) 3. [make](https://www.gnu.org/software/make/) 4. [docker](https://www.docker.com/) ## Repository Setup Fork the repo and checkout the upstream repo to your GOPATH by: ``` $ git clone git@github.com:open-telemetry/opentelemetry-collector.git ``` Add your fork as an origin: ```shell $ cd opentelemetry-collector $ git remote add fork git@github.com:YOUR_GITHUB_USERNAME/opentelemetry-collector.git ``` Run tests, fmt, and lint: ```shell $ make ``` ## Creating a PR Checkout a new branch, make modifications, build locally, and push the branch to your fork to open a new PR: ```shell $ git checkout -b feature # edit $ make $ make fmt $ git commit $ git push fork feature ``` ### Commit Messages Use descriptive commit messages. Here are [some recommendations](https://cbea.ms/git-commit/) on how to write good commit messages. When creating PRs GitHub will automatically copy commit messages into the PR description, so it is a useful habit to write good commit messages before the PR is created. Also, unless you actually want to tell a story with multiple commits make sure to squash into a single commit before creating the PR. When maintainers merge PRs with multiple commits, they will be squashed and GitHub will concatenate all commit messages right before you hit the "Confirm squash and merge" button. Maintainers must make sure to edit this concatenated message to make it right before merging. In some cases, if the commit messages are lacking the easiest approach to have at least something useful is copy/pasting the PR description into the commit message box before merging (but see the above paragraph about writing good commit messages in the first place). ## General Notes This project uses Go 1.24.* and [Github Actions.](https://github.com/features/actions) It is recommended to run `make gofmt all` before submitting your PR. ## Coding Guidelines See the [Coding Guidelines](docs/coding-guidelines.md) document for more information. ## Changelog ### Overview There are two Changelogs for this repository: - `CHANGELOG.md` is intended for users of the collector and lists changes that affect the behavior of the collector. - `CHANGELOG-API.md` is intended for developers who are importing packages from the collector codebase. ### When to add a Changelog Entry An entry into the changelog is required for the following reasons: - Changes made to the behaviour of the component - Changes to the configuration - Changes to default settings - New components being added - Changes to exported elements of a package It is reasonable to omit an entry to the changelog under these circumstances: - Updating test to remove flakiness or improve coverage - Updates to the CI/CD process - Updates to internal packages If there is some uncertainty with regards to if a changelog entry is needed, the recommendation is to create an entry to in the event that the change is important to the project consumers. ### Adding a Changelog Entry The [CHANGELOG.md](./CHANGELOG.md) and [CHANGELOG-API.md](./CHANGELOG-API.md) files in this repo is autogenerated from `.yaml` files in the `./.chloggen` directory. Your pull request should add a new `.yaml` file to this directory. The name of your file must be unique since the last release. During the collector release process, all `./chloggen/*.yaml` files are transcribed into `CHANGELOG.md` and `CHANGELOG-API.md` and then deleted. **Recommended Steps** 1. Create an entry file using `make chlog-new`. This generates a file based on your current branch (e.g. `./.chloggen/my-branch.yaml`) 2. Fill in all fields in the new file 3. Run `make chlog-validate` to ensure the new file is valid 4. Commit and push the file Alternatively, copy `./.chloggen/TEMPLATE.yaml`, or just create your file from scratch. ## Local Testing To manually test your changes, follow these steps to build and run the Collector locally. Ensure that you execute these commands from the root of the repository: 1. Build the Collector: ```shell make otelcorecol ``` 2. Run the Collector with a local configuration file: ```shell ./bin/otelcorecol__ --config ./examples/local/otel-config.yaml ``` The actual name of the binary will depend on your platform, adjust accordingly (e.g., `./bin/otelcorecol_darwin_arm64`). Replace `otel-config.yaml` with the appropriate configuration file as needed. 3. Verify that your changes are reflected in the Collector's behavior by testing it against the provided configuration. ## Membership, Roles, and Responsibilities ### Membership levels See the [OpenTelemetry membership guide](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md) for information on how to become a member of the OpenTelemetry organization and the different roles available. In addition to the roles listed there we also have a Collector-specific role: code owners. ### Becoming a Code Owner A Code Owner is responsible for one or multiple packages within the Collector. That responsibility includes maintaining the component, triaging and responding to issues, and reviewing pull requests. Maintainers are expected to seek feedback from code owners for changes that are not trivial, but they may merge PRs without code owner approval. Code Ownership does not have to be a full-time job. If you can find a couple hours to help out on a recurring basis, please consider pursuing Code Ownership. #### Requirements If you would like to help and become a Code Owner, you must meet the following requirements. These are more stringent requirements than those in the opentelemetry-collector-contrib repository due to the higher impact of changes in this repository: 1. [Be a member of the OpenTelemetry organization](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#member). 2. Be an existing [approver](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver) or [maintainer](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer) in at least one repository within the OpenTelemetry Github organization. 3. Have made significant contributions directly to the package you want to own. #### How to become a Code Owner To become a Code Owner, open a PR that adds you to the [.github/CODEOWNERS](.github/CODEOWNERS) file. Make sure to ping existing code owners for the package you want to own to get their approval. ## Release See [release](docs/release.md) for details. ## Contributing Images If you are adding any new images, please use [Excalidraw](https://excalidraw.com). It's a free and open-source web application and doesn't require any account to get started. Once you've created the design, while exporting the image, make sure to tick **"Embed scene into exported file"** option. This allows the image to be imported in an editable format for other contributors later. ## Common Issues Build fails due to dependency issues, e.g. ```sh go: github.com/golangci/golangci-lint@v1.31.0 requires github.com/tommy-muehle/go-mnd@v1.3.1-0.20200224220436-e6f9a994e8fa: invalid pseudo-version: git fetch --unshallow -f origin in /root/go/pkg/mod/cache/vcs/053b1e985f53e43f78db2b3feaeb7e40a2ae482c92734ba3982ca463d5bf19ce: exit status 128: fatal: git fetch-pack: expected shallow list ``` `go env GOPROXY` should return `https://proxy.golang.org,direct`. If it does not, set it as an environment variable: `export GOPROXY=https://proxy.golang.org,direct` ### Makefile Guidelines When adding or modifying the `Makefile`'s in this repository, consider the following design guidelines. Make targets are organized according to whether they apply to the entire repository, or only to an individual module. The [Makefile](./Makefile) SHOULD contain "repo-level" targets. (i.e. targets that apply to the entire repo.) Likewise, `Makefile.Common` SHOULD contain "module-level" targets. (i.e. targets that apply to one module at a time.) Each module should have a `Makefile` at its root that includes `Makefile.Common`. #### Module-level targets Module-level targets SHOULD NOT act on nested modules. For example, running `make lint` at the root of the repo will _only_ evaluate code that is part of the `go.opentelemetry.io/collector` module. This excludes nested modules such as `go.opentelemetry.io/collector/component`. Each module-level target SHOULD have a corresponding repo-level target. For example, `make golint` will run `make lint` in each module. In this way, the entire repository is covered. The root `Makefile` contains some "for each module" targets that can wrap a module-level target into a repo-level target. #### Repo-level targets Whenever reasonable, targets SHOULD be implemented as module-level targets (and wrapped with a repo-level target). However, there are many valid justifications for implementing a standalone repo-level target. 1. The target naturally applies to the repo as a whole. (e.g. Building the collector.) 2. Interaction between modules would be problematic. 3. A necessary tool does not provide a mechanism for scoping its application. (e.g. `porto` cannot be limited to a specific module.) 4. The "for each module" pattern would result in incomplete coverage of the codebase. (e.g. A target that scans all files, not just `.go` files.) #### Default targets The default module-level target (i.e. running `make` in the context of an individual module), should run a substantial set of module-level targets for an individual module. Ideally, this would include *all* module-level targets, but exceptions should be made if a particular target would result in unacceptable latency in the local development loop. The default repo-level target (i.e. running `make` at the root of the repo) should meaningfully validate the entire repo. This should include running the default common target for each module as well as additional repo-level targets. ## How to update the OTLP protocol version When a new OTLP version is published, the following steps are required to update this code base: 1. Edit the top-level Makefile's `OPENTELEMETRY_PROTO_VERSION` variable 2. Run `make genproto` 3. Inspect modifications to the generated code in `pdata/internal/data/protogen` 4. When new fields are added in the protocol, make corresponding changes in `pdata/internal/cmd/pdatagen/internal` 5. Run `make genpdata` 6. Inspect modifications to the generated code in `pdata/*` 7. Run `make genproto-cleanup`, to remove temporary files 8. Update the supported OTLP version in [README.md](./README.md). ## Exceptions While the rules in this and other documents in this repository are what we strive to follow, we acknowledge that it may be unfeasible to apply these rules in some situations. Exceptions to the rules on this and other documents are acceptable if consensus can be obtained from approvers in the pull request they are proposed. A reason for requesting the exception MUST be given in the pull request. Until unanimity is obtained, approvers and maintainers are encouraged to discuss the issue at hand. If a consensus (unanimity) cannot be obtained, the maintainers' group is then tasked with making a decision using its regular means (voting, TC help, etc.). opentelemetry-collector-0.141.0/LICENSE000066400000000000000000000261361511331344600175530ustar00rootroot00000000000000 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. opentelemetry-collector-0.141.0/Makefile000066400000000000000000000311431511331344600202000ustar00rootroot00000000000000include ./Makefile.Common # This is the code that we want to run lint, etc. ALL_SRC := $(shell find . -name '*.go' \ -not -path './internal/tools/*' \ -not -path '*/third_party/*' \ -not -path './pdata/internal/data/protogen/*' \ -not -path './service/internal/zpages/tmplgen/*' \ -type f | sort) # All source code and documents. Used in spell check. ALL_DOC := $(shell find . \( -name "*.md" -o -name "*.yaml" \) \ -type f | sort) # ALL_MODULES includes ./* dirs (excludes . dir) ALL_MODULES := $(shell find . -mindepth 2 \ -type f \ -name "go.mod" \ -not -path "./internal/tools/*" \ -exec dirname {} \; | sort ) CMD?= RUN_CONFIG?=examples/local/otel-config.yaml CONTRIB_PATH=$(CURDIR)/../opentelemetry-collector-contrib COMP_REL_PATH=cmd/otelcorecol/components.go MOD_NAME=go.opentelemetry.io/collector # Function to execute a command. Note the empty line before endef to make sure each command # gets executed separately instead of concatenated with previous one. # Accepts command to execute as first parameter. define exec-command $(1) endef .DEFAULT_GOAL := all .PHONY: all all: checklicense checkdoc misspell goimpi goporto multimod-verify golint gotest all-modules: @echo $(ALL_MODULES) | tr ' ' '\n' | sort .PHONY: gomoddownload gomoddownload: @$(MAKE) for-all-target TARGET="moddownload" .PHONY: gotest gotest: @$(MAKE) for-all-target TARGET="test" .PHONY: gobenchmark gobenchmark: @$(MAKE) for-all-target TARGET="benchmark" cat `find . -name benchmark.txt` > benchmarks.txt .PHONY: gotest-with-cover gotest-with-cover: @$(MAKE) for-all-target TARGET="test-with-cover" $(GOCMD) tool covdata textfmt -i=./coverage/unit -o ./coverage.txt .PHONY: gotest-with-junit gotest-with-junit: @$(MAKE) for-all-target TARGET="test-with-junit" .PHONY: goporto goporto: $(GO_TOOL) porto -w --include-internal --skip-dirs "^cmd/mdatagen/third_party$$" ./ .PHONY: for-all for-all: @echo "running $${CMD} in root" @$${CMD} @set -e; for dir in $(GOMODULES); do \ (cd "$${dir}" && \ echo "running $${CMD} in $${dir}" && \ $${CMD} ); \ done .PHONY: golint golint: @$(MAKE) for-all-target TARGET="lint" .PHONY: goimpi goimpi: @$(MAKE) for-all-target TARGET="impi" .PHONY: gofmt gofmt: @$(MAKE) for-all-target TARGET="fmt" .PHONY: gotidy gotidy: @$(MAKE) for-all-target TARGET="tidy" .PHONY: gogenerate gogenerate: cd cmd/mdatagen && $(GOCMD) install . @$(MAKE) for-all-target TARGET="generate" $(MAKE) fmt .PHONY: govulncheck govulncheck: @$(MAKE) for-all-target TARGET="vulncheck" .PHONY: addlicense addlicense: @ADDLICENSEOUT=`$(GO_TOOL) addlicense -s=only -y "" -c "The OpenTelemetry Authors" $(ALL_SRC) 2>&1`; \ if [ "$$ADDLICENSEOUT" ]; then \ echo "$(ADDLICENSE) FAILED => add License errors:\n"; \ echo "$$ADDLICENSEOUT\n"; \ exit 1; \ else \ echo "Add License finished successfully"; \ fi .PHONY: checklicense checklicense: @licRes=$$(for f in $$(find . -type f \( -iname '*.go' -o -iname '*.sh' \) ! -path '**/third_party/*') ; do \ awk '/Copyright The OpenTelemetry Authors|generated|GENERATED/ && NR<=3 { found=1; next } END { if (!found) print FILENAME }' $$f; \ awk '/SPDX-License-Identifier: Apache-2.0|generated|GENERATED/ && NR<=4 { found=1; next } END { if (!found) print FILENAME }' $$f; \ done); \ if [ -n "$${licRes}" ]; then \ echo "license header checking failed:"; echo "$${licRes}"; \ exit 1; \ fi .PHONY: misspell misspell: $(GO_TOOL) misspell -error $(ALL_DOC) .PHONY: misspell-correction misspell-correction: $(GO_TOOL) misspell -w $(ALL_DOC) .PHONY: run run: otelcorecol ./bin/otelcorecol_$(GOOS)_$(GOARCH) --config ${RUN_CONFIG} ${RUN_ARGS} # Append root module to all modules GOMODULES = $(ALL_MODULES) $(PWD) # Define a delegation target for each module .PHONY: $(GOMODULES) $(GOMODULES): @echo "Running target '$(TARGET)' in module '$@'" $(MAKE) -C $@ $(TARGET) # Triggers each module's delegation target .PHONY: for-all-target for-all-target: $(GOMODULES) .PHONY: check-component check-component: ifndef COMPONENT $(error COMPONENT variable was not defined) endif # Build the Collector executable. .PHONY: otelcorecol otelcorecol: pushd cmd/otelcorecol && CGO_ENABLED=0 $(GOCMD) build -trimpath -o ../../bin/otelcorecol_$(GOOS)_$(GOARCH) -tags "grpcnotrace" ./... && popd .PHONY: genotelcorecol genotelcorecol: pushd cmd/builder/ && $(GOCMD) run ./ --skip-compilation --config ../otelcorecol/builder-config.yaml --output-path ../otelcorecol && popd $(MAKE) -C cmd/otelcorecol fmt .PHONY: actionlint actionlint: $(GO_TOOL) actionlint -config-file .github/actionlint.yaml -color .github/workflows/*.yml .github/workflows/*.yaml .PHONY: ocb ocb: $(MAKE) -C cmd/builder config $(MAKE) -C cmd/builder ocb # Generate structs, functions and tests for pdata package. genpdata: cd internal/cmd/pdatagen && $(GOCMD) run main.go -C $(SRC_ROOT) $(MAKE) -C pdata fmt DOCKERCMD ?= docker DOCKER_PROTOBUF ?= otel/build-protobuf:0.23.0 PROTO_SRC_DIRS := exporter/exporterhelper/internal/queue PROTO_FILES := $(foreach dir,$(PROTO_SRC_DIRS),$(wildcard $(dir)/*.proto)) PROTOC := $(DOCKERCMD) run --rm -u ${shell id -u} -v${PWD}:${PWD} -w${PWD} ${DOCKER_PROTOBUF} --proto_path=${PWD} --go_out=plugins=grpc,paths=source_relative:. .PHONY: genproto genproto: @echo "Generating Go code for proto files" @echo "Found proto files: $(PROTO_FILES)" $(foreach file,$(PROTO_FILES),$(call exec-command,$(PROTOC) $(file))) $(MAKE) fmt ALL_MOD_PATHS := "" $(ALL_MODULES:.%=%) .PHONY: prepare-contrib prepare-contrib: @echo Setting contrib at $(CONTRIB_PATH) to use this core checkout @$(MAKE) -j2 -C $(CONTRIB_PATH) for-all CMD="$(GOCMD) mod edit \ $(addprefix -replace ,$(join $(ALL_MOD_PATHS:%=go.opentelemetry.io/collector%=),$(ALL_MOD_PATHS:%=$(CURDIR)%)))" @$(MAKE) -j2 -C $(CONTRIB_PATH) gotidy @$(MAKE) generate-contrib # Checks that the HEAD of the contrib repo checked out in CONTRIB_PATH compiles # against the current version of this repo. .PHONY: check-contrib check-contrib: @echo -e "\nRunning tests" @$(MAKE) -C $(CONTRIB_PATH) gotest @if [ -z "$(SKIP_RESTORE_CONTRIB)" ]; then \ $(MAKE) restore-contrib; \ fi .PHONY: generate-contrib generate-contrib: @echo -e "\nGenerating files in contrib" $(MAKE) -C $(CONTRIB_PATH) -B install-tools $(MAKE) -C $(CONTRIB_PATH) generate GROUP=all # Restores contrib to its original state after running check-contrib. .PHONY: restore-contrib restore-contrib: @echo -e "\nRestoring contrib at $(CONTRIB_PATH) to its original state" @$(MAKE) -C $(CONTRIB_PATH) for-all CMD="$(GOCMD) mod edit \ $(addprefix -dropreplace ,$(ALL_MOD_PATHS:%=go.opentelemetry.io/collector%))" @$(MAKE) -C $(CONTRIB_PATH) for-all CMD="$(GOCMD) mod tidy" # List of directories where certificates are stored for unit tests. CERT_DIRS := localhost|""|config/configgrpc/testdata \ localhost|""|config/confighttp/testdata \ example1|"-1"|config/configtls/testdata \ example2|"-2"|config/configtls/testdata cert-domain = $(firstword $(subst |, ,$1)) cert-suffix = $(word 2,$(subst |, ,$1)) cert-dir = $(word 3,$(subst |, ,$1)) # Generate certificates for unit tests relying on certificates. .PHONY: certs certs: $(foreach dir, $(CERT_DIRS), $(call exec-command, @internal/buildscripts/gen-certs.sh -o $(call cert-dir,$(dir)) -s $(call cert-suffix,$(dir)) -m $(call cert-domain,$(dir)))) # Generate certificates for unit tests relying on certificates without copying certs to specific test directories. .PHONY: certs-dryrun certs-dryrun: @internal/buildscripts/gen-certs.sh -d .PHONY: checkapi checkapi: $(GO_TOOL) checkapi -folder . -config .checkapi.yaml # Verify existence of READMEs for components specified as default components in the collector. .PHONY: checkdoc checkdoc: $(GO_TOOL) checkfile --project-path $(CURDIR) --component-rel-path $(COMP_REL_PATH) --module-name $(MOD_NAME) --file-name "README.md" # Construct new API state snapshots .PHONY: apidiff-build apidiff-build: @$(foreach pkg,$(ALL_PKGS),$(call exec-command,./internal/buildscripts/gen-apidiff.sh -p $(pkg))) # If we are running in CI, change input directory ifeq ($(CI), true) APICOMPARE_OPTS=$(COMPARE_OPTS) else APICOMPARE_OPTS=-d "./internal/data/apidiff" endif # Compare API state snapshots .PHONY: apidiff-compare apidiff-compare: @$(foreach pkg,$(ALL_PKGS),$(call exec-command,./internal/buildscripts/compare-apidiff.sh -p $(pkg))) .PHONY: multimod-verify multimod-verify: @echo "Validating versions.yaml" $(GO_TOOL) multimod verify MODSET?=stable .PHONY: multimod-prerelease multimod-prerelease: $(GO_TOOL) multimod prerelease -s=true -b=false -v ./versions.yaml -m ${MODSET} $(MAKE) gotidy COMMIT?=HEAD REMOTE?=git@github.com:open-telemetry/opentelemetry-collector.git .PHONY: push-tags push-tags: $(GO_TOOL) multimod verify set -e; for tag in `$(GO_TOOL) multimod tag -m ${MODSET} -c ${COMMIT} --print-tags | grep -v "Using" `; do \ echo "pushing tag $${tag}"; \ git push ${REMOTE} $${tag}; \ done; .PHONY: check-changes check-changes: $(GO_TOOL) multimod diff -p $(PREVIOUS_VERSION) -m $(MODSET) .PHONY: prepare-release prepare-release: ifndef MODSET @echo "MODSET not defined" @echo "usage: make prepare-release RELEASE_CANDIDATE= PREVIOUS_VERSION= MODSET=beta" exit 1 endif ifdef PREVIOUS_VERSION @echo "Previous version $(PREVIOUS_VERSION)" else @echo "PREVIOUS_VERSION not defined" @echo "usage: make prepare-release RELEASE_CANDIDATE= PREVIOUS_VERSION= MODSET=beta" exit 1 endif ifdef RELEASE_CANDIDATE @echo "Preparing ${MODSET} release $(RELEASE_CANDIDATE)" else @echo "RELEASE_CANDIDATE not defined" @echo "usage: make prepare-release RELEASE_CANDIDATE= PREVIOUS_VERSION= MODSET=beta" exit 1 endif # ensure a clean branch git diff -s --exit-code || (echo "local repository not clean"; exit 1) # update files with new version sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' versions.yaml sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' ./cmd/builder/internal/builder/config.go sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' ./cmd/builder/test/core.builder.yaml sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' ./cmd/otelcorecol/builder-config.yaml sed -i.bak 's/$(PREVIOUS_VERSION)/$(RELEASE_CANDIDATE)/g' examples/k8s/otel-config.yaml find . -name "*.bak" -type f -delete # commit changes before running multimod git add . git commit -m "prepare release $(RELEASE_CANDIDATE)" $(MAKE) multimod-prerelease # regenerate files $(MAKE) -C cmd/builder config $(MAKE) genotelcorecol git add . git commit -m "add multimod changes $(RELEASE_CANDIDATE)" || (echo "no multimod changes to commit") .PHONY: clean clean: test -d bin && $(RM) bin/* .PHONY: checklinks checklinks: command -v $(DOCKERCMD) >/dev/null 2>&1 || { echo >&2 "$(DOCKERCMD) not installed. Install before continuing"; exit 1; } $(DOCKERCMD) run -w /home/repo --rm \ --mount 'type=bind,source='$(PWD)',target=/home/repo' \ lycheeverse/lychee \ --config .github/lychee.toml \ --root-dir /home/repo \ -v \ --no-progress './**/*.md' # error message "failed to sync logger: sync /dev/stderr: inappropriate ioctl for device" # is a known issue but does not affect function. .PHONY: crosslink crosslink: @echo "Executing crosslink" $(GO_TOOL) crosslink --root=$(shell pwd) --prune FILENAME?=$(shell git branch --show-current) .PHONY: chlog-new chlog-new: $(GO_TOOL) chloggen new --config $(CHLOGGEN_CONFIG) --filename $(FILENAME) .PHONY: chlog-validate chlog-validate: $(GO_TOOL) chloggen validate --config $(CHLOGGEN_CONFIG) .PHONY: chlog-preview chlog-preview: $(GO_TOOL) chloggen update --config $(CHLOGGEN_CONFIG) --dry .PHONY: chlog-update chlog-update: $(GO_TOOL) chloggen update --config $(CHLOGGEN_CONFIG) --version $(VERSION) .PHONY: builder-integration-test builder-integration-test: cd ./cmd/builder && ./test/test.sh .PHONY: mdatagen-test mdatagen-test: cd cmd/mdatagen && $(GOCMD) install . cd cmd/mdatagen && $(GOCMD) generate ./... cd cmd/mdatagen && $(MAKE) fmt cd cmd/mdatagen && $(GOCMD) test ./... GITHUBGEN_ARGS ?= -skipgithub GITHUBGEN := $(GO_TOOL) githubgen $(GITHUBGEN_ARGS) .PHONY: generate-gh-issue-templates generate-gh-issue-templates: $(GITHUBGEN) issue-templates .PHONY: generate-codeowners generate-codeowners: $(GITHUBGEN) --default-codeowner "open-telemetry/collector-approvers" codeowners .PHONY: gengithub gengithub: generate-codeowners generate-gh-issue-templates .PHONY: gendistributions gendistributions: $(GITHUBGEN) distributions .PHONY: generate-chloggen-components generate-chloggen-components: $(GITHUBGEN) chloggen-components opentelemetry-collector-0.141.0/Makefile.Common000066400000000000000000000050621511331344600214300ustar00rootroot00000000000000SHELL = /bin/bash # ALL_PKGS is the list of all packages where ALL_SRC files reside. ALL_PKGS := $(sort $(shell go list ./...)) # COVER_PKGS is the list of packages to include in the coverage COVER_PKGS := $(shell go list ./... | tr "\n" ",") CURR_MOD := $(shell go list -m | tr '/' '-' ) GOCMD?= go GOOS := $(shell $(GOCMD) env GOOS) GOARCH := $(shell $(GOCMD) env GOARCH) GOTEST_TIMEOUT?=240s # -race is not supported on windows arm64 GOTEST_OPT?= -timeout $(GOTEST_TIMEOUT) $(if $(and $(filter windows,$(GOOS)), $(filter arm64,$(GOARCH))),, -race) # SRC_ROOT is the top of the source tree. SRC_ROOT := $(shell git rev-parse --show-toplevel) TOOLS_MOD_DIR := $(SRC_ROOT)/internal/tools TOOLS_MOD_FILE := $(TOOLS_MOD_DIR)/go.mod GO_TOOL := $(GOCMD) tool -modfile $(TOOLS_MOD_FILE) CHLOGGEN_CONFIG := .chloggen/config.yaml # no trailing slash JUNIT_OUT_DIR ?= $(TOOLS_MOD_DIR)/testresults .PHONY: test test: $(GO_TOOL) gotestsum --packages="./..." -- $(GOTEST_OPT) .PHONY: test-with-cover test-with-cover: mkdir -p $(PWD)/coverage/unit $(GO_TOOL) gotestsum \ --packages="./..." -- \ $(GOTEST_OPT) -cover -covermode=atomic -coverpkg $(COVER_PKGS) -args -test.gocoverdir="$(PWD)/coverage/unit" .PHONY: test-with-junit test-with-junit: mkdir -p $(JUNIT_OUT_DIR) $(GO_TOOL) gotestsum \ --packages="./..." --junitfile $(JUNIT_OUT_DIR)/$(CURR_MOD)-junit.xml -- \ $(GOTEST_OPT) ./... .PHONY: benchmark benchmark: MEMBENCH=yes $(GO_TOOL) gotestsum \ --packages="$(ALL_PKGS)" -- \ -bench=. -run=notests ./... | tee benchmark.txt .PHONY: fmt fmt: common/gofmt common/goimports common/gofumpt # `modernize' cannot be installed as a Go tool via `go get -tool'. # # See [1] for more details. # # [1]: https://github.com/golang/go/issues/73279 .PHONY: modernize modernize: $(GOCMD) run \ golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest \ -fix -test -v ./... .PHONY: tidy tidy: rm -fr go.sum $(GOCMD) mod tidy -compat=1.24.0 .PHONY: lint lint: $(GO_TOOL) golangci-lint run .PHONY: common/gofmt common/gofmt: gofmt -w -s ./ .PHONY: common/goimports common/goimports: $(GO_TOOL) goimports -w -local go.opentelemetry.io/collector ./ .PHONY: common/gofumpt common/gofumpt: $(GO_TOOL) gofumpt -l -w -extra . .PHONY: vulncheck vulncheck: $(GO_TOOL) govulncheck ./... .PHONY: generate generate: $(GOCMD) generate ./... .PHONY: impi impi: $(GO_TOOL) impi \ --local go.opentelemetry.io/collector \ --scheme stdThirdPartyLocal ./... .PHONY: moddownload moddownload: $(GOCMD) mod download timebenchmark: go test -bench=. -benchtime=1s ./... opentelemetry-collector-0.141.0/README.md000066400000000000000000000576311511331344600200310ustar00rootroot00000000000000---

Getting Started   •   Getting Involved   •   Getting In Touch

Build Status Go Report Card Codecov Status GitHub release (latest by date including pre-releases)
Fuzzing Status

Vision   •   Configuration   •   Monitoring   •   Security   •   Package

--- # OpenTelemetry Icon OpenTelemetry Collector The OpenTelemetry Collector offers a vendor-agnostic implementation on how to receive, process and export telemetry data. In addition, it removes the need to run, operate and maintain multiple agents/collectors in order to support open-source telemetry data formats (e.g. Jaeger, Prometheus, etc.) to multiple open-source or commercial back-ends. Objectives: - Usable: Reasonable default configuration, supports popular protocols, runs and collects out of the box. - Performant: Highly stable and performant under varying loads and configurations. - Observable: An exemplar of an observable service. - Extensible: Customizable without touching the core code. - Unified: Single codebase, deployable as an agent or collector with support for traces, metrics and logs. ## Community The OpenTelemetry Collector SIG is present at the [#otel-collector](https://cloud-native.slack.com/archives/C01N6P7KR6W) channel on the CNCF Slack and [meets once a week](https://github.com/open-telemetry/community#implementation-sigs) via video calls. Everyone is invited to join those calls, which typically serves the following purposes: - meet the humans behind the project - get an opinion about specific proposals - look for a sponsor for a proposed component after trying already via GitHub and Slack - get attention to a specific pull-request that got stuck and is difficult to discuss asynchronously We rotate our video calls between three time slots, in order to allow everyone to join at least once every three meetings. The rotation order is as follows: Tuesday: - [17:00 PT](https://dateful.com/convert/pst-pdt-pacific-time?t=1700) Wednesday: - [09:00 PT](https://dateful.com/convert/pst-pdt-pacific-time?t=0900) - [05:00 PT](https://dateful.com/convert/pst-pdt-pacific-time?t=0500) Contributors to the project are also welcome to have ad-hoc meetings for synchronous discussions about specific points. Post a note in #otel-collector-dev on Slack inviting others, specifying the topic to be discussed. Unless there are strong reasons to keep the meeting private, please make it an open invitation for other contributors to join. Try also to identify who would be the other contributors interested on that topic and in which timezones they are. Remember that our source of truth is GitHub: every decision made via Slack or video calls has to be recorded in the relevant GitHub issue. Ideally, the agenda items from the meeting notes would include a link to the issue or pull request where a discussion is happening already. We acknowledge that not everyone can join Slack or the synchronous calls and don't want them to feel excluded. ## Supported OTLP version This code base is currently built against using OTLP protocol v1.5.0, considered Stable. [See the OpenTelemetry Protocol Stability definition here.](https://github.com/open-telemetry/opentelemetry-proto?tab=readme-ov-file#stability-definition) ## Stability levels See [Stability Levels and versioning](docs/component-stability.md) for more details. ## Compatibility When used as a library, the OpenTelemetry Collector attempts to track the currently supported versions of Go, as [defined by the Go team](https://go.dev/doc/devel/release#policy). Removing support for an unsupported Go version is not considered a breaking change. Support for Go versions on the OpenTelemetry Collector is updated as follows: 1. The first release after the release of a new Go minor version `N` will add build and tests steps for the new Go minor version. 2. The first release after the release of a new Go minor version `N` will remove support for Go version `N-2`. Official OpenTelemetry Collector distro binaries will be built with a release in the latest Go minor version series. ## Verifying the images signatures > [!NOTE] > To verify a signed artifact or blob, first [install Cosign](https://docs.sigstore.dev/cosign/system_config/installation/), then follow the instructions below. We are signing the images `otel/opentelemetry-collector` and `otel/opentelemetry-collector-contrib` using [sigstore cosign](https://github.com/sigstore/cosign) tool and to verify the signatures you can run the following command: ```console $ cosign verify \ --certificate-identity=https://github.com/open-telemetry/opentelemetry-collector-releases/.github/workflows/base-release.yaml@refs/tags/ \ --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ ``` where: - ``: is the release that you want to validate - ``: is the image that you want to check Example: ```console $ cosign verify --certificate-identity=https://github.com/open-telemetry/opentelemetry-collector-releases/.github/workflows/base-release.yaml@refs/tags/v0.98.0 --certificate-oidc-issuer=https://token.actions.githubusercontent.com ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.98.0 Verification for ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib:0.98.0 -- The following checks were performed on each of these signatures: - The cosign claims were validated - Existence of the claims in the transparency log was verified offline - The code-signing certificate was verified using trusted certificate authority certificates [{"critical":{"identity":{"docker-reference":"ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib"},"image":{"docker-manifest-digest":"sha256:5cea85bcbc734a3c0a641368e5a4ea9d31b472997e9f2feca57eeb4a147fcf1a"},"type":"cosign container image signature"},"optional":{"1.3.6.1.4.1.57264.1.1":"https://token.actions.githubusercontent.com","1.3.6.1.4.1.57264.1.2":"push","1.3.6.1.4.1.57264.1.3":"9e20bf5c142e53070ccb8320a20315fffb41469e","1.3.6.1.4.1.57264.1.4":"Release Contrib","1.3.6.1.4.1.57264.1.5":"open-telemetry/opentelemetry-collector-releases","1.3.6.1.4.1.57264.1.6":"refs/tags/v0.98.0","Bundle":{"SignedEntryTimestamp":"MEUCIQDdlmNeKXQrHnonwWiHLhLLwFDVDNoOBCn2sv85J9P8mgIgDQFssWJImo1hn38VlojvSCL7Qq5FMmtnGu0oLsNdOm8=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiIxMzVjY2RlN2YzZTNhYjU2NmFmYzJhYWU3MDljYmJlNmFhMDZlZWMzNDA2MWNkZjMyNmRhYzM2MmY0NWM4Yjg4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUURFbDV6N0diMWRVYkM5KzR4c1VvbDhMcWZNV2hiTzhkdEpwdExyMXhUNWZnSWdTdEwwN1I0ZDA5R2x0ZkV0azJVbmlJSlJhQVdrVDJNWDVtRXJNSlplc2pRPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaG9ha05EUW5jeVowRjNTVUpCWjBsVlNETkNjRFZTYlVSU1VpOXphMWg0YVdWUFlrcFhSbmRrUjNNNGQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFJkMDVFUlhoTlJGRjRUMFJOTlZkb1kwNU5hbEYzVGtSRmVFMUVVWGxQUkUwMVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZyWlRsSE1ubHNjMjkzYVZZMmRFOVZSazlRVVhNd2NXY3hTSEV5WmpsVUx6UTJZbEFLU1ZSNE0ybFRkVXBhV0hGc1dEUldWV2Q1VlZndmNVazJhblZ2WlZSVEswaG5XVUoyYjBseVNERTFUeTltZEd0VmVtRlBRMEpwZDNkbloxbHZUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZHTkRrMUNrdDFNRWhqTm5rek1rNUNTVTFFU21ReVpuWkxNMHBCZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDJkWldVZEJNVlZrUlZGRlFpOTNVamhOU0hGSFpVZG9NR1JJUW5wUGFUaDJXakpzTUdGSVZtbE1iVTUyWWxNNWRtTkhWblZNV0ZKc1lrZFdkQXBhV0ZKNVpWTTVkbU5IVm5Wa1IxWnpXbGN4YkdSSVNqVk1WMDUyWWtkNGJGa3pVblpqYVRGNVdsZDRiRmxZVG14amVUaDFXakpzTUdGSVZtbE1NMlIyQ21OdGRHMWlSemt6WTNrNWFWbFlUbXhNV0Vwc1lrZFdhR015VlhWbFYwWjBZa1ZDZVZwWFducE1NMUpvV2pOTmRtUnFRWFZQVkdkMVRVUkJOVUpuYjNJS1FtZEZSVUZaVHk5TlFVVkNRa04wYjJSSVVuZGplbTkyVEROU2RtRXlWblZNYlVacVpFZHNkbUp1VFhWYU1td3dZVWhXYVdSWVRteGpiVTUyWW01U2JBcGlibEYxV1RJNWRFMUNTVWREYVhOSFFWRlJRbWMzT0hkQlVVbEZRa2hDTVdNeVozZE9aMWxMUzNkWlFrSkJSMFIyZWtGQ1FYZFJiMDlYVlhsTlIwcHRDazVYVFhoT1JFcHNUbFJOZDA1NlFtcFpNa2swVFhwSmQxbFVTWGROZWtVeFdtMWFiVmxxVVhoT1JGazFXbFJCWkVKbmIzSkNaMFZGUVZsUEwwMUJSVVVLUWtFNVUxcFhlR3haV0U1c1NVVk9kbUp1VW5saFYwbDNVRkZaUzB0M1dVSkNRVWRFZG5wQlFrSlJVWFppTTBKc1lta3hNRnBYZUd4aVYxWXdZMjVyZGdwaU0wSnNZbTVTYkdKSFZuUmFXRko1WlZNeGFtSXllSE5hVjA0d1lqTkpkR050Vm5OYVYwWjZXbGhOZDBoM1dVdExkMWxDUWtGSFJIWjZRVUpDWjFGU0NtTnRWbTFqZVRrd1dWZGtla3d6V1hkTWFtczBUR3BCZDA5M1dVdExkMWxDUWtGSFJIWjZRVUpEUVZGMFJFTjBiMlJJVW5kamVtOTJURE5TZG1FeVZuVUtURzFHYW1SSGJIWmliazExV2pKc01HRklWbWxrV0U1c1kyMU9kbUp1VW14aWJsRjFXVEk1ZEUxSlIwbENaMjl5UW1kRlJVRlpUeTlOUVVWS1FraHZUUXBsUjJnd1pFaENlazlwT0haYU1td3dZVWhXYVV4dFRuWmlVemwyWTBkV2RVeFlVbXhpUjFaMFdsaFNlV1ZUT1haalIxWjFaRWRXYzFwWE1XeGtTRW8xQ2t4WFRuWmlSM2hzV1ROU2RtTnBNWGxhVjNoc1dWaE9iR041T0hWYU1td3dZVWhXYVV3elpIWmpiWFJ0WWtjNU0yTjVPV2xaV0U1c1RGaEtiR0pIVm1nS1l6SlZkV1ZYUm5SaVJVSjVXbGRhZWt3elVtaGFNMDEyWkdwQmRVOVVaM1ZOUkVFMFFtZHZja0puUlVWQldVOHZUVUZGUzBKRGIwMUxSR3hzVFdwQ2FRcGFhbFpxVFZSUmVWcFVWWHBOUkdOM1dUSk9hVTlFVFhsTlIwVjVUVVJOZUU1WFdtMWFiVWt3VFZSUk1rOVhWWGRJVVZsTFMzZFpRa0pCUjBSMmVrRkNDa04zVVZCRVFURnVZVmhTYjJSWFNYUmhSemw2WkVkV2EwMUdTVWREYVhOSFFWRlJRbWMzT0hkQlVYZEZVa0Y0UTJGSVVqQmpTRTAyVEhrNWJtRllVbThLWkZkSmRWa3lPWFJNTWpsM1dsYzBkR1JIVm5OYVZ6RnNaRWhLTlV3eU9YZGFWelV3V2xkNGJHSlhWakJqYm10MFdUSTVjMkpIVm1wa1J6bDVURmhLYkFwaVIxWm9ZekpXZWsxRVowZERhWE5IUVZGUlFtYzNPSGRCVVRCRlMyZDNiMDlYVlhsTlIwcHRUbGROZUU1RVNteE9WRTEzVG5wQ2Fsa3lTVFJOZWtsM0NsbFVTWGROZWtVeFdtMWFiVmxxVVhoT1JGazFXbFJCYUVKbmIzSkNaMFZGUVZsUEwwMUJSVTlDUWsxTlJWaEtiRnB1VFhaa1IwWnVZM2s1TWsxRE5EVUtUME0wZDAxQ2EwZERhWE5IUVZGUlFtYzNPSGRCVVRoRlEzZDNTazVFUVhkTmFsVjZUbXBqTWsxRVJVZERhWE5IUVZGUlFtYzNPSGRCVWtGRlNYZDNhQXBoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NamwzV2xjMGRHUkhWbk5hVnpGc1pFaEtOVTFDWjBkRGFYTkhRVkZSUW1jM09IZEJVa1ZGQ2tObmQwbE9SR3MxVDFSbmQwMUVTWGRuV1hOSFEybHpSMEZSVVVKbk56aDNRVkpKUldaUmVEZGhTRkl3WTBoTk5reDVPVzVoV0ZKdlpGZEpkVmt5T1hRS1RESTVkMXBYTkhSa1IxWnpXbGN4YkdSSVNqVk1NamwzV2xjMU1GcFhlR3hpVjFZd1kyNXJkRmt5T1hOaVIxWnFaRWM1ZVV4WVNteGlSMVpvWXpKV2VncE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYUlpNamwxWkVoS2NGbHBOVFZaVnpGelVVaEtiRnB1VFhaa1IwWnVDbU41T1RKTlF6UTFUME0wZDAxRVowZERhWE5IUVZGUlFtYzNPSGRCVWsxRlMyZDNiMDlYVlhsTlIwcHRUbGROZUU1RVNteE9WRTEzVG5wQ2Fsa3lTVFFLVFhwSmQxbFVTWGROZWtVeFdtMWFiVmxxVVhoT1JGazFXbFJCVlVKbmIzSkNaMFZGUVZsUEwwMUJSVlZDUVZsTlFraENNV015WjNka1VWbExTM2RaUWdwQ1FVZEVkbnBCUWtaUlVtNUVSMVp2WkVoU2QyTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZak5DYkdKcE1UQmFWM2hzWWxkV01HTnVhM1ppTTBKc0NtSnVVbXhpUjFaMFdsaFNlV1ZUTVdwaU1uaHpXbGRPTUdJelNYUmpiVlp6V2xkR2VscFlUWFpaVjA0d1lWYzVkV041T1hsa1Z6VjZUSHBuTWs1RVJYZ0tUbnBGTVU1cVkzWlpXRkl3V2xjeGQyUklUWFpOYWtGWFFtZHZja0puUlVWQldVOHZUVUZGVjBKQlowMUNia0l4V1cxNGNGbDZRMEpwWjFsTFMzZFpRZ3BDUVVoWFpWRkpSVUZuVWpoQ1NHOUJaVUZDTWtGT01EbE5SM0pIZUhoRmVWbDRhMlZJU214dVRuZExhVk5zTmpRemFubDBMelJsUzJOdlFYWkxaVFpQQ2tGQlFVSnFjM1JvUlVOUlFVRkJVVVJCUldOM1VsRkpaMWg2Y2xaME0xQjRkU3ROWVZKRkswUkdORzlGUldNMGVucHphSGR1VDJ4bGMwZGlla2xwYnpNS0wxWmpRMGxSUkZNelJ6QmlNemRhYUhRNGFITjJUSEozYkc1UFFXYzJWRXh1U1ZSS09HTjNkMVEzTW5sMVRVdFlUbFJCUzBKblozRm9hMnBQVUZGUlJBcEJkMDV1UVVSQ2EwRnFRWGxFUkZSYVFqQlRPVXBGYkZsSGJuTnZWVmhLYm04MU5Fc3ZUVUZUTlN0RFFVMU9lbWRqUWpWQ2JrRk5OMWhNUjBoV01HRnhDbVpaY21weFkyOXFia3RaUTAxSFRWRnFjalpUVGt0Q2NVaEtZVGwxTDBSTlQySlpNa0pKTVV0ME4yTnhOemhFT0VOcVMzQmFVblJoYnpadFVVMUVZMk1LUms5M2VYWnhWalJPVld0dlpsRTlQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1712809120,"logIndex":84797936,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}},"Issuer":"https://token.actions.githubusercontent.com","Subject":"https://github.com/open-telemetry/opentelemetry-collector-releases/.github/workflows/base-release.yaml@refs/tags/v0.98.0","githubWorkflowName":"Release Contrib","githubWorkflowRef":"refs/tags/v0.98.0","githubWorkflowRepository":"open-telemetry/opentelemetry-collector-releases","githubWorkflowSha":"9e20bf5c142e53070ccb8320a20315fffb41469e","githubWorkflowTrigger":"push"}},{"critical":{"identity":{"docker-reference":"ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib"},"image":{"docker-manifest-digest":"sha256:5cea85bcbc734a3c0a641368e5a4ea9d31b472997e9f2feca57eeb4a147fcf1a"},"type":"cosign container image signature"},"optional":{"1.3.6.1.4.1.57264.1.1":"https://token.actions.githubusercontent.com","1.3.6.1.4.1.57264.1.2":"push","1.3.6.1.4.1.57264.1.3":"9e20bf5c142e53070ccb8320a20315fffb41469e","1.3.6.1.4.1.57264.1.4":"Release Contrib","1.3.6.1.4.1.57264.1.5":"open-telemetry/opentelemetry-collector-releases","1.3.6.1.4.1.57264.1.6":"refs/tags/v0.98.0","Bundle":{"SignedEntryTimestamp":"MEUCIQD1ehDnPO6fzoPIpeQ3KFuYHHBiX7RcEbpo9B2r7JAlzwIgZ1bsuQz7gAXbNU1IEdsTQgfAnRk3xVXO16GnKXM2sAQ=","Payload":{"body":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiIxMzVjY2RlN2YzZTNhYjU2NmFmYzJhYWU3MDljYmJlNmFhMDZlZWMzNDA2MWNkZjMyNmRhYzM2MmY0NWM4Yjg4In19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJRU92QXl0aE5RVGNvNHFMdG9GZUVOV0toNCtEK2I5SUxyYWhoa09WMmVBM0FpQjNEL2FpUGd1T05zUlB5alhaWk1hdnlCam0vMkVxNFNUMkZJWHozTnpyYWc9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaHBSRU5EUW5jMlowRjNTVUpCWjBsVlZuRlRLMnd4WXpoMWVFUktOWEppZDAxMlVuaDBSR3hXVW1nMGQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFJkMDVFUlhoTlJGRjRUMFJSZVZkb1kwNU5hbEYzVGtSRmVFMUVVWGxQUkZGNVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVYyWlRCdGJrRkdRVzl1TVZoUGRIVlRMMXBNT0djeE5YUlJkVmxPTmtRemVUUlBWM0FLT1ZSTFMwUlVkRkJHU2xST1ZrWlJkVTlKUWs1bVJqWk1ORTlGYkd4dlZuUndaSE5uYjB0NVZGTnlPR3hTV1c1S1JIRlBRMEpwTUhkbloxbHdUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZDSzFkSENuVmtlRE5IZUcxS1RWUkpUVVJyYW13clJtdzFXRzkzZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDJkWldVZEJNVlZrUlZGRlFpOTNVamhOU0hGSFpVZG9NR1JJUW5wUGFUaDJXakpzTUdGSVZtbE1iVTUyWWxNNWRtTkhWblZNV0ZKc1lrZFdkQXBhV0ZKNVpWTTVkbU5IVm5Wa1IxWnpXbGN4YkdSSVNqVk1WMDUyWWtkNGJGa3pVblpqYVRGNVdsZDRiRmxZVG14amVUaDFXakpzTUdGSVZtbE1NMlIyQ21OdGRHMWlSemt6WTNrNWFWbFlUbXhNV0Vwc1lrZFdhR015VlhWbFYwWjBZa1ZDZVZwWFducE1NMUpvV2pOTmRtUnFRWFZQVkdkMVRVUkJOVUpuYjNJS1FtZEZSVUZaVHk5TlFVVkNRa04wYjJSSVVuZGplbTkyVEROU2RtRXlWblZNYlVacVpFZHNkbUp1VFhWYU1td3dZVWhXYVdSWVRteGpiVTUyWW01U2JBcGlibEYxV1RJNWRFMUNTVWREYVhOSFFWRlJRbWMzT0hkQlVVbEZRa2hDTVdNeVozZE9aMWxMUzNkWlFrSkJSMFIyZWtGQ1FYZFJiMDlYVlhsTlIwcHRDazVYVFhoT1JFcHNUbFJOZDA1NlFtcFpNa2swVFhwSmQxbFVTWGROZWtVeFdtMWFiVmxxVVhoT1JGazFXbFJCWkVKbmIzSkNaMFZGUVZsUEwwMUJSVVVLUWtFNVUxcFhlR3haV0U1c1NVVk9kbUp1VW5saFYwbDNVRkZaUzB0M1dVSkNRVWRFZG5wQlFrSlJVWFppTTBKc1lta3hNRnBYZUd4aVYxWXdZMjVyZGdwaU0wSnNZbTVTYkdKSFZuUmFXRko1WlZNeGFtSXllSE5hVjA0d1lqTkpkR050Vm5OYVYwWjZXbGhOZDBoM1dVdExkMWxDUWtGSFJIWjZRVUpDWjFGU0NtTnRWbTFqZVRrd1dWZGtla3d6V1hkTWFtczBUR3BCZDA5M1dVdExkMWxDUWtGSFJIWjZRVUpEUVZGMFJFTjBiMlJJVW5kamVtOTJURE5TZG1FeVZuVUtURzFHYW1SSGJIWmliazExV2pKc01HRklWbWxrV0U1c1kyMU9kbUp1VW14aWJsRjFXVEk1ZEUxSlIwbENaMjl5UW1kRlJVRlpUeTlOUVVWS1FraHZUUXBsUjJnd1pFaENlazlwT0haYU1td3dZVWhXYVV4dFRuWmlVemwyWTBkV2RVeFlVbXhpUjFaMFdsaFNlV1ZUT1haalIxWjFaRWRXYzFwWE1XeGtTRW8xQ2t4WFRuWmlSM2hzV1ROU2RtTnBNWGxhVjNoc1dWaE9iR041T0hWYU1td3dZVWhXYVV3elpIWmpiWFJ0WWtjNU0yTjVPV2xaV0U1c1RGaEtiR0pIVm1nS1l6SlZkV1ZYUm5SaVJVSjVXbGRhZWt3elVtaGFNMDEyWkdwQmRVOVVaM1ZOUkVFMFFtZHZja0puUlVWQldVOHZUVUZGUzBKRGIwMUxSR3hzVFdwQ2FRcGFhbFpxVFZSUmVWcFVWWHBOUkdOM1dUSk9hVTlFVFhsTlIwVjVUVVJOZUU1WFdtMWFiVWt3VFZSUk1rOVhWWGRJVVZsTFMzZFpRa0pCUjBSMmVrRkNDa04zVVZCRVFURnVZVmhTYjJSWFNYUmhSemw2WkVkV2EwMUdTVWREYVhOSFFWRlJRbWMzT0hkQlVYZEZVa0Y0UTJGSVVqQmpTRTAyVEhrNWJtRllVbThLWkZkSmRWa3lPWFJNTWpsM1dsYzBkR1JIVm5OYVZ6RnNaRWhLTlV3eU9YZGFWelV3V2xkNGJHSlhWakJqYm10MFdUSTVjMkpIVm1wa1J6bDVURmhLYkFwaVIxWm9ZekpXZWsxRVowZERhWE5IUVZGUlFtYzNPSGRCVVRCRlMyZDNiMDlYVlhsTlIwcHRUbGROZUU1RVNteE9WRTEzVG5wQ2Fsa3lTVFJOZWtsM0NsbFVTWGROZWtVeFdtMWFiVmxxVVhoT1JGazFXbFJCYUVKbmIzSkNaMFZGUVZsUEwwMUJSVTlDUWsxTlJWaEtiRnB1VFhaa1IwWnVZM2s1TWsxRE5EVUtUME0wZDAxQ2EwZERhWE5IUVZGUlFtYzNPSGRCVVRoRlEzZDNTazVFUVhkTmFsVjZUbXBqTWsxRVJVZERhWE5IUVZGUlFtYzNPSGRCVWtGRlNYZDNhQXBoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NamwzV2xjMGRHUkhWbk5hVnpGc1pFaEtOVTFDWjBkRGFYTkhRVkZSUW1jM09IZEJVa1ZGQ2tObmQwbE9SR3MxVDFSbmQwMUVTWGRuV1hOSFEybHpSMEZSVVVKbk56aDNRVkpKUldaUmVEZGhTRkl3WTBoTk5reDVPVzVoV0ZKdlpGZEpkVmt5T1hRS1RESTVkMXBYTkhSa1IxWnpXbGN4YkdSSVNqVk1NamwzV2xjMU1GcFhlR3hpVjFZd1kyNXJkRmt5T1hOaVIxWnFaRWM1ZVV4WVNteGlSMVpvWXpKV2VncE1lVFZ1WVZoU2IyUlhTWFprTWpsNVlUSmFjMkl6WkhwTU0wcHNZa2RXYUdNeVZYUlpNamwxWkVoS2NGbHBOVFZaVnpGelVVaEtiRnB1VFhaa1IwWnVDbU41T1RKTlF6UTFUME0wZDAxRVowZERhWE5IUVZGUlFtYzNPSGRCVWsxRlMyZDNiMDlYVlhsTlIwcHRUbGROZUU1RVNteE9WRTEzVG5wQ2Fsa3lTVFFLVFhwSmQxbFVTWGROZWtVeFdtMWFiVmxxVVhoT1JGazFXbFJCVlVKbmIzSkNaMFZGUVZsUEwwMUJSVlZDUVZsTlFraENNV015WjNka1VWbExTM2RaUWdwQ1FVZEVkbnBCUWtaUlVtNUVSMVp2WkVoU2QyTjZiM1pNTW1Sd1pFZG9NVmxwTldwaU1qQjJZak5DYkdKcE1UQmFWM2hzWWxkV01HTnVhM1ppTTBKc0NtSnVVbXhpUjFaMFdsaFNlV1ZUTVdwaU1uaHpXbGRPTUdJelNYUmpiVlp6V2xkR2VscFlUWFpaVjA0d1lWYzVkV041T1hsa1Z6VjZUSHBuTWs1RVJYZ0tUbnBGTVU1cVkzWlpXRkl3V2xjeGQyUklUWFpOYWtGWFFtZHZja0puUlVWQldVOHZUVUZGVjBKQlowMUNia0l4V1cxNGNGbDZRMEpwZDFsTFMzZFpRZ3BDUVVoWFpWRkpSVUZuVWpsQ1NITkJaVkZDTTBGT01EbE5SM0pIZUhoRmVWbDRhMlZJU214dVRuZExhVk5zTmpRemFubDBMelJsUzJOdlFYWkxaVFpQQ2tGQlFVSnFjM1JvUjJKSlFVRkJVVVJCUldkM1VtZEphRUZQZUZNM2RteDRjVzVGYTBKVVRtSlZVRUpsUkZSbk0waGtlRlkyY0cxWk9FdGliREV6TjNBS1lWUnViMEZwUlVFelMyMUxVbU5uYWxBeVQzSmxORVpyVm5vNU4xaENNWGRsUzBOeWFXazFTMWx2UTB0bVkxRktSREJSZDBObldVbExiMXBKZW1vd1JRcEJkMDFFWVVGQmQxcFJTWGhCUzNwcVpHMUZTV2gzV21Kb1lVSlNlalk1Y1N0MWVrNVZSMmxhYlRWVk4xcE5aWFJMUTFSM1VFTkljRkZQVldvdlVERkJDa2R0YWt3elJucFFObTVpYkRGblNYZFNUbXN6UkhkNWMwOUJUMHhoUVVoR09IaHhZV0ZzT0U5WGNGRmFhRGh4TTJVMVNVSmFXR0ZWVkhocFlWbGFTM29LUXpWS1RGVlNWbnBMTURsd04wVjBUd290TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0=","integratedTime":1712809122,"logIndex":84797940,"logID":"c0d23d6ad406973f9559f3ba2d1ca01f84147d8ffc5b8445c224f98b9591801d"}},"Issuer":"https://token.actions.githubusercontent.com","Subject":"https://github.com/open-telemetry/opentelemetry-collector-releases/.github/workflows/base-release.yaml@refs/tags/v0.98.0","githubWorkflowName":"Release Contrib","githubWorkflowRef":"refs/tags/v0.98.0","githubWorkflowRepository":"open-telemetry/opentelemetry-collector-releases","githubWorkflowSha":"9e20bf5c142e53070ccb8320a20315fffb41469e","githubWorkflowTrigger":"push"}}] ``` > [!NOTE] > We started signing the images with release `v0.95.0` ## Contributing See the [Contributing Guide](CONTRIBUTING.md) for details. Here is a list of community roles with current and previous members: ### Maintainers - [Alex Boten](https://github.com/codeboten), Honeycomb - [Bogdan Drutu](https://github.com/bogdandrutu), Snowflake - [Dmitrii Anoshin](https://github.com/dmitryax), Splunk - [Pablo Baeyens](https://github.com/mx-psi), DataDog For more information about the maintainer role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#maintainer). ### Approvers - [Andrew Wilkins](https://github.com/axw), Elastic - [Antoine Toulme](https://github.com/atoulme), Splunk - [Damien Mathieu](https://github.com/dmathieu), Elastic - [Evan Bradley](https://github.com/evan-bradley), Dynatrace - [Jade Guiton](https://github.com/jade-guiton-dd), Datadog - [Joshua MacDonald](https://github.com/jmacd), Microsoft - [Tyler Helmuth](https://github.com/TylerHelmuth), Honeycomb - [Yang Song](https://github.com/songy23), Datadog For more information about the approver role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver). In addition to what is described at the organization-level, the SIG Collector requires all core approvers to take part in rotating the role of the [release manager](./docs/release.md#release-manager). ### Triagers - [Andrzej Stencel](https://github.com/andrzej-stencel), Elastic - [Chao Weng](https://github.com/sincejune), AppDynamics - [Vihas Makwana](https://github.com/VihasMakwana), Elastic - Actively seeking contributors to triage issues For more information about the triager role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#triager). ### Emeritus Maintainers - [Paulo Janotti](https://github.com/pjanotti) - [Tigran Najaryan](https://github.com/tigrannajaryan) For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager). ### Emeritus Approvers - [Anthony Mirabella](https://github.com/Aneurysm9) - [Daniel Jaglowski](https://github.com/djaglowski) - [James Bebbington](https://github.com/james-bebbington) - [Jay Camp](https://github.com/jrcamp) - [Juraci Paixรฃo Krรถhling](https://github.com/jpkrohling) - [Nail Islamov](https://github.com/nilebox) - [Owais Lone](https://github.com/owais) - [Rahul Patel](https://github.com/rghetia) - [Steven Karis](https://github.com/sjkaris) For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager). ### Emeritus Triagers - [Alolita Sharma](https://github.com/alolita) - [Andrew Hsu](https://github.com/andrewhsu) - [Punya Biswal](https://github.com/punya) - [Steve Flanders](https://github.com/flands) For more information about the emeritus role, see the [community repository](https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#emeritus-maintainerapprovertriager). ### Thanks to all of our contributors! Repo contributors opentelemetry-collector-0.141.0/VERSIONING.md000066400000000000000000000335241511331344600205520ustar00rootroot00000000000000# Versioning and stability The OpenTelemetry Collector SIG produces several artifacts for [a variety of audiences](CONTRIBUTING.md#target-audiences). This document describes the versioning and support policy for these artifacts. These policies are designed so that the following goal can be achieved: **Users are provided software artifacts of value that are stable and secure.** The policies are divided depending on the artifact's target audience. While an artifact is supported, [critical bugs](docs/release.md#bugfix-release-criteria) and security vulnerabilities MUST be addressed. The main criteria for the length of support for an artifact is how easy it is for an artifact's target audience to adapt to disruptive changes. These policies reflect the current consensus of the OpenTelemetry Collector SIG. They are subject to change as the project evolves. ## Software artifacts for end users Software artifacts intended for [end users](CONTRIBUTING.md#end-users) of the OpenTelemetry Collector include - Binary distributions of the OpenTelemetry Collector. - Go modules that expose Collector components, such as receivers, processors, connectors, extensions and exporters. These artifacts are versioned according to the [semantic versioning v2.0.0](https://semver.org/) specification. ### General considerations Binary distributions produced by the Collector SIG contain components and features with varying [levels of stability](README.md#stability-levels). We abide by the following principles to relate the Collector's version to the stability of its components and features: * The Collector's core framework behavior MUST be stable in order for a Collector distribution to be v1.0.0 or higher. * Users can easily understand when they are opting in to use a component or feature that is not stable. * The Collector MUST be configurable so that unstable components or features can be excluded ensuring that a fully stable configuration is possible. * The Collector's telemetry (e.g. Collector logs) MUST provide the ability to identify usage of unstable components or features. ### Long-term support after v1 The OpenTelemetry Collector SIG provides long-term support for stable binary distributions of the OpenTelemetry Collector and its components. The following policies apply to long-term support for any major version starting on v1: * A binary distribution of the OpenTelemetry Collector MUST be supported for a minimum of **one year** after the release of the next major version of said distribution. * Components MUST be supported for a minimum of **6 months** after the release of the next major version of said component or after the component has been marked as deprecated. If a component has been deprecated for 6 months it MAY be removed from a binary distribution of the OpenTelemetry Collector. This does not imply a major version change in the Collector distribution. ## Go modules Go modules are intended to be used by [component developers](CONTRIBUTING.md#component-developers) and [Collector library users](CONTRIBUTING.md#collector-library-users) of the OpenTelemetry Collector Unless otherwise specified, the following public API expectations apply to all modules in opentelemetry-collector and opentelemetry-collector-contrib. As a general rule, stability guarantees of modules versioned as `v1` or higher are aligned with [Go 1 compatibility promise](https://go.dev/doc/go1compat). ### General Go API considerations OpenTelemetry authors reserve the right to introduce API changes breaking compatibility between minor versions in the following scenarios: * **Struct literals.** It may be necessary to add new fields to exported structs in the API. Code that uses unkeyed struct literals (such as pkg.T{3, "x"}) to create values of these types would fail to compile after such a change. However, code that uses keyed literals (pkg.T{A: 3, B: "x"}) will continue to compile. We therefore recommend using OpenTelemetry collector structs with the keyed literals only. * **Methods.** As with struct fields, it may be necessary to add methods to types. Under some circumstances, such as when the type is embedded in a struct along with another type, the addition of the new method may break the struct by creating a conflict with an existing method of the other embedded type. We cannot protect against this rare case and do not guarantee compatibility in such scenarios. * **Dot imports.** If a program imports a package using `import .`, additional names defined in the imported package in future releases may conflict with other names defined in the program. We do not recommend the use of `import .` with OpenTelemetry Collector modules. Unless otherwise specified in the documentation, the following may change in any way between minor versions: * **String representation**. The `String` or `Error` method of any struct is intended to be human-readable and may change its output in any way. * **Go version compatibility**. Removing support for an unsupported Go version is not considered a breaking change. * **OS version compatibility**. Removing support for an unsupported OS version is not considered a breaking change. Upgrading or downgrading OS version support per the [platform support](docs/platform-support.md) document is not considered a breaking change. * **Protocol compatibility**. Changing the default minimum version of a supported protocol (e.g. TLS) or dropping support for protocols when there are security concerns is not considered a breaking change. * **Dependency updates**. Updating dependencies is not considered a breaking change except when their types are part of the public API or the update may change the behavior of applications in an incompatible way. * **Underlying type for interfaces**. If a struct exported as an interface has an experimental method, this method may change or be removed in a minor version. The method will be published in an optional interface under an experimental module to signal it is experimental. ### Configuration structures Configuration structures are part of the public API and backwards compatibility should be maintained through any changes made to configuration structures. Unless otherwise specified in the documentation, the following may change in any way between minor versions: * **Adding new fields to configuration structures**. Because configuration structures are typically instantiated through unmarshalling a serialized representation of the structure, and not through structure literals, additive changes to the set of exported fields in a configuration structure are not considered to break backward compatibility. * **Relaxing validation rules**. An invalid configuration struct as defined by its `Validate` method return value may become valid after a change to the validation rules. The following are explicitly considered to be breaking changes: * **Modifying struct tags related to serialization**. Struct tags used to configure serialization mechanisms (`yaml:`, `mapstructure:`, etc) are part of the structure definition and must maintain compatibility to the same extent as the structure. However, changes are allowed when tag modifications produce a functionally-equivalent result when serializing or deserializing the structure. For example, adding a tag to a field so it will not be emitted during serialization if it has a default value would not alter its value if the serialized representation were again deserialized, so such a change would be permitted. * **Making validation rules more strict**. A valid configuration struct as defined by its `Validate` method return value must continue to be valid after a change to the validation rules, except when the configuration struct would cause an error on its intended usage (e.g. when calling a method or when passed to any method or function in any module under opentelemetry-collector). ### Module versioning and schema * Versioning of this project will be idiomatic of a Go project using [Go modules](https://golang.org/ref/mod#versions). * [Semantic import versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning) will be used. * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html). * If a module is version `v2` or higher, the major version of the module must be included as a `/vN` at the end of the module paths used in `go.mod` files (e.g., `module go.opentelemetry.io/collector/v2`, `require go.opentelemetry.io/collector/v2 v2.0.1`) and in the package import path (e.g., `import "go.opentelemetry.io/collector/v2/component"`). This includes the paths used in `go get` commands (e.g., `go get go.opentelemetry.io/collector/v2@v2.0.1`. Note there is both a `/v2` and a `@v2.0.1` in that example. One way to think about it is that the module name now includes the `/v2`, so include `/v2` whenever you are using the module name). * If a module is version `v0` or `v1`, do not include the major version in either the module path or the import path. * Semantic convention packages will contain a complete version identifier in their import path to enable concurrent use of multiple convention versions in a single application. This identifies the version of the specification used to generate the package and is not related to the version of the module containing the package. * A single module should exist, rooted at the top level of this repository, that contains all packages provided for use outside this repository. * Additional modules may be created in this repository to provide for isolation of build-time tools, other commands or independent libraries. Such modules should be versioned in sync with the `go.opentelemetry.io/collector` module. * Experimental modules still under active development will be versioned with a major version of `v0` to imply the stability guarantee defined by [semver](https://semver.org/spec/v2.0.0.html#spec-item-4). > Major version zero (0.y.z) is for initial development. Anything MAY > change at any time. The public API SHOULD NOT be considered stable. * Versioning of the associated [contrib repository](https://github.com/open-telemetry/opentelemetry-collector-contrib) of this project will be idiomatic of a Go project using [Go modules](https://golang.org/ref/mod#versions). * [Semantic import versioning](https://github.com/golang/go/wiki/Modules#semantic-import-versioning) will be used. * Versions will comply with [semver 2.0](https://semver.org/spec/v2.0.0.html). * If a module is version `v2` or higher, the major version of the module must be included as a `/vN` at the end of the module paths used in `go.mod` files (e.g., `module github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sprocessor/v2`, `require github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sprocessor/v2 v2.0.1`) and in the package import path (e.g., `import "github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sprocessor/v2"`). This includes the paths used in `go get` commands (e.g., `go get github.com/open-telemetry/opentelemetry-collector-contrib/processor/k8sprocessor/v2@v2.0.1`. Note there is both a `/v2` and a `@v2.0.1` in that example. One way to think about it is that the module name now includes the `/v2`, so include `/v2` whenever you are using the module name). * If a module is version `v0` or `v1`, do not include the major version in either the module path or the import path. * Modules will be used to encapsulate receivers, processors, exporters, extensions, connectors and any other independent sets of related components. * Experimental modules still under active development will be versioned with a major version of `v0` to imply the stability guarantee defined by [semver](https://semver.org/spec/v2.0.0.html#spec-item-4). > Major version zero (0.y.z) is for initial development. Anything MAY > change at any time. The public API SHOULD NOT be considered stable. * Experimental modules will start their versioning at `v0.0.0` and will increment their minor version when backwards incompatible changes are released and increment their patch version when backwards compatible changes are released. * Mature modules for which we guarantee a stable public API will be versioned with a major version of `v1` or greater. * All stable contrib modules of the same major version with this project will use the same entire version. * Stable modules may be released with an incremented minor or patch version even though that module's code has not been changed. Instead the only change that will have been included is to have updated that modules dependency on this project's stable APIs. * Contrib modules will be kept up to date with this project's releases. * GitHub releases will be made for all releases. * Go modules will be made available at Go package mirrors. ### Long-term support after v1 The OpenTelemetry Collector SIG provides long-term support for stable Go modules. Support for modules depend on the module's [target audiences](CONTRIBUTING.md#target-audiences). The following policies apply to long-term support for any major version starting on v1: - Modules intended for **component developers** MUST be supported for a minimum of **1 year** after the release of the next major version of said module or after the module has been marked as deprecated. - Modules intended for **Collector library users** MUST be supported for a minimum of **6 months** after the release of the next major version of said module or after the module has been marked as deprecated. opentelemetry-collector-0.141.0/client/000077500000000000000000000000001511331344600200145ustar00rootroot00000000000000opentelemetry-collector-0.141.0/client/Makefile000066400000000000000000000000331511331344600214500ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/client/client.go000066400000000000000000000134341511331344600216260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package client contains generic representations of clients connecting to // different receivers. Components, such as processors or exporters, can make // use of this information to make decisions related to grouping of batches, // tenancy, load balancing, tagging, among others. // // The structs defined here are typically used within the context that is // propagated down the pipeline, with the values being produced by // authenticators and/or receivers, and consumed by processors and exporters. // // # Producers // // Receivers are responsible for obtaining a client.Info from the current // context and enhancing the client.Info with the net.Addr from the peer, // storing a new client.Info into the context that it passes down. For HTTP // requests, the net.Addr is typically the IP address of the client. // // Typically, however, receivers would delegate this processing to helpers such // as the confighttp or configgrpc packages: both contain interceptors that will // enhance the context with the client.Info, such that no actions are needed by // receivers that are built using confighttp.HTTPServerSettings or // configgrpc.GRPCServerSettings. // // Authenticators are responsible for obtaining a client.Info from the current // context, enhancing the client.Info with an implementation of client.AuthData, // and storing a new client.Info into the context that it passes down. The // attribute names should be documented with their return types and considered // part of the public API for the authenticator. // // # Consumers // // Provided that the pipeline does not contain processors that would discard or // rewrite the context, such as the batch processor, processors and exporters // have access to the client.Info via client.FromContext. Among other usages, // this data can be used to: // // - annotate data points with authentication data (username, tenant, ...) // // - route data points based on authentication data // // - rate limit client calls based on IP addresses // // Processors and exporters relying on the existence of data from the // client.Info, especially client.AuthData, should clearly document this as part // of the component's README file. The expected pattern for consuming data is to // allow users to specify the attribute name to use in the component. The // expected data type should also be communicated to users, who should then // compare this with the authenticators that are part of the pipeline. For // example, assuming that the OIDC authenticator pushes a "subject" string // attribute and that we have a hypothetical "authprinter" processor that prints // the "username" to the console, this is how an OpenTelemetry Collector // configuration would look like: // // extensions: // oidc: // issuer_url: http://localhost:8080/auth/realms/opentelemetry // audience: collector // receivers: // otlp: // protocols: // grpc: // auth: // authenticator: oidc // processors: // authprinter: // attribute: subject // exporters: // debug: // service: // extensions: [oidc] // pipelines: // traces: // receivers: [otlp] // processors: [authprinter] // exporters: [debug] package client // import "go.opentelemetry.io/collector/client" import ( "context" "iter" "maps" "net" "strings" ) type ctxKey struct{} // Info contains data related to the clients connecting to receivers. type Info struct { // Addr for the client connecting to this collector. Available in a // best-effort basis, and generally reliable for receivers making use of // confighttp.ToServer and configgrpc.ToServerOption. Addr net.Addr // Auth information from the incoming request as provided by // configauth.ServerAuthenticator implementations tied to the receiver for // this connection. Auth AuthData // Metadata is the request metadata from the client connecting to this connector. Metadata Metadata // prevent unkeyed literal initialization _ struct{} } // AuthData represents the authentication data as seen by authenticators tied to // the receivers. type AuthData interface { // GetAttribute returns the value for the given attribute. Authenticator // implementations might define different data types for different // attributes. While "string" is used most of the time, a key named // "membership" might return a list of strings. GetAttribute(string) any // GetAttributeNames returns the names of all attributes in this authentication data. GetAttributeNames() []string } const MetadataHostName = "Host" // NewContext takes an existing context and derives a new context with the // client.Info value stored on it. func NewContext(ctx context.Context, c Info) context.Context { return context.WithValue(ctx, ctxKey{}, c) } // FromContext takes a context and returns a ClientInfo from it. // When a ClientInfo isn't present, a new empty one is returned. func FromContext(ctx context.Context) Info { c, ok := ctx.Value(ctxKey{}).(Info) if !ok { c = Info{} } return c } // Metadata is an immutable map, meant to contain request metadata. type Metadata struct { data map[string][]string } // NewMetadata creates a new Metadata object to use in Info. func NewMetadata(md map[string][]string) Metadata { c := make(map[string][]string, len(md)) for k, v := range md { c[strings.ToLower(k)] = v } return Metadata{ data: c, } } // Keys returns an iterator for the metadata keys. func (m Metadata) Keys() iter.Seq[string] { return maps.Keys(m.data) } // Get gets the value of the key from metadata, returning a copy. // The key lookup is case-insensitive. func (m Metadata) Get(key string) []string { if len(m.data) == 0 { return nil } vals := m.data[strings.ToLower(key)] if len(vals) == 0 { return nil } ret := make([]string, len(vals)) copy(ret, vals) return ret } opentelemetry-collector-0.141.0/client/client_test.go000066400000000000000000000044411511331344600226630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package client contains generic representations of clients connecting to // different receivers package client import ( "context" "net" "slices" "testing" "github.com/stretchr/testify/assert" ) func TestNewContext(t *testing.T) { testCases := []struct { name string cl Info }{ { name: "valid client", cl: Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }, }, { name: "nil client", cl: Info{}, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { ctx := NewContext(context.Background(), tt.cl) assert.Equal(t, ctx.Value(ctxKey{}), tt.cl) }) } } func TestFromContext(t *testing.T) { testCases := []struct { name string input context.Context expected Info }{ { name: "context with client", input: context.WithValue(context.Background(), ctxKey{}, Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }), expected: Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }, }, { name: "context without client", input: context.Background(), expected: Info{}, }, { name: "context with something else in the key", input: context.WithValue(context.Background(), ctxKey{}, "unexpected!"), expected: Info{}, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { assert.Equal(t, tt.expected, FromContext(tt.input)) }) } } func TestMetadata(t *testing.T) { source := map[string][]string{"test-key": {"test-val"}, "TEST-KEY-2": {"test-val"}} md := NewMetadata(source) assert.Equal(t, []string{"test-key", "test-key-2"}, slices.Sorted(md.Keys())) assert.Equal(t, []string{"test-val"}, md.Get("test-key")) assert.Equal(t, []string{"test-val"}, md.Get("test-KEY")) // case insensitive lookup assert.Equal(t, []string{"test-val"}, md.Get("test-key-2")) // case insensitive lookup // test if copy. In regular use, source cannot change val := md.Get("test-key") source["test-key"][0] = "abc" assert.Equal(t, []string{"test-val"}, val) assert.Empty(t, md.Get("non-existent-key")) } func TestUninstantiatedMetadata(t *testing.T) { i := Info{} assert.Empty(t, slices.Collect(i.Metadata.Keys())) assert.Empty(t, i.Metadata.Get("test")) } opentelemetry-collector-0.141.0/client/doc_test.go000066400000000000000000000042251511331344600221520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package client_test import ( "context" "fmt" "net" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/ptrace" ) func Example_receiver() { // Your receiver get a next consumer when it's constructed next, err := consumer.NewTraces(func(_ context.Context, _ ptrace.Traces) error { return nil }) if err != nil { panic(err) } // You'll convert the incoming data into pipeline data td := ptrace.NewTraces() // You probably have a context with client metadata from your listener or // scraper ctx := context.Background() // Get the client from the context: if it doesn't exist, FromContext will // create one cl := client.FromContext(ctx) // Extract the client information based on your original context and set it // to Addr //nolint:govet cl.Addr = &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), } // When you are done, propagate the context down the pipeline to the next // consumer and handle error. if err = next.ConsumeTraces(ctx, td); err != nil { panic(err) } } func Example_processor() { // Your processor or exporter will receive a context, from which you get the // client information ctx := context.Background() cl := client.FromContext(ctx) // And use the information from the client as you need fmt.Println(cl.Addr) } func Example_authenticator() { // Your configauth.AuthenticateFunc receives a context ctx := context.Background() // Get the client from the context: if it doesn't exist, FromContext will // create one cl := client.FromContext(ctx) // After a successful authentication, place the data you want to propagate // as part of an AuthData implementation of your own cl.Auth = &exampleAuthData{ username: "jdoe", } // Your configauth.AuthenticateFunc should return this new context _ = client.NewContext(ctx, cl) } type exampleAuthData struct { username string } func (e *exampleAuthData) GetAttribute(key string) any { if key == "username" { return e.username } return nil } func (e *exampleAuthData) GetAttributeNames() []string { return []string{"username"} } opentelemetry-collector-0.141.0/client/go.mod000066400000000000000000000017601511331344600211260ustar00rootroot00000000000000module go.opentelemetry.io/collector/client go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/pdata v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/consumer => ../consumer replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/client/go.sum000066400000000000000000000077271511331344600211640ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/client/package_test.go000066400000000000000000000003071511331344600227750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package client import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/000077500000000000000000000000001511331344600173015ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/builder/000077500000000000000000000000001511331344600207275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/builder/Makefile000066400000000000000000000010371511331344600223700ustar00rootroot00000000000000include ../../Makefile.Common .PHONY: ocb ocb: CGO_ENABLED=0 $(GOCMD) build -trimpath -o ../../bin/ocb_$(GOOS)_$(GOARCH) . # Generate the default build config from otelcorecol, by removing the # "replaces" stanza, which is assumed to be at the end of the file. # # The default config file is checked in so that `go install` will work # and so that non-unix builds don't need sed to be installed. .PHONY: config config: internal/config/default.yaml sed '-e/replaces:/,$$d' <../otelcorecol/builder-config.yaml > internal/config/default.yaml opentelemetry-collector-0.141.0/cmd/builder/README.md000066400000000000000000000253661511331344600222220ustar00rootroot00000000000000# OpenTelemetry Collector Builder (ocb) This program generates a custom OpenTelemetry Collector binary based on a given configuration. ## TL;DR ```console $ go install go.opentelemetry.io/collector/cmd/builder@v0.129.0 $ cat > otelcol-builder.yaml < /tmp/otelcol.yaml < github.com/open-telemetry/opentelemetry-collector-contrib/internal/common v0.128.0 ``` The builder also allows setting the scheme to use as the default URI scheme via `conf_resolver.default_uri_scheme`: ```yaml conf_resolver: default_uri_scheme: "env" ``` This tells the builder to produce a Collector that uses the `env` scheme when expanding configuration that does not provide a scheme, such as `${HOST}` (instead of doing `${env:HOST}`). ## Steps The builder has 3 steps: * Generate: generates the golang source code * Get modules: generates the go.mod file based on the imported modules in the generated golang source code * Compilation: builds the OpenTelemetry Collector executable Each step can be skipped independently: `--skip-generate`, `--skip-get-modules` and `--skip-compilation`. For instance, a code generation step could execute ```console ocb --skip-compilation --config=config.yaml ``` then commit the code in a git repo. A CI can sync the code and execute ```console ocb --skip-generate --skip-get-modules --config=config.yaml ``` to only execute the compilation step. ### Strict versioning checks The builder checks the relevant `go.mod` file for the following things after `go get`ing all components and calling `go mod tidy`: 1. The `dist::otelcol_version` field in the build configuration must have matching major and minor versions as the core library version calculated by the Go toolchain, considering all components. A mismatch could happen, for example, when the builder or one of the components depends on a newer release of the core collector library. 2. For each component in the build configuration, the major and minor versions included in the `gomod` module specifier must match the one calculated by the Go toolchain, considering all components. A mismatch could happen, for example, when the enclosing Go module uses a newer release of the core collector library. The `--skip-strict-versioning` flag disables these versioning checks. This flag is available temporarily and **will be removed in a future minor version**. ### Cgo disabled by default By default, the OpenTelemetry Collector binary is built with `CGO_ENABLED=0` in accordance with how the official OpenTelemetry Collector releases are built. This can be overridden by adding the following configuration option to the `dist` section of the builder configuration file: ```yaml dist: cgo_enabled: true ``` opentelemetry-collector-0.141.0/cmd/builder/RELEASE.md000066400000000000000000000010271511331344600223310ustar00rootroot00000000000000# Releasing the OpenTelemetry Collector Builder This project uses [`goreleaser`](https://github.com/goreleaser/goreleaser) to manage the release of new versions. To release a new version, simply add a tag named `vX.Y.Z`, like: ``` git tag -a v0.1.1 -m "Release v0.1.1" git push upstream v0.1.1 ``` A new GitHub workflow should be started, and at the end, a GitHub release should have been created, similar with the ["Release v0.56.0"](https://github.com/open-telemetry/opentelemetry-collector/releases/tag/cmd%2Fbuilder%2Fv0.56.0).opentelemetry-collector-0.141.0/cmd/builder/go.mod000066400000000000000000000027131511331344600220400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 module go.opentelemetry.io/collector/cmd/builder go 1.24.0 require ( github.com/knadh/koanf/parsers/yaml v1.1.0 github.com/knadh/koanf/providers/env/v2 v2.0.0 github.com/knadh/koanf/providers/file v1.2.0 github.com/knadh/koanf/providers/fs v1.0.0 github.com/knadh/koanf/v2 v2.3.0 github.com/spf13/cobra v1.10.1 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.1 golang.org/x/mod v0.30.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.36.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 v0.57.1 // Release failed, use v0.57.2 v0.57.0 // Release failed, use v0.57.2 ) opentelemetry-collector-0.141.0/cmd/builder/go.sum000066400000000000000000000127261511331344600220720ustar00rootroot00000000000000github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= github.com/knadh/koanf/parsers/yaml v1.1.0 h1:3ltfm9ljprAHt4jxgeYLlFPmUaunuCgu1yILuTXRdM4= github.com/knadh/koanf/parsers/yaml v1.1.0/go.mod h1:HHmcHXUrp9cOPcuC+2wrr44GTUB0EC+PyfN3HZD9tFg= github.com/knadh/koanf/providers/env/v2 v2.0.0 h1:Ad5H3eun722u+FvchiIcEIJZsZ2M6oxCkgZfWN5B5KY= github.com/knadh/koanf/providers/env/v2 v2.0.0/go.mod h1:1g01PE+Ve1gBfWNNw2wmULRP0tc8RJrjn5p2N/jNCIc= github.com/knadh/koanf/providers/file v1.2.0 h1:hrUJ6Y9YOA49aNu/RSYzOTFlqzXSCpmYIDXI7OJU6+U= github.com/knadh/koanf/providers/file v1.2.0/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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/cmd/builder/header.txt000066400000000000000000000010601511331344600227150ustar00rootroot00000000000000Copyright The OpenTelemetry Authors 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.opentelemetry-collector-0.141.0/cmd/builder/internal/000077500000000000000000000000001511331344600225435ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/builder/internal/builder/000077500000000000000000000000001511331344600241715ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/builder/internal/builder/config.go000066400000000000000000000177131511331344600257760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builder // import "go.opentelemetry.io/collector/cmd/builder/internal/builder" import ( "errors" "fmt" "os" "os/exec" "path/filepath" "slices" "strings" "time" "go.uber.org/multierr" "go.uber.org/zap" ) const ( defaultBetaOtelColVersion = "v0.141.0" defaultStableOtelColVersion = "v1.47.0" ) // errMissingGoMod indicates an empty gomod field var errMissingGoMod = errors.New("missing gomod specification for module") // Config holds the builder's configuration type Config struct { Logger *zap.Logger OtelColVersion string `mapstructure:"-"` // only used be the go.mod template SkipGenerate bool `mapstructure:"-"` SkipCompilation bool `mapstructure:"-"` SkipGetModules bool `mapstructure:"-"` SkipStrictVersioning bool `mapstructure:"-"` LDFlags string `mapstructure:"-"` LDSet bool `mapstructure:"-"` // only used to override LDFlags GCFlags string `mapstructure:"-"` GCSet bool `mapstructure:"-"` // only used to override GCFlags Verbose bool `mapstructure:"-"` Distribution Distribution `mapstructure:"dist"` Exporters []Module `mapstructure:"exporters"` Extensions []Module `mapstructure:"extensions"` Receivers []Module `mapstructure:"receivers"` Processors []Module `mapstructure:"processors"` Connectors []Module `mapstructure:"connectors"` ConfmapProviders []Module `mapstructure:"providers"` ConfmapConverters []Module `mapstructure:"converters"` Replaces []string `mapstructure:"replaces"` Excludes []string `mapstructure:"excludes"` ConfResolver ConfResolver `mapstructure:"conf_resolver"` downloadModules retry `mapstructure:"-"` } type ConfResolver struct { // When set, will be used to set the CollectorSettings.ConfResolver.DefaultScheme value, // which determines how the Collector interprets URIs that have no scheme, such as ${ENV}. // See https://pkg.go.dev/go.opentelemetry.io/collector/confmap#ResolverSettings for more details. DefaultURIScheme string `mapstructure:"default_uri_scheme"` } // Distribution holds the parameters for the final binary type Distribution struct { Module string `mapstructure:"module"` Name string `mapstructure:"name"` Go string `mapstructure:"go"` Description string `mapstructure:"description"` OutputPath string `mapstructure:"output_path"` Version string `mapstructure:"version"` BuildTags string `mapstructure:"build_tags"` DebugCompilation bool `mapstructure:"debug_compilation"` CGoEnabled bool `mapstructure:"cgo_enabled"` } // Module represents a receiver, exporter, processor or extension for the distribution type Module struct { Name string `mapstructure:"name"` // if not specified, this is package part of the go mod (last part of the path) Import string `mapstructure:"import"` // if not specified, this is the path part of the go mods GoMod string `mapstructure:"gomod"` // a gomod-compatible spec for the module Path string `mapstructure:"path"` // an optional path to the local version of this module } type retry struct { numRetries int wait time.Duration } // NewDefaultConfig creates a new config, with default values func NewDefaultConfig() (*Config, error) { log, err := zap.NewDevelopment() if err != nil { panic(fmt.Sprintf("failed to obtain a logger instance: %v", err)) } outputDir, err := os.MkdirTemp("", "otelcol-distribution") if err != nil { return nil, err } return &Config{ OtelColVersion: defaultBetaOtelColVersion, Logger: log, Distribution: Distribution{ OutputPath: outputDir, Module: "go.opentelemetry.io/collector/cmd/builder", }, // basic retry if error from go mod command (in case of transient network error). // retry 3 times with 5 second spacing interval downloadModules: retry{ numRetries: 3, wait: 5 * time.Second, }, ConfmapProviders: []Module{ { GoMod: "go.opentelemetry.io/collector/confmap/provider/envprovider " + defaultStableOtelColVersion, }, { GoMod: "go.opentelemetry.io/collector/confmap/provider/fileprovider " + defaultStableOtelColVersion, }, { GoMod: "go.opentelemetry.io/collector/confmap/provider/httpprovider " + defaultStableOtelColVersion, }, { GoMod: "go.opentelemetry.io/collector/confmap/provider/httpsprovider " + defaultStableOtelColVersion, }, { GoMod: "go.opentelemetry.io/collector/confmap/provider/yamlprovider " + defaultStableOtelColVersion, }, }, }, nil } // Validate checks whether the current configuration is valid func (c *Config) Validate() error { return multierr.Combine( validateModules("extension", c.Extensions), validateModules("receiver", c.Receivers), validateModules("exporter", c.Exporters), validateModules("processor", c.Processors), validateModules("connector", c.Connectors), validateModules("provider", c.ConfmapProviders), validateModules("converter", c.ConfmapConverters), ) } // SetGoPath sets go path func (c *Config) SetGoPath() error { if !c.SkipCompilation || !c.SkipGetModules { //nolint:gosec // #nosec G204 if _, err := exec.Command(c.Distribution.Go, "env").CombinedOutput(); err != nil { path, err := exec.LookPath("go") if err != nil { return ErrGoNotFound } c.Distribution.Go = path } c.Logger.Info("Using go", zap.String("go-executable", c.Distribution.Go)) } return nil } // ParseModules will parse the Modules entries and populate the missing values func (c *Config) ParseModules() error { var err error usedNames := make(map[string]int) c.Extensions, err = parseModules(c.Extensions, usedNames) if err != nil { return err } c.Receivers, err = parseModules(c.Receivers, usedNames) if err != nil { return err } c.Exporters, err = parseModules(c.Exporters, usedNames) if err != nil { return err } c.Processors, err = parseModules(c.Processors, usedNames) if err != nil { return err } c.Connectors, err = parseModules(c.Connectors, usedNames) if err != nil { return err } c.ConfmapProviders, err = parseModules(c.ConfmapProviders, usedNames) if err != nil { return err } c.ConfmapConverters, err = parseModules(c.ConfmapConverters, usedNames) if err != nil { return err } return nil } func (c *Config) allComponents() []Module { return slices.Concat[[]Module](c.Exporters, c.Receivers, c.Processors, c.Extensions, c.Connectors, c.ConfmapProviders, c.ConfmapConverters) } func validateModules(name string, mods []Module) error { for i, mod := range mods { if mod.GoMod == "" { return fmt.Errorf("%s module at index %v: %w", name, i, errMissingGoMod) } } return nil } func parseModules(mods []Module, usedNames map[string]int) ([]Module, error) { var parsedModules []Module for _, mod := range mods { if mod.Import == "" { mod.Import = strings.Split(mod.GoMod, " ")[0] } if mod.Name == "" { parts := strings.Split(mod.Import, "/") mod.Name = parts[len(parts)-1] } originalModName := mod.Name if count, exists := usedNames[mod.Name]; exists { var newName string for { newName = fmt.Sprintf("%s%d", mod.Name, count+1) if _, transformedExists := usedNames[newName]; !transformedExists { break } count++ } mod.Name = newName usedNames[newName] = 1 } usedNames[originalModName] = 1 // Check if path is empty, otherwise filepath.Abs replaces it with current path ".". if mod.Path != "" { var err error mod.Path, err = filepath.Abs(mod.Path) if err != nil { return mods, fmt.Errorf("module has a relative \"path\" element, but we couldn't resolve the current working dir: %w", err) } // Check if the path exists if _, err := os.Stat(mod.Path); os.IsNotExist(err) { return mods, fmt.Errorf("filepath does not exist: %s", mod.Path) } } parsedModules = append(parsedModules, mod) } return parsedModules, nil } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/config_test.go000066400000000000000000000224151511331344600270300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builder import ( "os" "strings" "testing" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/v2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest" "go.opentelemetry.io/collector/cmd/builder/internal/config" ) func TestAliases(t *testing.T) { // prepare cfg := Config{ Extensions: []Module{ { GoMod: "github.com/org/repo/impl v0.1.2", }, { GoMod: "github.com/org/repo2/impl v0.1.2", }, { GoMod: "github.com/org/repo3/impl v0.1.2", }, }, Receivers: []Module{ { GoMod: "github.com/org/repo v0.1.2", }, { GoMod: "github.com/org2/repo v0.1.2", }, { GoMod: "github.com/org/repo4/impl v0.1.2", }, }, Exporters: []Module{ { GoMod: "github.com/another/module v0.1.2", }, { GoMod: "github.com/org/repo5/impl v0.1.2", }, }, Processors: []Module{ { GoMod: "github.com/another/module2 v0.1.2", }, { GoMod: "github.com/another2/module v0.1.2", }, }, Connectors: []Module{ { GoMod: "github.com/another/module3 v0.1.2", }, { GoMod: "github.com/another2/module4 v0.1.2", }, { GoMod: "github.com/another3/module v0.1.2", }, }, } // test err := cfg.ParseModules() require.NoError(t, err) // verify assert.Equal(t, "github.com/org/repo/impl v0.1.2", cfg.Extensions[0].GoMod) assert.Equal(t, "github.com/org/repo/impl", cfg.Extensions[0].Import) assert.Equal(t, "impl", cfg.Extensions[0].Name) assert.Equal(t, "github.com/org/repo2/impl v0.1.2", cfg.Extensions[1].GoMod) assert.Equal(t, "github.com/org/repo2/impl", cfg.Extensions[1].Import) assert.Equal(t, "impl2", cfg.Extensions[1].Name) assert.Equal(t, "github.com/org/repo3/impl v0.1.2", cfg.Extensions[2].GoMod) assert.Equal(t, "github.com/org/repo3/impl", cfg.Extensions[2].Import) assert.Equal(t, "impl3", cfg.Extensions[2].Name) assert.Equal(t, "github.com/org/repo v0.1.2", cfg.Receivers[0].GoMod) assert.Equal(t, "github.com/org/repo", cfg.Receivers[0].Import) assert.Equal(t, "repo", cfg.Receivers[0].Name) assert.Equal(t, "github.com/org2/repo v0.1.2", cfg.Receivers[1].GoMod) assert.Equal(t, "github.com/org2/repo", cfg.Receivers[1].Import) assert.Equal(t, "repo2", cfg.Receivers[1].Name) assert.Equal(t, "github.com/org/repo4/impl v0.1.2", cfg.Receivers[2].GoMod) assert.Equal(t, "github.com/org/repo4/impl", cfg.Receivers[2].Import) assert.Equal(t, "impl4", cfg.Receivers[2].Name) assert.Equal(t, "github.com/another/module v0.1.2", cfg.Exporters[0].GoMod) assert.Equal(t, "github.com/another/module", cfg.Exporters[0].Import) assert.Equal(t, "module", cfg.Exporters[0].Name) assert.Equal(t, "github.com/org/repo5/impl v0.1.2", cfg.Exporters[1].GoMod) assert.Equal(t, "github.com/org/repo5/impl", cfg.Exporters[1].Import) assert.Equal(t, "impl5", cfg.Exporters[1].Name) assert.Equal(t, "github.com/another/module2 v0.1.2", cfg.Processors[0].GoMod) assert.Equal(t, "github.com/another/module2", cfg.Processors[0].Import) assert.Equal(t, "module2", cfg.Processors[0].Name) assert.Equal(t, "github.com/another2/module v0.1.2", cfg.Processors[1].GoMod) assert.Equal(t, "github.com/another2/module", cfg.Processors[1].Import) assert.Equal(t, "module3", cfg.Processors[1].Name) assert.Equal(t, "github.com/another/module3 v0.1.2", cfg.Connectors[0].GoMod) assert.Equal(t, "github.com/another/module3", cfg.Connectors[0].Import) assert.Equal(t, "module32", cfg.Connectors[0].Name) assert.Equal(t, "github.com/another2/module4 v0.1.2", cfg.Connectors[1].GoMod) assert.Equal(t, "github.com/another2/module4", cfg.Connectors[1].Import) assert.Equal(t, "module4", cfg.Connectors[1].Name) assert.Equal(t, "github.com/another3/module v0.1.2", cfg.Connectors[2].GoMod) assert.Equal(t, "github.com/another3/module", cfg.Connectors[2].Import) assert.Equal(t, "module5", cfg.Connectors[2].Name) } func TestParseModules(t *testing.T) { // prepare cfg := Config{ Extensions: []Module{{ GoMod: "github.com/org/repo v0.1.2", }}, } // test err := cfg.ParseModules() require.NoError(t, err) // verify assert.Equal(t, "github.com/org/repo v0.1.2", cfg.Extensions[0].GoMod) assert.Equal(t, "github.com/org/repo", cfg.Extensions[0].Import) assert.Equal(t, "repo", cfg.Extensions[0].Name) } func TestInvalidConverter(t *testing.T) { // Create a Config instance with invalid Converters config := &Config{ ConfmapConverters: []Module{ { Path: "./invalid/module/path", // Invalid module path to trigger an error }, }, } // Call the method and expect an error err := config.ParseModules() require.Error(t, err, "expected an error when parsing invalid modules") } func TestRelativePath(t *testing.T) { // prepare cfg := Config{ Extensions: []Module{{ GoMod: "some-module", Path: "./templates", }}, } // test err := cfg.ParseModules() require.NoError(t, err) // verify cwd, err := os.Getwd() require.NoError(t, err) assert.True(t, strings.HasPrefix(cfg.Extensions[0].Path, cwd)) } func TestModuleFromCore(t *testing.T) { // prepare cfg := Config{ Extensions: []Module{ // see issue-12 { Import: "go.opentelemetry.io/collector/receiver/otlpreceiver", GoMod: "go.opentelemetry.io/collector v0.0.0", }, { Import: "go.opentelemetry.io/collector/receiver/otlpreceiver", GoMod: "go.opentelemetry.io/collector v0.0.0", }, }, } // test err := cfg.ParseModules() require.NoError(t, err) // verify assert.True(t, strings.HasPrefix(cfg.Extensions[0].Name, "otlpreceiver")) } func TestMissingModule(t *testing.T) { type invalidModuleTest struct { cfg Config err error } // prepare configurations := []invalidModuleTest{ { cfg: Config{ Logger: zap.NewNop(), ConfmapProviders: []Module{{ Import: "invalid", }}, }, err: errMissingGoMod, }, { cfg: Config{ Logger: zap.NewNop(), Extensions: []Module{{ Import: "invalid", }}, }, err: errMissingGoMod, }, { cfg: Config{ Logger: zap.NewNop(), Receivers: []Module{{ Import: "invalid", }}, }, err: errMissingGoMod, }, { cfg: Config{ Logger: zap.NewNop(), Exporters: []Module{{ Import: "invalid", }}, }, err: errMissingGoMod, }, { cfg: Config{ Logger: zap.NewNop(), Processors: []Module{{ Import: "invalid", }}, }, err: errMissingGoMod, }, { cfg: Config{ Logger: zap.NewNop(), Connectors: []Module{{ Import: "invalid", }}, }, err: errMissingGoMod, }, { cfg: Config{ Logger: zap.NewNop(), ConfmapConverters: []Module{{ Import: "invalid", }}, }, err: errMissingGoMod, }, } for _, test := range configurations { assert.ErrorIs(t, test.cfg.Validate(), test.err) } } func TestNewDefaultConfig(t *testing.T) { cfg, err := NewDefaultConfig() require.NoError(t, err) require.NoError(t, cfg.ParseModules()) assert.NoError(t, cfg.Validate()) assert.NoError(t, cfg.SetGoPath()) require.NoError(t, cfg.Validate()) assert.False(t, cfg.Distribution.DebugCompilation) assert.Empty(t, cfg.Distribution.BuildTags) assert.False(t, cfg.LDSet) assert.Empty(t, cfg.LDFlags) assert.False(t, cfg.GCSet) assert.Empty(t, cfg.GCFlags) } func TestNewBuiltinConfig(t *testing.T) { k := koanf.New(".") require.NoError(t, k.Load(config.DefaultProvider(), yaml.Parser())) cfg := Config{Logger: zaptest.NewLogger(t)} require.NoError(t, k.UnmarshalWithConf("", &cfg, koanf.UnmarshalConf{Tag: "mapstructure"})) assert.NoError(t, cfg.ParseModules()) assert.NoError(t, cfg.Validate()) assert.NoError(t, cfg.SetGoPath()) // Unlike the config initialized in NewDefaultConfig(), we expect // the builtin default to be practically useful, so there must be // a set of modules present. assert.NotEmpty(t, cfg.Receivers) assert.NotEmpty(t, cfg.Exporters) assert.NotEmpty(t, cfg.Extensions) assert.NotEmpty(t, cfg.Processors) } func TestSkipGoValidation(t *testing.T) { cfg := Config{ Distribution: Distribution{ Go: "invalid/go/binary/path", }, SkipCompilation: true, SkipGetModules: true, } assert.NoError(t, cfg.Validate()) assert.NoError(t, cfg.SetGoPath()) } func TestSkipGoInitialization(t *testing.T) { cfg := Config{ SkipCompilation: true, SkipGetModules: true, } assert.NoError(t, cfg.Validate()) assert.NoError(t, cfg.SetGoPath()) assert.Empty(t, cfg.Distribution.Go) } func TestBuildTagConfig(t *testing.T) { cfg := Config{ Distribution: Distribution{ BuildTags: "customTag", }, SkipCompilation: true, SkipGetModules: true, } require.NoError(t, cfg.Validate()) assert.Equal(t, "customTag", cfg.Distribution.BuildTags) } func TestDebugOptionSetConfig(t *testing.T) { cfg := Config{ Distribution: Distribution{ DebugCompilation: true, }, SkipCompilation: true, SkipGetModules: true, } require.NoError(t, cfg.Validate()) assert.True(t, cfg.Distribution.DebugCompilation) } func TestAddsDefaultProviders(t *testing.T) { cfg, err := NewDefaultConfig() require.NoError(t, err) require.NoError(t, cfg.ParseModules()) assert.Len(t, cfg.ConfmapProviders, 5) } func TestSkipsNilFieldValidation(t *testing.T) { cfg, err := NewDefaultConfig() require.NoError(t, err) cfg.ConfmapProviders = nil cfg.ConfmapConverters = nil assert.NoError(t, cfg.Validate()) } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/main.go000066400000000000000000000174151511331344600254540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builder // import "go.opentelemetry.io/collector/cmd/builder/internal/builder" import ( "bytes" "errors" "fmt" "os" "os/exec" "path/filepath" "strings" "text/template" "time" "go.uber.org/zap" "golang.org/x/mod/modfile" "golang.org/x/mod/semver" ) var ( // ErrGoNotFound is returned when a Go binary hasn't been found ErrGoNotFound = errors.New("go binary not found") ErrDepNotFound = errors.New("dependency not found in go mod file") ErrVersionMismatch = errors.New("mismatch in go.mod and builder configuration versions") errDownloadFailed = errors.New("failed to download go modules") errCompileFailed = errors.New("failed to compile the OpenTelemetry Collector distribution") skipStrictMsg = "Use --skip-strict-versioning to temporarily disable this check. This flag will be removed in a future minor version" ) const otelcolPath = "go.opentelemetry.io/collector/otelcol" func runGoCommand(cfg *Config, args ...string) ([]byte, error) { if cfg.Verbose { cfg.Logger.Info("Running go subcommand.", zap.Any("arguments", args)) } //nolint:gosec // #nosec G204 -- cfg.Distribution.Go is trusted to be a safe path and the caller is assumed to have carried out necessary input validation cmd := exec.Command(cfg.Distribution.Go, args...) cmd.Dir = cfg.Distribution.OutputPath cmd.Env = os.Environ() if cfg.Distribution.CGoEnabled { cmd.Env = append(cmd.Env, "CGO_ENABLED=1") } else { cmd.Env = append(cmd.Env, "CGO_ENABLED=0") } var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { return nil, fmt.Errorf("go subcommand failed with args '%v': %w, error message: %s", args, err, stderr.String()) } if cfg.Verbose && stderr.Len() != 0 { cfg.Logger.Info("go subcommand error", zap.String("message", stderr.String())) } return stdout.Bytes(), nil } // GenerateAndCompile will generate the source files based on the given configuration, update go mod, and will compile into a binary func GenerateAndCompile(cfg *Config) error { if err := Generate(cfg); err != nil { return err } // run go get to update go.mod and go.sum files if err := GetModules(cfg); err != nil { return err } return Compile(cfg) } // Generate assembles a new distribution based on the given configuration func Generate(cfg *Config) error { if cfg.SkipGenerate { cfg.Logger.Info("Skipping generating source codes.") return nil } // if the file does not exist, try to create it if _, err := os.Stat(cfg.Distribution.OutputPath); os.IsNotExist(err) { if err = os.Mkdir(cfg.Distribution.OutputPath, 0o750); err != nil { return fmt.Errorf("failed to create output path: %w", err) } } else if err != nil { return fmt.Errorf("failed to create output path: %w", err) } for _, tmpl := range []*template.Template{ mainTemplate, mainOthersTemplate, mainWindowsTemplate, componentsTemplate, goModTemplate, } { if err := processAndWrite(cfg, tmpl, tmpl.Name(), cfg); err != nil { return fmt.Errorf("failed to generate source file %q: %w", tmpl.Name(), err) } } cfg.Logger.Info("Sources created", zap.String("path", cfg.Distribution.OutputPath)) return nil } // Compile generates a binary from the sources based on the configuration func Compile(cfg *Config) error { if cfg.SkipCompilation { cfg.Logger.Info("Generating source codes only, the distribution will not be compiled.") return nil } cfg.Logger.Info("Compiling") ldflags := "-s -w" // we strip the symbols by default for smaller binaries gcflags := "" args := []string{"build", "-trimpath", "-o", cfg.Distribution.Name} if cfg.Distribution.DebugCompilation { cfg.Logger.Info("Debug compilation is enabled, the debug symbols will be left on the resulting binary") ldflags = cfg.LDFlags gcflags = "all=-N -l" } else { if cfg.LDSet { cfg.Logger.Info("Using custom ldflags", zap.String("ldflags", cfg.LDFlags)) ldflags = cfg.LDFlags } if cfg.GCSet { cfg.Logger.Info("Using custom gcflags", zap.String("gcflags", cfg.GCFlags)) gcflags = cfg.GCFlags } } if cfg.Distribution.CGoEnabled { cfg.Logger.Info("Building with cgo enabled") } args = append(args, "-ldflags="+ldflags, "-gcflags="+gcflags) if cfg.Distribution.BuildTags != "" { args = append(args, "-tags", cfg.Distribution.BuildTags) } if _, err := runGoCommand(cfg, args...); err != nil { return fmt.Errorf("%w: %s", errCompileFailed, err.Error()) } cfg.Logger.Info("Compiled", zap.String("binary", fmt.Sprintf("%s/%s", cfg.Distribution.OutputPath, cfg.Distribution.Name))) return nil } // GetModules retrieves the go modules, updating go.mod and go.sum in the process func GetModules(cfg *Config) error { if cfg.SkipGetModules { cfg.Logger.Info("Generating source codes only, will not update go.mod and retrieve Go modules.") return nil } if _, err := runGoCommand(cfg, "mod", "tidy", "-compat=1.24"); err != nil { return fmt.Errorf("failed to update go.mod: %w", err) } if cfg.SkipStrictVersioning { return downloadModules(cfg) } // Perform strict version checking. For each component listed and the // otelcol core dependency, check that the enclosing go module matches. modulePath, dependencyVersions, err := readGoModFile(cfg) if err != nil { return err } coreDepVersion, ok := dependencyVersions[otelcolPath] betaVersion := semver.MajorMinor(defaultBetaOtelColVersion) if !ok { return fmt.Errorf("core collector %w: '%s'. %s", ErrDepNotFound, otelcolPath, skipStrictMsg) } if semver.MajorMinor(coreDepVersion) != betaVersion { return fmt.Errorf( "%w: core collector version calculated by component dependencies %q does not match configured version %q. %s", ErrVersionMismatch, coreDepVersion, betaVersion, skipStrictMsg) } for _, mod := range cfg.allComponents() { module, version, _ := strings.Cut(mod.GoMod, " ") if module == modulePath { // No need to check the version of components that are part of the // module we're building from. continue } moduleDepVersion, ok := dependencyVersions[module] if !ok { return fmt.Errorf("component %w: '%s'. %s", ErrDepNotFound, module, skipStrictMsg) } if semver.MajorMinor(moduleDepVersion) != semver.MajorMinor(version) { return fmt.Errorf( "%w: component %q version calculated by dependencies %q does not match configured version %q. %s", ErrVersionMismatch, module, moduleDepVersion, version, skipStrictMsg) } } return downloadModules(cfg) } func downloadModules(cfg *Config) error { cfg.Logger.Info("Getting go modules") failReason := "unknown" for i := 1; i <= cfg.downloadModules.numRetries; i++ { if _, err := runGoCommand(cfg, "mod", "download"); err != nil { failReason = err.Error() cfg.Logger.Info("Failed modules download", zap.String("retry", fmt.Sprintf("%d/%d", i, cfg.downloadModules.numRetries))) time.Sleep(cfg.downloadModules.wait) continue } return nil } return fmt.Errorf("%w: %s", errDownloadFailed, failReason) } func processAndWrite(cfg *Config, tmpl *template.Template, outFile string, tmplParams any) error { out, err := os.Create(filepath.Clean(filepath.Join(cfg.Distribution.OutputPath, outFile))) if err != nil { return err } defer out.Close() return tmpl.Execute(out, tmplParams) } func readGoModFile(cfg *Config) (string, map[string]string, error) { var modPath string stdout, err := runGoCommand(cfg, "mod", "edit", "-print") if err != nil { return modPath, nil, err } parsedFile, err := modfile.Parse("go.mod", stdout, nil) if err != nil { return modPath, nil, err } if parsedFile.Module != nil { modPath = parsedFile.Module.Mod.Path } dependencies := map[string]string{} for _, req := range parsedFile.Require { if req == nil { continue } dependencies[req.Mod.Path] = req.Mod.Version } return modPath, dependencies, nil } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/main_test.go000066400000000000000000000332661511331344600265150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builder import ( "fmt" "io" "os" "path" "path/filepath" "runtime" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "golang.org/x/mod/modfile" ) const ( goModTestFile = `// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 module go.opentelemetry.io/collector/cmd/builder/internal/tester go 1.20 require ( go.opentelemetry.io/collector/component v0.96.0 go.opentelemetry.io/collector/connector v0.94.1 go.opentelemetry.io/collector/exporter v0.94.1 go.opentelemetry.io/collector/extension v0.94.1 go.opentelemetry.io/collector/otelcol v0.94.1 go.opentelemetry.io/collector/processor v0.94.1 go.opentelemetry.io/collector/receiver v0.94.1 go.opentelemetry.io/collector v0.96.0 )` modulePrefix = "go.opentelemetry.io/collector" ) var replaceModules = []string{ "", "/component", "/component/componentstatus", "/component/componenttest", "/client", "/config/configauth", "/config/configcompression", "/config/configgrpc", "/config/confighttp", "/config/configmiddleware", "/config/confignet", "/config/configopaque", "/config/configoptional", "/config/configretry", "/config/configtelemetry", "/config/configtls", "/confmap", "/confmap/xconfmap", "/confmap/provider/envprovider", "/confmap/provider/fileprovider", "/confmap/provider/httpprovider", "/confmap/provider/httpsprovider", "/confmap/provider/yamlprovider", "/consumer", "/consumer/consumererror", "/consumer/consumererror/xconsumererror", "/consumer/xconsumer", "/consumer/consumertest", "/connector", "/connector/connectortest", "/connector/xconnector", "/exporter", "/exporter/debugexporter", "/exporter/xexporter", "/exporter/exportertest", "/exporter/exporterhelper", "/exporter/exporterhelper/xexporterhelper", "/exporter/nopexporter", "/exporter/otlpexporter", "/exporter/otlphttpexporter", "/extension", "/extension/extensionauth", "/extension/extensionauth/extensionauthtest", "/extension/extensioncapabilities", "/extension/extensionmiddleware", "/extension/extensionmiddleware/extensionmiddlewaretest", "/extension/extensiontest", "/extension/zpagesextension", "/extension/xextension", "/featuregate", "/internal/memorylimiter", "/internal/fanoutconsumer", "/internal/sharedcomponent", "/internal/telemetry", "/internal/testutil", "/otelcol", "/pdata", "/pdata/testdata", "/pdata/pprofile", "/pdata/xpdata", "/pipeline", "/pipeline/xpipeline", "/processor", "/processor/processortest", "/processor/batchprocessor", "/processor/memorylimiterprocessor", "/processor/processorhelper", "/processor/processorhelper/xprocessorhelper", "/processor/xprocessor", "/receiver", "/receiver/nopreceiver", "/receiver/otlpreceiver", "/receiver/receivertest", "/receiver/receiverhelper", "/receiver/xreceiver", "/service", "/service/hostcapabilities", "/service/telemetry/telemetrytest", } func newTestConfig(tb testing.TB) *Config { cfg, err := NewDefaultConfig() require.NoError(tb, err) cfg.downloadModules.wait = 0 cfg.downloadModules.numRetries = 1 return cfg } func newInitializedConfig(t *testing.T) *Config { cfg := newTestConfig(t) // Validate and ParseModules will be called before the config is // given to Generate. assert.NoError(t, cfg.Validate()) assert.NoError(t, cfg.ParseModules()) return cfg } func TestGenerateDefault(t *testing.T) { require.NoError(t, Generate(newInitializedConfig(t))) } func TestGenerateInvalidOutputPath(t *testing.T) { cfg := newInitializedConfig(t) cfg.Distribution.OutputPath = ":/invalid" err := Generate(cfg) require.ErrorContains(t, err, "failed to create output path") } func TestVersioning(t *testing.T) { replaces := generateReplaces() tests := []struct { name string cfgBuilder func() *Config expectedErr error }{ { name: "defaults", cfgBuilder: func() *Config { cfg := newTestConfig(t) cfg.Distribution.Go = "go" cfg.Replaces = append(cfg.Replaces, replaces...) return cfg }, expectedErr: nil, }, { name: "only gomod file, skip generate", cfgBuilder: func() *Config { cfg := newTestConfig(t) tempDir := t.TempDir() err := makeModule(tempDir, []byte(goModTestFile)) require.NoError(t, err) cfg.Distribution.OutputPath = tempDir cfg.SkipGenerate = true cfg.Distribution.Go = "go" return cfg }, expectedErr: ErrDepNotFound, }, { name: "old component version", cfgBuilder: func() *Config { cfg := newTestConfig(t) cfg.Distribution.Go = "go" cfg.Exporters = []Module{ { GoMod: "go.opentelemetry.io/collector/exporter/otlpexporter v0.112.0", }, } cfg.ConfmapProviders = []Module{} cfg.Replaces = append(cfg.Replaces, replaces...) return cfg }, expectedErr: nil, }, { name: "old component version without strict mode", cfgBuilder: func() *Config { cfg := newTestConfig(t) cfg.Distribution.Go = "go" cfg.SkipStrictVersioning = true cfg.Exporters = []Module{ { GoMod: "go.opentelemetry.io/collector/exporter/otlpexporter v0.112.0", }, } cfg.ConfmapProviders = []Module{} cfg.Replaces = append(cfg.Replaces, replaces...) return cfg }, expectedErr: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // X25519 curves are not supported when GODEBUG=fips140=only is set, so we // detect if it is and conditionally also add the tlsmklem=0 flag to disable // these curves. See: https://pkg.go.dev/crypto/tls#Config.CurvePreferences if strings.Contains(os.Getenv("GODEBUG"), "fips140=only") { t.Setenv("GODEBUG", os.Getenv("GODEBUG")+",tlsmlkem=0") } cfg := tt.cfgBuilder() require.NoError(t, cfg.Validate()) require.NoError(t, cfg.ParseModules()) err := GenerateAndCompile(cfg) require.ErrorIs(t, err, tt.expectedErr) }) } } func TestSkipGenerate(t *testing.T) { cfg := newInitializedConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.SkipGenerate = true err := Generate(cfg) require.NoError(t, err) outputFile, err := os.Open(cfg.Distribution.OutputPath) defer func() { require.NoError(t, outputFile.Close()) }() require.NoError(t, err) _, err = outputFile.Readdirnames(1) require.ErrorIs(t, err, io.EOF, "skip generate should leave output directory empty") } func TestGenerateAndCompile(t *testing.T) { replaces := generateReplaces() testCases := []struct { name string cfgBuilder func(t *testing.T) *Config }{ { name: "Default Configuration Compilation", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) return cfg }, }, { name: "LDFlags Compilation", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) cfg.LDSet = true cfg.LDFlags = `-X "test.gitVersion=0743dc6c6411272b98494a9b32a63378e84c34da" -X "test.gitTag=local-testing" -X "test.goVersion=go version go1.20.7 darwin/amd64"` return cfg }, }, { name: "GCFlags Compilation", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) cfg.GCSet = true cfg.GCFlags = `all=-N -l` return cfg }, }, { name: "Build Tags Compilation", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) cfg.Distribution.BuildTags = "customTag" return cfg }, }, { name: "Debug Compilation", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) cfg.Logger = zap.NewNop() cfg.Distribution.DebugCompilation = true return cfg }, }, { name: "No providers", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) cfg.ConfmapProviders = []Module{} return cfg }, }, { name: "With confmap factories", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) cfg.SkipStrictVersioning = true return cfg }, }, { name: "ConfResolverDefaultURIScheme set", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.ConfResolver = ConfResolver{ DefaultURIScheme: "env", } cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) return cfg }, }, { name: "CGoEnabled set to true", cfgBuilder: func(t *testing.T) *Config { cfg := newTestConfig(t) cfg.Distribution.OutputPath = t.TempDir() cfg.Replaces = append(cfg.Replaces, replaces...) cfg.Distribution.CGoEnabled = true return cfg }, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgBuilder(t) assert.NoError(t, cfg.Validate()) assert.NoError(t, cfg.SetGoPath()) assert.NoError(t, cfg.ParseModules()) require.NoError(t, GenerateAndCompile(cfg)) }) } } // Test that the go.mod files that other tests in this file // may generate have all their modules covered by our // "replace" statements created in `generateReplaces`. // // An incomplete set of replace statements in these tests // may cause them to fail during the release process, when // the local version of modules in the release branch is // not yet available on the Go package repository. // Unless the replace statements route all modules to the // local copy, `go get` will try to fetch the unreleased // version remotely and some tests will fail. func TestReplaceStatementsAreComplete(t *testing.T) { workspaceDir := getWorkspaceDir() replaceMods := map[string]bool{} for _, suffix := range replaceModules { replaceMods[modulePrefix+suffix] = false } for _, mod := range replaceModules { verifyGoMod(t, workspaceDir+mod, replaceMods) } var err error dir := t.TempDir() cfg, err := NewDefaultConfig() require.NoError(t, err) cfg.Distribution.Go = "go" cfg.Distribution.OutputPath = dir cfg.Replaces = append(cfg.Replaces, generateReplaces()...) // Configure all components that we want to use elsewhere in these tests. // This ensures the resulting go.mod file has maximum coverage of modules // that exist in the Core repository. usedNames := make(map[string]int) cfg.Exporters, err = parseModules([]Module{ { GoMod: "go.opentelemetry.io/collector/exporter/debugexporter v1.9999.9999", }, { GoMod: "go.opentelemetry.io/collector/exporter/nopexporter v1.9999.9999", }, { GoMod: "go.opentelemetry.io/collector/exporter/otlpexporter v1.9999.9999", }, { GoMod: "go.opentelemetry.io/collector/exporter/otlphttpexporter v1.9999.9999", }, }, usedNames) require.NoError(t, err) cfg.Receivers, err = parseModules([]Module{ { GoMod: "go.opentelemetry.io/collector/receiver/nopreceiver v1.9999.9999", }, { GoMod: "go.opentelemetry.io/collector/receiver/otlpreceiver v1.9999.9999", }, }, usedNames) require.NoError(t, err) cfg.Extensions, err = parseModules([]Module{ { GoMod: "go.opentelemetry.io/collector/extension/zpagesextension v1.9999.9999", }, }, usedNames) require.NoError(t, err) cfg.Processors, err = parseModules([]Module{ { GoMod: "go.opentelemetry.io/collector/processor/batchprocessor v1.9999.9999", }, { GoMod: "go.opentelemetry.io/collector/processor/memorylimiterprocessor v1.9999.9999", }, }, usedNames) require.NoError(t, err) require.NoError(t, cfg.Validate()) require.NoError(t, cfg.ParseModules()) err = GenerateAndCompile(cfg) require.NoError(t, err) verifyGoMod(t, dir, replaceMods) for k, v := range replaceMods { assert.Truef(t, v, "Module not used: %s", k) } } func verifyGoMod(t *testing.T, dir string, replaceMods map[string]bool) { gomodpath := path.Join(dir, "go.mod") //nolint:gosec // #nosec G304 We control this path and generate the file inside, so we can assume it is safe. gomod, err := os.ReadFile(gomodpath) require.NoError(t, err) mod, err := modfile.Parse(gomodpath, gomod, nil) require.NoError(t, err) for _, req := range mod.Require { if !strings.HasPrefix(req.Mod.Path, modulePrefix) { continue } _, ok := replaceMods[req.Mod.Path] assert.Truef(t, ok, "Module missing from replace statements list: %s", req.Mod.Path) replaceMods[req.Mod.Path] = true } } func makeModule(dir string, fileContents []byte) error { // if the file does not exist, try to create it if _, err := os.Stat(dir); os.IsNotExist(err) { if err = os.Mkdir(dir, 0o750); err != nil { return fmt.Errorf("failed to create output path: %w", err) } } else if err != nil { return fmt.Errorf("failed to create output path: %w", err) } err := os.WriteFile(filepath.Clean(filepath.Join(dir, "go.mod")), fileContents, 0o600) if err != nil { return fmt.Errorf("failed to write go.mod file: %w", err) } return nil } func generateReplaces() []string { workspaceDir := getWorkspaceDir() modules := replaceModules replaces := make([]string, len(modules)) for i, mod := range modules { replaces[i] = fmt.Sprintf("%s%s => %s%s", modulePrefix, mod, workspaceDir, mod) } return replaces } func getWorkspaceDir() string { // This is dependent on the current file structure. // The goal is find the root of the repo so we can replace the root module. _, thisFile, _, _ := runtime.Caller(0) return filepath.Dir(filepath.Dir(filepath.Dir(filepath.Dir(filepath.Dir(thisFile))))) } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/package_test.go000066400000000000000000000003101511331344600271440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builder import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/templates.go000066400000000000000000000017401511331344600265200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builder // import "go.opentelemetry.io/collector/cmd/builder/internal/builder" import ( _ "embed" "text/template" ) var ( //go:embed templates/components.go.tmpl componentsBytes []byte componentsTemplate = parseTemplate("components.go", componentsBytes) //go:embed templates/main.go.tmpl mainBytes []byte mainTemplate = parseTemplate("main.go", mainBytes) //go:embed templates/main_others.go.tmpl mainOthersBytes []byte mainOthersTemplate = parseTemplate("main_others.go", mainOthersBytes) //go:embed templates/main_windows.go.tmpl mainWindowsBytes []byte mainWindowsTemplate = parseTemplate("main_windows.go", mainWindowsBytes) //go:embed templates/go.mod.tmpl goModBytes []byte goModTemplate = parseTemplate("go.mod", goModBytes) ) func parseTemplate(name string, bytes []byte) *template.Template { return template.Must(template.New(name).Parse(string(bytes))) } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/templates/000077500000000000000000000000001511331344600261675ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/builder/internal/builder/templates/components.go.tmpl000066400000000000000000000055171511331344600316660ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. package main import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" {{- range .Connectors}} {{.Name}} "{{.Import}}" {{- end}} {{- range .Exporters}} {{.Name}} "{{.Import}}" {{- end}} {{- range .Extensions}} {{.Name}} "{{.Import}}" {{- end}} {{- range .Processors}} {{.Name}} "{{.Import}}" {{- end}} {{- range .Receivers}} {{.Name}} "{{.Import}}" {{- end}} ) func components() (otelcol.Factories, error) { var err error factories := otelcol.Factories{ Telemetry: otelconftelemetry.NewFactory(), } factories.Extensions, err = otelcol.MakeFactoryMap[extension.Factory]( {{- range .Extensions}} {{.Name}}.NewFactory(), {{- end}} ) if err != nil { return otelcol.Factories{}, err } factories.ExtensionModules = make(map[component.Type]string, len(factories.Extensions)) {{- range .Extensions}} factories.ExtensionModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}" {{- end}} factories.Receivers, err = otelcol.MakeFactoryMap[receiver.Factory]( {{- range .Receivers}} {{.Name}}.NewFactory(), {{- end}} ) if err != nil { return otelcol.Factories{}, err } factories.ReceiverModules = make(map[component.Type]string, len(factories.Receivers)) {{- range .Receivers}} factories.ReceiverModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}" {{- end}} factories.Exporters, err = otelcol.MakeFactoryMap[exporter.Factory]( {{- range .Exporters}} {{.Name}}.NewFactory(), {{- end}} ) if err != nil { return otelcol.Factories{}, err } factories.ExporterModules = make(map[component.Type]string, len(factories.Exporters)) {{- range .Exporters}} factories.ExporterModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}" {{- end}} factories.Processors, err = otelcol.MakeFactoryMap[processor.Factory]( {{- range .Processors}} {{.Name}}.NewFactory(), {{- end}} ) if err != nil { return otelcol.Factories{}, err } factories.ProcessorModules = make(map[component.Type]string, len(factories.Processors)) {{- range .Processors}} factories.ProcessorModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}" {{- end}} factories.Connectors, err = otelcol.MakeFactoryMap[connector.Factory]( {{- range .Connectors}} {{.Name}}.NewFactory(), {{- end}} ) if err != nil { return otelcol.Factories{}, err } factories.ConnectorModules = make(map[component.Type]string, len(factories.Connectors)) {{- range .Connectors}} factories.ConnectorModules[{{.Name}}.NewFactory().Type()] = "{{.GoMod}}" {{- end}} return factories, nil } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/templates/go.mod.tmpl000066400000000000000000000030071511331344600302500ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. module {{.Distribution.Module}} go 1.24 require ( {{- range .ConfmapConverters}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} {{- range .ConfmapProviders}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} {{- range .Connectors}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} {{- range .Extensions}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} {{- range .Receivers}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} {{- range .Exporters}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} {{- range .Processors}} {{if .GoMod}}{{.GoMod}}{{end}} {{- end}} go.opentelemetry.io/collector/otelcol {{.OtelColVersion}} ) require ( github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/providers/confmap v0.1.0 // indirect ) {{- range .ConfmapConverters}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} {{- range .ConfmapProviders}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} {{- range .Connectors}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} {{- range .Extensions}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} {{- range .Receivers}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} {{- range .Exporters}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} {{- range .Processors}} {{if ne .Path ""}}replace {{.GoMod}} => {{.Path}}{{end}} {{- end}} {{- range .Replaces}} replace {{.}} {{- end}} {{- range .Excludes}} exclude {{.}} {{- end}} opentelemetry-collector-0.141.0/cmd/builder/internal/builder/templates/main.go.tmpl000066400000000000000000000034461511331344600304240ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. // Program {{ .Distribution.Name }} is an OpenTelemetry Collector binary. package main import ( "log" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" {{- range .ConfmapConverters}} {{.Name}} "{{.Import}}" {{- end}} {{- range .ConfmapProviders}} {{.Name}} "{{.Import}}" {{- end}} "go.opentelemetry.io/collector/otelcol" ) func main() { info := component.BuildInfo{ Command: "{{ .Distribution.Name }}", Description: "{{ .Distribution.Description }}", Version: "{{ .Distribution.Version }}", } set := otelcol.CollectorSettings{ BuildInfo: info, Factories: components, ConfigProviderSettings: otelcol.ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ ProviderFactories: []confmap.ProviderFactory{ {{- range .ConfmapProviders}} {{.Name}}.NewFactory(), {{- end}} }, {{- if .ConfmapConverters }} ConverterFactories: []confmap.ConverterFactory{ {{- range .ConfmapConverters}} {{.Name}}.NewFactory(), {{- end}} }, {{- end }} {{- if .ConfResolver.DefaultURIScheme }} DefaultScheme: "{{ .ConfResolver.DefaultURIScheme }}", {{- end }} }, }, ProviderModules: map[string]string{ {{- range .ConfmapProviders}} {{.Name}}.NewFactory().Create(confmap.ProviderSettings{}).Scheme(): "{{.GoMod}}", {{- end}} }, ConverterModules: []string{ {{- range .ConfmapConverters}} "{{.GoMod}}", {{- end}} }, } if err := run(set); err != nil { log.Fatal(err) } } func runInteractive(params otelcol.CollectorSettings) error { cmd := otelcol.NewCommand(params) if err := cmd.Execute(); err != nil { log.Fatalf("collector server run finished with error: %v", err) } return nil } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/templates/main_others.go.tmpl000066400000000000000000000003671511331344600320070ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. //go:build !windows package main import "go.opentelemetry.io/collector/otelcol" func run(params otelcol.CollectorSettings) error { return runInteractive(params) } opentelemetry-collector-0.141.0/cmd/builder/internal/builder/templates/main_windows.go.tmpl000066400000000000000000000015451511331344600321740ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. //go:build windows package main import ( "errors" "fmt" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "go.opentelemetry.io/collector/otelcol" ) func run(params otelcol.CollectorSettings) error { // No need to supply service name when startup is invoked through // the Service Control Manager directly. if err := svc.Run("", otelcol.NewSvcHandler(params)); err != nil { if errors.Is(err, windows.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { // Per https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-startservicectrldispatchera#return-value // this means that the process is not running as a service, so run interactively. return runInteractive(params) } return fmt.Errorf("failed to start collector server: %w", err) } return nil } opentelemetry-collector-0.141.0/cmd/builder/internal/command.go000066400000000000000000000127051511331344600245150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/builder/internal" import ( "fmt" "github.com/knadh/koanf/parsers/yaml" "github.com/knadh/koanf/providers/env/v2" "github.com/knadh/koanf/providers/file" "github.com/knadh/koanf/v2" "github.com/spf13/cobra" flag "github.com/spf13/pflag" "go.uber.org/multierr" "go.uber.org/zap" "go.opentelemetry.io/collector/cmd/builder/internal/builder" "go.opentelemetry.io/collector/cmd/builder/internal/config" ) const ( configFlag = "config" skipGenerateFlag = "skip-generate" skipCompilationFlag = "skip-compilation" skipGetModulesFlag = "skip-get-modules" skipStrictVersioningFlag = "skip-strict-versioning" ldflagsFlag = "ldflags" gcflagsFlag = "gcflags" distributionOutputPathFlag = "output-path" verboseFlag = "verbose" ) // Command is the main entrypoint for this application func Command() (*cobra.Command, error) { cmd := &cobra.Command{ SilenceUsage: true, // Don't print usage on Run error. SilenceErrors: true, // Don't print errors; main does it. Use: "ocb", Long: fmt.Sprintf("OpenTelemetry Collector Builder (%s)", version) + ` ocb generates a custom OpenTelemetry Collector binary using the build configuration given by the "--config" argument. If no build configuration is provided, ocb will generate a default Collector. `, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { cfg, err := initConfig(cmd.Flags()) if err != nil { return err } if err = cfg.Validate(); err != nil { return fmt.Errorf("invalid configuration: %w", err) } if err = cfg.SetGoPath(); err != nil { return fmt.Errorf("go not found: %w", err) } if err = cfg.ParseModules(); err != nil { return fmt.Errorf("invalid module configuration: %w", err) } return builder.GenerateAndCompile(cfg) }, } if err := initFlags(cmd.Flags()); err != nil { return nil, err } // version of this binary cmd.AddCommand(versionCommand()) return cmd, nil } func initFlags(flags *flag.FlagSet) error { flags.String(configFlag, "", "build configuration file") // the distribution parameters, which we accept as CLI flags as well flags.Bool(skipGenerateFlag, false, "Whether builder should skip generating go code (default false)") flags.Bool(skipCompilationFlag, false, "Whether builder should only generate go code with no compile of the collector (default false)") flags.Bool(skipGetModulesFlag, false, "Whether builder should skip updating go.mod and retrieve Go module list (default false)") flags.Bool(skipStrictVersioningFlag, true, "Whether builder should skip strictly checking the calculated versions following dependency resolution") flags.Bool(verboseFlag, false, "Whether builder should print verbose output (default false)") flags.String(ldflagsFlag, "", `ldflags to include in the "go build" command`) flags.String(gcflagsFlag, "", `gcflags to include in the "go build" command`) flags.String(distributionOutputPathFlag, "", "Where to write the resulting files") return flags.MarkDeprecated(distributionOutputPathFlag, "use config distribution::output_path") } func initConfig(flags *flag.FlagSet) (*builder.Config, error) { cfg, err := builder.NewDefaultConfig() if err != nil { return nil, err } cfg.Logger.Info("OpenTelemetry Collector Builder", zap.String("version", version)) var provider koanf.Provider cfgFile, _ := flags.GetString(configFlag) if cfgFile != "" { cfg.Logger.Info("Using config file", zap.String("path", cfgFile)) // load the config file provider = file.Provider(cfgFile) } else { cfg.Logger.Info("Using default build configuration") // or the default if the config isn't provided provider = config.DefaultProvider() } k := koanf.New(".") if err = k.Load(provider, yaml.Parser()); err != nil { return nil, fmt.Errorf("failed to load configuration file: %w", err) } // handle env variables if err = k.Load(env.Provider(".", env.Opt{}), nil); err != nil { return nil, fmt.Errorf("failed to load environment variables: %w", err) } if err = k.UnmarshalWithConf("", cfg, koanf.UnmarshalConf{Tag: "mapstructure"}); err != nil { return nil, fmt.Errorf("failed to unmarshal configuration: %w", err) } if err = applyFlags(flags, cfg); err != nil { return nil, fmt.Errorf("failed to apply flags configuration: %w", err) } return cfg, nil } func applyFlags(flags *flag.FlagSet, cfg *builder.Config) error { var errs, err error cfg.SkipGenerate, err = flags.GetBool(skipGenerateFlag) errs = multierr.Append(errs, err) cfg.SkipCompilation, err = flags.GetBool(skipCompilationFlag) errs = multierr.Append(errs, err) cfg.SkipGetModules, err = flags.GetBool(skipGetModulesFlag) errs = multierr.Append(errs, err) cfg.SkipStrictVersioning, err = flags.GetBool(skipStrictVersioningFlag) errs = multierr.Append(errs, err) if flags.Changed(ldflagsFlag) { cfg.LDSet = true cfg.LDFlags, err = flags.GetString(ldflagsFlag) errs = multierr.Append(errs, err) } if flags.Changed(gcflagsFlag) { cfg.GCSet = true cfg.GCFlags, err = flags.GetString(gcflagsFlag) errs = multierr.Append(errs, err) } cfg.Verbose, err = flags.GetBool(verboseFlag) errs = multierr.Append(errs, err) if flags.Changed(distributionOutputPathFlag) { cfg.Distribution.OutputPath, err = flags.GetString(distributionOutputPathFlag) errs = multierr.Append(errs, err) } return errs } opentelemetry-collector-0.141.0/cmd/builder/internal/command_test.go000066400000000000000000000065011511331344600255510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "strings" "testing" "github.com/spf13/cobra" flag "github.com/spf13/pflag" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/cmd/builder/internal/builder" ) func TestCommand(t *testing.T) { tests := []struct { name string want *cobra.Command wantErr bool }{ { name: "command created", want: &cobra.Command{ SilenceUsage: true, // Don't print usage on Run error. SilenceErrors: true, // Don't print errors; main does it. Use: "ocb", Long: "OpenTelemetry Collector Builder", Args: cobra.NoArgs, }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := Command() if !tt.wantErr { require.NoErrorf(t, err, "Command()") assert.Equal(t, tt.want.Aliases, got.Aliases) assert.Equal(t, tt.want.Annotations, got.Annotations) assert.Equal(t, tt.want.ValidArgs, got.ValidArgs) assert.Equal(t, tt.want.ArgAliases, got.ArgAliases) assert.Equal(t, tt.want.Use, got.Use) assert.Equal(t, tt.want.SilenceUsage, got.SilenceUsage) assert.Equal(t, tt.want.SilenceErrors, got.SilenceErrors) assert.True(t, strings.HasPrefix(got.Long, tt.want.Long)) assert.Empty(t, got.Short) assert.NotEqual(t, tt.want.HasFlags(), got.Flags().HasFlags()) } else { require.Error(t, err) } }) } } func TestApplyFlags(t *testing.T) { tests := []struct { name string flags []string want *builder.Config }{ { name: "Default flag values", want: &builder.Config{ SkipStrictVersioning: true, }, }, { name: "All flag values", flags: []string{"--skip-generate=true", "--skip-compilation=true", "--skip-get-modules=true", "--skip-strict-versioning=true", "--ldflags=test", "--gcflags=test", "--verbose=true"}, want: &builder.Config{ SkipGenerate: true, SkipCompilation: true, SkipGetModules: true, SkipStrictVersioning: true, LDFlags: "test", GCFlags: "test", Verbose: true, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { flags := flag.NewFlagSet("version=1.0.0", 1) require.NoError(t, initFlags(flags)) require.NoError(t, flags.Parse(tt.flags)) cfg, err := builder.NewDefaultConfig() require.NoError(t, err) require.NoError(t, applyFlags(flags, cfg)) assert.Equal(t, tt.want.SkipGenerate, cfg.SkipGenerate) assert.Equal(t, tt.want.SkipCompilation, cfg.SkipCompilation) assert.Equal(t, tt.want.SkipGetModules, cfg.SkipGetModules) assert.Equal(t, tt.want.SkipStrictVersioning, cfg.SkipStrictVersioning) assert.Equal(t, tt.want.LDFlags, cfg.LDFlags) assert.Equal(t, tt.want.Verbose, cfg.Verbose) }) } } func TestInitConfig(t *testing.T) { tests := []struct { name string flags *flag.FlagSet wantErr bool }{ { name: "initConfig created correctly", flags: flag.NewFlagSet("version=1.0.0", 1), wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { require.NoError(t, initFlags(tt.flags)) _, err := initConfig(tt.flags) if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) }) } } opentelemetry-collector-0.141.0/cmd/builder/internal/config/000077500000000000000000000000001511331344600240105ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/builder/internal/config/default.go000066400000000000000000000010431511331344600257610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package config // import "go.opentelemetry.io/collector/cmd/builder/internal/config" import ( "embed" "github.com/knadh/koanf/providers/fs" "github.com/knadh/koanf/v2" ) //go:embed *.yaml var configs embed.FS // DefaultProvider returns a koanf.Provider that provides the default build // configuration file. This is the same configuration that otelcorecol is // built with. func DefaultProvider() koanf.Provider { return fs.Provider(configs, "default.yaml") } opentelemetry-collector-0.141.0/cmd/builder/internal/config/default.yaml000066400000000000000000000035051511331344600263230ustar00rootroot00000000000000# NOTE: # This builder configuration is NOT used to build any official binary. # To see the builder manifests used for official binaries, # check https://github.com/open-telemetry/opentelemetry-collector-releases # # For the OpenTelemetry Collector Core official distribution sources, check # https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol dist: module: go.opentelemetry.io/collector/cmd/otelcorecol name: otelcorecol description: Local OpenTelemetry Collector binary, testing only. version: 0.141.0-dev receivers: - gomod: go.opentelemetry.io/collector/receiver/nopreceiver v0.141.0 - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.141.0 exporters: - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.141.0 - gomod: go.opentelemetry.io/collector/exporter/nopexporter v0.141.0 - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.141.0 - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.141.0 extensions: - gomod: go.opentelemetry.io/collector/extension/memorylimiterextension v0.141.0 - gomod: go.opentelemetry.io/collector/extension/zpagesextension v0.141.0 processors: - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.141.0 - gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.141.0 connectors: - gomod: go.opentelemetry.io/collector/connector/forwardconnector v0.141.0 providers: - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.47.0 opentelemetry-collector-0.141.0/cmd/builder/internal/package_test.go000066400000000000000000000003111511331344600255170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/builder/internal/version.go000066400000000000000000000014171511331344600245620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/builder/internal" import ( "fmt" "runtime/debug" "github.com/spf13/cobra" ) var version = "" func init() { // the second returned value is a boolean, which is true if the binaries are built with module support. if version != "" { return } info, ok := debug.ReadBuildInfo() if ok { version = info.Main.Version } } func versionCommand() *cobra.Command { return &cobra.Command{ Use: "version", Short: "Version of ocb", Long: "Prints the version of the ocb binary", RunE: func(cmd *cobra.Command, _ []string) error { cmd.Println(fmt.Sprintf("%s version %s", cmd.Parent().Name(), version)) return nil }, } } opentelemetry-collector-0.141.0/cmd/builder/main.go000066400000000000000000000004361511331344600222050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package main import ( "github.com/spf13/cobra" "go.opentelemetry.io/collector/cmd/builder/internal" ) func main() { cmd, err := internal.Command() cobra.CheckErr(err) cobra.CheckErr(cmd.Execute()) } opentelemetry-collector-0.141.0/cmd/builder/metadata.yaml000066400000000000000000000002701511331344600233720ustar00rootroot00000000000000type: builder github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: cmd stability: alpha: [metrics] codeowners: active: [] opentelemetry-collector-0.141.0/cmd/builder/test/000077500000000000000000000000001511331344600217065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/builder/test/README.md000066400000000000000000000006051511331344600231660ustar00rootroot00000000000000# Testing for the OpenTelemetry Collector Builder This is a set of end-to-end tests for the builder. As such, it includes only positive tests, based on the manifest files in this directory. Each manifest is expected to be in a working state and should yield an OpenTelemetry Collector instance that is ready within a time interval. "Ready" is defined by calling its healthcheck endpoint. opentelemetry-collector-0.141.0/cmd/builder/test/core.builder.yaml000066400000000000000000000005361511331344600251530ustar00rootroot00000000000000dist: name: core module: go.opentelemetry.io/collector/builder/test/core go: ${GOBIN} extensions: - gomod: go.opentelemetry.io/collector/extension/zpagesextension v0.141.0 receivers: - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.141.0 exporters: - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.141.0 opentelemetry-collector-0.141.0/cmd/builder/test/core.otel.yaml000066400000000000000000000003671511331344600244720ustar00rootroot00000000000000extensions: zpages: receivers: otlp: protocols: grpc: processors: exporters: debug: service: extensions: [zpages] pipelines: traces: receivers: - otlp processors: [] exporters: - debug opentelemetry-collector-0.141.0/cmd/builder/test/test.sh000077500000000000000000000077061511331344600232360ustar00rootroot00000000000000#!/bin/bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) WORKSPACE_DIR=$( cd -- "$( dirname "$(dirname "$(dirname -- "${SCRIPT_DIR}")")" )" &> /dev/null && pwd ) export WORKSPACE_DIR GOBIN=$(go env GOBIN) if [[ "$GO" == "" ]]; then GOBIN=$(which go) fi export GOBIN if [[ "$GOBIN" == "" ]]; then echo "Could not determine which Go binary to use." exit 1 fi echo "Using ${GOBIN} to compile the distributions." test_build_config() { local test="$1" local build_config="$2" out="${base}/${test}" if ! mkdir -p "${out}"; then echo "โŒ FAIL ${test}. Failed to create test directory for the test. Aborting tests." exit 2 fi echo "Starting test '${test}' at $(date)" >> "${out}/test.log" final_build_config=$(basename "${build_config}") go tool -modfile "${WORKSPACE_DIR}/internal/tools/go.mod" envsubst \ -o "${out}/${final_build_config}" -i <(cat "$build_config" "$replaces") if ! go run . --config "${out}/${final_build_config}" --output-path "${out}" > "${out}/builder.log" 2>&1; then echo "โŒ FAIL ${test}. Failed to compile the test ${test}. Build logs:" cat "${out}/builder.log" failed=true return fi if [ ! -f "${out}/${test}" ]; then echo "โŒ FAIL ${test}. Binary not found for ${test} at '${out}/${test}'. Build logs:" cat "${out}/builder.log" failed=true return fi # start the distribution if [ ! -f "./test/${test}.otel.yaml" ]; then echo "โŒ FAIL ${test}. Config file for ${test} not found at './test/${test}.otel.yaml'" failed=true return fi "${out}/${test}" --config "./test/${test}.otel.yaml" > "${out}/otelcol.log" 2>&1 & pid=$! retries=0 while true do if ! kill -0 "${pid}" >/dev/null 2>&1; then echo "โŒ FAIL ${test}. The OpenTelemetry Collector isn't running. Startup log:" cat "${out}/otelcol.log" failed=true break fi # Since the content of the servicez page depend on which extensions are # built into the collector, we depend only on the zpages extension # being present and serving something. if curl --fail --silent --output /dev/null http://localhost:55679/debug/servicez; then echo "โœ… PASS ${test}" kill "${pid}" ret=$? if [ $ret -ne 0 ]; then echo "Failed to stop the running instance for test ${test}. Return code: ${ret} . Skipping tests." exit 4 fi break fi echo "Server still unavailable for test '${test}'" >> "${out}/test.log" ((retries++)) if [ "$retries" -gt "$max_retries" ]; then echo "โŒ FAIL ${test}. Server wasn't up after about 5s." failed=true kill "${pid}" ret=$? if [ $ret -ne 0 ]; then echo "Failed to stop the running instance for test ${test}. Return code: ${ret} . Skipping tests." exit 8 fi break fi sleep 0.1s done echo "Stopping server for '${test}' (pid: ${pid})" >> "${out}/test.log" } # each attempt pauses for 100ms before retrying max_retries=50 tests="core" base=$(mktemp -d) echo "Running the tests in ${base}" replaces="$base/replaces" # Get path of all core modules, in sorted order core_mods=$(cd ../.. && find . -type f -name "go.mod" -exec dirname {} \; | sort) echo "replaces:" >> "$replaces" for mod_path in $core_mods; do mod=${mod_path#"."} # remove initial dot echo " - go.opentelemetry.io/collector$mod => \${WORKSPACE_DIR}$mod" >> "$replaces" done echo "Wrote replace statements to $replaces" failed=false for test in $tests do test_build_config "$test" "./test/${test}.builder.yaml" done if [[ "$failed" == "true" ]]; then exit 1 fi opentelemetry-collector-0.141.0/cmd/githubgen/000077500000000000000000000000001511331344600212555ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/githubgen/allowlist.txt000066400000000000000000000000001511331344600240160ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/000077500000000000000000000000001511331344600210615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/Makefile000066400000000000000000000000361511331344600225200ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/cmd/mdatagen/README.md000066400000000000000000000124201511331344600223370ustar00rootroot00000000000000# Metadata Generator | Status | | | ------------- |-----------| | Stability | [alpha]: metrics | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Acmd%2Fmdatagen%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Acmd%2Fmdatagen) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Acmd%2Fmdatagen%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Acmd%2Fmdatagen) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@dmitryax](https://www.github.com/dmitryax) | [alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha Every component's documentation should include a brief description of the component and guidance on how to use it. There is also some information about the component (or metadata) that should be included to help end-users understand the current state of the component and whether it is right for their use case. Examples of this metadata about a component are: * its stability level * the distributions containing it * the types of pipelines it supports * metrics emitted in the case of a scraping receiver, a scraper, or a connector The metadata generator defines a schema for specifying this information to ensure it is complete and well-formed. The metadata generator is then able to ingest the metadata, validate it against the schema and produce documentation in a standardized format. An example of how this generated documentation looks can be found in [documentation.md](https://github.com/open-telemetry/opentelemetry-collector/blob/main/cmd/mdatagen/internal/samplereceiver/documentation.md). ## Using the Metadata Generator In order for a component to benefit from the metadata generator (`mdatagen`) these requirements need to be met: 1. A yaml file containing the metadata that needs to be included in the component 2. The component should declare a `go:generate mdatagen` directive which tells `mdatagen` what to generate As an example, here is a minimal `metadata.yaml` for the [OTLP receiver](https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver/otlpreceiver): ```yaml type: otlp status: class: receiver stability: beta: [logs] stable: [metrics, traces] ``` Detailed information about the schema of `metadata.yaml` can be found in [metadata-schema.yaml](./metadata-schema.yaml). The `go:generate mdatagen` directive is usually defined in a `doc.go` file in the same package as the component, for example: ```go //go:generate mdatagen metadata.yaml package main ``` Below are some more examples that can be used for reference: * The ElasticSearch receiver has an extensive [metadata.yaml](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/elasticsearchreceiver/metadata.yaml) * The host metrics receiver has internal subcomponents, each with their own `metadata.yaml` and `doc.go`. See [cpuscraper](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/hostmetricsreceiver/internal/scraper/cpuscraper) for example. You can run `cd cmd/mdatagen && $(GOCMD) install .` to install the `mdatagen` tool in `GOBIN` and then run `mdatagen metadata.yaml` to generate documentation for a specific component or you can run `make generate` to generate documentation for all components. ### Generate multiple metadata packages By default, `mdatagen` will generate a package called `metadata` in the `internal` directory. If you want to generate a package with a different name, you can use the `generated_package_name` configuration field to provide an alternate name. ```yaml type: otlp generated_package_name: customname status: class: receiver stability: beta: [logs] stable: [metrics, traces] ``` The most common scenario for this would be making major changes to a receiver's metadata without breaking what exists. In this scenario, `mdatagen` could produce separate packages for different metadata specs in the same receiver: ```go //go:generate mdatagen metadata.yaml //go:generate mdatagen custom.yaml package main ``` With two different packages generated, the behaviour for which metadata is used can be easily controlled via featuregate or a similar mechanism. ## Contributing to the Metadata Generator The code for generating the documentation can be found in [loader.go](./internal/loader.go) and the templates for rendering the documentation can be found in [templates](./internal/templates). When making updates to the metadata generator or introducing support for new functionality: 1. Ensure the [metadata-schema.yaml](./metadata-schema.yaml) and [metadata.yaml](./metadata.yaml) files reflect the changes. 2. Run `make mdatagen-test`. 3. Make sure all tests are passing including [generated tests](./internal/samplereceiver/internal/metadata/generated_metrics_test.go). 4. Run `make generate`. opentelemetry-collector-0.141.0/cmd/mdatagen/generated_package_test.go000066400000000000000000000002431511331344600260570ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package main import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/mdatagen/go.mod000066400000000000000000000212041511331344600221660ustar00rootroot00000000000000module go.opentelemetry.io/collector/cmd/mdatagen go 1.24.0 require ( github.com/google/go-cmp v0.7.0 github.com/spf13/cobra v1.10.1 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/connector/connectortest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/filter v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/xpdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.opentelemetry.io/collector/scraper v0.141.0 go.opentelemetry.io/collector/scraper/scrapertest v0.141.0 go.opentelemetry.io/collector/service/hostcapabilities v0.141.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 golang.org/x/text v0.31.0 gopkg.in/yaml.v3 v3.0.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect github.com/spf13/pflag v1.0.9 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/component/componentstatus v0.141.0 // indirect go.opentelemetry.io/collector/connector/xconnector v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/collector/service v0.141.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.38.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider replace go.opentelemetry.io/collector/filter => ../../filter replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest retract ( v0.76.2 v0.76.1 v0.65.0 ) replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/processor/xprocessor => ../../processor/xprocessor replace go.opentelemetry.io/collector/processor/processortest => ../../processor/processortest replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/processor => ../../processor replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/scraper => ../../scraper replace go.opentelemetry.io/collector/scraper/scrapertest => ../../scraper/scrapertest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/connector => ../../connector replace go.opentelemetry.io/collector/connector/connectortest => ../../connector/connectortest replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer replace go.opentelemetry.io/collector/connector/xconnector => ../../connector/xconnector replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/exporter => ../../exporter replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/exporter/exportertest => ../../exporter/exportertest replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/otelcol => ../../otelcol replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/extension/zpagesextension => ../../extension/zpagesextension replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/service => ../../service replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/service/hostcapabilities => ../../service/hostcapabilities replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/exporter/xexporter => ../../exporter/xexporter replace go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../../extension/extensioncapabilities replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/exporter/exporterhelper => ../../exporter/exporterhelper replace go.opentelemetry.io/collector/service/telemetry/telemetrytest => ../../service/telemetry/telemetrytest replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/cmd/mdatagen/go.sum000066400000000000000000000217731511331344600222260ustar00rootroot00000000000000github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/cmd/mdatagen/internal/000077500000000000000000000000001511331344600226755ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/command.go000066400000000000000000000364201511331344600246470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import ( "bytes" "errors" "fmt" "go/format" "io/fs" "os" "path/filepath" "regexp" "runtime/debug" "slices" "sort" "strings" "text/template" "github.com/spf13/cobra" "golang.org/x/text/cases" "golang.org/x/text/language" "gopkg.in/yaml.v3" ) const ( statusStart = "" statusEnd = "" ) var nonComponents = []string{ "cmd", "converter", "pkg", "provider", } func getVersion() (string, error) { // the second returned value is a boolean, which is true if the binaries are built with module support. info, ok := debug.ReadBuildInfo() if !ok { return "", errors.New("could not read build info") } return info.Main.Version, nil } // NewCommand constructs a new cobra.Command using the given Settings. // Any URIs specified in CollectorSettings.ConfigProviderSettings.ResolverSettings.URIs // are considered defaults and will be overwritten by config flags passed as // command-line arguments to the executable. // At least one Provider must be set. func NewCommand() (*cobra.Command, error) { ver, err := getVersion() if err != nil { return nil, err } rootCmd := &cobra.Command{ Use: "mdatagen", Version: ver, SilenceUsage: true, RunE: func(_ *cobra.Command, args []string) error { return run(args[0]) }, } return rootCmd, nil } func run(ymlPath string) error { if ymlPath == "" { return errors.New("argument must be metadata.yaml file") } ymlPath, err := filepath.Abs(ymlPath) if err != nil { return fmt.Errorf("failed to get absolute path for %v: %w", ymlPath, err) } ymlDir := filepath.Dir(ymlPath) packageName := filepath.Base(ymlDir) raw, readErr := os.ReadFile(ymlPath) //nolint:gosec // G304: abs path is cleaned/validated above; safe to read if readErr != nil { return fmt.Errorf("failed reading %v: %w", ymlPath, readErr) } if err = validateYAMLKeyOrder(raw); err != nil { return fmt.Errorf("metadata.yaml ordering check failed: %w", err) } md, err := LoadMetadata(ymlPath) if err != nil { return fmt.Errorf("failed loading %v: %w", ymlPath, err) } tmplDir := "templates" codeDir := filepath.Join(ymlDir, "internal", md.GeneratedPackageName) toGenerate := map[string]string{} if md.Status != nil { if !slices.Contains(nonComponents, md.Status.Class) { toGenerate[filepath.Join(tmplDir, "status.go.tmpl")] = filepath.Join(codeDir, "generated_status.go") err = generateFile(filepath.Join(tmplDir, "component_test.go.tmpl"), filepath.Join(ymlDir, "generated_component_test.go"), md, packageName) if err != nil { return err } } else { if _, err = os.Stat(filepath.Join(codeDir, "generated_status.go")); err == nil { err = os.Remove(filepath.Join(codeDir, "generated_status.go")) if err != nil { return err } } if _, err = os.Stat(filepath.Join(ymlDir, "generated_component_test.go")); err == nil { err = os.Remove(filepath.Join(ymlDir, "generated_component_test.go")) if err != nil { return err } } } err = generateFile(filepath.Join(tmplDir, "package_test.go.tmpl"), filepath.Join(ymlDir, "generated_package_test.go"), md, packageName) if err != nil { return err } if _, err = os.Stat(filepath.Join(ymlDir, "README.md")); err == nil { err = inlineReplace( filepath.Join(tmplDir, "readme.md.tmpl"), filepath.Join(ymlDir, "README.md"), md, statusStart, statusEnd, md.GeneratedPackageName) if err != nil { return err } } } if len(md.Telemetry.Metrics) != 0 { // if there are telemetry metrics, generate telemetry specific files testDir := filepath.Join(ymlDir, "internal", md.GeneratedPackageName+"test") if err = os.MkdirAll(testDir, 0o700); err != nil { return fmt.Errorf("unable to create output test directory %q: %w", codeDir, err) } toGenerate[filepath.Join(tmplDir, "telemetry.go.tmpl")] = filepath.Join(codeDir, "generated_telemetry.go") toGenerate[filepath.Join(tmplDir, "telemetry_test.go.tmpl")] = filepath.Join(codeDir, "generated_telemetry_test.go") toGenerate[filepath.Join(tmplDir, "telemetrytest.go.tmpl")] = filepath.Join(testDir, "generated_telemetrytest.go") toGenerate[filepath.Join(tmplDir, "telemetrytest_test.go.tmpl")] = filepath.Join(testDir, "generated_telemetrytest_test.go") } else { if _, err = os.Stat(filepath.Join(ymlDir, "generated_telemetry.go")); err == nil { err = os.Remove(filepath.Join(ymlDir, "generated_telemetry.go")) if err != nil { return err } } if _, err = os.Stat(filepath.Join(ymlDir, "generated_telemetry_test.go")); err == nil { err = os.Remove(filepath.Join(ymlDir, "generated_telemetry_test.go")) if err != nil { return err } } if _, err = os.Stat(filepath.Join(ymlDir, "generated_telemetrytest.go")); err == nil { err = os.Remove(filepath.Join(ymlDir, "generated_telemetrytest.go")) if err != nil { return err } } if _, err = os.Stat(filepath.Join(ymlDir, "generated_telemetrytest_test.go")); err == nil { err = os.Remove(filepath.Join(ymlDir, "generated_telemetrytest_test.go")) if err != nil { return err } } } if len(md.Metrics) != 0 || len(md.Telemetry.Metrics) != 0 || len(md.ResourceAttributes) != 0 || len(md.Events) != 0 { // if there's metrics or internal metrics or events, generate documentation for them toGenerate[filepath.Join(tmplDir, "documentation.md.tmpl")] = filepath.Join(ymlDir, "documentation.md") } if len(md.Metrics) > 0 || len(md.Events) > 0 || len(md.ResourceAttributes) > 0 { testdataDir := filepath.Join(codeDir, "testdata") if err = os.MkdirAll(filepath.Join(codeDir, "testdata"), 0o700); err != nil { return fmt.Errorf("unable to create output directory %q: %w", testdataDir, err) } toGenerate[filepath.Join(tmplDir, "testdata", "config.yaml.tmpl")] = filepath.Join(testdataDir, "config.yaml") toGenerate[filepath.Join(tmplDir, "config.go.tmpl")] = filepath.Join(codeDir, "generated_config.go") toGenerate[filepath.Join(tmplDir, "config_test.go.tmpl")] = filepath.Join(codeDir, "generated_config_test.go") } if len(md.ResourceAttributes) > 0 { // only generate resource files if resource attributes are configured toGenerate[filepath.Join(tmplDir, "resource.go.tmpl")] = filepath.Join(codeDir, "generated_resource.go") toGenerate[filepath.Join(tmplDir, "resource_test.go.tmpl")] = filepath.Join(codeDir, "generated_resource_test.go") } if len(md.Metrics) > 0 { // only generate metrics if metrics are present toGenerate[filepath.Join(tmplDir, "metrics.go.tmpl")] = filepath.Join(codeDir, "generated_metrics.go") toGenerate[filepath.Join(tmplDir, "metrics_test.go.tmpl")] = filepath.Join(codeDir, "generated_metrics_test.go") } if md.supportsSignal("logs") && (md.Status.Class == "receiver" || md.Status.Class == "scraper") { toGenerate[filepath.Join(tmplDir, "logs.go.tmpl")] = filepath.Join(codeDir, "generated_logs.go") toGenerate[filepath.Join(tmplDir, "logs_test.go.tmpl")] = filepath.Join(codeDir, "generated_logs_test.go") } // If at least one file to generate, will need the codeDir if len(toGenerate) > 0 { if err = os.MkdirAll(codeDir, 0o700); err != nil { return fmt.Errorf("unable to create output directory %q: %w", codeDir, err) } } for tmpl, dst := range toGenerate { if err := generateFile(tmpl, dst, md, md.GeneratedPackageName); err != nil { return err } } return nil } func templatize(tmplFile string, md Metadata) *template.Template { return template.Must( template. New(filepath.Base(tmplFile)). Option("missingkey=error"). Funcs(map[string]any{ "publicVar": func(s string) (string, error) { return FormatIdentifier(s, true) }, "attributeInfo": func(an AttributeName) Attribute { return md.Attributes[an] }, "getEventConditionalAttributes": func(attrs map[AttributeName]Attribute) []AttributeName { seen := make(map[AttributeName]bool) used := make([]AttributeName, 0) for _, event := range md.Events { for _, attribute := range event.Attributes { v, exists := attrs[attribute] if exists && v.IsConditional() && !seen[attribute] { used = append(used, attribute) seen[attribute] = true } } } sort.Slice(used, func(i, j int) bool { return string(used[i]) < string(used[j]) }) return used }, "getMetricConditionalAttributes": func(attrs map[AttributeName]Attribute) []AttributeName { seen := make(map[AttributeName]bool) used := make([]AttributeName, 0) for _, event := range md.Metrics { for _, attribute := range event.Attributes { v, exists := attrs[attribute] if exists && v.IsConditional() && !seen[attribute] { used = append(used, attribute) seen[attribute] = true } } } sort.Slice(used, func(i, j int) bool { return string(used[i]) < string(used[j]) }) return used }, "metricInfo": func(mn MetricName) Metric { return md.Metrics[mn] }, "eventInfo": func(en EventName) Event { return md.Events[en] }, "telemetryInfo": func(mn MetricName) Metric { return md.Telemetry.Metrics[mn] }, "parseImportsRequired": func(metrics map[MetricName]Metric) bool { for _, m := range metrics { if m.Data().HasMetricInputType() { return true } } return false }, "stringsJoin": strings.Join, "stringsSplit": strings.Split, "userLinks": func(elems []string) []string { result := make([]string, len(elems)) for i, elem := range elems { if elem == "open-telemetry/collector-approvers" { result[i] = "[@open-telemetry/collector-approvers](https://github.com/orgs/open-telemetry/teams/collector-approvers)" } else { result[i] = fmt.Sprintf("[@%s](https://www.github.com/%s)", elem, elem) } } return result }, "casesTitle": cases.Title(language.English).String, "toLowerCase": strings.ToLower, "toCamelCase": func(s string) string { caser := cases.Title(language.English).String parts := strings.Split(s, "_") var result strings.Builder for _, part := range parts { fmt.Fprintf(&result, "%s", caser(part)) } return result.String() }, "inc": func(i int) int { return i + 1 }, "distroURL": distroURL, "isExporter": func() bool { return md.Status.Class == "exporter" }, "isProcessor": func() bool { return md.Status.Class == "processor" }, "isReceiver": func() bool { return md.Status.Class == "receiver" }, "isExtension": func() bool { return md.Status.Class == "extension" }, "isConnector": func() bool { return md.Status.Class == "connector" }, "isScraper": func() bool { return md.Status.Class == "scraper" }, "isCommand": func() bool { return md.Status.Class == "cmd" }, "supportsLogs": func() bool { return md.supportsSignal("logs") }, "supportsMetrics": func() bool { return md.supportsSignal("metrics") }, "supportsTraces": func() bool { return md.supportsSignal("traces") }, "supportsLogsToLogs": func() bool { return md.supportsSignal("logs_to_logs") }, "supportsLogsToMetrics": func() bool { return md.supportsSignal("logs_to_metrics") }, "supportsLogsToTraces": func() bool { return md.supportsSignal("logs_to_traces") }, "supportsMetricsToLogs": func() bool { return md.supportsSignal("metrics_to_logs") }, "supportsMetricsToMetrics": func() bool { return md.supportsSignal("metrics_to_metrics") }, "supportsMetricsToTraces": func() bool { return md.supportsSignal("metrics_to_traces") }, "supportsTracesToLogs": func() bool { return md.supportsSignal("traces_to_logs") }, "supportsTracesToMetrics": func() bool { return md.supportsSignal("traces_to_metrics") }, "supportsTracesToTraces": func() bool { return md.supportsSignal("traces_to_traces") }, "expectConsumerError": func() bool { return md.Tests.ExpectConsumerError }, // ParseFS delegates the parsing of the files to `Glob` // which uses the `\` as a special character. // Meaning on windows based machines, the `\` needs to be replaced // with a `/` for it to find the file. }).ParseFS(TemplateFS, "templates/helper.tmpl", strings.ReplaceAll(tmplFile, "\\", "/"))) } func executeTemplate(tmplFile string, md Metadata, goPackage string) ([]byte, error) { tmpl := templatize(tmplFile, md) buf := bytes.Buffer{} if err := tmpl.Execute(&buf, TemplateContext{Metadata: md, Package: goPackage}); err != nil { return []byte{}, fmt.Errorf("failed executing template: %w", err) } return buf.Bytes(), nil } func inlineReplace(tmplFile, outputFile string, md Metadata, start, end, goPackage string) error { var readmeContents []byte var err error if readmeContents, err = os.ReadFile(outputFile); err != nil { //nolint:gosec return err } re := regexp.MustCompile(fmt.Sprintf("%s[\\s\\S]*%s", start, end)) if !re.Match(readmeContents) { return nil } if md.GithubProject == "" { md.GithubProject = "open-telemetry/opentelemetry-collector-contrib" } buf, err := executeTemplate(tmplFile, md, goPackage) if err != nil { return err } s := re.ReplaceAllString(string(readmeContents), string(buf)) if err := os.WriteFile(outputFile, []byte(s), 0o600); err != nil { return fmt.Errorf("failed writing %q: %w", outputFile, err) } return nil } func generateFile(tmplFile, outputFile string, md Metadata, goPackage string) error { if err := os.Remove(outputFile); err != nil && !errors.Is(err, fs.ErrNotExist) { return fmt.Errorf("unable to remove generated file %q: %w", outputFile, err) } result, err := executeTemplate(tmplFile, md, goPackage) if err != nil { return err } var formatErr error if strings.HasSuffix(outputFile, ".go") { if formatted, err := format.Source(result); err == nil { result = formatted } else { formatErr = fmt.Errorf("failed formatting %s:%w", outputFile, err) } } if err := os.WriteFile(outputFile, result, 0o600); err != nil { return fmt.Errorf("failed writing %q: %w", outputFile, err) } return formatErr } func validateMappingKeysSorted(root *yaml.Node, path ...string) error { // unwrap doc n := root if n.Kind == yaml.DocumentNode && len(n.Content) > 0 { n = n.Content[0] } // follow path for _, seg := range path { if n.Kind != yaml.MappingNode { return nil } var next *yaml.Node for i := 0; i < len(n.Content); i += 2 { if n.Content[i].Value == seg { next = n.Content[i+1] break } } if next == nil { return nil } n = next } if n.Kind != yaml.MappingNode { return nil } // collect keys keys := make([]string, 0, len(n.Content)/2) for i := 0; i < len(n.Content); i += 2 { keys = append(keys, n.Content[i].Value) } if !slices.IsSorted(keys) { return fmt.Errorf("%v keys are not sorted: %v", path, keys) } return nil } // ValidateYAMLKeyOrder checks the sections we care about. func validateYAMLKeyOrder(raw []byte) error { var doc yaml.Node if err := yaml.Unmarshal(raw, &doc); err != nil { return err } for _, p := range [][]string{ {"resource_attributes"}, {"entities"}, {"attributes"}, {"metrics"}, {"events"}, {"telemetry", "metrics"}, } { if err := validateMappingKeysSorted(&doc, p...); err != nil { return err } } return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/command_test.go000066400000000000000000000570601511331344600257110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "bytes" "fmt" "go/parser" "go/token" "os" "path/filepath" "testing" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" ) func TestNewCommand(t *testing.T) { cmd, err := NewCommand() require.NoError(t, err) assert.NotNil(t, cmd) assert.IsType(t, &cobra.Command{}, cmd) assert.Equal(t, "mdatagen", cmd.Use) assert.True(t, cmd.SilenceUsage) } func TestRunContents(t *testing.T) { tests := []struct { yml string wantMetricsGenerated bool // TODO: we should add one more flag for logs builder wantEventsGenerated bool wantMetricsContext bool wantLogsGenerated bool wantConfigGenerated bool wantTelemetryGenerated bool wantResourceAttributesGenerated bool wantReadmeGenerated bool wantStatusGenerated bool wantComponentTestGenerated bool wantGoleakIgnore bool wantGoleakSkip bool wantGoleakSetup bool wantGoleakTeardown bool wantErr bool wantOrderErr bool wantAttributes []string }{ { yml: "invalid.yaml", wantErr: true, }, { yml: "unsorted_rattr.yaml", wantOrderErr: true, }, { yml: "basic_connector.yaml", wantErr: false, wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "basic_receiver.yaml", wantErr: false, wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, wantLogsGenerated: true, }, { yml: "basic_pkg.yaml", wantErr: false, wantStatusGenerated: false, wantReadmeGenerated: true, }, { yml: "metrics_and_type.yaml", wantMetricsGenerated: true, wantConfigGenerated: true, wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "resource_attributes_only.yaml", wantConfigGenerated: true, wantStatusGenerated: true, wantResourceAttributesGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, wantLogsGenerated: true, }, { yml: "status_only.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_tests_receiver.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, wantLogsGenerated: true, }, { yml: "with_tests_exporter.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_tests_processor.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_tests_extension.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_tests_connector.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_goleak_ignores.yaml", wantStatusGenerated: true, wantGoleakIgnore: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_goleak_skip.yaml", wantStatusGenerated: true, wantGoleakSkip: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_goleak_setup.yaml", wantStatusGenerated: true, wantGoleakSetup: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_goleak_teardown.yaml", wantStatusGenerated: true, wantGoleakTeardown: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "with_telemetry.yaml", wantStatusGenerated: true, wantTelemetryGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, wantAttributes: []string{"name"}, wantLogsGenerated: true, }, { yml: "invalid_telemetry_missing_value_type_for_histogram.yaml", wantErr: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "async_metric.yaml", wantMetricsGenerated: true, wantConfigGenerated: true, wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, }, { yml: "custom_generated_package_name.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, wantLogsGenerated: true, }, { yml: "with_conditional_attribute.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantMetricsGenerated: true, wantLogsGenerated: true, wantConfigGenerated: true, wantComponentTestGenerated: true, }, { yml: "events/basic_event.yaml", wantStatusGenerated: true, wantReadmeGenerated: true, wantComponentTestGenerated: true, wantConfigGenerated: true, wantEventsGenerated: true, wantLogsGenerated: true, }, } for _, tt := range tests { t.Run(tt.yml, func(t *testing.T) { tmpdir := filepath.Join(t.TempDir(), "shortname") err := os.MkdirAll(tmpdir, 0o750) require.NoError(t, err) ymlContent, err := os.ReadFile(filepath.Join("testdata", tt.yml)) require.NoError(t, err) metadataFile := filepath.Join(tmpdir, "metadata.yaml") require.NoError(t, os.WriteFile(metadataFile, ymlContent, 0o600)) require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "empty.go"), []byte("package shortname"), 0o600)) require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte("module shortname"), 0o600)) require.NoError(t, os.WriteFile(filepath.Join(tmpdir, "README.md"), []byte(` foo `), 0o600)) md, err := LoadMetadata(metadataFile) if tt.wantErr { require.Error(t, err) return } require.NoError(t, err) generatedPackageDir := filepath.Join("internal", md.GeneratedPackageName) require.NoError(t, os.MkdirAll(filepath.Join(tmpdir, generatedPackageDir), 0o700)) require.NoError(t, os.WriteFile(filepath.Join(tmpdir, generatedPackageDir, "generated_status.go"), []byte("status"), 0o600)) require.NoError(t, os.WriteFile(filepath.Join(tmpdir, generatedPackageDir, "generated_telemetry_test.go"), []byte("test"), 0o600)) require.NoError(t, os.WriteFile(filepath.Join(tmpdir, generatedPackageDir, "generated_component_test.go"), []byte("test"), 0o600)) err = run(metadataFile) if tt.wantOrderErr { require.Error(t, err) require.Contains(t, err.Error(), "metadata.yaml ordering check failed") return } require.NoError(t, err) var contents []byte if tt.wantMetricsGenerated { require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_metrics.go")) require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_metrics_test.go")) require.FileExists(t, filepath.Join(tmpdir, "documentation.md")) if len(tt.wantAttributes) > 0 { contents, err = os.ReadFile(filepath.Join(tmpdir, "documentation.md")) //nolint:gosec require.NoError(t, err) for _, attr := range tt.wantAttributes { require.Contains(t, string(contents), attr) } } contents, err = os.ReadFile(filepath.Join(tmpdir, generatedPackageDir, "generated_metrics.go")) //nolint:gosec require.NoError(t, err) if tt.wantMetricsContext { require.Contains(t, string(contents), "\"context\"") } else { require.NotContains(t, string(contents), "\"context\"") } } else { require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_metrics.go")) require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_metrics_test.go")) } if tt.wantLogsGenerated { require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs.go")) require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs_test.go")) } else { require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs.go")) require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_logs_test.go")) } if tt.wantConfigGenerated { require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_config.go")) require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_config_test.go")) } else { require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_config.go")) require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_config_test.go")) } if tt.wantTelemetryGenerated { require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_telemetry.go")) require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_telemetry_test.go")) require.FileExists(t, filepath.Join(tmpdir, "documentation.md")) contents, err = os.ReadFile(filepath.Join(tmpdir, generatedPackageDir, "generated_telemetry.go")) //nolint:gosec require.NoError(t, err) if tt.wantMetricsContext { require.Contains(t, string(contents), "\"context\"") } else { require.NotContains(t, string(contents), "\"context\"") } } else { require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_telemetry.go")) } if !tt.wantMetricsGenerated && !tt.wantTelemetryGenerated && !tt.wantResourceAttributesGenerated && !tt.wantEventsGenerated { require.NoFileExists(t, filepath.Join(tmpdir, "documentation.md")) } if tt.wantStatusGenerated { require.FileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_status.go")) } else { require.NoFileExists(t, filepath.Join(tmpdir, generatedPackageDir, "generated_status.go")) } contents, err = os.ReadFile(filepath.Join(tmpdir, "README.md")) //nolint:gosec require.NoError(t, err) if tt.wantReadmeGenerated { require.NotContains(t, string(contents), "foo") } else { require.Contains(t, string(contents), "foo") } if tt.wantComponentTestGenerated { require.FileExists(t, filepath.Join(tmpdir, "generated_component_test.go")) contents, err = os.ReadFile(filepath.Join(tmpdir, "generated_component_test.go")) //nolint:gosec require.NoError(t, err) require.Contains(t, string(contents), "func Test") _, err = parser.ParseFile(token.NewFileSet(), "", contents, parser.DeclarationErrors) require.NoError(t, err) } else { require.NoFileExists(t, filepath.Join(tmpdir, "generated_component_test.go")) } require.FileExists(t, filepath.Join(tmpdir, "generated_package_test.go")) contents, err = os.ReadFile(filepath.Join(tmpdir, "generated_package_test.go")) //nolint:gosec require.NoError(t, err) require.Contains(t, string(contents), "func TestMain") _, err = parser.ParseFile(token.NewFileSet(), "", contents, parser.DeclarationErrors) require.NoError(t, err) if tt.wantGoleakSkip { require.Contains(t, string(contents), "skipping goleak test") } else { require.NotContains(t, string(contents), "skipping goleak test") } if tt.wantGoleakIgnore { require.Contains(t, string(contents), "IgnoreTopFunction") require.Contains(t, string(contents), "IgnoreAnyFunction") } else { require.NotContains(t, string(contents), "IgnoreTopFunction") require.NotContains(t, string(contents), "IgnoreAnyFunction") } if tt.wantGoleakSetup { require.Contains(t, string(contents), "setupFunc") } else { require.NotContains(t, string(contents), "setupFunc") } if tt.wantGoleakTeardown { require.Contains(t, string(contents), "teardownFunc") } else { require.NotContains(t, string(contents), "teardownFunc") } }) } } func TestRun(t *testing.T) { type args struct { ymlPath string } tests := []struct { name string args args wantErr bool }{ { name: "no argument", args: args{""}, wantErr: true, }, { name: "no such file", args: args{"/no/such/file"}, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := run(tt.args.ymlPath) if !tt.wantErr { require.NoError(t, err, "run()") } else { require.Error(t, err) } }) } } func TestInlineReplace(t *testing.T) { tests := []struct { name string markdown string outputFile string componentClass string warnings []string stability map[component.StabilityLevel][]string deprecation map[string]DeprecationInfo distros []string codeowners *Codeowners githubProject string }{ { name: "readme with empty status", markdown: `# Some component Some info about a component `, outputFile: "readme_with_status.md", componentClass: "receiver", distros: []string{"contrib"}, githubProject: "open-telemetry/opentelemetry-collector", }, { name: "readme with status for extension", markdown: `# Some component Some info about a component `, outputFile: "readme_with_status_extension.md", componentClass: "extension", distros: []string{"contrib"}, }, { name: "readme with status for converter", markdown: `# Some component Some info about a component `, outputFile: "readme_with_status_converter.md", componentClass: "converter", distros: []string{"contrib"}, }, { name: "readme with status for provider", markdown: `# Some component Some info about a component `, outputFile: "readme_with_status_provider.md", componentClass: "provider", distros: []string{"contrib"}, }, { name: "readme with status with codeowners and seeking new", markdown: `# Some component Some info about a component `, outputFile: "readme_with_status_codeowners_and_seeking_new.md", componentClass: "receiver", distros: []string{"contrib"}, codeowners: &Codeowners{ Active: []string{"foo"}, SeekingNew: true, }, }, { name: "readme with status with codeowners and emeritus", markdown: `# Some component Some info about a component `, outputFile: "readme_with_status_codeowners_and_emeritus.md", componentClass: "receiver", distros: []string{"contrib"}, codeowners: &Codeowners{ Active: []string{"foo"}, Emeritus: []string{"bar"}, }, }, { name: "readme with status with codeowners", markdown: `# Some component Some info about a component `, outputFile: "readme_with_status_codeowners.md", componentClass: "receiver", distros: []string{"contrib"}, codeowners: &Codeowners{ Active: []string{"open-telemetry/collector-approvers"}, }, }, { name: "readme with status table", markdown: `# Some component | Status | | | ------------------------ |-----------| Some info about a component `, outputFile: "readme_with_status.md", componentClass: "receiver", distros: []string{"contrib"}, githubProject: "open-telemetry/opentelemetry-collector", }, { name: "readme with no status", markdown: `# Some component Some info about a component `, outputFile: "readme_without_status.md", distros: []string{"contrib"}, }, { name: "component with warnings", markdown: `# Some component Some info about a component ### warnings Some warning there. `, outputFile: "readme_with_warnings.md", warnings: []string{"warning1"}, distros: []string{"contrib"}, }, { name: "readme with multiple signals", markdown: `# Some component Some info about a component `, outputFile: "readme_with_multiple_signals.md", stability: map[component.StabilityLevel][]string{ component.StabilityLevelBeta: {"metrics"}, component.StabilityLevelAlpha: {"logs"}, }, distros: []string{"contrib"}, }, { name: "readme with multiple signals and deprecation", markdown: `# Some component Some info about a component `, outputFile: "readme_with_multiple_signals_and_deprecation.md", stability: map[component.StabilityLevel][]string{ component.StabilityLevelBeta: {"metrics"}, component.StabilityLevelAlpha: {"logs"}, component.StabilityLevelDeprecated: {"traces"}, }, deprecation: DeprecationMap{ "traces": DeprecationInfo{ Date: "2025-02-05", Migration: "no migration needed", }, }, distros: []string{"contrib"}, }, { name: "readme with cmd class", markdown: `# Some component Some info about a component `, outputFile: "readme_with_cmd_class.md", stability: map[component.StabilityLevel][]string{ component.StabilityLevelBeta: {"metrics"}, component.StabilityLevelAlpha: {"logs"}, }, componentClass: "cmd", distros: []string{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stability := map[component.StabilityLevel][]string{component.StabilityLevelBeta: {"metrics"}} if len(tt.stability) > 0 { stability = tt.stability } md := Metadata{ GithubProject: tt.githubProject, Type: "foo", ShortFolderName: "foo", Status: &Status{ DisableCodeCov: true, Stability: stability, Distributions: tt.distros, Class: tt.componentClass, Warnings: tt.warnings, Codeowners: tt.codeowners, Deprecation: tt.deprecation, }, } tmpdir := t.TempDir() readmeFile := filepath.Join(tmpdir, "README.md") require.NoError(t, os.WriteFile(readmeFile, []byte(tt.markdown), 0o600)) err := inlineReplace("templates/readme.md.tmpl", readmeFile, md, statusStart, statusEnd, "metadata") require.NoError(t, err) require.FileExists(t, filepath.Join(tmpdir, "README.md")) got, err := os.ReadFile(filepath.Join(tmpdir, "README.md")) //nolint:gosec require.NoError(t, err) got = bytes.ReplaceAll(got, []byte("\r\n"), []byte("\n")) expected, err := os.ReadFile(filepath.Join("testdata", tt.outputFile)) require.NoError(t, err) expected = bytes.ReplaceAll(expected, []byte("\r\n"), []byte("\n")) fmt.Println(string(got)) fmt.Println(string(expected)) require.Equal(t, string(expected), string(got)) }) } } func TestGenerateStatusMetadata(t *testing.T) { tests := []struct { name string output string md Metadata expected string }{ { name: "foo component with beta status", md: Metadata{ Type: "foo", Status: &Status{ Stability: map[component.StabilityLevel][]string{ component.StabilityLevelBeta: {"metrics"}, }, Distributions: []string{"contrib"}, Class: "receiver", }, }, expected: `// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("foo") ScopeName = "" ) const ( MetricsStability = component.StabilityLevelBeta ) `, }, { name: "foo component with alpha status", md: Metadata{ Type: "foo", Status: &Status{ Stability: map[component.StabilityLevel][]string{ component.StabilityLevelAlpha: {"metrics"}, }, Distributions: []string{"contrib"}, Class: "receiver", }, }, expected: `// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("foo") ScopeName = "" ) const ( MetricsStability = component.StabilityLevelAlpha ) `, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tmpdir := t.TempDir() err := generateFile("templates/status.go.tmpl", filepath.Join(tmpdir, "generated_status.go"), tt.md, "metadata") require.NoError(t, err) actual, err := os.ReadFile(filepath.Join(tmpdir, "generated_status.go")) //nolint:gosec require.NoError(t, err) require.Equal(t, tt.expected, string(actual)) }) } } func TestGenerateTelemetryMetadata(t *testing.T) { tests := []struct { name string output string md Metadata expected string }{ { name: "foo component with beta status", md: Metadata{ Type: "foo", Status: &Status{ Stability: map[component.StabilityLevel][]string{ component.StabilityLevelBeta: {"metrics"}, }, Distributions: []string{"contrib"}, Class: "receiver", }, }, expected: `// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("") } `, }, { name: "foo component with alpha status", md: Metadata{ Type: "foo", Status: &Status{ Stability: map[component.StabilityLevel][]string{ component.StabilityLevelAlpha: {"metrics"}, }, Distributions: []string{"contrib"}, Class: "receiver", }, }, expected: `// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("") } `, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tmpdir := t.TempDir() err := generateFile("templates/telemetry.go.tmpl", filepath.Join(tmpdir, "generated_telemetry.go"), tt.md, "metadata") require.NoError(t, err) actual, err := os.ReadFile(filepath.Join(tmpdir, "generated_telemetry.go")) //nolint:gosec require.NoError(t, err) require.Equal(t, tt.expected, string(actual)) }) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/embedded_templates.go000066400000000000000000000006401511331344600270330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import "embed" // TemplateFS ensures that the files needed // to generate metadata as an embedded filesystem since // `go get` doesn't require these files to be downloaded. // //go:embed templates/*.tmpl templates/testdata/*.tmpl var TemplateFS embed.FS opentelemetry-collector-0.141.0/cmd/mdatagen/internal/embedded_templates_test.go000066400000000000000000000034141511331344600300740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "io/fs" "path" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestEnsureTemplatesLoaded(t *testing.T) { t.Parallel() const ( rootDir = "templates" ) var ( templateFiles = map[string]struct{}{ path.Join(rootDir, "component_test.go.tmpl"): {}, path.Join(rootDir, "documentation.md.tmpl"): {}, path.Join(rootDir, "metrics.go.tmpl"): {}, path.Join(rootDir, "metrics_test.go.tmpl"): {}, path.Join(rootDir, "logs.go.tmpl"): {}, path.Join(rootDir, "logs_test.go.tmpl"): {}, path.Join(rootDir, "resource.go.tmpl"): {}, path.Join(rootDir, "resource_test.go.tmpl"): {}, path.Join(rootDir, "config.go.tmpl"): {}, path.Join(rootDir, "config_test.go.tmpl"): {}, path.Join(rootDir, "package_test.go.tmpl"): {}, path.Join(rootDir, "readme.md.tmpl"): {}, path.Join(rootDir, "status.go.tmpl"): {}, path.Join(rootDir, "telemetry.go.tmpl"): {}, path.Join(rootDir, "telemetry_test.go.tmpl"): {}, path.Join(rootDir, "testdata", "config.yaml.tmpl"): {}, path.Join(rootDir, "telemetrytest.go.tmpl"): {}, path.Join(rootDir, "telemetrytest_test.go.tmpl"): {}, path.Join(rootDir, "helper.tmpl"): {}, } count = 0 ) require.NoError(t, fs.WalkDir(TemplateFS, ".", func(path string, d fs.DirEntry, _ error) error { if d != nil && d.IsDir() { return nil } count++ assert.Contains(t, templateFiles, path) return nil })) assert.Equal(t, len(templateFiles), count, "Must match the expected number of calls") } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/event.go000066400000000000000000000015171511331344600243510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import ( "errors" "go.opentelemetry.io/collector/confmap" ) type ( EventName string ) func (ln EventName) Render() (string, error) { return FormatIdentifier(string(ln), true) } func (ln EventName) RenderUnexported() (string, error) { return FormatIdentifier(string(ln), false) } type Event struct { Signal `mapstructure:",squash"` } func (l *Event) validate() error { var errs error if l.Description == "" { errs = errors.Join(errs, errors.New(`missing event description`)) } return errs } func (l *Event) Unmarshal(parser *confmap.Conf) error { if !parser.IsSet("enabled") { return errors.New("missing required field: `enabled`") } return parser.Unmarshal(l) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/event_test.go000066400000000000000000000015471511331344600254130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestEventNameRender(t *testing.T) { for _, tt := range []struct { name EventName success bool expectedExported string expectedUnExported string }{ {"", false, "", ""}, {"otel.val", true, "OtelVal", "otelVal"}, {"otel_val_2", true, "OtelVal2", "otelVal2"}, } { exported, err := tt.name.Render() if tt.success { require.NoError(t, err) assert.Equal(t, tt.expectedExported, exported) } else { require.Error(t, err) } unexported, err := tt.name.RenderUnexported() if tt.success { require.NoError(t, err) assert.Equal(t, tt.expectedUnExported, unexported) } else { require.Error(t, err) } } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/lint.go000066400000000000000000000030721511331344600241740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import ( "errors" "strings" "unicode" "go.opentelemetry.io/collector/cmd/mdatagen/third_party/golint" ) // FormatIdentifier variable in a go-safe way func FormatIdentifier(s string, exported bool) (string, error) { if s == "" { return "", errors.New("string cannot be empty") } // Convert various characters to . for strings.Title to operate on. replace := strings.NewReplacer("_", ".", "-", ".", "<", ".", ">", ".", "/", ".", ":", ".") str := replace.Replace(s) str = strings.Title(str) //nolint:staticcheck // SA1019 str = strings.ReplaceAll(str, ".", "") var word string var output string // Fixup acronyms to make lint happy. for idx, r := range str { if idx == 0 { if exported { r = unicode.ToUpper(r) } else { r = unicode.ToLower(r) } } if unicode.IsUpper(r) || unicode.IsNumber(r) { // If the current word is an acronym and it's either exported or it's not the // beginning of an unexported variable then upper case it. if golint.Acronyms[strings.ToUpper(word)] && (exported || output != "") { output += strings.ToUpper(word) word = string(r) } else { output += word word = string(r) } } else { word += string(r) } } if golint.Acronyms[strings.ToUpper(word)] && output != "" { output += strings.ToUpper(word) } else { output += word } // Remove white spaces output = strings.Join(strings.Fields(output), "") return output, nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/lint_test.go000066400000000000000000000023421511331344600252320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/require" ) func TestFormatIdentifier(t *testing.T) { tests := []struct { input string want string exported bool wantErr string }{ // Unexported. {input: "max.cpu", want: "maxCPU"}, {input: "max.foo", want: "maxFoo"}, {input: "cpu.utilization", want: "cpuUtilization"}, {input: "cpu", want: "cpu"}, {input: "max.ip.addr", want: "maxIPAddr"}, {input: "some_metric", want: "someMetric"}, {input: "some-metric", want: "someMetric"}, {input: "Upper.Case", want: "upperCase"}, {input: "max.ip6", want: "maxIP6"}, {input: "max.ip6.idle", want: "maxIP6Idle"}, {input: "node_netstat_IpExt_OutOctets", want: "nodeNetstatIPExtOutOctets"}, // Exported. {input: "cpu.state", want: "CPUState", exported: true}, // Errors {input: "", want: "", wantErr: "string cannot be empty"}, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) { got, err := FormatIdentifier(tt.input, tt.exported) if tt.wantErr != "" { require.EqualError(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/loader.go000066400000000000000000000047341511331344600245020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import ( "context" "errors" "fmt" "os/exec" "path/filepath" "strings" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/provider/fileprovider" ) func setAttributeDefaultFields(attrs map[AttributeName]Attribute) { for k, v := range attrs { v.FullName = k if v.RequirementLevel == "" { v.RequirementLevel = AttributeRequirementLevelRecommended } attrs[k] = v } } type TemplateContext struct { Metadata // Package name for generated code. Package string } func LoadMetadata(filePath string) (Metadata, error) { cp, err := fileprovider.NewFactory().Create(confmaptest.NewNopProviderSettings()).Retrieve(context.Background(), "file:"+filePath, nil) if err != nil { return Metadata{}, err } conf, err := cp.AsConf() if err != nil { return Metadata{}, err } md := Metadata{ShortFolderName: shortFolderName(filePath), Tests: Tests{Host: "newMdatagenNopHost()"}} err = conf.Unmarshal(&md) if err != nil { return md, err } packageName, err := packageName(filepath.Dir(filePath)) if err != nil { return md, fmt.Errorf("unable to determine package name: %w", err) } md.PackageName = packageName if md.ScopeName == "" { md.ScopeName = packageName } if md.GeneratedPackageName == "" { md.GeneratedPackageName = "metadata" } if err := md.Validate(); err != nil { return md, err } setAttributeDefaultFields(md.Attributes) setAttributeDefaultFields(md.ResourceAttributes) return md, nil } var componentTypes = []string{ "connector", "exporter", "extension", "processor", "scraper", "receiver", } func shortFolderName(filePath string) string { parentFolder := filepath.Base(filepath.Dir(filePath)) for _, cType := range componentTypes { if before, ok := strings.CutSuffix(parentFolder, cType); ok { return before } } return parentFolder } func packageName(filePath string) (string, error) { cmd := exec.Command("go", "list", "-f", "{{.ImportPath}}") cmd.Dir = filePath output, err := cmd.Output() if err != nil { var ee *exec.ExitError if errors.As(err, &ee) { return "", fmt.Errorf("unable to determine package name: %v failed: (stderr) %v", cmd.Args, string(ee.Stderr)) } return "", fmt.Errorf("unable to determine package name: %v failed: %v %w", cmd.Args, string(output), err) } return strings.TrimSpace(string(output)), nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/loader_test.go000066400000000000000000000534011511331344600255340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) func boolPtr(b bool) *bool { return &b } func TestTwoPackagesInDirectory(t *testing.T) { contents, err := os.ReadFile("testdata/twopackages.yaml") require.NoError(t, err) tempDir := t.TempDir() metadataPath := filepath.Join(tempDir, "metadata.yaml") // we create a trivial module and packages to avoid having invalid go checked into our test directory. require.NoError(t, os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte("module twopackages"), 0o600)) require.NoError(t, os.WriteFile(filepath.Join(tempDir, "package1.go"), []byte("package package1"), 0o600)) require.NoError(t, os.WriteFile(filepath.Join(tempDir, "package2.go"), []byte("package package2"), 0o600)) require.NoError(t, os.WriteFile(metadataPath, contents, 0o600)) _, err = LoadMetadata(metadataPath) require.Error(t, err) require.ErrorContains(t, err, "unable to determine package name: [go list -f {{.ImportPath}}] failed: (stderr) found packages package1 (package1.go) and package2 (package2.go)") } func TestLoadMetadata(t *testing.T) { tests := []struct { name string want Metadata wantErr string }{ { name: "samplereceiver/metadata.yaml", want: Metadata{ GithubProject: "open-telemetry/opentelemetry-collector", GeneratedPackageName: "metadata", Type: "sample", SemConvVersion: "1.37.0", PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver", Status: &Status{ DisableCodeCov: true, Class: "receiver", Stability: map[component.StabilityLevel][]string{ component.StabilityLevelDevelopment: {"logs"}, component.StabilityLevelBeta: {"traces"}, component.StabilityLevelStable: {"metrics"}, component.StabilityLevelDeprecated: {"profiles"}, }, Distributions: []string{}, Deprecation: DeprecationMap{ "profiles": DeprecationInfo{ Date: "2025-02-05", Migration: "no migration needed", }, }, Codeowners: &Codeowners{ Active: []string{"dmitryax"}, }, Warnings: []string{"Any additional information that should be brought to the consumer's attention"}, UnsupportedPlatforms: []string{"freebsd", "illumos"}, }, ResourceAttributes: map[AttributeName]Attribute{ "string.resource.attr": { Description: "Resource attribute with any string value.", EnabledPtr: boolPtr(true), Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "string.resource.attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "string.enum.resource.attr": { Description: "Resource attribute with a known set of string values.", EnabledPtr: boolPtr(true), Enum: []string{"one", "two"}, Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "string.enum.resource.attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "optional.resource.attr": { Description: "Explicitly disabled ResourceAttribute.", EnabledPtr: boolPtr(false), Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "optional.resource.attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "slice.resource.attr": { Description: "Resource attribute with a slice value.", EnabledPtr: boolPtr(true), Type: ValueType{ ValueType: pcommon.ValueTypeSlice, }, FullName: "slice.resource.attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "map.resource.attr": { Description: "Resource attribute with a map value.", EnabledPtr: boolPtr(true), Type: ValueType{ ValueType: pcommon.ValueTypeMap, }, FullName: "map.resource.attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "string.resource.attr_disable_warning": { Description: "Resource attribute with any string value.", Warnings: Warnings{ IfEnabledNotSet: "This resource_attribute will be disabled by default soon.", }, EnabledPtr: boolPtr(true), Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "string.resource.attr_disable_warning", RequirementLevel: AttributeRequirementLevelRecommended, }, "string.resource.attr_remove_warning": { Description: "Resource attribute with any string value.", Warnings: Warnings{ IfConfigured: "This resource_attribute is deprecated and will be removed soon.", }, EnabledPtr: boolPtr(false), Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "string.resource.attr_remove_warning", RequirementLevel: AttributeRequirementLevelRecommended, }, "string.resource.attr_to_be_removed": { Description: "Resource attribute with any string value.", Warnings: Warnings{ IfEnabled: "This resource_attribute is deprecated and will be removed soon.", }, EnabledPtr: boolPtr(true), Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "string.resource.attr_to_be_removed", RequirementLevel: AttributeRequirementLevelRecommended, }, }, Attributes: map[AttributeName]Attribute{ "enum_attr": { Description: "Attribute with a known set of string values.", NameOverride: "", Enum: []string{"red", "green", "blue"}, Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "enum_attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "string_attr": { Description: "Attribute with any string value.", NameOverride: "", Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "string_attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "overridden_int_attr": { Description: "Integer attribute with overridden name.", NameOverride: "state", Type: ValueType{ ValueType: pcommon.ValueTypeInt, }, FullName: "overridden_int_attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "boolean_attr": { Description: "Attribute with a boolean value.", Type: ValueType{ ValueType: pcommon.ValueTypeBool, }, FullName: "boolean_attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "boolean_attr2": { Description: "Another attribute with a boolean value.", Type: ValueType{ ValueType: pcommon.ValueTypeBool, }, FullName: "boolean_attr2", RequirementLevel: AttributeRequirementLevelRecommended, }, "slice_attr": { Description: "Attribute with a slice value.", Type: ValueType{ ValueType: pcommon.ValueTypeSlice, }, FullName: "slice_attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "map_attr": { Description: "Attribute with a map value.", Type: ValueType{ ValueType: pcommon.ValueTypeMap, }, FullName: "map_attr", RequirementLevel: AttributeRequirementLevelRecommended, }, "conditional_int_attr": { Description: "A conditional attribute with an integer value", Type: ValueType{ ValueType: pcommon.ValueTypeInt, }, FullName: "conditional_int_attr", RequirementLevel: AttributeRequirementLevelConditionallyRequired, }, "conditional_string_attr": { Description: "A conditional attribute with any string value", Type: ValueType{ ValueType: pcommon.ValueTypeStr, }, FullName: "conditional_string_attr", RequirementLevel: AttributeRequirementLevelConditionallyRequired, }, "opt_in_bool_attr": { Description: "An opt-in attribute with a boolean value", Type: ValueType{ ValueType: pcommon.ValueTypeBool, }, FullName: "opt_in_bool_attr", RequirementLevel: AttributeRequirementLevelOptIn, }, }, Metrics: map[MetricName]Metric{ "default.metric": { Signal: Signal{ Enabled: true, Description: "Monotonic cumulative sum int metric enabled by default.", ExtendedDocumentation: "The metric will be become optional soon.", Stability: Stability{Level: component.StabilityLevelDevelopment}, Warnings: Warnings{ IfEnabledNotSet: "This metric will be disabled by default soon.", }, Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr", "conditional_int_attr", "conditional_string_attr", "opt_in_bool_attr"}, }, Unit: strPtr("s"), Sum: &Sum{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt}, AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityCumulative}, Mono: Mono{Monotonic: true}, }, }, "system.cpu.time": { Signal: Signal{ Enabled: true, Stability: Stability{Level: component.StabilityLevelBeta}, SemanticConvention: &SemanticConvention{SemanticConventionRef: "https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime"}, Description: "Monotonic cumulative sum int metric enabled by default.", ExtendedDocumentation: "The metric will be become optional soon.", }, Unit: strPtr("s"), Sum: &Sum{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt}, AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityCumulative}, Mono: Mono{Monotonic: true}, }, }, "optional.metric": { Signal: Signal{ Enabled: false, Description: "[DEPRECATED] Gauge double metric disabled by default.", Stability: Stability{Level: component.StabilityLevelDeprecated}, Warnings: Warnings{ IfConfigured: "This metric is deprecated and will be removed soon.", }, Attributes: []AttributeName{"string_attr", "boolean_attr", "boolean_attr2", "conditional_string_attr"}, }, Unit: strPtr("1"), Gauge: &Gauge{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble}, }, }, "optional.metric.empty_unit": { Signal: Signal{ Enabled: false, Description: "[DEPRECATED] Gauge double metric disabled by default.", Stability: Stability{Level: component.StabilityLevelDeprecated}, Warnings: Warnings{ IfConfigured: "This metric is deprecated and will be removed soon.", }, Attributes: []AttributeName{"string_attr", "boolean_attr"}, }, Unit: strPtr(""), Gauge: &Gauge{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble}, }, }, "default.metric.to_be_removed": { Signal: Signal{ Enabled: true, Description: "[DEPRECATED] Non-monotonic delta sum double metric enabled by default.", ExtendedDocumentation: "The metric will be removed soon.", Stability: Stability{Level: component.StabilityLevelDeprecated}, Warnings: Warnings{ IfEnabled: "This metric is deprecated and will be removed soon.", }, }, Unit: strPtr("s"), Sum: &Sum{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble}, AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityDelta}, Mono: Mono{Monotonic: false}, }, }, "metric.input_type": { Signal: Signal{ Enabled: true, Description: "Monotonic cumulative sum int metric with string input_type enabled by default.", Stability: Stability{Level: component.StabilityLevelDevelopment}, Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr"}, }, Unit: strPtr("s"), Sum: &Sum{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt}, MetricInputType: MetricInputType{InputType: "string"}, AggregationTemporality: AggregationTemporality{Aggregation: pmetric.AggregationTemporalityCumulative}, Mono: Mono{Monotonic: true}, }, }, }, Events: map[EventName]Event{ "default.event": { Signal: Signal{ Enabled: true, Description: "Example event enabled by default.", Warnings: Warnings{ IfEnabledNotSet: "This event will be disabled by default soon.", }, Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr", "conditional_int_attr", "conditional_string_attr", "opt_in_bool_attr"}, }, }, "default.event.to_be_renamed": { Signal: Signal{ Enabled: false, Description: "[DEPRECATED] Example event disabled by default.", ExtendedDocumentation: "The event will be renamed soon.", Warnings: Warnings{ IfConfigured: "This event is deprecated and will be renamed soon.", }, Attributes: []AttributeName{"string_attr", "boolean_attr", "boolean_attr2", "conditional_string_attr"}, }, }, "default.event.to_be_removed": { Signal: Signal{ Enabled: true, Description: "[DEPRECATED] Example to-be-removed event enabled by default.", ExtendedDocumentation: "The event will be removed soon.", Warnings: Warnings{ IfEnabled: "This event is deprecated and will be removed soon.", }, Attributes: []AttributeName{"string_attr", "overridden_int_attr", "enum_attr", "slice_attr", "map_attr"}, }, }, }, Telemetry: Telemetry{ Metrics: map[MetricName]Metric{ "batch_size_trigger_send": { Signal: Signal{ Enabled: true, Stability: Stability{Level: component.StabilityLevelDeprecated, From: "v0.110.0"}, Description: "Number of times the batch was sent due to a size trigger", }, Unit: strPtr("{times}"), Sum: &Sum{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt}, Mono: Mono{Monotonic: true}, }, }, "request_duration": { Signal: Signal{ Enabled: true, Stability: Stability{Level: component.StabilityLevelAlpha}, Description: "Duration of request", }, Unit: strPtr("s"), Histogram: &Histogram{ MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble}, Boundaries: []float64{1, 10, 100}, }, }, "process_runtime_total_alloc_bytes": { Signal: Signal{ Enabled: true, Stability: Stability{Level: component.StabilityLevelStable}, Description: "Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')", }, Unit: strPtr("By"), Sum: &Sum{ Mono: Mono{true}, MetricValueType: MetricValueType{ ValueType: pmetric.NumberDataPointValueTypeInt, }, Async: true, }, }, "queue_length": { Signal: Signal{ Enabled: true, Stability: Stability{Level: component.StabilityLevelAlpha}, Description: "This metric is optional and therefore not initialized in NewTelemetryBuilder.", ExtendedDocumentation: "For example this metric only exists if feature A is enabled.", }, Unit: strPtr("{items}"), Optional: true, Gauge: &Gauge{ MetricValueType: MetricValueType{ ValueType: pmetric.NumberDataPointValueTypeInt, }, Async: true, }, }, "queue_capacity": { Signal: Signal{ Enabled: true, Description: "Queue capacity - sync gauge example.", Stability: Stability{Level: component.StabilityLevelDevelopment}, }, Unit: strPtr("{items}"), Gauge: &Gauge{ MetricValueType: MetricValueType{ ValueType: pmetric.NumberDataPointValueTypeInt, }, }, }, }, }, ScopeName: "go.opentelemetry.io/collector/internal/receiver/samplereceiver", ShortFolderName: "sample", Tests: Tests{Host: "newMdatagenNopHost()"}, }, }, { name: "testdata/parent.yaml", want: Metadata{ Type: "subcomponent", Parent: "parentComponent", GeneratedPackageName: "metadata", ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", ShortFolderName: "testdata", Tests: Tests{Host: "newMdatagenNopHost()"}, }, }, { name: "testdata/generated_package_name.yaml", want: Metadata{ Type: "custom", GeneratedPackageName: "customname", ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", ShortFolderName: "testdata", Tests: Tests{Host: "newMdatagenNopHost()"}, Status: &Status{ Class: "receiver", Stability: map[component.StabilityLevel][]string{ component.StabilityLevelDevelopment: {"logs"}, component.StabilityLevelBeta: {"traces"}, component.StabilityLevelStable: {"metrics"}, }, }, }, }, { name: "testdata/empty_test_config.yaml", want: Metadata{ Type: "test", GeneratedPackageName: "metadata", ScopeName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", PackageName: "go.opentelemetry.io/collector/cmd/mdatagen/internal/testdata", ShortFolderName: "testdata", Tests: Tests{Host: "newMdatagenNopHost()"}, Status: &Status{ Class: "receiver", Stability: map[component.StabilityLevel][]string{ component.StabilityLevelBeta: {"logs"}, }, }, }, }, { name: "testdata/invalid_type_rattr.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'resource_attributes[string.resource.attr].type' invalid type: \"invalidtype\"", }, { name: "testdata/no_enabled.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'metrics[system.cpu.time]' missing required field: `enabled`", }, { name: "testdata/events/no_enabled.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'events[system.event]' missing required field: `enabled`", }, { name: "testdata/no_value_type.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'metrics[system.cpu.time]' decoding failed due to the following error(s):\n\n" + "'sum' missing required field: `value_type`", }, { name: "testdata/unknown_value_type.yaml", wantErr: "decoding failed due to the following error(s):\n\n'metrics[system.cpu.time]' decoding failed due to the following error(s):\n\n'sum' decoding failed due to the following error(s):\n\n'value_type' invalid value_type: \"unknown\"", }, { name: "testdata/invalid_aggregation.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'metrics[default.metric]' decoding failed due to the following error(s):\n\n'sum' decoding failed due to the following error(s):\n\n'aggregation_temporality' invalid aggregation: \"invalidaggregation\"", }, { name: "testdata/invalid_type_attr.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'attributes[used_attr].type' invalid type: \"invalidtype\"", }, { name: "testdata/invalid_metric_stability.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'metrics[default.metric]' decoding failed due to the following error(s):\n\n'stability' decoding failed due to the following error(s):\n\n'level' unsupported stability level: \"development42\"", }, { name: "testdata/invalid_metric_semconvref.yaml", want: Metadata{}, wantErr: "metric \"default.metric\": invalid semantic-conventions URL: want https://github.com/open-telemetry/semantic-conventions/blob/v1.37.2/*#metric-defaultmetric, got \"https://github.com/open-telemetry/semantic-conventions/blob/v1.38.0/docs/system/system-metrics.md#metric-systemcputime\"", }, { name: "testdata/no_metric_stability.yaml", want: Metadata{}, wantErr: "decoding failed due to the following error(s):\n\n'metrics[default.metric]' decoding failed due to the following error(s):\n\n'stability' missing required field: `stability.level`", }, { name: "testdata/~~this file doesn't exist~~.yaml", wantErr: "unable to read the file file:testdata/~~this file doesn't exist~~.yaml", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := LoadMetadata(tt.name) if tt.wantErr != "" { require.Error(t, err) require.ErrorContains(t, err, tt.wantErr) } else { require.NoError(t, err) require.Equal(t, tt.want, got) } }) } } func strPtr(s string) *string { return &s } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/metadata.go000066400000000000000000000426301511331344600250110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import ( "errors" "fmt" "regexp" "slices" "strconv" "strings" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" ) type Metadata struct { // Type of the component. Type string `mapstructure:"type"` // Type of the parent component (applicable to subcomponents). Parent string `mapstructure:"parent"` // Status information for the component. Status *Status `mapstructure:"status"` // The name of the package that will be generated. GeneratedPackageName string `mapstructure:"generated_package_name"` // Telemetry information for the component. Telemetry Telemetry `mapstructure:"telemetry"` // SemConvVersion is a version number of OpenTelemetry semantic conventions applied to the scraped metrics. SemConvVersion string `mapstructure:"sem_conv_version"` // ResourceAttributes that can be emitted by the component. ResourceAttributes map[AttributeName]Attribute `mapstructure:"resource_attributes"` // Entities organizes resource attributes into logical entities. Entities []Entity `mapstructure:"entities"` // Attributes emitted by one or more metrics. Attributes map[AttributeName]Attribute `mapstructure:"attributes"` // Metrics that can be emitted by the component. Metrics map[MetricName]Metric `mapstructure:"metrics"` // Events that can be emitted by the component. Events map[EventName]Event `mapstructure:"events"` // GithubProject is the project where the component README lives in the format of org/repo, defaults to open-telemetry/opentelemetry-collector-contrib GithubProject string `mapstructure:"github_project"` // ScopeName of the metrics emitted by the component. ScopeName string `mapstructure:"scope_name"` // ShortFolderName is the shortened folder name of the component, removing class if present ShortFolderName string `mapstructure:"-"` // Tests is the set of tests generated with the component Tests Tests `mapstructure:"tests"` // PackageName is the name of the package where the component is defined. PackageName string `mapstructure:"package_name"` } func (md Metadata) GetCodeCovComponentID() string { if md.Status.CodeCovComponentID != "" { return md.Status.CodeCovComponentID } return strings.ReplaceAll(md.Status.Class+"_"+md.Type, "/", "_") } func (md Metadata) HasEntities() bool { return len(md.Entities) > 0 } func (md *Metadata) Validate() error { var errs error if err := md.validateType(); err != nil { errs = errors.Join(errs, err) } if md.Parent != "" { if md.Status != nil { // status is not required for subcomponents. errs = errors.Join(errs, errors.New("status must be empty for subcomponents")) } } else { errs = errors.Join(errs, md.Status.Validate()) } if err := md.validateResourceAttributes(); err != nil { errs = errors.Join(errs, err) } if err := md.validateEntities(); err != nil { errs = errors.Join(errs, err) } if err := md.validateMetricsAndEvents(); err != nil { errs = errors.Join(errs, err) } return errs } // typeRegexp is used to validate the type of a component. // A type must start with an ASCII alphabetic character and // can only contain ASCII alphanumeric characters and '_'. // We allow '/' for subcomponents. // This must be kept in sync with the regex in component/config.go. var typeRegexp = regexp.MustCompile(`^[a-zA-Z][0-9a-zA-Z_]{0,62}$`) func (md *Metadata) validateType() error { if md.Type == "" { return errors.New("missing type") } if md.Parent != "" { // subcomponents are allowed to have a '/' in their type. return nil } if !typeRegexp.MatchString(md.Type) { return fmt.Errorf("invalid character(s) in type %q", md.Type) } return nil } func (md *Metadata) validateResourceAttributes() error { var errs error for name, attr := range md.ResourceAttributes { if attr.Description == "" { errs = errors.Join(errs, fmt.Errorf("empty description for resource attribute: %v", name)) } empty := ValueType{ValueType: pcommon.ValueTypeEmpty} if attr.Type == empty { errs = errors.Join(errs, fmt.Errorf("empty type for resource attribute: %v", name)) } if attr.EnabledPtr == nil { errs = errors.Join(errs, fmt.Errorf("enabled field is required for resource attribute: %v", name)) } } return errs } func (md *Metadata) validateEntities() error { var errs error usedAttrs := make(map[AttributeName]string) seenTypes := make(map[string]bool) for _, entity := range md.Entities { if entity.Type == "" { errs = errors.Join(errs, errors.New("entity type cannot be empty")) continue } if seenTypes[entity.Type] { errs = errors.Join(errs, fmt.Errorf(`duplicate entity type: %v`, entity.Type)) } seenTypes[entity.Type] = true if entity.Brief == "" { errs = errors.Join(errs, fmt.Errorf(`entity "%v": brief is required`, entity.Type)) } if len(entity.Identity) == 0 { errs = errors.Join(errs, fmt.Errorf(`entity "%v": identity is required`, entity.Type)) } for _, ref := range entity.Identity { if _, ok := md.ResourceAttributes[ref.Ref]; !ok { errs = errors.Join(errs, fmt.Errorf(`entity "%v": identity refers to undefined resource attribute: %v`, entity.Type, ref.Ref)) } if otherEntity, used := usedAttrs[ref.Ref]; used { errs = errors.Join(errs, fmt.Errorf(`entity "%v": attribute %v is already used by entity "%v"`, entity.Type, ref.Ref, otherEntity)) } else { usedAttrs[ref.Ref] = entity.Type } } for _, ref := range entity.Description { if _, ok := md.ResourceAttributes[ref.Ref]; !ok { errs = errors.Join(errs, fmt.Errorf(`entity "%v": description refers to undefined resource attribute: %v`, entity.Type, ref.Ref)) } if otherEntity, used := usedAttrs[ref.Ref]; used { errs = errors.Join(errs, fmt.Errorf(`entity "%v": attribute %v is already used by entity "%v"`, entity.Type, ref.Ref, otherEntity)) } else { usedAttrs[ref.Ref] = entity.Type } } } return errs } func (md *Metadata) validateMetricsAndEvents() error { var errs error usedAttrs := map[AttributeName]bool{} errs = errors.Join(errs, validateMetrics(md.Metrics, md.Attributes, usedAttrs, md.SemConvVersion), validateMetrics(md.Telemetry.Metrics, md.Attributes, usedAttrs, md.SemConvVersion), validateEvents(md.Events, md.Attributes, usedAttrs), md.validateAttributes(usedAttrs)) return errs } func (md *Metadata) validateAttributes(usedAttrs map[AttributeName]bool) error { var errs error unusedAttrs := make([]AttributeName, 0, len(md.Attributes)) for attrName, attr := range md.Attributes { if attr.Description == "" { errs = errors.Join(errs, fmt.Errorf(`missing attribute description for: %v`, attrName)) } empty := ValueType{ValueType: pcommon.ValueTypeEmpty} if attr.Type == empty { errs = errors.Join(errs, fmt.Errorf("empty type for attribute: %v", attrName)) } if attr.EnabledPtr != nil { errs = errors.Join(errs, fmt.Errorf("enabled field is not allowed for regular attribute: %v", attrName)) } if !usedAttrs[attrName] { unusedAttrs = append(unusedAttrs, attrName) } } if len(unusedAttrs) > 0 { errs = errors.Join(errs, fmt.Errorf("unused attributes: %v", unusedAttrs)) } return errs } func (md *Metadata) supportsSignal(signal string) bool { if md.Status == nil { return false } for _, signals := range md.Status.Stability { if slices.Contains(signals, signal) { return true } } return false } func validateMetrics(metrics map[MetricName]Metric, attributes map[AttributeName]Attribute, usedAttrs map[AttributeName]bool, semConvVersion string) error { var errs error for mn, m := range metrics { if err := m.validate(mn, semConvVersion); err != nil { errs = errors.Join(errs, fmt.Errorf(`metric "%v": %w`, mn, err)) continue } unknownAttrs := make([]AttributeName, 0, len(m.Attributes)) for _, attr := range m.Attributes { if _, ok := attributes[attr]; ok { usedAttrs[attr] = true } else { unknownAttrs = append(unknownAttrs, attr) } } if len(unknownAttrs) > 0 { errs = errors.Join(errs, fmt.Errorf(`metric "%v" refers to undefined attributes: %v`, mn, unknownAttrs)) } } return errs } func validateEvents(events map[EventName]Event, attributes map[AttributeName]Attribute, usedAttrs map[AttributeName]bool) error { var errs error for en, e := range events { if err := e.validate(); err != nil { errs = errors.Join(errs, fmt.Errorf(`event "%v": %w`, en, err)) continue } unknownAttrs := make([]AttributeName, 0, len(e.Attributes)) for _, attr := range e.Attributes { if _, ok := attributes[attr]; ok { usedAttrs[attr] = true } else { unknownAttrs = append(unknownAttrs, attr) } } if len(unknownAttrs) > 0 { errs = errors.Join(errs, fmt.Errorf(`event "%v" refers to undefined attributes: %v`, en, unknownAttrs)) } } return errs } type AttributeName string // AttributeRequirementLevel defines the requirement level of an attribute. type AttributeRequirementLevel string const ( // AttributeRequirementLevelRequired means the attribute is always included and cannot be excluded. AttributeRequirementLevelRequired AttributeRequirementLevel = "required" // AttributeRequirementLevelConditionallyRequired means the attribute is included by default when certain conditions are met. AttributeRequirementLevelConditionallyRequired AttributeRequirementLevel = "conditionally_required" // AttributeRequirementLevelRecommended means the attribute is included by default but can be disabled via configuration. AttributeRequirementLevelRecommended AttributeRequirementLevel = "recommended" // AttributeRequirementLevelOptIn means the attribute is not included unless explicitly enabled in user config. AttributeRequirementLevelOptIn AttributeRequirementLevel = "opt_in" ) // String returns capitalized display name of the requirement level for documentation. func (rl AttributeRequirementLevel) String() string { switch rl { case AttributeRequirementLevelRequired: return "Required" case AttributeRequirementLevelConditionallyRequired: return "Conditionally Required" case AttributeRequirementLevelRecommended: return "Recommended" case AttributeRequirementLevelOptIn: return "Opt-In" } return "" } func (mn AttributeName) Render() (string, error) { return FormatIdentifier(string(mn), true) } func (mn AttributeName) RenderUnexported() (string, error) { return FormatIdentifier(string(mn), false) } // ValueType defines an attribute value type. type ValueType struct { // ValueType is type of the attribute value. ValueType pcommon.ValueType } // UnmarshalText implements the encoding.TextUnmarshaler interface. func (mvt *ValueType) UnmarshalText(text []byte) error { switch vtStr := string(text); vtStr { case "string": mvt.ValueType = pcommon.ValueTypeStr case "int": mvt.ValueType = pcommon.ValueTypeInt case "double": mvt.ValueType = pcommon.ValueTypeDouble case "bool": mvt.ValueType = pcommon.ValueTypeBool case "bytes": mvt.ValueType = pcommon.ValueTypeBytes case "slice": mvt.ValueType = pcommon.ValueTypeSlice case "map": mvt.ValueType = pcommon.ValueTypeMap default: return fmt.Errorf("invalid type: %q", vtStr) } return nil } // String returns capitalized name of the ValueType. func (mvt ValueType) String() string { return strings.Title(strings.ToLower(mvt.ValueType.String())) //nolint:staticcheck // SA1019 } // Primitive returns name of primitive type for the ValueType. func (mvt ValueType) Primitive() string { switch mvt.ValueType { case pcommon.ValueTypeStr: return "string" case pcommon.ValueTypeInt: return "int64" case pcommon.ValueTypeDouble: return "float64" case pcommon.ValueTypeBool: return "bool" case pcommon.ValueTypeBytes: return "[]byte" case pcommon.ValueTypeSlice: return "[]any" case pcommon.ValueTypeMap: return "map[string]any" case pcommon.ValueTypeEmpty: return "" default: return "" } } type SemanticConvention struct { SemanticConventionRef string `mapstructure:"ref"` } type Warnings struct { // A warning that will be displayed if the field is enabled in user config. IfEnabled string `mapstructure:"if_enabled"` // A warning that will be displayed if `enabled` field is not set explicitly in user config. IfEnabledNotSet string `mapstructure:"if_enabled_not_set"` // A warning that will be displayed if the field is configured by user in any way. IfConfigured string `mapstructure:"if_configured"` } type Attribute struct { // Description describes the purpose of the attribute. Description string `mapstructure:"description"` // NameOverride can be used to override the attribute name. NameOverride string `mapstructure:"name_override"` // EnabledPtr defines whether the attribute is enabled by default. EnabledPtr *bool `mapstructure:"enabled"` // Include can be used to filter attributes. Include []filter.Config `mapstructure:"include"` // Include can be used to filter attributes. Exclude []filter.Config `mapstructure:"exclude"` // Enum can optionally describe the set of values to which the attribute can belong. Enum []string `mapstructure:"enum"` // Type is an attribute type. Type ValueType `mapstructure:"type"` // FullName is the attribute name populated from the map key. FullName AttributeName `mapstructure:"-"` // Warnings that will be shown to user under specified conditions. Warnings Warnings `mapstructure:"warnings"` // RequirementLevel defines the requirement level of the attribute. RequirementLevel AttributeRequirementLevel `mapstructure:"requirement_level"` } // IsConditional returns true if the attribute is conditionally required. func (a Attribute) IsConditional() bool { return a.RequirementLevel == AttributeRequirementLevelConditionallyRequired } // UnmarshalText implements the encoding.TextUnmarshaler interface. func (rl *AttributeRequirementLevel) UnmarshalText(text []byte) error { switch string(text) { case "required": *rl = AttributeRequirementLevelRequired case "conditionally_required": *rl = AttributeRequirementLevelConditionallyRequired case "recommended": *rl = AttributeRequirementLevelRecommended case "opt_in": *rl = AttributeRequirementLevelOptIn case "": *rl = AttributeRequirementLevelRecommended default: return fmt.Errorf("invalid requirement_level %q", string(text)) } return nil } // Enabled returns the boolean value of EnabledPtr. // This method is needed to differentiate between different types of attributes: // - Resource attributes: EnabledPtr is always set (non-nil) due to validation // - Regular attributes: EnabledPtr is always nil due to validation // Panics if EnabledPtr is nil, indicating incorrect template usage. func (a Attribute) Enabled() bool { if a.EnabledPtr == nil { panic("Enabled() must not be called on regular attributes, only on resource attributes") } return *a.EnabledPtr } // Name returns actual name of the attribute that is set on the metric after applying NameOverride. func (a Attribute) Name() AttributeName { if a.NameOverride != "" { return AttributeName(a.NameOverride) } return a.FullName } func (a Attribute) TestValue() string { if a.Enum != nil { return fmt.Sprintf(`%q`, a.Enum[0]) } switch a.Type.ValueType { case pcommon.ValueTypeEmpty: return "" case pcommon.ValueTypeStr: return fmt.Sprintf(`"%s-val"`, a.FullName) case pcommon.ValueTypeInt: return strconv.Itoa(len(a.FullName)) case pcommon.ValueTypeDouble: return fmt.Sprintf("%f", 0.1+float64(len(a.FullName))) case pcommon.ValueTypeBool: return strconv.FormatBool(len(a.FullName)%2 == 0) case pcommon.ValueTypeMap: return fmt.Sprintf(`map[string]any{"key1": "%s-val1", "key2": "%s-val2"}`, a.FullName, a.FullName) case pcommon.ValueTypeSlice: return fmt.Sprintf(`[]any{"%s-item1", "%s-item2"}`, a.FullName, a.FullName) case pcommon.ValueTypeBytes: return fmt.Sprintf(`[]byte("%s-val")`, a.FullName) } return "" } type Signal struct { // Enabled defines whether the signal is enabled by default. Enabled bool `mapstructure:"enabled"` // Warnings that will be shown to user under specified conditions. Warnings Warnings `mapstructure:"warnings"` // Description of the signal. Description string `mapstructure:"description"` // The semantic convention reference of the signal. SemanticConvention *SemanticConvention `mapstructure:"semantic_convention"` // The stability level of the signal. Stability Stability `mapstructure:"stability"` // Extended documentation of the signal. If specified, this will be appended to the description used in generated documentation. ExtendedDocumentation string `mapstructure:"extended_documentation"` // Attributes is the list of attributes that the signal emits. Attributes []AttributeName `mapstructure:"attributes"` } func (s Signal) HasConditionalAttributes(attrs map[AttributeName]Attribute) bool { for _, attr := range s.Attributes { if v, exists := attrs[attr]; exists && v.IsConditional() { return true } } return false } type Entity struct { // Type is the type of the entity. Type string `mapstructure:"type"` // Brief is a brief description of the entity. Brief string `mapstructure:"brief"` // Stability is the stability level of the entity. Stability string `mapstructure:"stability"` // Identity contains references to resource attributes that uniquely identify the entity. Identity []EntityAttributeRef `mapstructure:"identity"` // Description contains references to resource attributes that describe the entity. Description []EntityAttributeRef `mapstructure:"description"` } type EntityAttributeRef struct { // Ref is the reference to a resource attribute. Ref AttributeName `mapstructure:"ref"` } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/metadata_test.go000066400000000000000000000204651511331344600260520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "io/fs" "path/filepath" "slices" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestValidate(t *testing.T) { tests := []struct { name string wantErr string }{ { name: "testdata/no_type.yaml", wantErr: "missing type", }, { name: "testdata/no_status.yaml", wantErr: "missing status", }, { name: "testdata/no_class.yaml", wantErr: "missing class", }, { name: "testdata/invalid_class.yaml", wantErr: "invalid class: incorrectclass", }, { name: "testdata/no_stability.yaml", wantErr: "missing stability", }, { name: "testdata/no_deprecation_info.yaml", wantErr: "deprecated component missing deprecation date and migration guide for traces", }, { name: "testdata/no_deprecation_date_info.yaml", wantErr: "deprecated component missing date in YYYY-MM-DD format: traces", }, { name: "testdata/no_deprecation_migration_info.yaml", wantErr: "deprecated component missing migration guide: traces", }, { name: "testdata/deprecation_info_invalid_date.yaml", wantErr: "deprecated component missing valid date in YYYY-MM-DD format: traces", }, { name: "testdata/invalid_stability.yaml", wantErr: "decoding failed due to the following error(s):\n\n'status.stability' unsupported stability level: \"incorrectstability\"", }, { name: "testdata/no_stability_component.yaml", wantErr: "missing component for stability: Beta", }, { name: "testdata/invalid_stability_component.yaml", wantErr: "invalid component: incorrectcomponent", }, { name: "testdata/no_description_rattr.yaml", wantErr: "empty description for resource attribute: string.resource.attr", }, { name: "testdata/no_type_rattr.yaml", wantErr: "empty type for resource attribute: string.resource.attr", }, { name: "testdata/no_metric_description.yaml", wantErr: "metric \"default.metric\": missing metric description", }, { name: "testdata/events/no_description.yaml", wantErr: "event \"default.event\": missing event description", }, { name: "testdata/no_metric_unit.yaml", wantErr: "metric \"default.metric\": missing metric unit", }, { name: "testdata/no_metric_type.yaml", wantErr: "metric \"system.cpu.time\": missing metric type key, " + "one of the following has to be specified: sum, gauge, histogram", }, { name: "testdata/two_metric_types.yaml", wantErr: "metric \"system.cpu.time\": more than one metric type keys, " + "only one of the following has to be specified: sum, gauge, histogram", }, { name: "testdata/invalid_input_type.yaml", wantErr: "metric \"system.cpu.time\": invalid `input_type` value \"double\", must be \"\" or \"string\"", }, { name: "testdata/unknown_metric_attribute.yaml", wantErr: "metric \"system.cpu.time\" refers to undefined attributes: [missing]", }, { name: "testdata/events/unknown_attribute.yaml", wantErr: "event \"system.event\" refers to undefined attributes: [missing]", }, { name: "testdata/unused_attribute.yaml", wantErr: "unused attributes: [unused_attr]", }, { name: "testdata/no_description_attr.yaml", wantErr: "missing attribute description for: string_attr", }, { name: "testdata/no_type_attr.yaml", wantErr: "empty type for attribute: used_attr", }, { name: "testdata/entity_undefined_id_attribute.yaml", wantErr: `entity "host": identity refers to undefined resource attribute: host.missing`, }, { name: "testdata/entity_undefined_description_attribute.yaml", wantErr: `entity "host": description refers to undefined resource attribute: host.missing`, }, { name: "testdata/entity_empty_id_attributes.yaml", wantErr: `entity "host": identity is required`, }, { name: "testdata/entity_duplicate_attributes.yaml", wantErr: `attribute host.name is already used by entity`, }, { name: "testdata/entity_duplicate_types.yaml", wantErr: `duplicate entity type: host`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := LoadMetadata(tt.name) require.Error(t, err) require.ErrorContains(t, err, tt.wantErr) }) } } func TestValidateMetricDuplicates(t *testing.T) { allowedMetrics := map[string][]string{ "container.cpu.utilization": {"docker_stats", "kubeletstats"}, "container.memory.rss": {"docker_stats", "kubeletstats"}, "container.uptime": {"docker_stats", "kubeletstats"}, } allMetrics := map[string][]string{} err := filepath.Walk("../../../receiver", func(path string, info fs.FileInfo, _ error) error { if info.Name() == "metadata.yaml" { md, err := LoadMetadata(path) require.NoError(t, err) if len(md.Metrics) > 0 { for metricName := range md.Metrics { allMetrics[md.Type] = append(allMetrics[md.Type], string(metricName)) } } } return nil }) require.NoError(t, err) seen := make(map[string]string) for receiver, metrics := range allMetrics { for _, metricName := range metrics { if val, exists := seen[metricName]; exists { receivers, allowed := allowedMetrics[metricName] assert.Truef( t, allowed && slices.Contains(receivers, receiver) && slices.Contains(receivers, val), "Duplicate metric %v in receivers %v and %v. Please validate that this is intentional by adding the metric name and receiver types in the allowedMetrics map in this test\n", metricName, receiver, val, ) } seen[metricName] = receiver } } } func TestSupportsSignal(t *testing.T) { md := Metadata{} assert.False(t, md.supportsSignal("logs")) } func TestCodeCovID(t *testing.T) { tests := []struct { md Metadata want string }{ { md: Metadata{ Type: "aes", Status: &Status{ Class: "provider", CodeCovComponentID: "my_custom_id", }, }, want: "my_custom_id", }, { md: Metadata{ Type: "count", Status: &Status{ Class: "connector", }, }, want: "connector_count", }, { md: Metadata{ Type: "file", Status: &Status{ Class: "exporter", }, }, want: "exporter_file", }, } for _, tt := range tests { t.Run(tt.md.Type, func(t *testing.T) { got := tt.md.GetCodeCovComponentID() assert.Equal(t, tt.want, got) }) } } func TestAttributeRequirementLevel(t *testing.T) { tests := []struct { name string requirementLevel AttributeRequirementLevel wantConditional bool }{ { name: "required", requirementLevel: AttributeRequirementLevelRequired, wantConditional: false, }, { name: "conditionally_required", requirementLevel: AttributeRequirementLevelConditionallyRequired, wantConditional: true, }, { name: "recommended", requirementLevel: AttributeRequirementLevelRecommended, wantConditional: false, }, { name: "opt_in", requirementLevel: AttributeRequirementLevelOptIn, wantConditional: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { attr := Attribute{RequirementLevel: tt.requirementLevel} assert.Equal(t, tt.wantConditional, attr.IsConditional()) }) } } func TestAttributeRequirementLevelUnmarshalText(t *testing.T) { tests := []struct { name string input string want AttributeRequirementLevel wantErr bool }{ { name: "required", input: "required", want: AttributeRequirementLevelRequired, }, { name: "conditionally_required", input: "conditionally_required", want: AttributeRequirementLevelConditionallyRequired, }, { name: "recommended", input: "recommended", want: AttributeRequirementLevelRecommended, }, { name: "opt_in", input: "opt_in", want: AttributeRequirementLevelOptIn, }, { name: "empty defaults to recommended", input: "", want: AttributeRequirementLevelRecommended, }, { name: "invalid value", input: "invalid", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var rl AttributeRequirementLevel err := rl.UnmarshalText([]byte(tt.input)) if tt.wantErr { assert.Error(t, err) return } require.NoError(t, err) assert.Equal(t, tt.want, rl) }) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/metric.go000066400000000000000000000263651511331344600245230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import ( "errors" "fmt" "regexp" "strings" "golang.org/x/text/cases" "golang.org/x/text/language" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/pdata/pmetric" ) var reNonAlnum = regexp.MustCompile(`[^a-z0-9]+`) type MetricName string func (mn MetricName) Render() (string, error) { return FormatIdentifier(string(mn), true) } func (mn MetricName) RenderUnexported() (string, error) { return FormatIdentifier(string(mn), false) } type Metric struct { Signal `mapstructure:",squash"` // Optional can be used to specify metrics that may // or may not be present in all cases, depending on configuration. Optional bool `mapstructure:"optional"` // Unit of the metric. Unit *string `mapstructure:"unit"` // Sum stores metadata for sum metric type Sum *Sum `mapstructure:"sum,omitempty"` // Gauge stores metadata for gauge metric type Gauge *Gauge `mapstructure:"gauge,omitempty"` // Histogram stores metadata for histogram metric type Histogram *Histogram `mapstructure:"histogram,omitempty"` // Override the default prefix for the metric name. Prefix string `mapstructure:"prefix"` } type Stability struct { Level component.StabilityLevel `mapstructure:"level"` From string `mapstructure:"from"` } func (s Stability) String() string { if s.Level == component.StabilityLevelUndefined || s.Level == component.StabilityLevelStable { return "" } if s.From != "" { return fmt.Sprintf(" [%s since %s]", s.Level.String(), s.From) } return fmt.Sprintf(" [%s]", s.Level.String()) } func (s *Stability) Unmarshal(parser *confmap.Conf) error { if !parser.IsSet("level") { return errors.New("missing required field: `stability.level`") } return parser.Unmarshal(s) } func (m *Metric) validate(metricName MetricName, semConvVersion string) error { var errs error if m.Sum == nil && m.Gauge == nil && m.Histogram == nil { errs = errors.Join(errs, errors.New("missing metric type key, "+ "one of the following has to be specified: sum, gauge, histogram")) } if (m.Sum != nil && m.Gauge != nil) || (m.Sum != nil && m.Histogram != nil) || (m.Gauge != nil && m.Histogram != nil) { errs = errors.Join(errs, errors.New("more than one metric type keys, "+ "only one of the following has to be specified: sum, gauge, histogram")) } if m.Description == "" { errs = errors.Join(errs, errors.New(`missing metric description`)) } if m.Unit == nil { errs = errors.Join(errs, errors.New(`missing metric unit`)) } if m.Sum != nil { errs = errors.Join(errs, m.Sum.Validate()) } if m.Gauge != nil { errs = errors.Join(errs, m.Gauge.Validate()) } if m.SemanticConvention != nil { if err := validateSemConvMetricURL(m.SemanticConvention.SemanticConventionRef, semConvVersion, string(metricName)); err != nil { errs = errors.Join(errs, err) } } return errs } func metricAnchor(metricName string) string { m := strings.ToLower(strings.TrimSpace(metricName)) m = reNonAlnum.ReplaceAllString(m, "") return "metric-" + m } // validateSemConvMetricURL verifies the URL matches exactly: // https://github.com/open-telemetry/semantic-conventions/blob//*#metric- func validateSemConvMetricURL(rawURL, semConvVersion, metricName string) error { if strings.TrimSpace(rawURL) == "" { return errors.New("url is empty") } if strings.TrimSpace(semConvVersion) == "" { return errors.New("semConvVersion is empty") } if strings.TrimSpace(metricName) == "" { return errors.New("metricName is empty") } semConvVersion = "v" + semConvVersion anchor := metricAnchor(metricName) // Build a strict regex that enforces https, repo, blob, given version, any doc path, and exact anchor. pattern := fmt.Sprintf(`^https://github\.com/open-telemetry/semantic-conventions/blob/%s/[^#\s]+#%s$`, semConvVersion, anchor, ) re := regexp.MustCompile(pattern) if !re.MatchString(rawURL) { return fmt.Errorf( "invalid semantic-conventions URL: want https://github.com/open-telemetry/semantic-conventions/blob/%s/*#%s, got %q", semConvVersion, anchor, rawURL) } return nil } func (m *Metric) Unmarshal(parser *confmap.Conf) error { if !parser.IsSet("enabled") { return errors.New("missing required field: `enabled`") } if !parser.IsSet("stability") { return errors.New("missing required field: `stability`") } return parser.Unmarshal(m) } func (m Metric) Data() MetricData { if m.Sum != nil { return m.Sum } if m.Gauge != nil { return m.Gauge } if m.Histogram != nil { return m.Histogram } return nil } // MetricData is generic interface for all metric datatypes. type MetricData interface { Type() string HasMonotonic() bool HasAggregated() bool HasMetricInputType() bool Instrument() string IsAsync() bool } // AggregationTemporality defines a metric aggregation type. type AggregationTemporality struct { // Aggregation describes if the aggregator reports delta changes // since last report time, or cumulative changes since a fixed start time. Aggregation pmetric.AggregationTemporality } // UnmarshalText implements the encoding.TextUnmarshaler interface. func (agg *AggregationTemporality) UnmarshalText(text []byte) error { switch vtStr := string(text); vtStr { case "cumulative": agg.Aggregation = pmetric.AggregationTemporalityCumulative case "delta": agg.Aggregation = pmetric.AggregationTemporalityDelta default: return fmt.Errorf("invalid aggregation: %q", vtStr) } return nil } // String returns string representation of the aggregation temporality. func (agg *AggregationTemporality) String() string { return agg.Aggregation.String() } // Mono defines the metric monotonicity. type Mono struct { // Monotonic is true if the sum is monotonic. Monotonic bool `mapstructure:"monotonic"` } // MetricInputType defines the metric input value type type MetricInputType struct { // InputType is the type the metric needs to be parsed from, options are "string" InputType string `mapstructure:"input_type"` } func (mit MetricInputType) HasMetricInputType() bool { return mit.InputType != "" } // String returns name of the datapoint type. func (mit MetricInputType) String() string { return mit.InputType } func (mit MetricInputType) Validate() error { if mit.InputType != "" && mit.InputType != "string" { return fmt.Errorf("invalid `input_type` value \"%v\", must be \"\" or \"string\"", mit.InputType) } return nil } // MetricValueType defines the metric number type. type MetricValueType struct { // ValueType is type of the metric number, options are "double", "int". ValueType pmetric.NumberDataPointValueType } func (mvt *MetricValueType) Unmarshal(parser *confmap.Conf) error { if !parser.IsSet("value_type") { return errors.New("missing required field: `value_type`") } return nil } // UnmarshalText implements the encoding.TextUnmarshaler interface. func (mvt *MetricValueType) UnmarshalText(text []byte) error { switch vtStr := string(text); vtStr { case "int": mvt.ValueType = pmetric.NumberDataPointValueTypeInt case "double": mvt.ValueType = pmetric.NumberDataPointValueTypeDouble default: return fmt.Errorf("invalid value_type: %q", vtStr) } return nil } // String returns name of the datapoint type. func (mvt MetricValueType) String() string { return mvt.ValueType.String() } // BasicType returns name of a golang basic type for the datapoint type. func (mvt MetricValueType) BasicType() string { switch mvt.ValueType { case pmetric.NumberDataPointValueTypeInt: return "int64" case pmetric.NumberDataPointValueTypeDouble: return "float64" case pmetric.NumberDataPointValueTypeEmpty: return "" default: return "" } } var _ MetricData = (*Gauge)(nil) type Gauge struct { MetricValueType `mapstructure:"value_type"` MetricInputType `mapstructure:",squash"` Async bool `mapstructure:"async,omitempty"` } // Unmarshal is a custom unmarshaler for gauge. Needed mostly to avoid MetricValueType.Unmarshal inheritance. func (d *Gauge) Unmarshal(parser *confmap.Conf) error { if err := d.MetricValueType.Unmarshal(parser); err != nil { return err } return parser.Unmarshal(d, confmap.WithIgnoreUnused()) } func (d *Gauge) Type() string { return "Gauge" } func (d *Gauge) HasMonotonic() bool { return false } func (d *Gauge) HasAggregated() bool { return false } func (d *Gauge) Instrument() string { instrumentName := cases.Title(language.English).String(d.BasicType()) if d.Async { instrumentName += "Observable" } instrumentName += "Gauge" return instrumentName } func (d *Gauge) IsAsync() bool { return d.Async } var _ MetricData = (*Sum)(nil) type Sum struct { AggregationTemporality `mapstructure:"aggregation_temporality"` Mono `mapstructure:",squash"` MetricValueType `mapstructure:"value_type"` MetricInputType `mapstructure:",squash"` Async bool `mapstructure:"async,omitempty"` } // Unmarshal is a custom unmarshaler for sum. Needed mostly to avoid MetricValueType.Unmarshal inheritance. func (d *Sum) Unmarshal(parser *confmap.Conf) error { if err := d.MetricValueType.Unmarshal(parser); err != nil { return err } return parser.Unmarshal(d, confmap.WithIgnoreUnused()) } // TODO: Currently, this func will not be called because of https://github.com/open-telemetry/opentelemetry-collector/issues/6671. Uncomment function and // add a test case to Test_LoadMetadata for file no_monotonic.yaml once the issue is solved. // // Unmarshal is a custom unmarshaler for Mono. // func (m *Mono) Unmarshal(parser *confmap.Conf) error { // if !parser.IsSet("monotonic") { // return errors.New("missing required field: `monotonic`") // } // return parser.Unmarshal(m) // } func (d *Sum) Type() string { return "Sum" } func (d *Sum) HasMonotonic() bool { return true } func (d *Sum) HasAggregated() bool { return true } func (d *Sum) Instrument() string { instrumentName := cases.Title(language.English).String(d.BasicType()) if d.Async { instrumentName += "Observable" } if !d.Monotonic { instrumentName += "UpDown" } instrumentName += "Counter" return instrumentName } func (d *Sum) IsAsync() bool { return d.Async } var _ MetricData = (*Histogram)(nil) type Histogram struct { AggregationTemporality `mapstructure:"aggregation_temporality"` Mono `mapstructure:",squash"` MetricValueType `mapstructure:"value_type"` MetricInputType `mapstructure:",squash"` Async bool `mapstructure:"async,omitempty"` Boundaries []float64 `mapstructure:"bucket_boundaries"` } func (d *Histogram) Type() string { return "Histogram" } func (d *Histogram) HasMonotonic() bool { return false } func (d *Histogram) HasAggregated() bool { return true } func (d *Histogram) Instrument() string { instrumentName := cases.Title(language.English).String(d.BasicType()) return instrumentName + d.Type() } // Unmarshal is a custom unmarshaler for histogram. Needed mostly to avoid MetricValueType.Unmarshal inheritance. func (d *Histogram) Unmarshal(parser *confmap.Conf) error { if err := d.MetricValueType.Unmarshal(parser); err != nil { return err } return parser.Unmarshal(d, confmap.WithIgnoreUnused()) } func (d *Histogram) IsAsync() bool { return d.Async } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/metric_test.go000066400000000000000000000033511511331344600255500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pmetric" ) func TestMetricData(t *testing.T) { for _, arg := range []struct { metricData MetricData wantType string wantHasAggregated bool wantHasMonotonic bool wantInstrument string wantAsync bool }{ {&Gauge{}, "Gauge", false, false, "Gauge", false}, {&Gauge{Async: true}, "Gauge", false, false, "ObservableGauge", true}, {&Gauge{MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt}, Async: true}, "Gauge", false, false, "Int64ObservableGauge", true}, {&Gauge{MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble}, Async: true}, "Gauge", false, false, "Float64ObservableGauge", true}, {&Sum{}, "Sum", true, true, "UpDownCounter", false}, {&Sum{Mono: Mono{true}}, "Sum", true, true, "Counter", false}, {&Sum{Async: true}, "Sum", true, true, "ObservableUpDownCounter", true}, {&Sum{MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeInt}, Async: true}, "Sum", true, true, "Int64ObservableUpDownCounter", true}, {&Sum{MetricValueType: MetricValueType{pmetric.NumberDataPointValueTypeDouble}, Async: true}, "Sum", true, true, "Float64ObservableUpDownCounter", true}, {&Histogram{}, "Histogram", true, false, "Histogram", false}, } { assert.Equal(t, arg.wantType, arg.metricData.Type()) assert.Equal(t, arg.wantHasAggregated, arg.metricData.HasAggregated()) assert.Equal(t, arg.wantHasMonotonic, arg.metricData.HasMonotonic()) assert.Equal(t, arg.wantInstrument, arg.metricData.Instrument()) assert.Equal(t, arg.wantAsync, arg.metricData.IsAsync()) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/000077500000000000000000000000001511331344600260715ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/doc.go000066400000000000000000000004761511331344600271740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Generate a test metrics builder from a sample metrics set covering all configuration options. //go:generate mdatagen metadata.yaml package sampleconnector // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleconnector" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/documentation.md000066400000000000000000000110611511331344600312630ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # sample ## Default Metrics The following metrics are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml metrics: : enabled: false ``` ### default.metric Monotonic cumulative sum int metric enabled by default. The metric will be become optional soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Int | Cumulative | true | Development | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | state | Integer attribute with overridden name. | Any Int | Recommended | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | Recommended | | slice_attr | Attribute with a slice value. | Any Slice | Recommended | | map_attr | Attribute with a map value. | Any Map | Recommended | ### default.metric.to_be_removed [DEPRECATED] Non-monotonic delta sum double metric enabled by default. The metric will be removed soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Double | Delta | false | Deprecated | ### metric.input_type Monotonic cumulative sum int metric with string input_type enabled by default. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Int | Cumulative | true | Development | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | state | Integer attribute with overridden name. | Any Int | Recommended | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | Recommended | | slice_attr | Attribute with a slice value. | Any Slice | Recommended | | map_attr | Attribute with a map value. | Any Map | Recommended | ## Optional Metrics The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml metrics: : enabled: true ``` ### optional.metric [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | 1 | Gauge | Double | Deprecated | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | boolean_attr | Attribute with a boolean value. | Any Bool | Recommended | | boolean_attr2 | Another attribute with a boolean value. | Any Bool | Recommended | ### optional.metric.empty_unit [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | | Gauge | Double | Deprecated | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | boolean_attr | Attribute with a boolean value. | Any Bool | Recommended | ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | | map.resource.attr | Resource attribute with a map value. | Any Map | true | | optional.resource.attr | Explicitly disabled ResourceAttribute. | Any Str | false | | slice.resource.attr | Resource attribute with a slice value. | Any Slice | true | | string.enum.resource.attr | Resource attribute with a known set of string values. | Str: ``one``, ``two`` | true | | string.resource.attr | Resource attribute with any string value. | Any Str | true | | string.resource.attr_disable_warning | Resource attribute with any string value. | Any Str | true | | string.resource.attr_remove_warning | Resource attribute with any string value. | Any Str | false | | string.resource.attr_to_be_removed | Resource attribute with any string value. | Any Str | true | ## Entities The following entities are defined for this component: ### test.entity A test entity. **Stability:** stable **Identity Attributes:** - `string.resource.attr` **Description Attributes:** - `map.resource.attr` opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/factory.go000066400000000000000000000023551511331344600300740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sampleconnector // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleconnector" import ( "context" "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleconnector/internal/metadata" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pmetric" ) // NewFactory returns a connector.Factory for sample connector. func NewFactory() connector.Factory { return connector.NewFactory( metadata.Type, func() component.Config { return &struct{}{} }, connector.WithMetricsToMetrics(createMetricsToMetricsConnector, metadata.MetricsToMetricsStability)) } func createMetricsToMetricsConnector(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Metrics, error) { return nopInstance, nil } var nopInstance = &nopConnector{} type nopConnector struct { component.StartFunc component.ShutdownFunc } func (n nopConnector) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: false} } func (n nopConnector) ConsumeMetrics(context.Context, pmetric.Metrics) error { return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/generated_component_test.go000066400000000000000000000055751511331344600335130ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. //go:build !freebsd && !illumos package sampleconnector import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pipeline" ) var typ = component.MustNewType("sample") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "metrics_to_metrics", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewMetricsRouter(map[pipeline.ID]consumer.Metrics{pipeline.NewID(pipeline.SignalMetrics): consumertest.NewNop()}) return factory.CreateMetricsToMetrics(ctx, set, cfg, router) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstConnector.Start(context.Background(), host)) require.NoError(t, firstConnector.Shutdown(context.Background())) secondConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondConnector.Start(context.Background(), host)) require.NoError(t, secondConnector.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/generated_package_test.go000066400000000000000000000002561511331344600330730ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package sampleconnector import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/000077500000000000000000000000001511331344600277055ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata/000077500000000000000000000000001511331344600314655ustar00rootroot00000000000000generated_config.go000066400000000000000000000105461511331344600352260ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/filter" ) // MetricConfig provides common config for a particular metric. type MetricConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ms) if err != nil { return err } ms.enabledSetByUser = parser.IsSet("enabled") return nil } // MetricsConfig provides config for sample metrics. type MetricsConfig struct { DefaultMetric MetricConfig `mapstructure:"default.metric"` DefaultMetricToBeRemoved MetricConfig `mapstructure:"default.metric.to_be_removed"` MetricInputType MetricConfig `mapstructure:"metric.input_type"` OptionalMetric MetricConfig `mapstructure:"optional.metric"` OptionalMetricEmptyUnit MetricConfig `mapstructure:"optional.metric.empty_unit"` } func DefaultMetricsConfig() MetricsConfig { return MetricsConfig{ DefaultMetric: MetricConfig{ Enabled: true, }, DefaultMetricToBeRemoved: MetricConfig{ Enabled: true, }, MetricInputType: MetricConfig{ Enabled: true, }, OptionalMetric: MetricConfig{ Enabled: false, }, OptionalMetricEmptyUnit: MetricConfig{ Enabled: false, }, } } // ResourceAttributeConfig provides common config for a particular resource attribute. type ResourceAttributeConfig struct { Enabled bool `mapstructure:"enabled"` // Experimental: MetricsInclude defines a list of filters for attribute values. // If the list is not empty, only metrics with matching resource attribute values will be emitted. MetricsInclude []filter.Config `mapstructure:"metrics_include"` // Experimental: MetricsExclude defines a list of filters for attribute values. // If the list is not empty, metrics with matching resource attribute values will not be emitted. // MetricsInclude has higher priority than MetricsExclude. MetricsExclude []filter.Config `mapstructure:"metrics_exclude"` enabledSetByUser bool } func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(rac) if err != nil { return err } rac.enabledSetByUser = parser.IsSet("enabled") return nil } // ResourceAttributesConfig provides config for sample resource attributes. type ResourceAttributesConfig struct { MapResourceAttr ResourceAttributeConfig `mapstructure:"map.resource.attr"` OptionalResourceAttr ResourceAttributeConfig `mapstructure:"optional.resource.attr"` SliceResourceAttr ResourceAttributeConfig `mapstructure:"slice.resource.attr"` StringEnumResourceAttr ResourceAttributeConfig `mapstructure:"string.enum.resource.attr"` StringResourceAttr ResourceAttributeConfig `mapstructure:"string.resource.attr"` StringResourceAttrDisableWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_disable_warning"` StringResourceAttrRemoveWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_remove_warning"` StringResourceAttrToBeRemoved ResourceAttributeConfig `mapstructure:"string.resource.attr_to_be_removed"` } func DefaultResourceAttributesConfig() ResourceAttributesConfig { return ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{ Enabled: true, }, OptionalResourceAttr: ResourceAttributeConfig{ Enabled: false, }, SliceResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringEnumResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrDisableWarning: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrRemoveWarning: ResourceAttributeConfig{ Enabled: false, }, StringResourceAttrToBeRemoved: ResourceAttributeConfig{ Enabled: true, }, } } // MetricsBuilderConfig is a configuration for sample metrics builder. type MetricsBuilderConfig struct { Metrics MetricsConfig `mapstructure:"metrics"` ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` } func DefaultMetricsBuilderConfig() MetricsBuilderConfig { return MetricsBuilderConfig{ Metrics: DefaultMetricsConfig(), ResourceAttributes: DefaultResourceAttributesConfig(), } } generated_config_test.go000066400000000000000000000130041511331344600362550ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestMetricsBuilderConfig(t *testing.T) { tests := []struct { name string want MetricsBuilderConfig }{ { name: "default", want: DefaultMetricsBuilderConfig(), }, { name: "all_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: true}, DefaultMetricToBeRemoved: MetricConfig{Enabled: true}, MetricInputType: MetricConfig{Enabled: true}, OptionalMetric: MetricConfig{Enabled: true}, OptionalMetricEmptyUnit: MetricConfig{Enabled: true}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, }, { name: "none_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: false}, DefaultMetricToBeRemoved: MetricConfig{Enabled: false}, MetricInputType: MetricConfig{Enabled: false}, OptionalMetric: MetricConfig{Enabled: false}, OptionalMetricEmptyUnit: MetricConfig{Enabled: false}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadMetricsBuilderConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(MetricConfig{}, ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadMetricsBuilderConfig(t *testing.T, name string) MetricsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultMetricsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } func TestResourceAttributesConfig(t *testing.T) { tests := []struct { name string want ResourceAttributesConfig }{ { name: "default", want: DefaultResourceAttributesConfig(), }, { name: "all_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, { name: "none_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadResourceAttributesConfig(t *testing.T, name string) ResourceAttributesConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) sub, err = sub.Sub("resource_attributes") require.NoError(t, err) cfg := DefaultResourceAttributesConfig() require.NoError(t, sub.Unmarshal(&cfg)) return cfg } generated_metrics.go000066400000000000000000000636231511331344600354330ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "fmt" "strconv" "time" conventions "go.opentelemetry.io/otel/semconv/v1.9.0" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) // AttributeEnumAttr specifies the value enum_attr attribute. type AttributeEnumAttr int const ( _ AttributeEnumAttr = iota AttributeEnumAttrRed AttributeEnumAttrGreen AttributeEnumAttrBlue ) // String returns the string representation of the AttributeEnumAttr. func (av AttributeEnumAttr) String() string { switch av { case AttributeEnumAttrRed: return "red" case AttributeEnumAttrGreen: return "green" case AttributeEnumAttrBlue: return "blue" } return "" } // MapAttributeEnumAttr is a helper map of string to AttributeEnumAttr attribute value. var MapAttributeEnumAttr = map[string]AttributeEnumAttr{ "red": AttributeEnumAttrRed, "green": AttributeEnumAttrGreen, "blue": AttributeEnumAttrBlue, } var MetricsInfo = metricsInfo{ DefaultMetric: metricInfo{ Name: "default.metric", }, DefaultMetricToBeRemoved: metricInfo{ Name: "default.metric.to_be_removed", }, MetricInputType: metricInfo{ Name: "metric.input_type", }, OptionalMetric: metricInfo{ Name: "optional.metric", }, OptionalMetricEmptyUnit: metricInfo{ Name: "optional.metric.empty_unit", }, } type metricsInfo struct { DefaultMetric metricInfo DefaultMetricToBeRemoved metricInfo MetricInputType metricInfo OptionalMetric metricInfo OptionalMetricEmptyUnit metricInfo } type metricInfo struct { Name string } type metricDefaultMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric metric with initial data. func (m *metricDefaultMetric) init() { m.data.SetName("default.metric") m.data.SetDescription("Monotonic cumulative sum int metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricDefaultMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetric) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetric(cfg MetricConfig) metricDefaultMetric { m := metricDefaultMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricDefaultMetricToBeRemoved struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric.to_be_removed metric with initial data. func (m *metricDefaultMetricToBeRemoved) init() { m.data.SetName("default.metric.to_be_removed") m.data.SetDescription("[DEPRECATED] Non-monotonic delta sum double metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(false) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) } func (m *metricDefaultMetricToBeRemoved) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetricToBeRemoved) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetricToBeRemoved) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetricToBeRemoved(cfg MetricConfig) metricDefaultMetricToBeRemoved { m := metricDefaultMetricToBeRemoved{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricMetricInputType struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills metric.input_type metric with initial data. func (m *metricMetricInputType) init() { m.data.SetName("metric.input_type") m.data.SetDescription("Monotonic cumulative sum int metric with string input_type enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricMetricInputType) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricMetricInputType) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricMetricInputType) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricMetricInputType(cfg MetricConfig) metricMetricInputType { m := metricMetricInputType{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric metric with initial data. func (m *metricOptionalMetric) init() { m.data.SetName("optional.metric") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("1") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) dp.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetric) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetric(cfg MetricConfig) metricOptionalMetric { m := metricOptionalMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetricEmptyUnit struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric.empty_unit metric with initial data. func (m *metricOptionalMetricEmptyUnit) init() { m.data.SetName("optional.metric.empty_unit") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetricEmptyUnit) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetricEmptyUnit) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetricEmptyUnit) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetricEmptyUnit(cfg MetricConfig) metricOptionalMetricEmptyUnit { m := metricOptionalMetricEmptyUnit{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } // MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations // required to produce metric representation defined in metadata and user config. type MetricsBuilder struct { config MetricsBuilderConfig // config of the metrics builder. startTime pcommon.Timestamp // start time that will be applied to all recorded data points. metricsCapacity int // maximum observed number of metrics per resource. metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. buildInfo component.BuildInfo // contains version information. resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter metricDefaultMetric metricDefaultMetric metricDefaultMetricToBeRemoved metricDefaultMetricToBeRemoved metricMetricInputType metricMetricInputType metricOptionalMetric metricOptionalMetric metricOptionalMetricEmptyUnit metricOptionalMetricEmptyUnit } // MetricBuilderOption applies changes to default metrics builder. type MetricBuilderOption interface { apply(*MetricsBuilder) } type metricBuilderOptionFunc func(mb *MetricsBuilder) func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { mbof(mb) } // WithStartTime sets startTime on the metrics builder. func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime }) } func NewMetricsBuilder(mbc MetricsBuilderConfig, settings connector.Settings, options ...MetricBuilderOption) *MetricsBuilder { if !mbc.Metrics.DefaultMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.") } if mbc.Metrics.DefaultMetricToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetricEmptyUnit.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.") } if !mbc.ResourceAttributes.StringResourceAttrDisableWarning.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.") } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.enabledSetByUser || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { settings.Logger.Warn("[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.") } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.") } mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), metricsBuffer: pmetric.NewMetrics(), buildInfo: settings.BuildInfo, metricDefaultMetric: newMetricDefaultMetric(mbc.Metrics.DefaultMetric), metricDefaultMetricToBeRemoved: newMetricDefaultMetricToBeRemoved(mbc.Metrics.DefaultMetricToBeRemoved), metricMetricInputType: newMetricMetricInputType(mbc.Metrics.MetricInputType), metricOptionalMetric: newMetricOptionalMetric(mbc.Metrics.OptionalMetric), metricOptionalMetricEmptyUnit: newMetricOptionalMetricEmptyUnit(mbc.Metrics.OptionalMetricEmptyUnit), resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), } if mbc.ResourceAttributes.MapResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.MapResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude) } for _, op := range options { op.apply(mb) } return mb } // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted metrics. func (mb *MetricsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder(mb.config.ResourceAttributes) } // updateCapacity updates max length of metrics and resource attributes that will be used for the slice capacity. func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { if mb.metricsCapacity < rm.ScopeMetrics().At(0).Metrics().Len() { mb.metricsCapacity = rm.ScopeMetrics().At(0).Metrics().Len() } } // ResourceMetricsOption applies changes to provided resource metrics. type ResourceMetricsOption interface { apply(pmetric.ResourceMetrics) } type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { rmof(rm) } // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { switch metrics.At(i).Type() { case pmetric.MetricTypeGauge: dps = metrics.At(i).Gauge().DataPoints() case pmetric.MetricTypeSum: dps = metrics.At(i).Sum().DataPoints() } for j := 0; j < dps.Len(); j++ { dps.At(j).SetStartTimestamp(start) } } }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for // recording another set of data points as part of another resource. This function can be helpful when one scraper // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() rm.SetSchemaUrl(conventions.SchemaURL) ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(mb.buildInfo.Version) ils.Metrics().EnsureCapacity(mb.metricsCapacity) mb.metricDefaultMetric.emit(ils.Metrics()) mb.metricDefaultMetricToBeRemoved.emit(ils.Metrics()) mb.metricMetricInputType.emit(ils.Metrics()) mb.metricOptionalMetric.emit(ils.Metrics()) mb.metricOptionalMetricEmptyUnit.emit(ils.Metrics()) for _, op := range options { op.apply(rm) } for attr, filter := range mb.resourceAttributeIncludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { return } } for attr, filter := range mb.resourceAttributeExcludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { return } } if ils.Metrics().Len() > 0 { mb.updateCapacity(rm) rm.MoveTo(mb.metricsBuffer.ResourceMetrics().AppendEmpty()) } } // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics } // RecordDefaultMetricDataPoint adds a data point to default.metric metric. func (mb *MetricsBuilder) RecordDefaultMetricDataPoint(ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { mb.metricDefaultMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) } // RecordDefaultMetricToBeRemovedDataPoint adds a data point to default.metric.to_be_removed metric. func (mb *MetricsBuilder) RecordDefaultMetricToBeRemovedDataPoint(ts pcommon.Timestamp, val float64) { mb.metricDefaultMetricToBeRemoved.recordDataPoint(mb.startTime, ts, val) } // RecordMetricInputTypeDataPoint adds a data point to metric.input_type metric. func (mb *MetricsBuilder) RecordMetricInputTypeDataPoint(ts pcommon.Timestamp, inputVal string, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) error { val, err := strconv.ParseInt(inputVal, 10, 64) if err != nil { return fmt.Errorf("failed to parse int64 for MetricInputType, value was %s: %w", inputVal, err) } mb.metricMetricInputType.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) return nil } // RecordOptionalMetricDataPoint adds a data point to optional.metric metric. func (mb *MetricsBuilder) RecordOptionalMetricDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { mb.metricOptionalMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue) } // RecordOptionalMetricEmptyUnitDataPoint adds a data point to optional.metric.empty_unit metric. func (mb *MetricsBuilder) RecordOptionalMetricEmptyUnitDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { mb.metricOptionalMetricEmptyUnit.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue) } // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { op.apply(mb) } } generated_metrics_test.go000066400000000000000000000274311511331344600364670ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) type testDataSet int const ( testDataSetDefault testDataSet = iota testDataSetAll testDataSetNone ) func TestMetricsBuilder(t *testing.T) { tests := []struct { name string metricsSet testDataSet resAttrsSet testDataSet expectEmpty bool }{ { name: "default", }, { name: "all_set", metricsSet: testDataSetAll, resAttrsSet: testDataSetAll, }, { name: "none_set", metricsSet: testDataSetNone, resAttrsSet: testDataSetNone, expectEmpty: true, }, { name: "filter_set_include", resAttrsSet: testDataSetAll, }, { name: "filter_set_exclude", resAttrsSet: testDataSetAll, expectEmpty: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := connectortest.NewNopSettings(connectortest.NopType) settings.Logger = zap.New(observedZapCore) mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 if tt.metricsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetDefault || tt.metricsSet == testDataSetAll { assert.Equal(t, "[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetAll || tt.resAttrsSet == testDataSetNone { assert.Equal(t, "[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault || tt.resAttrsSet == testDataSetAll { assert.Equal(t, "[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } assert.Equal(t, expectedWarnings, observedLogs.Len()) defaultMetricsCount := 0 allMetricsCount := 0 defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricDataPoint(ts, 1, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricToBeRemovedDataPoint(ts, 1) defaultMetricsCount++ allMetricsCount++ mb.RecordMetricInputTypeDataPoint(ts, "1", "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) allMetricsCount++ mb.RecordOptionalMetricDataPoint(ts, 1, "string_attr-val", true, false) allMetricsCount++ mb.RecordOptionalMetricEmptyUnitDataPoint(ts, 1, "string_attr-val", true) rb := mb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() metrics := mb.Emit(WithResource(res)) if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } assert.Equal(t, 1, metrics.ResourceMetrics().Len()) rm := metrics.ResourceMetrics().At(0) assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) for i := 0; i < ms.Len(); i++ { switch ms.At(i).Name() { case "default.metric": assert.False(t, validatedMetrics["default.metric"], "Found a duplicate in the metrics slice: default.metric") validatedMetrics["default.metric"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "default.metric.to_be_removed": assert.False(t, validatedMetrics["default.metric.to_be_removed"], "Found a duplicate in the metrics slice: default.metric.to_be_removed") validatedMetrics["default.metric.to_be_removed"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Non-monotonic delta sum double metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.False(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityDelta, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) case "metric.input_type": assert.False(t, validatedMetrics["metric.input_type"], "Found a duplicate in the metrics slice: metric.input_type") validatedMetrics["metric.input_type"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric with string input_type enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "optional.metric": assert.False(t, validatedMetrics["optional.metric"], "Found a duplicate in the metrics slice: optional.metric") validatedMetrics["optional.metric"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Equal(t, "1", ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) attrVal, ok = dp.Attributes().Get("boolean_attr2") assert.True(t, ok) assert.False(t, attrVal.Bool()) case "optional.metric.empty_unit": assert.False(t, validatedMetrics["optional.metric.empty_unit"], "Found a duplicate in the metrics slice: optional.metric.empty_unit") validatedMetrics["optional.metric.empty_unit"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Empty(t, ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) } } }) } } generated_resource.go000066400000000000000000000076321511331344600356120ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/xpdata/entity" ) // ResourceBuilder is a helper struct to build resources predefined in metadata.yaml. // The ResourceBuilder is not thread-safe and must not to be used in multiple goroutines. type ResourceBuilder struct { config ResourceAttributesConfig res pcommon.Resource } // NewResourceBuilder creates a new ResourceBuilder. This method should be called on the start of the application. func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { return &ResourceBuilder{ config: rac, res: pcommon.NewResource(), } } // SetMapResourceAttr sets provided value as "map.resource.attr" attribute. func (rb *ResourceBuilder) SetMapResourceAttr(val map[string]any) { if rb.config.MapResourceAttr.Enabled { rb.res.Attributes().PutEmptyMap("map.resource.attr").FromRaw(val) } } // SetOptionalResourceAttr sets provided value as "optional.resource.attr" attribute. func (rb *ResourceBuilder) SetOptionalResourceAttr(val string) { if rb.config.OptionalResourceAttr.Enabled { rb.res.Attributes().PutStr("optional.resource.attr", val) } } // SetSliceResourceAttr sets provided value as "slice.resource.attr" attribute. func (rb *ResourceBuilder) SetSliceResourceAttr(val []any) { if rb.config.SliceResourceAttr.Enabled { rb.res.Attributes().PutEmptySlice("slice.resource.attr").FromRaw(val) } } // SetStringEnumResourceAttrOne sets "string.enum.resource.attr=one" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrOne() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "one") } } // SetStringEnumResourceAttrTwo sets "string.enum.resource.attr=two" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrTwo() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "two") } } // SetStringResourceAttr sets provided value as "string.resource.attr" attribute. func (rb *ResourceBuilder) SetStringResourceAttr(val string) { if rb.config.StringResourceAttr.Enabled { rb.res.Attributes().PutStr("string.resource.attr", val) } } // SetStringResourceAttrDisableWarning sets provided value as "string.resource.attr_disable_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrDisableWarning(val string) { if rb.config.StringResourceAttrDisableWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_disable_warning", val) } } // SetStringResourceAttrRemoveWarning sets provided value as "string.resource.attr_remove_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrRemoveWarning(val string) { if rb.config.StringResourceAttrRemoveWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_remove_warning", val) } } // SetStringResourceAttrToBeRemoved sets provided value as "string.resource.attr_to_be_removed" attribute. func (rb *ResourceBuilder) SetStringResourceAttrToBeRemoved(val string) { if rb.config.StringResourceAttrToBeRemoved.Enabled { rb.res.Attributes().PutStr("string.resource.attr_to_be_removed", val) } } // AssociateWithTestEntity associates the resource with entity type "test.entity". // This method is experimental and will be replaced with an entity builder pattern in the future. // However, for now, it allows associating resources with entities and producing correct entity references. func (rb *ResourceBuilder) AssociateWithTestEntity() { entityRef := entity.ResourceEntityRefs(rb.res).AppendEmpty() entityRef.SetType("test.entity") idKeys := entityRef.IdKeys() idKeys.Append("string.resource.attr") descKeys := entityRef.DescriptionKeys() descKeys.Append("map.resource.attr") } // Emit returns the built resource and resets the internal builder state. func (rb *ResourceBuilder) Emit() pcommon.Resource { r := rb.res rb.res = pcommon.NewResource() return r } generated_resource_test.go000066400000000000000000000054211511331344600366430ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" ) func TestResourceBuilder(t *testing.T) { for _, tt := range []string{"default", "all_set", "none_set"} { t.Run(tt, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt) rb := NewResourceBuilder(cfg) rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource switch tt { case "default": assert.Equal(t, 6, res.Attributes().Len()) case "all_set": assert.Equal(t, 8, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return default: assert.Failf(t, "unexpected test case: %s", tt) } val, ok := res.Attributes().Get("map.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}, val.Map().AsRaw()) } val, ok = res.Attributes().Get("optional.resource.attr") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "optional.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("slice.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, []any{"slice.resource.attr-item1", "slice.resource.attr-item2"}, val.Slice().AsRaw()) } val, ok = res.Attributes().Get("string.enum.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "one", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_disable_warning") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_disable_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_remove_warning") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "string.resource.attr_remove_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_to_be_removed") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_to_be_removed-val", val.Str()) } }) } } generated_status.go000066400000000000000000000005121511331344600352740ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("sample") ScopeName = "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleconnector" ) const ( MetricsToMetricsStability = component.StabilityLevelDevelopment ) opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata/testdata/000077500000000000000000000000001511331344600332765ustar00rootroot00000000000000config.yaml000066400000000000000000000062151511331344600353540ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/internal/metadata/testdatadefault: all_set: metrics: default.metric: enabled: true default.metric.to_be_removed: enabled: true metric.input_type: enabled: true optional.metric: enabled: true optional.metric.empty_unit: enabled: true resource_attributes: map.resource.attr: enabled: true optional.resource.attr: enabled: true slice.resource.attr: enabled: true string.enum.resource.attr: enabled: true string.resource.attr: enabled: true string.resource.attr_disable_warning: enabled: true string.resource.attr_remove_warning: enabled: true string.resource.attr_to_be_removed: enabled: true none_set: metrics: default.metric: enabled: false default.metric.to_be_removed: enabled: false metric.input_type: enabled: false optional.metric: enabled: false optional.metric.empty_unit: enabled: false resource_attributes: map.resource.attr: enabled: false optional.resource.attr: enabled: false slice.resource.attr: enabled: false string.enum.resource.attr: enabled: false string.resource.attr: enabled: false string.resource.attr_disable_warning: enabled: false string.resource.attr_remove_warning: enabled: false string.resource.attr_to_be_removed: enabled: false filter_set_include: resource_attributes: map.resource.attr: enabled: true metrics_include: - regexp: ".*" optional.resource.attr: enabled: true metrics_include: - regexp: ".*" slice.resource.attr: enabled: true metrics_include: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_include: - regexp: ".*" string.resource.attr: enabled: true metrics_include: - regexp: ".*" string.resource.attr_disable_warning: enabled: true metrics_include: - regexp: ".*" string.resource.attr_remove_warning: enabled: true metrics_include: - regexp: ".*" string.resource.attr_to_be_removed: enabled: true metrics_include: - regexp: ".*" filter_set_exclude: resource_attributes: map.resource.attr: enabled: true metrics_exclude: - regexp: ".*" optional.resource.attr: enabled: true metrics_exclude: - strict: "optional.resource.attr-val" slice.resource.attr: enabled: true metrics_exclude: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_exclude: - strict: "one" string.resource.attr: enabled: true metrics_exclude: - strict: "string.resource.attr-val" string.resource.attr_disable_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_disable_warning-val" string.resource.attr_remove_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_remove_warning-val" string.resource.attr_to_be_removed: enabled: true metrics_exclude: - strict: "string.resource.attr_to_be_removed-val" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/metadata.yaml000066400000000000000000000113261511331344600305400ustar00rootroot00000000000000# Sample metadata file with all available configurations for a connector. type: sample github_project: open-telemetry/opentelemetry-collector sem_conv_version: 1.9.0 status: disable_codecov_badge: true class: connector stability: development: [metrics_to_metrics] distributions: [] unsupported_platforms: [freebsd, illumos] codeowners: active: [] warnings: - Any additional information that should be brought to the consumer's attention resource_attributes: map.resource.attr: description: Resource attribute with a map value. type: map enabled: true optional.resource.attr: description: Explicitly disabled ResourceAttribute. type: string enabled: false slice.resource.attr: description: Resource attribute with a slice value. type: slice enabled: true string.enum.resource.attr: description: Resource attribute with a known set of string values. type: string enum: [one, two] enabled: true string.resource.attr: description: Resource attribute with any string value. type: string enabled: true string.resource.attr_disable_warning: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled_not_set: This resource_attribute will be disabled by default soon. string.resource.attr_remove_warning: description: Resource attribute with any string value. type: string enabled: false warnings: if_configured: This resource_attribute is deprecated and will be removed soon. string.resource.attr_to_be_removed: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled: This resource_attribute is deprecated and will be removed soon. entities: - type: test.entity brief: A test entity. stability: stable identity: - ref: string.resource.attr description: - ref: map.resource.attr attributes: boolean_attr: description: Attribute with a boolean value. type: bool # This 2nd boolean attribute allows us to test both values for boolean attributes, # as test values are based on the parity of the attribute name length. boolean_attr2: description: Another attribute with a boolean value. type: bool enum_attr: description: Attribute with a known set of string values. type: string enum: [red, green, blue] map_attr: description: Attribute with a map value. type: map overridden_int_attr: name_override: state description: Integer attribute with overridden name. type: int slice_attr: description: Attribute with a slice value. type: slice string_attr: description: Attribute with any string value. type: string metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr] warnings: if_enabled_not_set: This metric will be disabled by default soon. default.metric.to_be_removed: enabled: true description: "[DEPRECATED] Non-monotonic delta sum double metric enabled by default." extended_documentation: The metric will be removed soon. stability: level: deprecated unit: s sum: value_type: double monotonic: false aggregation_temporality: delta warnings: if_enabled: This metric is deprecated and will be removed soon. metric.input_type: enabled: true description: Monotonic cumulative sum int metric with string input_type enabled by default. stability: level: development unit: s sum: value_type: int input_type: string monotonic: true aggregation_temporality: cumulative attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr] optional.metric: enabled: false description: "[DEPRECATED] Gauge double metric disabled by default." stability: level: deprecated unit: "1" gauge: value_type: double attributes: [string_attr, boolean_attr, boolean_attr2] warnings: if_configured: This metric is deprecated and will be removed soon. optional.metric.empty_unit: enabled: false description: "[DEPRECATED] Gauge double metric disabled by default." stability: level: deprecated unit: "" gauge: value_type: double attributes: [string_attr, boolean_attr] warnings: if_configured: This metric is deprecated and will be removed soon. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleconnector/metrics_test.go000066400000000000000000000021451511331344600311270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sampleconnector import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleconnector/internal/metadata" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pmetric" ) // TestGeneratedMetrics verifies that the internal/metadata API is generated correctly. func TestGeneratedMetrics(t *testing.T) { mb := metadata.NewMetricsBuilder(metadata.DefaultMetricsBuilderConfig(), connectortest.NewNopSettings(metadata.Type)) m := mb.Emit() require.Equal(t, 0, m.ResourceMetrics().Len()) } func TestNopConnector(t *testing.T) { connector, err := createMetricsToMetricsConnector(context.Background(), connectortest.NewNopSettings(metadata.Type), newMdatagenNopHost(), new(consumertest.MetricsSink)) require.NoError(t, err) require.False(t, connector.Capabilities().MutatesData) require.NoError(t, connector.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/000077500000000000000000000000001511331344600272735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/README.md000066400000000000000000000044541511331344600305610ustar00rootroot00000000000000# Sample Receiver This receiver is used for testing purposes to check the output of mdatagen. | Status | | | ------------- |-----------| | Stability | [deprecated]: profiles | | | [development]: logs | | | [beta]: traces | | | [stable]: metrics | | Deprecation of profiles | [Date]: 2025-02-05 | | | [Migration Note]: no migration needed | | Unsupported Platforms | freebsd, illumos | | Distributions | [] | | Warnings | [Any additional information that should be brought to the consumer's attention](#warnings) | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fsamplefactory%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fsamplefactory) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fsamplefactory%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fsamplefactory) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@dmitryax](https://www.github.com/dmitryax) | [deprecated]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecated [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [Date]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information [Migration Note]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information ## Warnings This is where warnings are described. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/doc.go000066400000000000000000000005121511331344600303650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Generate a test metrics builder from a sample metrics set covering all configuration options. //go:generate mdatagen metadata.yaml package samplefactoryreceiver // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplefactoryreceiver" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/documentation.md000066400000000000000000000166451511331344600325020ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # sample ## Default Metrics The following metrics are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml metrics: : enabled: false ``` ### default.metric Monotonic cumulative sum int metric enabled by default. The metric will be become optional soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | | ---- | ----------- | ---------- | ----------------------- | --------- | | s | Sum | Int | Cumulative | true | #### Attributes | Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | false | | state | Integer attribute with overridden name. | Any Int | false | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | | slice_attr | Attribute with a slice value. | Any Slice | false | | map_attr | Attribute with a map value. | Any Map | false | | optional_int_attr | An optional attribute with an integer value | Any Int | true | | optional_string_attr | An optional attribute with any string value | Any Str | true | ### default.metric.to_be_removed [DEPRECATED] Non-monotonic delta sum double metric enabled by default. The metric will be removed soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | | ---- | ----------- | ---------- | ----------------------- | --------- | | s | Sum | Double | Delta | false | ### metric.input_type Monotonic cumulative sum int metric with string input_type enabled by default. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | | ---- | ----------- | ---------- | ----------------------- | --------- | | s | Sum | Int | Cumulative | true | #### Attributes | Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | false | | state | Integer attribute with overridden name. | Any Int | false | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | false | | slice_attr | Attribute with a slice value. | Any Slice | false | | map_attr | Attribute with a map value. | Any Map | false | ## Optional Metrics The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml metrics: : enabled: true ``` ### optional.metric [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | | ---- | ----------- | ---------- | | 1 | Gauge | Double | #### Attributes | Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | false | | boolean_attr | Attribute with a boolean value. | Any Bool | false | | boolean_attr2 | Another attribute with a boolean value. | Any Bool | false | | optional_string_attr | An optional attribute with any string value | Any Str | true | ### optional.metric.empty_unit [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | | ---- | ----------- | ---------- | | | Gauge | Double | #### Attributes | Name | Description | Values | Optional | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | false | | boolean_attr | Attribute with a boolean value. | Any Bool | false | ## Default Events The following events are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml events: : enabled: false ``` ### default.event Example event enabled by default. #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | | string_attr | Attribute with any string value. | Any Str | | state | Integer attribute with overridden name. | Any Int | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | | slice_attr | Attribute with a slice value. | Any Slice | | map_attr | Attribute with a map value. | Any Map | | optional_int_attr | An optional attribute with an integer value | Any Int | | optional_string_attr | An optional attribute with any string value | Any Str | ### default.event.to_be_removed [DEPRECATED] Example to-be-removed event enabled by default. The event will be removed soon. #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | | string_attr | Attribute with any string value. | Any Str | | state | Integer attribute with overridden name. | Any Int | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | | slice_attr | Attribute with a slice value. | Any Slice | | map_attr | Attribute with a map value. | Any Map | ## Optional Events The following events are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml events: : enabled: true ``` ### default.event.to_be_renamed [DEPRECATED] Example event disabled by default. The event will be renamed soon. #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | | string_attr | Attribute with any string value. | Any Str | | boolean_attr | Attribute with a boolean value. | Any Bool | | boolean_attr2 | Another attribute with a boolean value. | Any Bool | | optional_string_attr | An optional attribute with any string value | Any Str | ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | | map.resource.attr | Resource attribute with a map value. | Any Map | true | | optional.resource.attr | Explicitly disabled ResourceAttribute. | Any Str | false | | slice.resource.attr | Resource attribute with a slice value. | Any Slice | true | | string.enum.resource.attr | Resource attribute with a known set of string values. | Str: ``one``, ``two`` | true | | string.resource.attr | Resource attribute with any string value. | Any Str | true | | string.resource.attr_disable_warning | Resource attribute with any string value. | Any Str | true | | string.resource.attr_remove_warning | Resource attribute with any string value. | Any Str | false | | string.resource.attr_to_be_removed | Resource attribute with any string value. | Any Str | true | ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_batch_size_trigger_send Number of times the batch was sent due to a size trigger [deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | | ---- | ----------- | ---------- | --------- | | {times} | Sum | Int | true | ### otelcol_process_runtime_total_alloc_bytes Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') | Unit | Metric Type | Value Type | Monotonic | | ---- | ----------- | ---------- | --------- | | By | Sum | Int | true | ### otelcol_queue_capacity Queue capacity - sync gauge example. | Unit | Metric Type | Value Type | | ---- | ----------- | ---------- | | {items} | Gauge | Int | ### otelcol_queue_length This metric is optional and therefore not initialized in NewTelemetryBuilder. [alpha] For example this metric only exists if feature A is enabled. | Unit | Metric Type | Value Type | | ---- | ----------- | ---------- | | {items} | Gauge | Int | ### otelcol_request_duration Duration of request [alpha] | Unit | Metric Type | Value Type | | ---- | ----------- | ---------- | | s | Histogram | Double | opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/factory.go000066400000000000000000000044241511331344600312750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package samplefactoryreceiver // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplefactoryreceiver" import ( "context" "errors" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service/hostcapabilities" ) // NewFactory returns a receiver.Factory for sample receiver. func NewFactory() receiver.Factory { return receiver.NewFactory( metadata.Type, func() component.Config { return &struct{}{} }, receiver.WithTraces(createTraces, metadata.TracesStability), receiver.WithMetrics(createMetrics, metadata.MetricsStability), receiver.WithLogs(createLogs, metadata.LogsStability)) } func createTraces(context.Context, receiver.Settings, component.Config, consumer.Traces) (receiver.Traces, error) { return nopInstance, nil } func createMetrics(ctx context.Context, set receiver.Settings, _ component.Config, _ consumer.Metrics) (receiver.Metrics, error) { telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return nil, err } err = telemetryBuilder.RegisterProcessRuntimeTotalAllocBytesCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(2) return nil }) if err != nil { return nil, err } telemetryBuilder.BatchSizeTriggerSend.Add(ctx, 1) return nopReceiver{telemetryBuilder: telemetryBuilder}, nil } func createLogs(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { return nopInstance, nil } var nopInstance = &nopReceiver{} type nopReceiver struct { component.StartFunc telemetryBuilder *metadata.TelemetryBuilder } func (r nopReceiver) Start(_ context.Context, host component.Host) error { if _, ok := host.(hostcapabilities.ComponentFactory); !ok { return errors.New("host does not implement hostcapabilities.ComponentFactory") } return nil } // Shutdown shuts down the component. func (r nopReceiver) Shutdown(context.Context) error { if r.telemetryBuilder != nil { r.telemetryBuilder.Shutdown() } return nil } generated_component_test.go000066400000000000000000000060561511331344600346310ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver// Code generated by mdatagen. DO NOT EDIT. //go:build !freebsd && !illumos package samplefactoryreceiver import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" ) var typ = component.MustNewType("sample") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "metrics", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "traces", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } generated_package_test.go000066400000000000000000000002641511331344600342150ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver// Code generated by mdatagen. DO NOT EDIT. package samplefactoryreceiver import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/000077500000000000000000000000001511331344600311075ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/000077500000000000000000000000001511331344600326675ustar00rootroot00000000000000generated_config.go000066400000000000000000000143441511331344600364300ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/filter" ) // MetricConfig provides common config for a particular metric. type MetricConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ms) if err != nil { return err } ms.enabledSetByUser = parser.IsSet("enabled") return nil } // MetricsConfig provides config for sample metrics. type MetricsConfig struct { DefaultMetric MetricConfig `mapstructure:"default.metric"` DefaultMetricToBeRemoved MetricConfig `mapstructure:"default.metric.to_be_removed"` MetricInputType MetricConfig `mapstructure:"metric.input_type"` OptionalMetric MetricConfig `mapstructure:"optional.metric"` OptionalMetricEmptyUnit MetricConfig `mapstructure:"optional.metric.empty_unit"` } func DefaultMetricsConfig() MetricsConfig { return MetricsConfig{ DefaultMetric: MetricConfig{ Enabled: true, }, DefaultMetricToBeRemoved: MetricConfig{ Enabled: true, }, MetricInputType: MetricConfig{ Enabled: true, }, OptionalMetric: MetricConfig{ Enabled: false, }, OptionalMetricEmptyUnit: MetricConfig{ Enabled: false, }, } } // EventConfig provides common config for a particular event. type EventConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ec *EventConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ec) if err != nil { return err } ec.enabledSetByUser = parser.IsSet("enabled") return nil } // EventsConfig provides config for sample events. type EventsConfig struct { DefaultEvent EventConfig `mapstructure:"default.event"` DefaultEventToBeRemoved EventConfig `mapstructure:"default.event.to_be_removed"` DefaultEventToBeRenamed EventConfig `mapstructure:"default.event.to_be_renamed"` } func DefaultEventsConfig() EventsConfig { return EventsConfig{ DefaultEvent: EventConfig{ Enabled: true, }, DefaultEventToBeRemoved: EventConfig{ Enabled: true, }, DefaultEventToBeRenamed: EventConfig{ Enabled: false, }, } } // ResourceAttributeConfig provides common config for a particular resource attribute. type ResourceAttributeConfig struct { Enabled bool `mapstructure:"enabled"` // Experimental: MetricsInclude defines a list of filters for attribute values. // If the list is not empty, only metrics with matching resource attribute values will be emitted. MetricsInclude []filter.Config `mapstructure:"metrics_include"` // Experimental: MetricsExclude defines a list of filters for attribute values. // If the list is not empty, metrics with matching resource attribute values will not be emitted. // MetricsInclude has higher priority than MetricsExclude. MetricsExclude []filter.Config `mapstructure:"metrics_exclude"` // Experimental: EventsInclude defines a list of filters for attribute values. // If the list is not empty, only events with matching resource attribute values will be emitted. EventsInclude []filter.Config `mapstructure:"events_include"` // Experimental: EventsExclude defines a list of filters for attribute values. // If the list is not empty, events with matching resource attribute values will not be emitted. // EventsInclude has higher priority than EventsExclude. EventsExclude []filter.Config `mapstructure:"events_exclude"` enabledSetByUser bool } func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(rac) if err != nil { return err } rac.enabledSetByUser = parser.IsSet("enabled") return nil } // ResourceAttributesConfig provides config for sample resource attributes. type ResourceAttributesConfig struct { MapResourceAttr ResourceAttributeConfig `mapstructure:"map.resource.attr"` OptionalResourceAttr ResourceAttributeConfig `mapstructure:"optional.resource.attr"` SliceResourceAttr ResourceAttributeConfig `mapstructure:"slice.resource.attr"` StringEnumResourceAttr ResourceAttributeConfig `mapstructure:"string.enum.resource.attr"` StringResourceAttr ResourceAttributeConfig `mapstructure:"string.resource.attr"` StringResourceAttrDisableWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_disable_warning"` StringResourceAttrRemoveWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_remove_warning"` StringResourceAttrToBeRemoved ResourceAttributeConfig `mapstructure:"string.resource.attr_to_be_removed"` } func DefaultResourceAttributesConfig() ResourceAttributesConfig { return ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{ Enabled: true, }, OptionalResourceAttr: ResourceAttributeConfig{ Enabled: false, }, SliceResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringEnumResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrDisableWarning: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrRemoveWarning: ResourceAttributeConfig{ Enabled: false, }, StringResourceAttrToBeRemoved: ResourceAttributeConfig{ Enabled: true, }, } } // MetricsBuilderConfig is a configuration for sample metrics builder. type MetricsBuilderConfig struct { Metrics MetricsConfig `mapstructure:"metrics"` ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` } func DefaultMetricsBuilderConfig() MetricsBuilderConfig { return MetricsBuilderConfig{ Metrics: DefaultMetricsConfig(), ResourceAttributes: DefaultResourceAttributesConfig(), } } // LogsBuilderConfig is a configuration for sample logs builder. type LogsBuilderConfig struct { Events EventsConfig `mapstructure:"events"` ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` } func DefaultLogsBuilderConfig() LogsBuilderConfig { return LogsBuilderConfig{ Events: DefaultEventsConfig(), ResourceAttributes: DefaultResourceAttributesConfig(), } } generated_config_test.go000066400000000000000000000135341511331344600374670ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestMetricsBuilderConfig(t *testing.T) { tests := []struct { name string want MetricsBuilderConfig }{ { name: "default", want: DefaultMetricsBuilderConfig(), }, { name: "all_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: true}, DefaultMetricToBeRemoved: MetricConfig{Enabled: true}, MetricInputType: MetricConfig{Enabled: true}, OptionalMetric: MetricConfig{Enabled: true}, OptionalMetricEmptyUnit: MetricConfig{Enabled: true}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, }, { name: "none_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: false}, DefaultMetricToBeRemoved: MetricConfig{Enabled: false}, MetricInputType: MetricConfig{Enabled: false}, OptionalMetric: MetricConfig{Enabled: false}, OptionalMetricEmptyUnit: MetricConfig{Enabled: false}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadMetricsBuilderConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(MetricConfig{}, ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadMetricsBuilderConfig(t *testing.T, name string) MetricsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultMetricsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } func loadLogsBuilderConfig(t *testing.T, name string) LogsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultLogsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } func TestResourceAttributesConfig(t *testing.T) { tests := []struct { name string want ResourceAttributesConfig }{ { name: "default", want: DefaultResourceAttributesConfig(), }, { name: "all_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, { name: "none_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadResourceAttributesConfig(t *testing.T, name string) ResourceAttributesConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) sub, err = sub.Sub("resource_attributes") require.NoError(t, err) cfg := DefaultResourceAttributesConfig() require.NoError(t, sub.Unmarshal(&cfg)) return cfg } generated_logs.go000066400000000000000000000061751511331344600361320ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( conventions "go.opentelemetry.io/otel/semconv/v1.9.0" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver" ) // LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations // required to produce log representation defined in metadata and user config. type LogsBuilder struct { logsBuffer plog.Logs logRecordsBuffer plog.LogRecordSlice buildInfo component.BuildInfo // contains version information. } // LogBuilderOption applies changes to default logs builder. type LogBuilderOption interface { apply(*LogsBuilder) } func NewLogsBuilder(settings receiver.Settings) *LogsBuilder { lb := &LogsBuilder{ logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, } return lb } // ResourceLogsOption applies changes to provided resource logs. type ResourceLogsOption interface { apply(plog.ResourceLogs) } type resourceLogsOptionFunc func(plog.ResourceLogs) func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { rlof(rl) } // WithLogsResource sets the provided resource on the emitted ResourceLogs. // It's recommended to use ResourceBuilder to create the resource. func WithLogsResource(res pcommon.Resource) ResourceLogsOption { return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { res.CopyTo(rl.Resource()) }) } // AppendLogRecord adds a log record to the logs builder. func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) } // EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for // recording another set of log records as part of another resource. This function can be helpful when one scraper // needs to emit logs from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceLogsOption arguments. func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { rl := plog.NewResourceLogs() rl.SetSchemaUrl(conventions.SchemaURL) ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) for _, op := range options { op.apply(rl) } if lb.logRecordsBuffer.Len() > 0 { lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) lb.logRecordsBuffer = plog.NewLogRecordSlice() } if ils.LogRecords().Len() > 0 { rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) } } // Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for // recording another set of logs. This function will be responsible for applying all the transformations required to // produce logs representation defined in metadata and user config. func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { lb.EmitForResource(options...) logs := lb.logsBuffer lb.logsBuffer = plog.NewLogs() return logs } generated_logs_test.go000066400000000000000000000036611511331344600371660ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "time" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver/receivertest" ) func TestLogsBuilderAppendLogRecord(t *testing.T) { observedZapCore, _ := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder(settings) res := pcommon.NewResource() // append the first log record lr := plog.NewLogRecord() lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr.Attributes().PutStr("type", "log") lr.Body().SetStr("the first log record") // append the second log record lr2 := plog.NewLogRecord() lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr2.Attributes().PutStr("type", "event") lr2.Body().SetStr("the second log record") lb.AppendLogRecord(lr) lb.AppendLogRecord(lr2) logs := lb.Emit(WithLogsResource(res)) assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, 1, rl.ScopeLogs().Len()) sl := rl.ScopeLogs().At(0) assert.Equal(t, ScopeName, sl.Scope().Name()) assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) assert.Equal(t, 2, sl.LogRecords().Len()) attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "log", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "event", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) } generated_metrics.go000066400000000000000000000655711511331344600366410ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "fmt" "strconv" "time" conventions "go.opentelemetry.io/otel/semconv/v1.9.0" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver" ) // AttributeEnumAttr specifies the value enum_attr attribute. type AttributeEnumAttr int const ( _ AttributeEnumAttr = iota AttributeEnumAttrRed AttributeEnumAttrGreen AttributeEnumAttrBlue ) // String returns the string representation of the AttributeEnumAttr. func (av AttributeEnumAttr) String() string { switch av { case AttributeEnumAttrRed: return "red" case AttributeEnumAttrGreen: return "green" case AttributeEnumAttrBlue: return "blue" } return "" } // MapAttributeEnumAttr is a helper map of string to AttributeEnumAttr attribute value. var MapAttributeEnumAttr = map[string]AttributeEnumAttr{ "red": AttributeEnumAttrRed, "green": AttributeEnumAttrGreen, "blue": AttributeEnumAttrBlue, } var MetricsInfo = metricsInfo{ DefaultMetric: metricInfo{ Name: "default.metric", }, DefaultMetricToBeRemoved: metricInfo{ Name: "default.metric.to_be_removed", }, MetricInputType: metricInfo{ Name: "metric.input_type", }, OptionalMetric: metricInfo{ Name: "optional.metric", }, OptionalMetricEmptyUnit: metricInfo{ Name: "optional.metric.empty_unit", }, } type metricsInfo struct { DefaultMetric metricInfo DefaultMetricToBeRemoved metricInfo MetricInputType metricInfo OptionalMetric metricInfo OptionalMetricEmptyUnit metricInfo } type metricInfo struct { Name string } type MetricAttributeOption interface { apply(pmetric.NumberDataPoint) } type metricAttributeOptionFunc func(pmetric.NumberDataPoint) func (maof metricAttributeOptionFunc) apply(dp pmetric.NumberDataPoint) { maof(dp) } func WithOptionalIntAttrMetricAttribute(optionalIntAttrAttributeValue int64) MetricAttributeOption { return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { dp.Attributes().PutInt("optional_int_attr", optionalIntAttrAttributeValue) }) } func WithOptionalStringAttrMetricAttribute(optionalStringAttrAttributeValue string) MetricAttributeOption { return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { dp.Attributes().PutStr("optional_string_attr", optionalStringAttrAttributeValue) }) } type metricDefaultMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric metric with initial data. func (m *metricDefaultMetric) init() { m.data.SetName("default.metric") m.data.SetDescription("Monotonic cumulative sum int metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricDefaultMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, options ...MetricAttributeOption) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) for _, op := range options { op.apply(dp) } } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetric) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetric(cfg MetricConfig) metricDefaultMetric { m := metricDefaultMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricDefaultMetricToBeRemoved struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric.to_be_removed metric with initial data. func (m *metricDefaultMetricToBeRemoved) init() { m.data.SetName("default.metric.to_be_removed") m.data.SetDescription("[DEPRECATED] Non-monotonic delta sum double metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(false) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) } func (m *metricDefaultMetricToBeRemoved) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetricToBeRemoved) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetricToBeRemoved) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetricToBeRemoved(cfg MetricConfig) metricDefaultMetricToBeRemoved { m := metricDefaultMetricToBeRemoved{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricMetricInputType struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills metric.input_type metric with initial data. func (m *metricMetricInputType) init() { m.data.SetName("metric.input_type") m.data.SetDescription("Monotonic cumulative sum int metric with string input_type enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricMetricInputType) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricMetricInputType) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricMetricInputType) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricMetricInputType(cfg MetricConfig) metricMetricInputType { m := metricMetricInputType{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric metric with initial data. func (m *metricOptionalMetric) init() { m.data.SetName("optional.metric") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("1") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...MetricAttributeOption) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) dp.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) for _, op := range options { op.apply(dp) } } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetric) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetric(cfg MetricConfig) metricOptionalMetric { m := metricOptionalMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetricEmptyUnit struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric.empty_unit metric with initial data. func (m *metricOptionalMetricEmptyUnit) init() { m.data.SetName("optional.metric.empty_unit") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetricEmptyUnit) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetricEmptyUnit) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetricEmptyUnit) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetricEmptyUnit(cfg MetricConfig) metricOptionalMetricEmptyUnit { m := metricOptionalMetricEmptyUnit{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } // MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations // required to produce metric representation defined in metadata and user config. type MetricsBuilder struct { config MetricsBuilderConfig // config of the metrics builder. startTime pcommon.Timestamp // start time that will be applied to all recorded data points. metricsCapacity int // maximum observed number of metrics per resource. metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. buildInfo component.BuildInfo // contains version information. resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter metricDefaultMetric metricDefaultMetric metricDefaultMetricToBeRemoved metricDefaultMetricToBeRemoved metricMetricInputType metricMetricInputType metricOptionalMetric metricOptionalMetric metricOptionalMetricEmptyUnit metricOptionalMetricEmptyUnit } // MetricBuilderOption applies changes to default metrics builder. type MetricBuilderOption interface { apply(*MetricsBuilder) } type metricBuilderOptionFunc func(mb *MetricsBuilder) func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { mbof(mb) } // WithStartTime sets startTime on the metrics builder. func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime }) } func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { if !mbc.Metrics.DefaultMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.") } if mbc.Metrics.DefaultMetricToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetricEmptyUnit.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.") } if !mbc.ResourceAttributes.StringResourceAttrDisableWarning.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.") } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.enabledSetByUser || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { settings.Logger.Warn("[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.") } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.") } mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), metricsBuffer: pmetric.NewMetrics(), buildInfo: settings.BuildInfo, metricDefaultMetric: newMetricDefaultMetric(mbc.Metrics.DefaultMetric), metricDefaultMetricToBeRemoved: newMetricDefaultMetricToBeRemoved(mbc.Metrics.DefaultMetricToBeRemoved), metricMetricInputType: newMetricMetricInputType(mbc.Metrics.MetricInputType), metricOptionalMetric: newMetricOptionalMetric(mbc.Metrics.OptionalMetric), metricOptionalMetricEmptyUnit: newMetricOptionalMetricEmptyUnit(mbc.Metrics.OptionalMetricEmptyUnit), resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), } if mbc.ResourceAttributes.MapResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.MapResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude) } for _, op := range options { op.apply(mb) } return mb } // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted metrics. func (mb *MetricsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder(mb.config.ResourceAttributes) } // updateCapacity updates max length of metrics and resource attributes that will be used for the slice capacity. func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { if mb.metricsCapacity < rm.ScopeMetrics().At(0).Metrics().Len() { mb.metricsCapacity = rm.ScopeMetrics().At(0).Metrics().Len() } } // ResourceMetricsOption applies changes to provided resource metrics. type ResourceMetricsOption interface { apply(pmetric.ResourceMetrics) } type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { rmof(rm) } // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { switch metrics.At(i).Type() { case pmetric.MetricTypeGauge: dps = metrics.At(i).Gauge().DataPoints() case pmetric.MetricTypeSum: dps = metrics.At(i).Sum().DataPoints() } for j := 0; j < dps.Len(); j++ { dps.At(j).SetStartTimestamp(start) } } }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for // recording another set of data points as part of another resource. This function can be helpful when one scraper // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() rm.SetSchemaUrl(conventions.SchemaURL) ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(mb.buildInfo.Version) ils.Metrics().EnsureCapacity(mb.metricsCapacity) mb.metricDefaultMetric.emit(ils.Metrics()) mb.metricDefaultMetricToBeRemoved.emit(ils.Metrics()) mb.metricMetricInputType.emit(ils.Metrics()) mb.metricOptionalMetric.emit(ils.Metrics()) mb.metricOptionalMetricEmptyUnit.emit(ils.Metrics()) for _, op := range options { op.apply(rm) } for attr, filter := range mb.resourceAttributeIncludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { return } } for attr, filter := range mb.resourceAttributeExcludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { return } } if ils.Metrics().Len() > 0 { mb.updateCapacity(rm) rm.MoveTo(mb.metricsBuffer.ResourceMetrics().AppendEmpty()) } } // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics } // RecordDefaultMetricDataPoint adds a data point to default.metric metric. func (mb *MetricsBuilder) RecordDefaultMetricDataPoint(ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, options ...MetricAttributeOption) { mb.metricDefaultMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue, options...) } // RecordDefaultMetricToBeRemovedDataPoint adds a data point to default.metric.to_be_removed metric. func (mb *MetricsBuilder) RecordDefaultMetricToBeRemovedDataPoint(ts pcommon.Timestamp, val float64) { mb.metricDefaultMetricToBeRemoved.recordDataPoint(mb.startTime, ts, val) } // RecordMetricInputTypeDataPoint adds a data point to metric.input_type metric. func (mb *MetricsBuilder) RecordMetricInputTypeDataPoint(ts pcommon.Timestamp, inputVal string, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) error { val, err := strconv.ParseInt(inputVal, 10, 64) if err != nil { return fmt.Errorf("failed to parse int64 for MetricInputType, value was %s: %w", inputVal, err) } mb.metricMetricInputType.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) return nil } // RecordOptionalMetricDataPoint adds a data point to optional.metric metric. func (mb *MetricsBuilder) RecordOptionalMetricDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...MetricAttributeOption) { mb.metricOptionalMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue, options...) } // RecordOptionalMetricEmptyUnitDataPoint adds a data point to optional.metric.empty_unit metric. func (mb *MetricsBuilder) RecordOptionalMetricEmptyUnitDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { mb.metricOptionalMetricEmptyUnit.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue) } // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { op.apply(mb) } } generated_metrics_test.go000066400000000000000000000305631511331344600376710ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver/receivertest" ) type testDataSet int const ( testDataSetDefault testDataSet = iota testDataSetAll testDataSetNone ) func TestMetricsBuilder(t *testing.T) { tests := []struct { name string metricsSet testDataSet resAttrsSet testDataSet expectEmpty bool }{ { name: "default", }, { name: "all_set", metricsSet: testDataSetAll, resAttrsSet: testDataSetAll, }, { name: "none_set", metricsSet: testDataSetNone, resAttrsSet: testDataSetNone, expectEmpty: true, }, { name: "filter_set_include", resAttrsSet: testDataSetAll, }, { name: "filter_set_exclude", resAttrsSet: testDataSetAll, expectEmpty: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 if tt.metricsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetDefault || tt.metricsSet == testDataSetAll { assert.Equal(t, "[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetAll || tt.resAttrsSet == testDataSetNone { assert.Equal(t, "[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault || tt.resAttrsSet == testDataSetAll { assert.Equal(t, "[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } assert.Equal(t, expectedWarnings, observedLogs.Len()) defaultMetricsCount := 0 allMetricsCount := 0 defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricDataPoint(ts, 1, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, WithOptionalIntAttrMetricAttribute(17), WithOptionalStringAttrMetricAttribute("optional_string_attr-val")) defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricToBeRemovedDataPoint(ts, 1) defaultMetricsCount++ allMetricsCount++ mb.RecordMetricInputTypeDataPoint(ts, "1", "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) allMetricsCount++ mb.RecordOptionalMetricDataPoint(ts, 1, "string_attr-val", true, false, WithOptionalStringAttrMetricAttribute("optional_string_attr-val")) allMetricsCount++ mb.RecordOptionalMetricEmptyUnitDataPoint(ts, 1, "string_attr-val", true) rb := mb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() metrics := mb.Emit(WithResource(res)) if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } assert.Equal(t, 1, metrics.ResourceMetrics().Len()) rm := metrics.ResourceMetrics().At(0) assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) for i := 0; i < ms.Len(); i++ { switch ms.At(i).Name() { case "default.metric": assert.False(t, validatedMetrics["default.metric"], "Found a duplicate in the metrics slice: default.metric") validatedMetrics["default.metric"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) attrVal, ok = dp.Attributes().Get("optional_int_attr") assert.True(t, ok) assert.EqualValues(t, 17, attrVal.Int()) attrVal, ok = dp.Attributes().Get("optional_string_attr") assert.True(t, ok) assert.Equal(t, "optional_string_attr-val", attrVal.Str()) case "default.metric.to_be_removed": assert.False(t, validatedMetrics["default.metric.to_be_removed"], "Found a duplicate in the metrics slice: default.metric.to_be_removed") validatedMetrics["default.metric.to_be_removed"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Non-monotonic delta sum double metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.False(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityDelta, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) case "metric.input_type": assert.False(t, validatedMetrics["metric.input_type"], "Found a duplicate in the metrics slice: metric.input_type") validatedMetrics["metric.input_type"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric with string input_type enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "optional.metric": assert.False(t, validatedMetrics["optional.metric"], "Found a duplicate in the metrics slice: optional.metric") validatedMetrics["optional.metric"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Equal(t, "1", ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) attrVal, ok = dp.Attributes().Get("boolean_attr2") assert.True(t, ok) assert.False(t, attrVal.Bool()) attrVal, ok = dp.Attributes().Get("optional_string_attr") assert.True(t, ok) assert.Equal(t, "optional_string_attr-val", attrVal.Str()) case "optional.metric.empty_unit": assert.False(t, validatedMetrics["optional.metric.empty_unit"], "Found a duplicate in the metrics slice: optional.metric.empty_unit") validatedMetrics["optional.metric.empty_unit"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Empty(t, ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) } } }) } } generated_resource.go000066400000000000000000000064261511331344600370140ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceBuilder is a helper struct to build resources predefined in metadata.yaml. // The ResourceBuilder is not thread-safe and must not to be used in multiple goroutines. type ResourceBuilder struct { config ResourceAttributesConfig res pcommon.Resource } // NewResourceBuilder creates a new ResourceBuilder. This method should be called on the start of the application. func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { return &ResourceBuilder{ config: rac, res: pcommon.NewResource(), } } // SetMapResourceAttr sets provided value as "map.resource.attr" attribute. func (rb *ResourceBuilder) SetMapResourceAttr(val map[string]any) { if rb.config.MapResourceAttr.Enabled { rb.res.Attributes().PutEmptyMap("map.resource.attr").FromRaw(val) } } // SetOptionalResourceAttr sets provided value as "optional.resource.attr" attribute. func (rb *ResourceBuilder) SetOptionalResourceAttr(val string) { if rb.config.OptionalResourceAttr.Enabled { rb.res.Attributes().PutStr("optional.resource.attr", val) } } // SetSliceResourceAttr sets provided value as "slice.resource.attr" attribute. func (rb *ResourceBuilder) SetSliceResourceAttr(val []any) { if rb.config.SliceResourceAttr.Enabled { rb.res.Attributes().PutEmptySlice("slice.resource.attr").FromRaw(val) } } // SetStringEnumResourceAttrOne sets "string.enum.resource.attr=one" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrOne() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "one") } } // SetStringEnumResourceAttrTwo sets "string.enum.resource.attr=two" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrTwo() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "two") } } // SetStringResourceAttr sets provided value as "string.resource.attr" attribute. func (rb *ResourceBuilder) SetStringResourceAttr(val string) { if rb.config.StringResourceAttr.Enabled { rb.res.Attributes().PutStr("string.resource.attr", val) } } // SetStringResourceAttrDisableWarning sets provided value as "string.resource.attr_disable_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrDisableWarning(val string) { if rb.config.StringResourceAttrDisableWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_disable_warning", val) } } // SetStringResourceAttrRemoveWarning sets provided value as "string.resource.attr_remove_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrRemoveWarning(val string) { if rb.config.StringResourceAttrRemoveWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_remove_warning", val) } } // SetStringResourceAttrToBeRemoved sets provided value as "string.resource.attr_to_be_removed" attribute. func (rb *ResourceBuilder) SetStringResourceAttrToBeRemoved(val string) { if rb.config.StringResourceAttrToBeRemoved.Enabled { rb.res.Attributes().PutStr("string.resource.attr_to_be_removed", val) } } // Emit returns the built resource and resets the internal builder state. func (rb *ResourceBuilder) Emit() pcommon.Resource { r := rb.res rb.res = pcommon.NewResource() return r } generated_resource_test.go000066400000000000000000000054211511331344600400450ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" ) func TestResourceBuilder(t *testing.T) { for _, tt := range []string{"default", "all_set", "none_set"} { t.Run(tt, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt) rb := NewResourceBuilder(cfg) rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource switch tt { case "default": assert.Equal(t, 6, res.Attributes().Len()) case "all_set": assert.Equal(t, 8, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return default: assert.Failf(t, "unexpected test case: %s", tt) } val, ok := res.Attributes().Get("map.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}, val.Map().AsRaw()) } val, ok = res.Attributes().Get("optional.resource.attr") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "optional.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("slice.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, []any{"slice.resource.attr-item1", "slice.resource.attr-item2"}, val.Slice().AsRaw()) } val, ok = res.Attributes().Get("string.enum.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "one", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_disable_warning") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_disable_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_remove_warning") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "string.resource.attr_remove_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_to_be_removed") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_to_be_removed-val", val.Str()) } }) } } generated_status.go000066400000000000000000000007421511331344600365030ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("sample") ScopeName = "go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver" ) const ( ProfilesStability = component.StabilityLevelDeprecated LogsStability = component.StabilityLevelDevelopment TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelStable ) generated_telemetry.go000066400000000000000000000113041511331344600371660ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "context" "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/embedded" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration BatchSizeTriggerSend metric.Int64Counter ProcessRuntimeTotalAllocBytes metric.Int64ObservableCounter QueueCapacity metric.Int64Gauge QueueLength metric.Int64ObservableGauge RequestDuration metric.Float64Histogram } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // RegisterProcessRuntimeTotalAllocBytesCallback sets callback for observable ProcessRuntimeTotalAllocBytes metric. func (builder *TelemetryBuilder) RegisterProcessRuntimeTotalAllocBytesCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ProcessRuntimeTotalAllocBytes, obs: o}) return nil }, builder.ProcessRuntimeTotalAllocBytes) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterQueueLengthCallback sets callback for observable QueueLength metric. func (builder *TelemetryBuilder) RegisterQueueLengthCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.QueueLength, obs: o}) return nil }, builder.QueueLength) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } type observerInt64 struct { embedded.Int64Observer inst metric.Int64Observable obs metric.Observer } func (oi *observerInt64) Observe(value int64, opts ...metric.ObserveOption) { oi.obs.ObserveInt64(oi.inst, value, opts...) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.BatchSizeTriggerSend, err = builder.meter.Int64Counter( "otelcol_batch_size_trigger_send", metric.WithDescription("Number of times the batch was sent due to a size trigger [deprecated since v0.110.0]"), metric.WithUnit("{times}"), ) errs = errors.Join(errs, err) builder.ProcessRuntimeTotalAllocBytes, err = builder.meter.Int64ObservableCounter( "otelcol_process_runtime_total_alloc_bytes", metric.WithDescription("Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')"), metric.WithUnit("By"), ) errs = errors.Join(errs, err) builder.QueueCapacity, err = builder.meter.Int64Gauge( "otelcol_queue_capacity", metric.WithDescription("Queue capacity - sync gauge example."), metric.WithUnit("{items}"), ) errs = errors.Join(errs, err) builder.QueueLength, err = builder.meter.Int64ObservableGauge( "otelcol_queue_length", metric.WithDescription("This metric is optional and therefore not initialized in NewTelemetryBuilder. [Alpha]"), metric.WithUnit("{items}"), ) errs = errors.Join(errs, err) builder.RequestDuration, err = builder.meter.Float64Histogram( "otelcol_request_duration", metric.WithDescription("Duration of request [Alpha]"), metric.WithUnit("s"), metric.WithExplicitBucketBoundaries([]float64{1, 10, 100}...), ) errs = errors.Join(errs, err) return &builder, errs } generated_telemetry_test.go000066400000000000000000000035411511331344600402310ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } testdata/000077500000000000000000000000001511331344600344215ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadataconfig.yaml000066400000000000000000000104641511331344600365570ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/internal/metadata/testdatadefault: all_set: metrics: default.metric: enabled: true default.metric.to_be_removed: enabled: true metric.input_type: enabled: true optional.metric: enabled: true optional.metric.empty_unit: enabled: true events: default.event: enabled: true default.event.to_be_removed: enabled: true default.event.to_be_renamed: enabled: true resource_attributes: map.resource.attr: enabled: true optional.resource.attr: enabled: true slice.resource.attr: enabled: true string.enum.resource.attr: enabled: true string.resource.attr: enabled: true string.resource.attr_disable_warning: enabled: true string.resource.attr_remove_warning: enabled: true string.resource.attr_to_be_removed: enabled: true none_set: metrics: default.metric: enabled: false default.metric.to_be_removed: enabled: false metric.input_type: enabled: false optional.metric: enabled: false optional.metric.empty_unit: enabled: false events: default.event: enabled: false default.event.to_be_removed: enabled: false default.event.to_be_renamed: enabled: false resource_attributes: map.resource.attr: enabled: false optional.resource.attr: enabled: false slice.resource.attr: enabled: false string.enum.resource.attr: enabled: false string.resource.attr: enabled: false string.resource.attr_disable_warning: enabled: false string.resource.attr_remove_warning: enabled: false string.resource.attr_to_be_removed: enabled: false filter_set_include: resource_attributes: map.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" optional.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" slice.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr_disable_warning: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr_remove_warning: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr_to_be_removed: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" filter_set_exclude: resource_attributes: map.resource.attr: enabled: true metrics_exclude: - regexp: ".*" events_exclude: - regexp: ".*" optional.resource.attr: enabled: true metrics_exclude: - strict: "optional.resource.attr-val" events_exclude: - strict: "optional.resource.attr-val" slice.resource.attr: enabled: true metrics_exclude: - regexp: ".*" events_exclude: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_exclude: - strict: "one" events_exclude: - strict: "one" string.resource.attr: enabled: true metrics_exclude: - strict: "string.resource.attr-val" events_exclude: - strict: "string.resource.attr-val" string.resource.attr_disable_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_disable_warning-val" events_exclude: - strict: "string.resource.attr_disable_warning-val" string.resource.attr_remove_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_remove_warning-val" events_exclude: - strict: "string.resource.attr_remove_warning-val" string.resource.attr_to_be_removed: enabled: true metrics_exclude: - strict: "string.resource.attr_to_be_removed-val" events_exclude: - strict: "string.resource.attr_to_be_removed-val" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplefactoryreceiver/metadata.yaml000066400000000000000000000012761511331344600317450ustar00rootroot00000000000000# Sample metadata file with all available configurations for a receiver. type: sample scope_name: go.opentelemetry.io/collector/internal/receiver/samplefactoryreceiver github_project: open-telemetry/opentelemetry-collector sem_conv_version: 1.9.0 status: disable_codecov_badge: true class: receiver stability: development: [logs] beta: [traces] stable: [metrics] deprecated: [profiles] deprecation: profiles: migration: "no migration needed" date: "2025-02-05" distributions: [] unsupported_platforms: [freebsd, illumos] codeowners: active: [dmitryax] warnings: - Any additional information that should be brought to the consumer's attention opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/000077500000000000000000000000001511331344600261165ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/README.md000066400000000000000000000033041511331344600273750ustar00rootroot00000000000000# Sample Processor This processor is used for testing purposes to check the output of mdatagen. | Status | | | ------------- |-----------| | Stability | [development]: logs | | | [beta]: traces | | | [stable]: metrics | | Unsupported Platforms | freebsd, illumos | | Distributions | [] | | Warnings | [Any additional information that should be brought to the consumer's attention](#warnings) | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprocessor%2Fsample%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprocessor%2Fsample) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprocessor%2Fsample%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprocessor%2Fsample) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable ## Warnings This is where warnings are described. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/doc.go000066400000000000000000000004761511331344600272210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Generate a test metrics builder from a sample metrics set covering all configuration options. //go:generate mdatagen metadata.yaml package sampleprocessor // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleprocessor" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/documentation.md000066400000000000000000000016431511331344600313150ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # sample ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | | map.resource.attr | Resource attribute with a map value. | Any Map | true | | optional.resource.attr | Explicitly disabled ResourceAttribute. | Any Str | false | | slice.resource.attr | Resource attribute with a slice value. | Any Slice | true | | string.enum.resource.attr | Resource attribute with a known set of string values. | Str: ``one``, ``two`` | true | | string.resource.attr | Resource attribute with any string value. | Any Str | true | | string.resource.attr_disable_warning | Resource attribute with any string value. | Any Str | true | | string.resource.attr_remove_warning | Resource attribute with any string value. | Any Str | false | | string.resource.attr_to_be_removed | Resource attribute with any string value. | Any Str | true | opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/factory.go000066400000000000000000000036141511331344600301200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sampleprocessor // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleprocessor" import ( "context" "go.opentelemetry.io/collector/cmd/mdatagen/internal/sampleprocessor/internal/metadata" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor" ) // NewFactory returns a receiver.Factory for sample receiver. func NewFactory() processor.Factory { return processor.NewFactory( metadata.Type, func() component.Config { return &struct{}{} }, processor.WithTraces(createTracesProcessor, metadata.TracesStability), processor.WithMetrics(createMetricsProcessor, metadata.MetricsStability), processor.WithLogs(createLogsProcessor, metadata.LogsStability)) } func createTracesProcessor(context.Context, processor.Settings, component.Config, consumer.Traces) (processor.Traces, error) { return nopInstance, nil } func createMetricsProcessor(context.Context, processor.Settings, component.Config, consumer.Metrics) (processor.Metrics, error) { return nopInstance, nil } func createLogsProcessor(context.Context, processor.Settings, component.Config, consumer.Logs) (processor.Logs, error) { return nopInstance, nil } var nopInstance = &nopProcessor{} type nopProcessor struct { component.StartFunc component.ShutdownFunc } func (n nopProcessor) ConsumeTraces(context.Context, ptrace.Traces) error { return nil } func (n nopProcessor) ConsumeLogs(context.Context, plog.Logs) error { return nil } func (n nopProcessor) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } func (n nopProcessor) ConsumeMetrics(context.Context, pmetric.Metrics) error { return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/generated_component_test.go000066400000000000000000000120771511331344600335330ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. //go:build !freebsd && !illumos package sampleprocessor import ( "context" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" ) var typ = component.MustNewType("sample") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "metrics", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "traces", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(processor.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(processor.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(processor.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) } } func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/generated_package_test.go000066400000000000000000000002561511331344600331200ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package sampleprocessor import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/000077500000000000000000000000001511331344600277325ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata/000077500000000000000000000000001511331344600315125ustar00rootroot00000000000000generated_config.go000066400000000000000000000042121511331344600352440ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/confmap" ) // ResourceAttributeConfig provides common config for a particular resource attribute. type ResourceAttributeConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(rac) if err != nil { return err } rac.enabledSetByUser = parser.IsSet("enabled") return nil } // ResourceAttributesConfig provides config for sample resource attributes. type ResourceAttributesConfig struct { MapResourceAttr ResourceAttributeConfig `mapstructure:"map.resource.attr"` OptionalResourceAttr ResourceAttributeConfig `mapstructure:"optional.resource.attr"` SliceResourceAttr ResourceAttributeConfig `mapstructure:"slice.resource.attr"` StringEnumResourceAttr ResourceAttributeConfig `mapstructure:"string.enum.resource.attr"` StringResourceAttr ResourceAttributeConfig `mapstructure:"string.resource.attr"` StringResourceAttrDisableWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_disable_warning"` StringResourceAttrRemoveWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_remove_warning"` StringResourceAttrToBeRemoved ResourceAttributeConfig `mapstructure:"string.resource.attr_to_be_removed"` } func DefaultResourceAttributesConfig() ResourceAttributesConfig { return ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{ Enabled: true, }, OptionalResourceAttr: ResourceAttributeConfig{ Enabled: false, }, SliceResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringEnumResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrDisableWarning: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrRemoveWarning: ResourceAttributeConfig{ Enabled: false, }, StringResourceAttrToBeRemoved: ResourceAttributeConfig{ Enabled: true, }, } } generated_config_test.go000066400000000000000000000047771511331344600363230ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestResourceAttributesConfig(t *testing.T) { tests := []struct { name string want ResourceAttributesConfig }{ { name: "default", want: DefaultResourceAttributesConfig(), }, { name: "all_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, { name: "none_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadResourceAttributesConfig(t *testing.T, name string) ResourceAttributesConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) sub, err = sub.Sub("resource_attributes") require.NoError(t, err) cfg := DefaultResourceAttributesConfig() require.NoError(t, sub.Unmarshal(&cfg)) return cfg } generated_resource.go000066400000000000000000000064261511331344600356370ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceBuilder is a helper struct to build resources predefined in metadata.yaml. // The ResourceBuilder is not thread-safe and must not to be used in multiple goroutines. type ResourceBuilder struct { config ResourceAttributesConfig res pcommon.Resource } // NewResourceBuilder creates a new ResourceBuilder. This method should be called on the start of the application. func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { return &ResourceBuilder{ config: rac, res: pcommon.NewResource(), } } // SetMapResourceAttr sets provided value as "map.resource.attr" attribute. func (rb *ResourceBuilder) SetMapResourceAttr(val map[string]any) { if rb.config.MapResourceAttr.Enabled { rb.res.Attributes().PutEmptyMap("map.resource.attr").FromRaw(val) } } // SetOptionalResourceAttr sets provided value as "optional.resource.attr" attribute. func (rb *ResourceBuilder) SetOptionalResourceAttr(val string) { if rb.config.OptionalResourceAttr.Enabled { rb.res.Attributes().PutStr("optional.resource.attr", val) } } // SetSliceResourceAttr sets provided value as "slice.resource.attr" attribute. func (rb *ResourceBuilder) SetSliceResourceAttr(val []any) { if rb.config.SliceResourceAttr.Enabled { rb.res.Attributes().PutEmptySlice("slice.resource.attr").FromRaw(val) } } // SetStringEnumResourceAttrOne sets "string.enum.resource.attr=one" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrOne() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "one") } } // SetStringEnumResourceAttrTwo sets "string.enum.resource.attr=two" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrTwo() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "two") } } // SetStringResourceAttr sets provided value as "string.resource.attr" attribute. func (rb *ResourceBuilder) SetStringResourceAttr(val string) { if rb.config.StringResourceAttr.Enabled { rb.res.Attributes().PutStr("string.resource.attr", val) } } // SetStringResourceAttrDisableWarning sets provided value as "string.resource.attr_disable_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrDisableWarning(val string) { if rb.config.StringResourceAttrDisableWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_disable_warning", val) } } // SetStringResourceAttrRemoveWarning sets provided value as "string.resource.attr_remove_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrRemoveWarning(val string) { if rb.config.StringResourceAttrRemoveWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_remove_warning", val) } } // SetStringResourceAttrToBeRemoved sets provided value as "string.resource.attr_to_be_removed" attribute. func (rb *ResourceBuilder) SetStringResourceAttrToBeRemoved(val string) { if rb.config.StringResourceAttrToBeRemoved.Enabled { rb.res.Attributes().PutStr("string.resource.attr_to_be_removed", val) } } // Emit returns the built resource and resets the internal builder state. func (rb *ResourceBuilder) Emit() pcommon.Resource { r := rb.res rb.res = pcommon.NewResource() return r } generated_resource_test.go000066400000000000000000000054211511331344600366700ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" ) func TestResourceBuilder(t *testing.T) { for _, tt := range []string{"default", "all_set", "none_set"} { t.Run(tt, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt) rb := NewResourceBuilder(cfg) rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource switch tt { case "default": assert.Equal(t, 6, res.Attributes().Len()) case "all_set": assert.Equal(t, 8, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return default: assert.Failf(t, "unexpected test case: %s", tt) } val, ok := res.Attributes().Get("map.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}, val.Map().AsRaw()) } val, ok = res.Attributes().Get("optional.resource.attr") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "optional.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("slice.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, []any{"slice.resource.attr-item1", "slice.resource.attr-item2"}, val.Slice().AsRaw()) } val, ok = res.Attributes().Get("string.enum.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "one", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_disable_warning") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_disable_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_remove_warning") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "string.resource.attr_remove_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_to_be_removed") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_to_be_removed-val", val.Str()) } }) } } generated_status.go000066400000000000000000000006401511331344600353230ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("sample") ScopeName = "go.opentelemetry.io/collector/internal/receiver/samplereceiver" ) const ( LogsStability = component.StabilityLevelDevelopment TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelStable ) opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata/testdata/000077500000000000000000000000001511331344600333235ustar00rootroot00000000000000config.yaml000066400000000000000000000016221511331344600353760ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/internal/metadata/testdatadefault: all_set: resource_attributes: map.resource.attr: enabled: true optional.resource.attr: enabled: true slice.resource.attr: enabled: true string.enum.resource.attr: enabled: true string.resource.attr: enabled: true string.resource.attr_disable_warning: enabled: true string.resource.attr_remove_warning: enabled: true string.resource.attr_to_be_removed: enabled: true none_set: resource_attributes: map.resource.attr: enabled: false optional.resource.attr: enabled: false slice.resource.attr: enabled: false string.enum.resource.attr: enabled: false string.resource.attr: enabled: false string.resource.attr_disable_warning: enabled: false string.resource.attr_remove_warning: enabled: false string.resource.attr_to_be_removed: enabled: false opentelemetry-collector-0.141.0/cmd/mdatagen/internal/sampleprocessor/metadata.yaml000066400000000000000000000035551511331344600305720ustar00rootroot00000000000000# Sample metadata file with all available configurations for a receiver. type: sample scope_name: go.opentelemetry.io/collector/internal/receiver/samplereceiver github_project: open-telemetry/opentelemetry-collector sem_conv_version: 1.9.0 status: disable_codecov_badge: true class: processor stability: development: [logs] beta: [traces] stable: [metrics] distributions: [] unsupported_platforms: [freebsd, illumos] codeowners: active: [] warnings: - Any additional information that should be brought to the consumer's attention resource_attributes: map.resource.attr: description: Resource attribute with a map value. type: map enabled: true optional.resource.attr: description: Explicitly disabled ResourceAttribute. type: string enabled: false slice.resource.attr: description: Resource attribute with a slice value. type: slice enabled: true string.enum.resource.attr: description: Resource attribute with a known set of string values. type: string enum: [one, two] enabled: true string.resource.attr: description: Resource attribute with any string value. type: string enabled: true string.resource.attr_disable_warning: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled_not_set: This resource_attribute will be disabled by default soon. string.resource.attr_remove_warning: description: Resource attribute with any string value. type: string enabled: false warnings: if_configured: This resource_attribute is deprecated and will be removed soon. string.resource.attr_to_be_removed: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled: This resource_attribute is deprecated and will be removed soon. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/000077500000000000000000000000001511331344600257035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/README.md000066400000000000000000000044201511331344600271620ustar00rootroot00000000000000# Sample Receiver This receiver is used for testing purposes to check the output of mdatagen. | Status | | | ------------- |-----------| | Stability | [deprecated]: profiles | | | [development]: logs | | | [beta]: traces | | | [stable]: metrics | | Deprecation of profiles | [Date]: 2025-02-05 | | | [Migration Note]: no migration needed | | Unsupported Platforms | freebsd, illumos | | Distributions | [] | | Warnings | [Any additional information that should be brought to the consumer's attention](#warnings) | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fsample%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fsample) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fsample%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fsample) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@dmitryax](https://www.github.com/dmitryax) | [deprecated]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecated [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [Date]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information [Migration Note]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information ## Warnings This is where warnings are described. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/doc.go000066400000000000000000000004741511331344600270040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Generate a test metrics builder from a sample metrics set covering all configuration options. //go:generate mdatagen metadata.yaml package samplereceiver // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/documentation.md000066400000000000000000000212251511331344600311000ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # sample ## Default Metrics The following metrics are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml metrics: : enabled: false ``` ### default.metric Monotonic cumulative sum int metric enabled by default. The metric will be become optional soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Int | Cumulative | true | Development | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | state | Integer attribute with overridden name. | Any Int | Recommended | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | Recommended | | slice_attr | Attribute with a slice value. | Any Slice | Recommended | | map_attr | Attribute with a map value. | Any Map | Recommended | | conditional_int_attr | A conditional attribute with an integer value | Any Int | Conditionally Required | | conditional_string_attr | A conditional attribute with any string value | Any Str | Conditionally Required | | opt_in_bool_attr | An opt-in attribute with a boolean value | Any Bool | Opt-In | ### default.metric.to_be_removed [DEPRECATED] Non-monotonic delta sum double metric enabled by default. The metric will be removed soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Double | Delta | false | Deprecated | ### metric.input_type Monotonic cumulative sum int metric with string input_type enabled by default. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Int | Cumulative | true | Development | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | state | Integer attribute with overridden name. | Any Int | Recommended | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | Recommended | | slice_attr | Attribute with a slice value. | Any Slice | Recommended | | map_attr | Attribute with a map value. | Any Map | Recommended | ### system.cpu.time Monotonic cumulative sum int metric enabled by default. The metric will be become optional soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | Semantic Convention | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | ------------------- | | s | Sum | Int | Cumulative | true | Beta | [system.cpu.time](https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime) | ## Optional Metrics The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml metrics: : enabled: true ``` ### optional.metric [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | 1 | Gauge | Double | Deprecated | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | boolean_attr | Attribute with a boolean value. | Any Bool | Recommended | | boolean_attr2 | Another attribute with a boolean value. | Any Bool | Recommended | | conditional_string_attr | A conditional attribute with any string value | Any Str | Conditionally Required | ### optional.metric.empty_unit [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | | Gauge | Double | Deprecated | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | boolean_attr | Attribute with a boolean value. | Any Bool | Recommended | ## Default Events The following events are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml events: : enabled: false ``` ### default.event Example event enabled by default. #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | | string_attr | Attribute with any string value. | Any Str | | state | Integer attribute with overridden name. | Any Int | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | | slice_attr | Attribute with a slice value. | Any Slice | | map_attr | Attribute with a map value. | Any Map | | conditional_int_attr | A conditional attribute with an integer value | Any Int | | conditional_string_attr | A conditional attribute with any string value | Any Str | | opt_in_bool_attr | An opt-in attribute with a boolean value | Any Bool | ### default.event.to_be_removed [DEPRECATED] Example to-be-removed event enabled by default. The event will be removed soon. #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | | string_attr | Attribute with any string value. | Any Str | | state | Integer attribute with overridden name. | Any Int | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | | slice_attr | Attribute with a slice value. | Any Slice | | map_attr | Attribute with a map value. | Any Map | ## Optional Events The following events are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml events: : enabled: true ``` ### default.event.to_be_renamed [DEPRECATED] Example event disabled by default. The event will be renamed soon. #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | | string_attr | Attribute with any string value. | Any Str | | boolean_attr | Attribute with a boolean value. | Any Bool | | boolean_attr2 | Another attribute with a boolean value. | Any Bool | | conditional_string_attr | A conditional attribute with any string value | Any Str | ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | | map.resource.attr | Resource attribute with a map value. | Any Map | true | | optional.resource.attr | Explicitly disabled ResourceAttribute. | Any Str | false | | slice.resource.attr | Resource attribute with a slice value. | Any Slice | true | | string.enum.resource.attr | Resource attribute with a known set of string values. | Str: ``one``, ``two`` | true | | string.resource.attr | Resource attribute with any string value. | Any Str | true | | string.resource.attr_disable_warning | Resource attribute with any string value. | Any Str | true | | string.resource.attr_remove_warning | Resource attribute with any string value. | Any Str | false | | string.resource.attr_to_be_removed | Resource attribute with any string value. | Any Str | true | ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_batch_size_trigger_send Number of times the batch was sent due to a size trigger [Deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {times} | Sum | Int | true | Deprecated | ### otelcol_process_runtime_total_alloc_bytes Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | By | Sum | Int | true | Stable | ### otelcol_queue_capacity Queue capacity - sync gauge example. [Development] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | {items} | Gauge | Int | Development | ### otelcol_queue_length This metric is optional and therefore not initialized in NewTelemetryBuilder. [Alpha] For example this metric only exists if feature A is enabled. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | {items} | Gauge | Int | Alpha | ### otelcol_request_duration Duration of request [Alpha] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | s | Histogram | Double | Alpha | opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/factory.go000066400000000000000000000042301511331344600277000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package samplereceiver // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver" import ( "context" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver/internal/metadata" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/receiver" ) // NewFactory returns a receiver.Factory for sample receiver. func NewFactory() receiver.Factory { return receiver.NewFactory( metadata.Type, func() component.Config { return &struct{}{} }, receiver.WithTraces(createTraces, metadata.TracesStability), receiver.WithMetrics(createMetrics, metadata.MetricsStability), receiver.WithLogs(createLogs, metadata.LogsStability)) } func createTraces(context.Context, receiver.Settings, component.Config, consumer.Traces) (receiver.Traces, error) { return nopInstance, nil } func createMetrics(ctx context.Context, set receiver.Settings, _ component.Config, _ consumer.Metrics) (receiver.Metrics, error) { telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return nil, err } err = telemetryBuilder.RegisterProcessRuntimeTotalAllocBytesCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(2) return nil }) if err != nil { return nil, err } telemetryBuilder.BatchSizeTriggerSend.Add(ctx, 1) return nopReceiver{telemetryBuilder: telemetryBuilder}, nil } func createLogs(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { return nopInstance, nil } var nopInstance = &nopReceiver{} type nopReceiver struct { component.StartFunc telemetryBuilder *metadata.TelemetryBuilder } func (r nopReceiver) initOptionalMetric() { _ = r.telemetryBuilder.RegisterQueueLengthCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(3) return nil }) } // Shutdown shuts down the component. func (r nopReceiver) Shutdown(context.Context) error { if r.telemetryBuilder != nil { r.telemetryBuilder.Shutdown() } return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/generated_component_test.go000066400000000000000000000060471511331344600333200ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. //go:build !freebsd && !illumos package samplereceiver import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" ) var typ = component.MustNewType("sample") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "metrics", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "traces", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/generated_package_test.go000066400000000000000000000002551511331344600327040ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package samplereceiver import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/000077500000000000000000000000001511331344600275175ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata/000077500000000000000000000000001511331344600312775ustar00rootroot00000000000000generated_config.go000066400000000000000000000145421511331344600350400ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/filter" ) // MetricConfig provides common config for a particular metric. type MetricConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ms) if err != nil { return err } ms.enabledSetByUser = parser.IsSet("enabled") return nil } // MetricsConfig provides config for sample metrics. type MetricsConfig struct { DefaultMetric MetricConfig `mapstructure:"default.metric"` DefaultMetricToBeRemoved MetricConfig `mapstructure:"default.metric.to_be_removed"` MetricInputType MetricConfig `mapstructure:"metric.input_type"` OptionalMetric MetricConfig `mapstructure:"optional.metric"` OptionalMetricEmptyUnit MetricConfig `mapstructure:"optional.metric.empty_unit"` SystemCPUTime MetricConfig `mapstructure:"system.cpu.time"` } func DefaultMetricsConfig() MetricsConfig { return MetricsConfig{ DefaultMetric: MetricConfig{ Enabled: true, }, DefaultMetricToBeRemoved: MetricConfig{ Enabled: true, }, MetricInputType: MetricConfig{ Enabled: true, }, OptionalMetric: MetricConfig{ Enabled: false, }, OptionalMetricEmptyUnit: MetricConfig{ Enabled: false, }, SystemCPUTime: MetricConfig{ Enabled: true, }, } } // EventConfig provides common config for a particular event. type EventConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ec *EventConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ec) if err != nil { return err } ec.enabledSetByUser = parser.IsSet("enabled") return nil } // EventsConfig provides config for sample events. type EventsConfig struct { DefaultEvent EventConfig `mapstructure:"default.event"` DefaultEventToBeRemoved EventConfig `mapstructure:"default.event.to_be_removed"` DefaultEventToBeRenamed EventConfig `mapstructure:"default.event.to_be_renamed"` } func DefaultEventsConfig() EventsConfig { return EventsConfig{ DefaultEvent: EventConfig{ Enabled: true, }, DefaultEventToBeRemoved: EventConfig{ Enabled: true, }, DefaultEventToBeRenamed: EventConfig{ Enabled: false, }, } } // ResourceAttributeConfig provides common config for a particular resource attribute. type ResourceAttributeConfig struct { Enabled bool `mapstructure:"enabled"` // Experimental: MetricsInclude defines a list of filters for attribute values. // If the list is not empty, only metrics with matching resource attribute values will be emitted. MetricsInclude []filter.Config `mapstructure:"metrics_include"` // Experimental: MetricsExclude defines a list of filters for attribute values. // If the list is not empty, metrics with matching resource attribute values will not be emitted. // MetricsInclude has higher priority than MetricsExclude. MetricsExclude []filter.Config `mapstructure:"metrics_exclude"` // Experimental: EventsInclude defines a list of filters for attribute values. // If the list is not empty, only events with matching resource attribute values will be emitted. EventsInclude []filter.Config `mapstructure:"events_include"` // Experimental: EventsExclude defines a list of filters for attribute values. // If the list is not empty, events with matching resource attribute values will not be emitted. // EventsInclude has higher priority than EventsExclude. EventsExclude []filter.Config `mapstructure:"events_exclude"` enabledSetByUser bool } func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(rac) if err != nil { return err } rac.enabledSetByUser = parser.IsSet("enabled") return nil } // ResourceAttributesConfig provides config for sample resource attributes. type ResourceAttributesConfig struct { MapResourceAttr ResourceAttributeConfig `mapstructure:"map.resource.attr"` OptionalResourceAttr ResourceAttributeConfig `mapstructure:"optional.resource.attr"` SliceResourceAttr ResourceAttributeConfig `mapstructure:"slice.resource.attr"` StringEnumResourceAttr ResourceAttributeConfig `mapstructure:"string.enum.resource.attr"` StringResourceAttr ResourceAttributeConfig `mapstructure:"string.resource.attr"` StringResourceAttrDisableWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_disable_warning"` StringResourceAttrRemoveWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_remove_warning"` StringResourceAttrToBeRemoved ResourceAttributeConfig `mapstructure:"string.resource.attr_to_be_removed"` } func DefaultResourceAttributesConfig() ResourceAttributesConfig { return ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{ Enabled: true, }, OptionalResourceAttr: ResourceAttributeConfig{ Enabled: false, }, SliceResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringEnumResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrDisableWarning: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrRemoveWarning: ResourceAttributeConfig{ Enabled: false, }, StringResourceAttrToBeRemoved: ResourceAttributeConfig{ Enabled: true, }, } } // MetricsBuilderConfig is a configuration for sample metrics builder. type MetricsBuilderConfig struct { Metrics MetricsConfig `mapstructure:"metrics"` ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` } func DefaultMetricsBuilderConfig() MetricsBuilderConfig { return MetricsBuilderConfig{ Metrics: DefaultMetricsConfig(), ResourceAttributes: DefaultResourceAttributesConfig(), } } // LogsBuilderConfig is a configuration for sample logs builder. type LogsBuilderConfig struct { Events EventsConfig `mapstructure:"events"` ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` } func DefaultLogsBuilderConfig() LogsBuilderConfig { return LogsBuilderConfig{ Events: DefaultEventsConfig(), ResourceAttributes: DefaultResourceAttributesConfig(), } } generated_config_test.go000066400000000000000000000137251511331344600361010ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestMetricsBuilderConfig(t *testing.T) { tests := []struct { name string want MetricsBuilderConfig }{ { name: "default", want: DefaultMetricsBuilderConfig(), }, { name: "all_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: true}, DefaultMetricToBeRemoved: MetricConfig{Enabled: true}, MetricInputType: MetricConfig{Enabled: true}, OptionalMetric: MetricConfig{Enabled: true}, OptionalMetricEmptyUnit: MetricConfig{Enabled: true}, SystemCPUTime: MetricConfig{Enabled: true}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, }, { name: "none_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: false}, DefaultMetricToBeRemoved: MetricConfig{Enabled: false}, MetricInputType: MetricConfig{Enabled: false}, OptionalMetric: MetricConfig{Enabled: false}, OptionalMetricEmptyUnit: MetricConfig{Enabled: false}, SystemCPUTime: MetricConfig{Enabled: false}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadMetricsBuilderConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(MetricConfig{}, ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadMetricsBuilderConfig(t *testing.T, name string) MetricsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultMetricsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } func loadLogsBuilderConfig(t *testing.T, name string) LogsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultLogsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } func TestResourceAttributesConfig(t *testing.T) { tests := []struct { name string want ResourceAttributesConfig }{ { name: "default", want: DefaultResourceAttributesConfig(), }, { name: "all_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, { name: "none_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadResourceAttributesConfig(t *testing.T, name string) ResourceAttributesConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) sub, err = sub.Sub("resource_attributes") require.NoError(t, err) cfg := DefaultResourceAttributesConfig() require.NoError(t, sub.Unmarshal(&cfg)) return cfg } generated_logs.go000066400000000000000000000414751511331344600345440ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "context" conventions "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver" ) type EventAttributeOption interface { apply(plog.LogRecord) } type eventAttributeOptionFunc func(plog.LogRecord) func (eaof eventAttributeOptionFunc) apply(lr plog.LogRecord) { eaof(lr) } func WithConditionalIntAttrEventAttribute(conditionalIntAttrAttributeValue int64) EventAttributeOption { return eventAttributeOptionFunc(func(dp plog.LogRecord) { dp.Attributes().PutInt("conditional_int_attr", conditionalIntAttrAttributeValue) }) } func WithConditionalStringAttrEventAttribute(conditionalStringAttrAttributeValue string) EventAttributeOption { return eventAttributeOptionFunc(func(dp plog.LogRecord) { dp.Attributes().PutStr("conditional_string_attr", conditionalStringAttrAttributeValue) }) } type eventDefaultEvent struct { data plog.LogRecordSlice // data buffer for generated log records. config EventConfig // event config provided by user. } func (e *eventDefaultEvent) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, optInBoolAttrAttributeValue bool, options ...EventAttributeOption) { if !e.config.Enabled { return } dp := e.data.AppendEmpty() dp.SetEventName("default.event") dp.SetTimestamp(timestamp) if span := trace.SpanContextFromContext(ctx); span.IsValid() { dp.SetTraceID(pcommon.TraceID(span.TraceID())) dp.SetSpanID(pcommon.SpanID(span.SpanID())) } dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) dp.Attributes().PutBool("opt_in_bool_attr", optInBoolAttrAttributeValue) for _, op := range options { op.apply(dp) } } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. func (e *eventDefaultEvent) emit(lrs plog.LogRecordSlice) { if e.config.Enabled && e.data.Len() > 0 { e.data.MoveAndAppendTo(lrs) } } func newEventDefaultEvent(cfg EventConfig) eventDefaultEvent { e := eventDefaultEvent{config: cfg} if cfg.Enabled { e.data = plog.NewLogRecordSlice() } return e } type eventDefaultEventToBeRemoved struct { data plog.LogRecordSlice // data buffer for generated log records. config EventConfig // event config provided by user. } func (e *eventDefaultEventToBeRemoved) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { if !e.config.Enabled { return } dp := e.data.AppendEmpty() dp.SetEventName("default.event.to_be_removed") dp.SetTimestamp(timestamp) if span := trace.SpanContextFromContext(ctx); span.IsValid() { dp.SetTraceID(pcommon.TraceID(span.TraceID())) dp.SetSpanID(pcommon.SpanID(span.SpanID())) } dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. func (e *eventDefaultEventToBeRemoved) emit(lrs plog.LogRecordSlice) { if e.config.Enabled && e.data.Len() > 0 { e.data.MoveAndAppendTo(lrs) } } func newEventDefaultEventToBeRemoved(cfg EventConfig) eventDefaultEventToBeRemoved { e := eventDefaultEventToBeRemoved{config: cfg} if cfg.Enabled { e.data = plog.NewLogRecordSlice() } return e } type eventDefaultEventToBeRenamed struct { data plog.LogRecordSlice // data buffer for generated log records. config EventConfig // event config provided by user. } func (e *eventDefaultEventToBeRenamed) recordEvent(ctx context.Context, timestamp pcommon.Timestamp, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...EventAttributeOption) { if !e.config.Enabled { return } dp := e.data.AppendEmpty() dp.SetEventName("default.event.to_be_renamed") dp.SetTimestamp(timestamp) if span := trace.SpanContextFromContext(ctx); span.IsValid() { dp.SetTraceID(pcommon.TraceID(span.TraceID())) dp.SetSpanID(pcommon.SpanID(span.SpanID())) } dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) dp.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) for _, op := range options { op.apply(dp) } } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. func (e *eventDefaultEventToBeRenamed) emit(lrs plog.LogRecordSlice) { if e.config.Enabled && e.data.Len() > 0 { e.data.MoveAndAppendTo(lrs) } } func newEventDefaultEventToBeRenamed(cfg EventConfig) eventDefaultEventToBeRenamed { e := eventDefaultEventToBeRenamed{config: cfg} if cfg.Enabled { e.data = plog.NewLogRecordSlice() } return e } // LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations // required to produce log representation defined in metadata and user config. type LogsBuilder struct { config LogsBuilderConfig // config of the logs builder. logsBuffer plog.Logs logRecordsBuffer plog.LogRecordSlice buildInfo component.BuildInfo // contains version information. resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter eventDefaultEvent eventDefaultEvent eventDefaultEventToBeRemoved eventDefaultEventToBeRemoved eventDefaultEventToBeRenamed eventDefaultEventToBeRenamed } // LogBuilderOption applies changes to default logs builder. type LogBuilderOption interface { apply(*LogsBuilder) } func NewLogsBuilder(lbc LogsBuilderConfig, settings receiver.Settings) *LogsBuilder { if !lbc.Events.DefaultEvent.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `default.event`: This event will be disabled by default soon.") } if lbc.Events.DefaultEventToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `default.event.to_be_removed` should not be enabled: This event is deprecated and will be removed soon.") } if lbc.Events.DefaultEventToBeRenamed.enabledSetByUser { settings.Logger.Warn("[WARNING] `default.event.to_be_renamed` should not be configured: This event is deprecated and will be renamed soon.") } if !lbc.ResourceAttributes.StringResourceAttrDisableWarning.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.") } if lbc.ResourceAttributes.StringResourceAttrRemoveWarning.enabledSetByUser || lbc.ResourceAttributes.StringResourceAttrRemoveWarning.EventsInclude != nil || lbc.ResourceAttributes.StringResourceAttrRemoveWarning.EventsExclude != nil { settings.Logger.Warn("[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.") } if lbc.ResourceAttributes.StringResourceAttrToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.") } lb := &LogsBuilder{ config: lbc, logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, eventDefaultEvent: newEventDefaultEvent(lbc.Events.DefaultEvent), eventDefaultEventToBeRemoved: newEventDefaultEventToBeRemoved(lbc.Events.DefaultEventToBeRemoved), eventDefaultEventToBeRenamed: newEventDefaultEventToBeRenamed(lbc.Events.DefaultEventToBeRenamed), resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), } if lbc.ResourceAttributes.MapResourceAttr.EventsInclude != nil { lb.resourceAttributeIncludeFilter["map.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.MapResourceAttr.EventsInclude) } if lbc.ResourceAttributes.MapResourceAttr.EventsExclude != nil { lb.resourceAttributeExcludeFilter["map.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.MapResourceAttr.EventsExclude) } if lbc.ResourceAttributes.OptionalResourceAttr.EventsInclude != nil { lb.resourceAttributeIncludeFilter["optional.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.OptionalResourceAttr.EventsInclude) } if lbc.ResourceAttributes.OptionalResourceAttr.EventsExclude != nil { lb.resourceAttributeExcludeFilter["optional.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.OptionalResourceAttr.EventsExclude) } if lbc.ResourceAttributes.SliceResourceAttr.EventsInclude != nil { lb.resourceAttributeIncludeFilter["slice.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.SliceResourceAttr.EventsInclude) } if lbc.ResourceAttributes.SliceResourceAttr.EventsExclude != nil { lb.resourceAttributeExcludeFilter["slice.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.SliceResourceAttr.EventsExclude) } if lbc.ResourceAttributes.StringEnumResourceAttr.EventsInclude != nil { lb.resourceAttributeIncludeFilter["string.enum.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.StringEnumResourceAttr.EventsInclude) } if lbc.ResourceAttributes.StringEnumResourceAttr.EventsExclude != nil { lb.resourceAttributeExcludeFilter["string.enum.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.StringEnumResourceAttr.EventsExclude) } if lbc.ResourceAttributes.StringResourceAttr.EventsInclude != nil { lb.resourceAttributeIncludeFilter["string.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttr.EventsInclude) } if lbc.ResourceAttributes.StringResourceAttr.EventsExclude != nil { lb.resourceAttributeExcludeFilter["string.resource.attr"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttr.EventsExclude) } if lbc.ResourceAttributes.StringResourceAttrDisableWarning.EventsInclude != nil { lb.resourceAttributeIncludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttrDisableWarning.EventsInclude) } if lbc.ResourceAttributes.StringResourceAttrDisableWarning.EventsExclude != nil { lb.resourceAttributeExcludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttrDisableWarning.EventsExclude) } if lbc.ResourceAttributes.StringResourceAttrRemoveWarning.EventsInclude != nil { lb.resourceAttributeIncludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttrRemoveWarning.EventsInclude) } if lbc.ResourceAttributes.StringResourceAttrRemoveWarning.EventsExclude != nil { lb.resourceAttributeExcludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttrRemoveWarning.EventsExclude) } if lbc.ResourceAttributes.StringResourceAttrToBeRemoved.EventsInclude != nil { lb.resourceAttributeIncludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttrToBeRemoved.EventsInclude) } if lbc.ResourceAttributes.StringResourceAttrToBeRemoved.EventsExclude != nil { lb.resourceAttributeExcludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(lbc.ResourceAttributes.StringResourceAttrToBeRemoved.EventsExclude) } return lb } // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted logs. func (lb *LogsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder(lb.config.ResourceAttributes) } // ResourceLogsOption applies changes to provided resource logs. type ResourceLogsOption interface { apply(plog.ResourceLogs) } type resourceLogsOptionFunc func(plog.ResourceLogs) func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { rlof(rl) } // WithLogsResource sets the provided resource on the emitted ResourceLogs. // It's recommended to use ResourceBuilder to create the resource. func WithLogsResource(res pcommon.Resource) ResourceLogsOption { return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { res.CopyTo(rl.Resource()) }) } // AppendLogRecord adds a log record to the logs builder. func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) } // EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for // recording another set of log records as part of another resource. This function can be helpful when one scraper // needs to emit logs from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceLogsOption arguments. func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { rl := plog.NewResourceLogs() rl.SetSchemaUrl(conventions.SchemaURL) ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) lb.eventDefaultEvent.emit(ils.LogRecords()) lb.eventDefaultEventToBeRemoved.emit(ils.LogRecords()) lb.eventDefaultEventToBeRenamed.emit(ils.LogRecords()) for _, op := range options { op.apply(rl) } if lb.logRecordsBuffer.Len() > 0 { lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) lb.logRecordsBuffer = plog.NewLogRecordSlice() } for attr, filter := range lb.resourceAttributeIncludeFilter { if val, ok := rl.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { return } } for attr, filter := range lb.resourceAttributeExcludeFilter { if val, ok := rl.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { return } } if ils.LogRecords().Len() > 0 { rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) } } // Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for // recording another set of logs. This function will be responsible for applying all the transformations required to // produce logs representation defined in metadata and user config. func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { lb.EmitForResource(options...) logs := lb.logsBuffer lb.logsBuffer = plog.NewLogs() return logs } // RecordDefaultEventEvent adds a log record of default.event event. func (lb *LogsBuilder) RecordDefaultEventEvent(ctx context.Context, timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, optInBoolAttrAttributeValue bool, options ...EventAttributeOption) { lb.eventDefaultEvent.recordEvent(ctx, timestamp, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue, optInBoolAttrAttributeValue, options...) } // RecordDefaultEventToBeRemovedEvent adds a log record of default.event.to_be_removed event. func (lb *LogsBuilder) RecordDefaultEventToBeRemovedEvent(ctx context.Context, timestamp pcommon.Timestamp, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { lb.eventDefaultEventToBeRemoved.recordEvent(ctx, timestamp, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) } // RecordDefaultEventToBeRenamedEvent adds a log record of default.event.to_be_renamed event. func (lb *LogsBuilder) RecordDefaultEventToBeRenamedEvent(ctx context.Context, timestamp pcommon.Timestamp, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...EventAttributeOption) { lb.eventDefaultEventToBeRenamed.recordEvent(ctx, timestamp, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue, options...) } generated_logs_test.go000066400000000000000000000272051511331344600355760ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver/receivertest" ) type eventsTestDataSet int const ( eventTestDataSetDefault eventsTestDataSet = iota eventTestDataSetAll eventTestDataSetNone ) func TestLogsBuilderAppendLogRecord(t *testing.T) { observedZapCore, _ := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder(loadLogsBuilderConfig(t, "all_set"), settings) rb := lb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() // append the first log record lr := plog.NewLogRecord() lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr.Attributes().PutStr("type", "log") lr.Body().SetStr("the first log record") // append the second log record lr2 := plog.NewLogRecord() lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr2.Attributes().PutStr("type", "event") lr2.Body().SetStr("the second log record") lb.AppendLogRecord(lr) lb.AppendLogRecord(lr2) logs := lb.Emit(WithLogsResource(res)) assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, 1, rl.ScopeLogs().Len()) sl := rl.ScopeLogs().At(0) assert.Equal(t, ScopeName, sl.Scope().Name()) assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) assert.Equal(t, 2, sl.LogRecords().Len()) attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "log", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "event", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) } func TestLogsBuilder(t *testing.T) { tests := []struct { name string eventsSet eventsTestDataSet resAttrsSet eventsTestDataSet expectEmpty bool }{ { name: "default", }, { name: "all_set", eventsSet: eventTestDataSetAll, resAttrsSet: eventTestDataSetAll, }, { name: "none_set", eventsSet: eventTestDataSetNone, resAttrsSet: eventTestDataSetNone, expectEmpty: true, }, { name: "filter_set_include", resAttrsSet: eventTestDataSetAll, }, { name: "filter_set_exclude", resAttrsSet: eventTestDataSetAll, expectEmpty: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { timestamp := pcommon.Timestamp(1_000_001_000) traceID := [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} spanID := [8]byte{0, 1, 2, 3, 4, 5, 6, 7} ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID(traceID), SpanID: trace.SpanID(spanID), TraceFlags: trace.FlagsSampled, })) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder(loadLogsBuilderConfig(t, tt.name), settings) expectedWarnings := 0 if tt.eventsSet == eventTestDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `default.event`: This event will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.eventsSet == eventTestDataSetDefault || tt.eventsSet == eventTestDataSetAll { assert.Equal(t, "[WARNING] `default.event.to_be_removed` should not be enabled: This event is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.eventsSet == eventTestDataSetAll || tt.eventsSet == eventTestDataSetNone { assert.Equal(t, "[WARNING] `default.event.to_be_renamed` should not be configured: This event is deprecated and will be renamed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == eventTestDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == eventTestDataSetAll || tt.resAttrsSet == eventTestDataSetNone { assert.Equal(t, "[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == eventTestDataSetDefault || tt.resAttrsSet == eventTestDataSetAll { assert.Equal(t, "[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } assert.Equal(t, expectedWarnings, observedLogs.Len()) defaultEventsCount := 0 allEventsCount := 0 defaultEventsCount++ allEventsCount++ lb.RecordDefaultEventEvent(ctx, timestamp, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, true, WithConditionalIntAttrEventAttribute(20), WithConditionalStringAttrEventAttribute("conditional_string_attr-val")) defaultEventsCount++ allEventsCount++ lb.RecordDefaultEventToBeRemovedEvent(ctx, timestamp, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) allEventsCount++ lb.RecordDefaultEventToBeRenamedEvent(ctx, timestamp, "string_attr-val", true, false, WithConditionalStringAttrEventAttribute("conditional_string_attr-val")) rb := lb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() logs := lb.Emit(WithLogsResource(res)) if tt.expectEmpty || ((tt.name == "default" || tt.name == "filter_set_include") && defaultEventsCount == 0) { assert.Equal(t, 0, logs.ResourceLogs().Len()) return } assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, res, rl.Resource()) assert.Equal(t, 1, rl.ScopeLogs().Len()) lrs := rl.ScopeLogs().At(0).LogRecords() if tt.eventsSet == eventTestDataSetDefault { assert.Equal(t, defaultEventsCount, lrs.Len()) } if tt.eventsSet == eventTestDataSetAll { assert.Equal(t, allEventsCount, lrs.Len()) } validatedEvents := make(map[string]bool) for i := 0; i < lrs.Len(); i++ { switch lrs.At(i).EventName() { case "default.event": assert.False(t, validatedEvents["default.event"], "Found a duplicate in the events slice: default.event") validatedEvents["default.event"] = true lr := lrs.At(i) assert.Equal(t, timestamp, lr.Timestamp()) assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) attrVal, ok := lr.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = lr.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = lr.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = lr.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = lr.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) attrVal, ok = lr.Attributes().Get("conditional_int_attr") assert.True(t, ok) assert.EqualValues(t, 20, attrVal.Int()) attrVal, ok = lr.Attributes().Get("conditional_string_attr") assert.True(t, ok) assert.Equal(t, "conditional_string_attr-val", attrVal.Str()) attrVal, ok = lr.Attributes().Get("opt_in_bool_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) case "default.event.to_be_removed": assert.False(t, validatedEvents["default.event.to_be_removed"], "Found a duplicate in the events slice: default.event.to_be_removed") validatedEvents["default.event.to_be_removed"] = true lr := lrs.At(i) assert.Equal(t, timestamp, lr.Timestamp()) assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) attrVal, ok := lr.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = lr.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = lr.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = lr.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = lr.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "default.event.to_be_renamed": assert.False(t, validatedEvents["default.event.to_be_renamed"], "Found a duplicate in the events slice: default.event.to_be_renamed") validatedEvents["default.event.to_be_renamed"] = true lr := lrs.At(i) assert.Equal(t, timestamp, lr.Timestamp()) assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) attrVal, ok := lr.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = lr.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) attrVal, ok = lr.Attributes().Get("boolean_attr2") assert.True(t, ok) assert.False(t, attrVal.Bool()) attrVal, ok = lr.Attributes().Get("conditional_string_attr") assert.True(t, ok) assert.Equal(t, "conditional_string_attr-val", attrVal.Str()) } } }) } } generated_metrics.go000066400000000000000000000722351511331344600352440ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "fmt" "strconv" "time" conventions "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver" ) // AttributeEnumAttr specifies the value enum_attr attribute. type AttributeEnumAttr int const ( _ AttributeEnumAttr = iota AttributeEnumAttrRed AttributeEnumAttrGreen AttributeEnumAttrBlue ) // String returns the string representation of the AttributeEnumAttr. func (av AttributeEnumAttr) String() string { switch av { case AttributeEnumAttrRed: return "red" case AttributeEnumAttrGreen: return "green" case AttributeEnumAttrBlue: return "blue" } return "" } // MapAttributeEnumAttr is a helper map of string to AttributeEnumAttr attribute value. var MapAttributeEnumAttr = map[string]AttributeEnumAttr{ "red": AttributeEnumAttrRed, "green": AttributeEnumAttrGreen, "blue": AttributeEnumAttrBlue, } var MetricsInfo = metricsInfo{ DefaultMetric: metricInfo{ Name: "default.metric", }, DefaultMetricToBeRemoved: metricInfo{ Name: "default.metric.to_be_removed", }, MetricInputType: metricInfo{ Name: "metric.input_type", }, OptionalMetric: metricInfo{ Name: "optional.metric", }, OptionalMetricEmptyUnit: metricInfo{ Name: "optional.metric.empty_unit", }, SystemCPUTime: metricInfo{ Name: "system.cpu.time", }, } type metricsInfo struct { DefaultMetric metricInfo DefaultMetricToBeRemoved metricInfo MetricInputType metricInfo OptionalMetric metricInfo OptionalMetricEmptyUnit metricInfo SystemCPUTime metricInfo } type metricInfo struct { Name string } type MetricAttributeOption interface { apply(pmetric.NumberDataPoint) } type metricAttributeOptionFunc func(pmetric.NumberDataPoint) func (maof metricAttributeOptionFunc) apply(dp pmetric.NumberDataPoint) { maof(dp) } func WithConditionalIntAttrMetricAttribute(conditionalIntAttrAttributeValue int64) MetricAttributeOption { return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { dp.Attributes().PutInt("conditional_int_attr", conditionalIntAttrAttributeValue) }) } func WithConditionalStringAttrMetricAttribute(conditionalStringAttrAttributeValue string) MetricAttributeOption { return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { dp.Attributes().PutStr("conditional_string_attr", conditionalStringAttrAttributeValue) }) } type metricDefaultMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric metric with initial data. func (m *metricDefaultMetric) init() { m.data.SetName("default.metric") m.data.SetDescription("Monotonic cumulative sum int metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricDefaultMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, optInBoolAttrAttributeValue bool, options ...MetricAttributeOption) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) dp.Attributes().PutBool("opt_in_bool_attr", optInBoolAttrAttributeValue) for _, op := range options { op.apply(dp) } } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetric) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetric(cfg MetricConfig) metricDefaultMetric { m := metricDefaultMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricDefaultMetricToBeRemoved struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric.to_be_removed metric with initial data. func (m *metricDefaultMetricToBeRemoved) init() { m.data.SetName("default.metric.to_be_removed") m.data.SetDescription("[DEPRECATED] Non-monotonic delta sum double metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(false) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) } func (m *metricDefaultMetricToBeRemoved) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetricToBeRemoved) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetricToBeRemoved) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetricToBeRemoved(cfg MetricConfig) metricDefaultMetricToBeRemoved { m := metricDefaultMetricToBeRemoved{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricMetricInputType struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills metric.input_type metric with initial data. func (m *metricMetricInputType) init() { m.data.SetName("metric.input_type") m.data.SetDescription("Monotonic cumulative sum int metric with string input_type enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricMetricInputType) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricMetricInputType) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricMetricInputType) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricMetricInputType(cfg MetricConfig) metricMetricInputType { m := metricMetricInputType{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric metric with initial data. func (m *metricOptionalMetric) init() { m.data.SetName("optional.metric") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("1") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...MetricAttributeOption) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) dp.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) for _, op := range options { op.apply(dp) } } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetric) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetric(cfg MetricConfig) metricOptionalMetric { m := metricOptionalMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetricEmptyUnit struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric.empty_unit metric with initial data. func (m *metricOptionalMetricEmptyUnit) init() { m.data.SetName("optional.metric.empty_unit") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetricEmptyUnit) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetricEmptyUnit) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetricEmptyUnit) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetricEmptyUnit(cfg MetricConfig) metricOptionalMetricEmptyUnit { m := metricOptionalMetricEmptyUnit{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricSystemCPUTime struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills system.cpu.time metric with initial data. func (m *metricSystemCPUTime) init() { m.data.SetName("system.cpu.time") m.data.SetDescription("Monotonic cumulative sum int metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) } func (m *metricSystemCPUTime) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricSystemCPUTime) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricSystemCPUTime) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricSystemCPUTime(cfg MetricConfig) metricSystemCPUTime { m := metricSystemCPUTime{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } // MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations // required to produce metric representation defined in metadata and user config. type MetricsBuilder struct { config MetricsBuilderConfig // config of the metrics builder. startTime pcommon.Timestamp // start time that will be applied to all recorded data points. metricsCapacity int // maximum observed number of metrics per resource. metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. buildInfo component.BuildInfo // contains version information. resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter metricDefaultMetric metricDefaultMetric metricDefaultMetricToBeRemoved metricDefaultMetricToBeRemoved metricMetricInputType metricMetricInputType metricOptionalMetric metricOptionalMetric metricOptionalMetricEmptyUnit metricOptionalMetricEmptyUnit metricSystemCPUTime metricSystemCPUTime } // MetricBuilderOption applies changes to default metrics builder. type MetricBuilderOption interface { apply(*MetricsBuilder) } type metricBuilderOptionFunc func(mb *MetricsBuilder) func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { mbof(mb) } // WithStartTime sets startTime on the metrics builder. func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime }) } func NewMetricsBuilder(mbc MetricsBuilderConfig, settings receiver.Settings, options ...MetricBuilderOption) *MetricsBuilder { if !mbc.Metrics.DefaultMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.") } if mbc.Metrics.DefaultMetricToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetricEmptyUnit.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.") } if !mbc.ResourceAttributes.StringResourceAttrDisableWarning.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.") } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.enabledSetByUser || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { settings.Logger.Warn("[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.") } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.") } mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), metricsBuffer: pmetric.NewMetrics(), buildInfo: settings.BuildInfo, metricDefaultMetric: newMetricDefaultMetric(mbc.Metrics.DefaultMetric), metricDefaultMetricToBeRemoved: newMetricDefaultMetricToBeRemoved(mbc.Metrics.DefaultMetricToBeRemoved), metricMetricInputType: newMetricMetricInputType(mbc.Metrics.MetricInputType), metricOptionalMetric: newMetricOptionalMetric(mbc.Metrics.OptionalMetric), metricOptionalMetricEmptyUnit: newMetricOptionalMetricEmptyUnit(mbc.Metrics.OptionalMetricEmptyUnit), metricSystemCPUTime: newMetricSystemCPUTime(mbc.Metrics.SystemCPUTime), resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), } if mbc.ResourceAttributes.MapResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.MapResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude) } for _, op := range options { op.apply(mb) } return mb } // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted metrics. func (mb *MetricsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder(mb.config.ResourceAttributes) } // updateCapacity updates max length of metrics and resource attributes that will be used for the slice capacity. func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { if mb.metricsCapacity < rm.ScopeMetrics().At(0).Metrics().Len() { mb.metricsCapacity = rm.ScopeMetrics().At(0).Metrics().Len() } } // ResourceMetricsOption applies changes to provided resource metrics. type ResourceMetricsOption interface { apply(pmetric.ResourceMetrics) } type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { rmof(rm) } // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { switch metrics.At(i).Type() { case pmetric.MetricTypeGauge: dps = metrics.At(i).Gauge().DataPoints() case pmetric.MetricTypeSum: dps = metrics.At(i).Sum().DataPoints() } for j := 0; j < dps.Len(); j++ { dps.At(j).SetStartTimestamp(start) } } }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for // recording another set of data points as part of another resource. This function can be helpful when one scraper // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() rm.SetSchemaUrl(conventions.SchemaURL) ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(mb.buildInfo.Version) ils.Metrics().EnsureCapacity(mb.metricsCapacity) mb.metricDefaultMetric.emit(ils.Metrics()) mb.metricDefaultMetricToBeRemoved.emit(ils.Metrics()) mb.metricMetricInputType.emit(ils.Metrics()) mb.metricOptionalMetric.emit(ils.Metrics()) mb.metricOptionalMetricEmptyUnit.emit(ils.Metrics()) mb.metricSystemCPUTime.emit(ils.Metrics()) for _, op := range options { op.apply(rm) } for attr, filter := range mb.resourceAttributeIncludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { return } } for attr, filter := range mb.resourceAttributeExcludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { return } } if ils.Metrics().Len() > 0 { mb.updateCapacity(rm) rm.MoveTo(mb.metricsBuffer.ResourceMetrics().AppendEmpty()) } } // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics } // RecordDefaultMetricDataPoint adds a data point to default.metric metric. func (mb *MetricsBuilder) RecordDefaultMetricDataPoint(ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any, optInBoolAttrAttributeValue bool, options ...MetricAttributeOption) { mb.metricDefaultMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue, optInBoolAttrAttributeValue, options...) } // RecordDefaultMetricToBeRemovedDataPoint adds a data point to default.metric.to_be_removed metric. func (mb *MetricsBuilder) RecordDefaultMetricToBeRemovedDataPoint(ts pcommon.Timestamp, val float64) { mb.metricDefaultMetricToBeRemoved.recordDataPoint(mb.startTime, ts, val) } // RecordMetricInputTypeDataPoint adds a data point to metric.input_type metric. func (mb *MetricsBuilder) RecordMetricInputTypeDataPoint(ts pcommon.Timestamp, inputVal string, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) error { val, err := strconv.ParseInt(inputVal, 10, 64) if err != nil { return fmt.Errorf("failed to parse int64 for MetricInputType, value was %s: %w", inputVal, err) } mb.metricMetricInputType.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) return nil } // RecordOptionalMetricDataPoint adds a data point to optional.metric metric. func (mb *MetricsBuilder) RecordOptionalMetricDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool, options ...MetricAttributeOption) { mb.metricOptionalMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue, options...) } // RecordOptionalMetricEmptyUnitDataPoint adds a data point to optional.metric.empty_unit metric. func (mb *MetricsBuilder) RecordOptionalMetricEmptyUnitDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { mb.metricOptionalMetricEmptyUnit.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue) } // RecordSystemCPUTimeDataPoint adds a data point to system.cpu.time metric. func (mb *MetricsBuilder) RecordSystemCPUTimeDataPoint(ts pcommon.Timestamp, val int64) { mb.metricSystemCPUTime.recordDataPoint(mb.startTime, ts, val) } // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { op.apply(mb) } } generated_metrics_test.go000066400000000000000000000327141511331344600363010ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver/receivertest" ) type testDataSet int const ( testDataSetDefault testDataSet = iota testDataSetAll testDataSetNone ) func TestMetricsBuilder(t *testing.T) { tests := []struct { name string metricsSet testDataSet resAttrsSet testDataSet expectEmpty bool }{ { name: "default", }, { name: "all_set", metricsSet: testDataSetAll, resAttrsSet: testDataSetAll, }, { name: "none_set", metricsSet: testDataSetNone, resAttrsSet: testDataSetNone, expectEmpty: true, }, { name: "filter_set_include", resAttrsSet: testDataSetAll, }, { name: "filter_set_exclude", resAttrsSet: testDataSetAll, expectEmpty: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 if tt.metricsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetDefault || tt.metricsSet == testDataSetAll { assert.Equal(t, "[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetAll || tt.resAttrsSet == testDataSetNone { assert.Equal(t, "[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault || tt.resAttrsSet == testDataSetAll { assert.Equal(t, "[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } assert.Equal(t, expectedWarnings, observedLogs.Len()) defaultMetricsCount := 0 allMetricsCount := 0 defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricDataPoint(ts, 1, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, true, WithConditionalIntAttrMetricAttribute(20), WithConditionalStringAttrMetricAttribute("conditional_string_attr-val")) defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricToBeRemovedDataPoint(ts, 1) defaultMetricsCount++ allMetricsCount++ mb.RecordMetricInputTypeDataPoint(ts, "1", "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) allMetricsCount++ mb.RecordOptionalMetricDataPoint(ts, 1, "string_attr-val", true, false, WithConditionalStringAttrMetricAttribute("conditional_string_attr-val")) allMetricsCount++ mb.RecordOptionalMetricEmptyUnitDataPoint(ts, 1, "string_attr-val", true) defaultMetricsCount++ allMetricsCount++ mb.RecordSystemCPUTimeDataPoint(ts, 1) rb := mb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() metrics := mb.Emit(WithResource(res)) if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } assert.Equal(t, 1, metrics.ResourceMetrics().Len()) rm := metrics.ResourceMetrics().At(0) assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) for i := 0; i < ms.Len(); i++ { switch ms.At(i).Name() { case "default.metric": assert.False(t, validatedMetrics["default.metric"], "Found a duplicate in the metrics slice: default.metric") validatedMetrics["default.metric"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) attrVal, ok = dp.Attributes().Get("conditional_int_attr") assert.True(t, ok) assert.EqualValues(t, 20, attrVal.Int()) attrVal, ok = dp.Attributes().Get("conditional_string_attr") assert.True(t, ok) assert.Equal(t, "conditional_string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("opt_in_bool_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) case "default.metric.to_be_removed": assert.False(t, validatedMetrics["default.metric.to_be_removed"], "Found a duplicate in the metrics slice: default.metric.to_be_removed") validatedMetrics["default.metric.to_be_removed"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Non-monotonic delta sum double metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.False(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityDelta, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) case "metric.input_type": assert.False(t, validatedMetrics["metric.input_type"], "Found a duplicate in the metrics slice: metric.input_type") validatedMetrics["metric.input_type"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric with string input_type enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "optional.metric": assert.False(t, validatedMetrics["optional.metric"], "Found a duplicate in the metrics slice: optional.metric") validatedMetrics["optional.metric"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Equal(t, "1", ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) attrVal, ok = dp.Attributes().Get("boolean_attr2") assert.True(t, ok) assert.False(t, attrVal.Bool()) attrVal, ok = dp.Attributes().Get("conditional_string_attr") assert.True(t, ok) assert.Equal(t, "conditional_string_attr-val", attrVal.Str()) case "optional.metric.empty_unit": assert.False(t, validatedMetrics["optional.metric.empty_unit"], "Found a duplicate in the metrics slice: optional.metric.empty_unit") validatedMetrics["optional.metric.empty_unit"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Empty(t, ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) case "system.cpu.time": assert.False(t, validatedMetrics["system.cpu.time"], "Found a duplicate in the metrics slice: system.cpu.time") validatedMetrics["system.cpu.time"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) } } }) } } generated_resource.go000066400000000000000000000064261511331344600354240ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceBuilder is a helper struct to build resources predefined in metadata.yaml. // The ResourceBuilder is not thread-safe and must not to be used in multiple goroutines. type ResourceBuilder struct { config ResourceAttributesConfig res pcommon.Resource } // NewResourceBuilder creates a new ResourceBuilder. This method should be called on the start of the application. func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { return &ResourceBuilder{ config: rac, res: pcommon.NewResource(), } } // SetMapResourceAttr sets provided value as "map.resource.attr" attribute. func (rb *ResourceBuilder) SetMapResourceAttr(val map[string]any) { if rb.config.MapResourceAttr.Enabled { rb.res.Attributes().PutEmptyMap("map.resource.attr").FromRaw(val) } } // SetOptionalResourceAttr sets provided value as "optional.resource.attr" attribute. func (rb *ResourceBuilder) SetOptionalResourceAttr(val string) { if rb.config.OptionalResourceAttr.Enabled { rb.res.Attributes().PutStr("optional.resource.attr", val) } } // SetSliceResourceAttr sets provided value as "slice.resource.attr" attribute. func (rb *ResourceBuilder) SetSliceResourceAttr(val []any) { if rb.config.SliceResourceAttr.Enabled { rb.res.Attributes().PutEmptySlice("slice.resource.attr").FromRaw(val) } } // SetStringEnumResourceAttrOne sets "string.enum.resource.attr=one" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrOne() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "one") } } // SetStringEnumResourceAttrTwo sets "string.enum.resource.attr=two" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrTwo() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "two") } } // SetStringResourceAttr sets provided value as "string.resource.attr" attribute. func (rb *ResourceBuilder) SetStringResourceAttr(val string) { if rb.config.StringResourceAttr.Enabled { rb.res.Attributes().PutStr("string.resource.attr", val) } } // SetStringResourceAttrDisableWarning sets provided value as "string.resource.attr_disable_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrDisableWarning(val string) { if rb.config.StringResourceAttrDisableWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_disable_warning", val) } } // SetStringResourceAttrRemoveWarning sets provided value as "string.resource.attr_remove_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrRemoveWarning(val string) { if rb.config.StringResourceAttrRemoveWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_remove_warning", val) } } // SetStringResourceAttrToBeRemoved sets provided value as "string.resource.attr_to_be_removed" attribute. func (rb *ResourceBuilder) SetStringResourceAttrToBeRemoved(val string) { if rb.config.StringResourceAttrToBeRemoved.Enabled { rb.res.Attributes().PutStr("string.resource.attr_to_be_removed", val) } } // Emit returns the built resource and resets the internal builder state. func (rb *ResourceBuilder) Emit() pcommon.Resource { r := rb.res rb.res = pcommon.NewResource() return r } generated_resource_test.go000066400000000000000000000054211511331344600364550ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" ) func TestResourceBuilder(t *testing.T) { for _, tt := range []string{"default", "all_set", "none_set"} { t.Run(tt, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt) rb := NewResourceBuilder(cfg) rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource switch tt { case "default": assert.Equal(t, 6, res.Attributes().Len()) case "all_set": assert.Equal(t, 8, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return default: assert.Failf(t, "unexpected test case: %s", tt) } val, ok := res.Attributes().Get("map.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}, val.Map().AsRaw()) } val, ok = res.Attributes().Get("optional.resource.attr") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "optional.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("slice.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, []any{"slice.resource.attr-item1", "slice.resource.attr-item2"}, val.Slice().AsRaw()) } val, ok = res.Attributes().Get("string.enum.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "one", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_disable_warning") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_disable_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_remove_warning") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "string.resource.attr_remove_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_to_be_removed") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_to_be_removed-val", val.Str()) } }) } } generated_status.go000066400000000000000000000007331511331344600351130ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("sample") ScopeName = "go.opentelemetry.io/collector/internal/receiver/samplereceiver" ) const ( ProfilesStability = component.StabilityLevelDeprecated LogsStability = component.StabilityLevelDevelopment TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelStable ) generated_telemetry.go000066400000000000000000000113041511331344600355760ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "context" "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/embedded" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/internal/receiver/samplereceiver") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/internal/receiver/samplereceiver") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration BatchSizeTriggerSend metric.Int64Counter ProcessRuntimeTotalAllocBytes metric.Int64ObservableCounter QueueCapacity metric.Int64Gauge QueueLength metric.Int64ObservableGauge RequestDuration metric.Float64Histogram } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // RegisterProcessRuntimeTotalAllocBytesCallback sets callback for observable ProcessRuntimeTotalAllocBytes metric. func (builder *TelemetryBuilder) RegisterProcessRuntimeTotalAllocBytesCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ProcessRuntimeTotalAllocBytes, obs: o}) return nil }, builder.ProcessRuntimeTotalAllocBytes) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterQueueLengthCallback sets callback for observable QueueLength metric. func (builder *TelemetryBuilder) RegisterQueueLengthCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.QueueLength, obs: o}) return nil }, builder.QueueLength) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } type observerInt64 struct { embedded.Int64Observer inst metric.Int64Observable obs metric.Observer } func (oi *observerInt64) Observe(value int64, opts ...metric.ObserveOption) { oi.obs.ObserveInt64(oi.inst, value, opts...) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.BatchSizeTriggerSend, err = builder.meter.Int64Counter( "otelcol_batch_size_trigger_send", metric.WithDescription("Number of times the batch was sent due to a size trigger [Deprecated since v0.110.0]"), metric.WithUnit("{times}"), ) errs = errors.Join(errs, err) builder.ProcessRuntimeTotalAllocBytes, err = builder.meter.Int64ObservableCounter( "otelcol_process_runtime_total_alloc_bytes", metric.WithDescription("Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')"), metric.WithUnit("By"), ) errs = errors.Join(errs, err) builder.QueueCapacity, err = builder.meter.Int64Gauge( "otelcol_queue_capacity", metric.WithDescription("Queue capacity - sync gauge example. [Development]"), metric.WithUnit("{items}"), ) errs = errors.Join(errs, err) builder.QueueLength, err = builder.meter.Int64ObservableGauge( "otelcol_queue_length", metric.WithDescription("This metric is optional and therefore not initialized in NewTelemetryBuilder. [Alpha]"), metric.WithUnit("{items}"), ) errs = errors.Join(errs, err) builder.RequestDuration, err = builder.meter.Float64Histogram( "otelcol_request_duration", metric.WithDescription("Duration of request [Alpha]"), metric.WithUnit("s"), metric.WithExplicitBucketBoundaries([]float64{1, 10, 100}...), ) errs = errors.Join(errs, err) return &builder, errs } generated_telemetry_test.go000066400000000000000000000035231511331344600366410ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/internal/receiver/samplereceiver", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/internal/receiver/samplereceiver", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata/testdata/000077500000000000000000000000001511331344600331105ustar00rootroot00000000000000config.yaml000066400000000000000000000106071511331344600351660ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadata/testdatadefault: all_set: metrics: default.metric: enabled: true default.metric.to_be_removed: enabled: true metric.input_type: enabled: true optional.metric: enabled: true optional.metric.empty_unit: enabled: true system.cpu.time: enabled: true events: default.event: enabled: true default.event.to_be_removed: enabled: true default.event.to_be_renamed: enabled: true resource_attributes: map.resource.attr: enabled: true optional.resource.attr: enabled: true slice.resource.attr: enabled: true string.enum.resource.attr: enabled: true string.resource.attr: enabled: true string.resource.attr_disable_warning: enabled: true string.resource.attr_remove_warning: enabled: true string.resource.attr_to_be_removed: enabled: true none_set: metrics: default.metric: enabled: false default.metric.to_be_removed: enabled: false metric.input_type: enabled: false optional.metric: enabled: false optional.metric.empty_unit: enabled: false system.cpu.time: enabled: false events: default.event: enabled: false default.event.to_be_removed: enabled: false default.event.to_be_renamed: enabled: false resource_attributes: map.resource.attr: enabled: false optional.resource.attr: enabled: false slice.resource.attr: enabled: false string.enum.resource.attr: enabled: false string.resource.attr: enabled: false string.resource.attr_disable_warning: enabled: false string.resource.attr_remove_warning: enabled: false string.resource.attr_to_be_removed: enabled: false filter_set_include: resource_attributes: map.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" optional.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" slice.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr_disable_warning: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr_remove_warning: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" string.resource.attr_to_be_removed: enabled: true metrics_include: - regexp: ".*" events_include: - regexp: ".*" filter_set_exclude: resource_attributes: map.resource.attr: enabled: true metrics_exclude: - regexp: ".*" events_exclude: - regexp: ".*" optional.resource.attr: enabled: true metrics_exclude: - strict: "optional.resource.attr-val" events_exclude: - strict: "optional.resource.attr-val" slice.resource.attr: enabled: true metrics_exclude: - regexp: ".*" events_exclude: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_exclude: - strict: "one" events_exclude: - strict: "one" string.resource.attr: enabled: true metrics_exclude: - strict: "string.resource.attr-val" events_exclude: - strict: "string.resource.attr-val" string.resource.attr_disable_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_disable_warning-val" events_exclude: - strict: "string.resource.attr_disable_warning-val" string.resource.attr_remove_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_remove_warning-val" events_exclude: - strict: "string.resource.attr_remove_warning-val" string.resource.attr_to_be_removed: enabled: true metrics_exclude: - strict: "string.resource.attr_to_be_removed-val" events_exclude: - strict: "string.resource.attr_to_be_removed-val" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadatatest/000077500000000000000000000000001511331344600321775ustar00rootroot00000000000000generated_telemetrytest.go000066400000000000000000000067251511331344600374110ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" ) func NewSettings(tt *componenttest.Telemetry) receiver.Settings { set := receivertest.NewNopSettings(receivertest.NopType) set.ID = component.NewID(component.MustNewType("sample")) set.TelemetrySettings = tt.NewTelemetrySettings() return set } func AssertEqualBatchSizeTriggerSend(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_batch_size_trigger_send", Description: "Number of times the batch was sent due to a size trigger [Deprecated since v0.110.0]", Unit: "{times}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_batch_size_trigger_send") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessRuntimeTotalAllocBytes(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_process_runtime_total_alloc_bytes", Description: "Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc')", Unit: "By", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_process_runtime_total_alloc_bytes") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualQueueCapacity(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_queue_capacity", Description: "Queue capacity - sync gauge example. [Development]", Unit: "{items}", Data: metricdata.Gauge[int64]{ DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_queue_capacity") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualQueueLength(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_queue_length", Description: "This metric is optional and therefore not initialized in NewTelemetryBuilder. [Alpha]", Unit: "{items}", Data: metricdata.Gauge[int64]{ DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_queue_length") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualRequestDuration(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.HistogramDataPoint[float64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_request_duration", Description: "Duration of request [Alpha]", Unit: "s", Data: metricdata.Histogram[float64]{ Temporality: metricdata.CumulativeTemporality, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_request_duration") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } generated_telemetrytest_test.go000066400000000000000000000034511511331344600404410ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver/internal/metadata" "go.opentelemetry.io/collector/component/componenttest" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() require.NoError(t, tb.RegisterProcessRuntimeTotalAllocBytesCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) require.NoError(t, tb.RegisterQueueLengthCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) tb.BatchSizeTriggerSend.Add(context.Background(), 1) tb.QueueCapacity.Record(context.Background(), 1) tb.RequestDuration.Record(context.Background(), 1) AssertEqualBatchSizeTriggerSend(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessRuntimeTotalAllocBytes(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualQueueCapacity(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualQueueLength(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualRequestDuration(t, testTel, []metricdata.HistogramDataPoint[float64]{{}}, metricdatatest.IgnoreValue(), metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/metadata.yaml000066400000000000000000000203561511331344600303550ustar00rootroot00000000000000# Sample metadata file with all available configurations for a receiver. type: sample scope_name: go.opentelemetry.io/collector/internal/receiver/samplereceiver github_project: open-telemetry/opentelemetry-collector sem_conv_version: 1.37.0 status: disable_codecov_badge: true class: receiver stability: development: [logs] beta: [traces] stable: [metrics] deprecated: [profiles] deprecation: profiles: migration: "no migration needed" date: "2025-02-05" distributions: [] unsupported_platforms: [freebsd, illumos] codeowners: active: [dmitryax] warnings: - Any additional information that should be brought to the consumer's attention resource_attributes: map.resource.attr: description: Resource attribute with a map value. type: map enabled: true optional.resource.attr: description: Explicitly disabled ResourceAttribute. type: string enabled: false slice.resource.attr: description: Resource attribute with a slice value. type: slice enabled: true string.enum.resource.attr: description: Resource attribute with a known set of string values. type: string enum: [one, two] enabled: true string.resource.attr: description: Resource attribute with any string value. type: string enabled: true string.resource.attr_disable_warning: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled_not_set: This resource_attribute will be disabled by default soon. string.resource.attr_remove_warning: description: Resource attribute with any string value. type: string enabled: false warnings: if_configured: This resource_attribute is deprecated and will be removed soon. string.resource.attr_to_be_removed: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled: This resource_attribute is deprecated and will be removed soon. attributes: boolean_attr: description: Attribute with a boolean value. type: bool # This 2nd boolean attribute allows us to test both values for boolean attributes, # as test values are based on the parity of the attribute name length. boolean_attr2: description: Another attribute with a boolean value. type: bool conditional_int_attr: description: A conditional attribute with an integer value type: int requirement_level: conditionally_required conditional_string_attr: description: A conditional attribute with any string value type: string requirement_level: conditionally_required enum_attr: description: Attribute with a known set of string values. type: string enum: [red, green, blue] map_attr: description: Attribute with a map value. type: map opt_in_bool_attr: description: An opt-in attribute with a boolean value type: bool requirement_level: opt_in overridden_int_attr: name_override: state description: Integer attribute with overridden name. type: int slice_attr: description: Attribute with a slice value. type: slice string_attr: description: Attribute with any string value. type: string events: default.event: enabled: true description: Example event enabled by default. attributes: [ string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr, conditional_int_attr, conditional_string_attr, opt_in_bool_attr, ] warnings: if_enabled_not_set: This event will be disabled by default soon. default.event.to_be_removed: enabled: true description: "[DEPRECATED] Example to-be-removed event enabled by default." extended_documentation: The event will be removed soon. warnings: if_enabled: This event is deprecated and will be removed soon. attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr] default.event.to_be_renamed: enabled: false description: "[DEPRECATED] Example event disabled by default." extended_documentation: The event will be renamed soon. attributes: [string_attr, boolean_attr, boolean_attr2, conditional_string_attr] warnings: if_configured: This event is deprecated and will be renamed soon. metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative attributes: [ string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr, conditional_int_attr, conditional_string_attr, opt_in_bool_attr, ] warnings: if_enabled_not_set: This metric will be disabled by default soon. default.metric.to_be_removed: enabled: true description: "[DEPRECATED] Non-monotonic delta sum double metric enabled by default." extended_documentation: The metric will be removed soon. stability: level: deprecated unit: s sum: value_type: double monotonic: false aggregation_temporality: delta warnings: if_enabled: This metric is deprecated and will be removed soon. metric.input_type: enabled: true description: Monotonic cumulative sum int metric with string input_type enabled by default. stability: level: development unit: s sum: value_type: int input_type: string monotonic: true aggregation_temporality: cumulative attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr] optional.metric: enabled: false description: "[DEPRECATED] Gauge double metric disabled by default." stability: level: deprecated unit: "1" gauge: value_type: double attributes: [string_attr, boolean_attr, boolean_attr2, conditional_string_attr] warnings: if_configured: This metric is deprecated and will be removed soon. optional.metric.empty_unit: enabled: false description: "[DEPRECATED] Gauge double metric disabled by default." stability: level: deprecated unit: "" gauge: value_type: double attributes: [string_attr, boolean_attr] warnings: if_configured: This metric is deprecated and will be removed soon. system.cpu.time: enabled: true stability: level: beta description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative semantic_convention: ref: https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime telemetry: metrics: batch_size_trigger_send: enabled: true stability: level: deprecated from: v0.110.0 description: Number of times the batch was sent due to a size trigger unit: "{times}" sum: value_type: int monotonic: true process_runtime_total_alloc_bytes: enabled: true stability: level: stable description: Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') unit: By sum: async: true value_type: int monotonic: true queue_capacity: enabled: true description: Queue capacity - sync gauge example. stability: level: development unit: "{items}" gauge: value_type: int queue_length: enabled: true stability: level: alpha description: This metric is optional and therefore not initialized in NewTelemetryBuilder. extended_documentation: For example this metric only exists if feature A is enabled. unit: "{items}" optional: true gauge: async: true value_type: int request_duration: enabled: true stability: level: alpha description: Duration of request unit: s histogram: value_type: double bucket_boundaries: [1, 10, 100] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplereceiver/metrics_test.go000066400000000000000000000034331511331344600307420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package samplereceiver import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver/internal/metadata" "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplereceiver/internal/metadatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver/receivertest" ) // TestGeneratedMetrics verifies that the internal/metadata API is generated correctly. func TestGeneratedMetrics(t *testing.T) { mb := metadata.NewMetricsBuilder(metadata.DefaultMetricsBuilderConfig(), receivertest.NewNopSettings(metadata.Type)) m := mb.Emit() require.Equal(t, 0, m.ResourceMetrics().Len()) } func TestComponentTelemetry(t *testing.T) { tt := componenttest.NewTelemetry() factory := NewFactory() receiver, err := factory.CreateMetrics(context.Background(), metadatatest.NewSettings(tt), newMdatagenNopHost(), new(consumertest.MetricsSink)) require.NoError(t, err) metadatatest.AssertEqualBatchSizeTriggerSend(t, tt, []metricdata.DataPoint[int64]{ { Value: 1, }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessRuntimeTotalAllocBytes(t, tt, []metricdata.DataPoint[int64]{ { Value: 2, }, }, metricdatatest.IgnoreTimestamp()) rcv, ok := receiver.(nopReceiver) require.True(t, ok) rcv.initOptionalMetric() metadatatest.AssertEqualQueueLength(t, tt, []metricdata.DataPoint[int64]{ { Value: 3, }, }, metricdatatest.IgnoreTimestamp()) require.NoError(t, tt.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/000077500000000000000000000000001511331344600255365ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/README.md000066400000000000000000000031221511331344600270130ustar00rootroot00000000000000# Sample Scraper This scraper is used for testing purposes to check the output of mdatagen. | Status | | | ------------- |-----------| | Stability | [development]: logs | | | [stable]: metrics | | Unsupported Platforms | freebsd, illumos | | Distributions | [] | | Warnings | [Any additional information that should be brought to the consumer's attention](#warnings) | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Ascraper%2Fsample%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Ascraper%2Fsample) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Ascraper%2Fsample%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Ascraper%2Fsample) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@dmitryax](https://www.github.com/dmitryax) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable ## Warnings This is where warnings are described. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/doc.go000066400000000000000000000004721511331344600266350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Generate a test metrics builder from a sample metrics set covering all configuration options. //go:generate mdatagen metadata.yaml package samplescraper // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplescraper" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/documentation.md000066400000000000000000000115301511331344600307310ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # sample ## Default Metrics The following metrics are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml metrics: : enabled: false ``` ### default.metric Monotonic cumulative sum int metric enabled by default. The metric will be become optional soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Int | Cumulative | true | Development | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | state | Integer attribute with overridden name. | Any Int | Recommended | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | Recommended | | slice_attr | Attribute with a slice value. | Any Slice | Recommended | | map_attr | Attribute with a map value. | Any Map | Recommended | ### default.metric.to_be_removed [DEPRECATED] Non-monotonic delta sum double metric enabled by default. The metric will be removed soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Double | Delta | false | Deprecated | ### metric.input_type Monotonic cumulative sum int metric with string input_type enabled by default. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | | s | Sum | Int | Cumulative | true | Development | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | state | Integer attribute with overridden name. | Any Int | Recommended | | enum_attr | Attribute with a known set of string values. | Str: ``red``, ``green``, ``blue`` | Recommended | | slice_attr | Attribute with a slice value. | Any Slice | Recommended | | map_attr | Attribute with a map value. | Any Map | Recommended | ### system.cpu.time Monotonic cumulative sum int metric enabled by default. The metric will be become optional soon. | Unit | Metric Type | Value Type | Aggregation Temporality | Monotonic | Stability | Semantic Convention | | ---- | ----------- | ---------- | ----------------------- | --------- | --------- | ------------------- | | s | Sum | Int | Cumulative | true | Beta | [system.cpu.time](https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime) | ## Optional Metrics The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml metrics: : enabled: true ``` ### optional.metric [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | 1 | Gauge | Double | Deprecated | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | boolean_attr | Attribute with a boolean value. | Any Bool | Recommended | | boolean_attr2 | Another attribute with a boolean value. | Any Bool | Recommended | ### optional.metric.empty_unit [DEPRECATED] Gauge double metric disabled by default. | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | | Gauge | Double | Deprecated | #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | | string_attr | Attribute with any string value. | Any Str | Recommended | | boolean_attr | Attribute with a boolean value. | Any Bool | Recommended | ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | | map.resource.attr | Resource attribute with a map value. | Any Map | true | | optional.resource.attr | Explicitly disabled ResourceAttribute. | Any Str | false | | slice.resource.attr | Resource attribute with a slice value. | Any Slice | true | | string.enum.resource.attr | Resource attribute with a known set of string values. | Str: ``one``, ``two`` | true | | string.resource.attr | Resource attribute with any string value. | Any Str | true | | string.resource.attr_disable_warning | Resource attribute with any string value. | Any Str | true | | string.resource.attr_remove_warning | Resource attribute with any string value. | Any Str | false | | string.resource.attr_to_be_removed | Resource attribute with any string value. | Any Str | true | opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/factory.go000066400000000000000000000022451511331344600275370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package samplescraper // import "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplescraper" import ( "context" "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplescraper/internal/metadata" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/scraper" ) // NewFactory returns a receiver.Factory for sample receiver. func NewFactory() scraper.Factory { return scraper.NewFactory( metadata.Type, func() component.Config { return &struct{}{} }, scraper.WithMetrics(createMetrics, metadata.MetricsStability), scraper.WithLogs(createLogs, metadata.LogsStability)) } func createMetrics(context.Context, scraper.Settings, component.Config) (scraper.Metrics, error) { return scraper.NewMetrics(func(context.Context) (pmetric.Metrics, error) { return pmetric.NewMetrics(), nil }) } func createLogs(context.Context, scraper.Settings, component.Config) (scraper.Logs, error) { return scraper.NewLogs(func(context.Context) (plog.Logs, error) { return plog.Logs{}, nil }) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/generated_component_test.go000066400000000000000000000053341511331344600331510ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. //go:build !freebsd && !illumos package samplescraper import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapertest" ) var typ = component.MustNewType("sample") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set scraper.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set scraper.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg) }, }, { name: "metrics", createFn: func(ctx context.Context, set scraper.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), scrapertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), scrapertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), scrapertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/generated_package_test.go000066400000000000000000000002541511331344600325360ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package samplescraper import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/000077500000000000000000000000001511331344600273525ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata/000077500000000000000000000000001511331344600311325ustar00rootroot00000000000000generated_config.go000066400000000000000000000107441511331344600346730ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/filter" ) // MetricConfig provides common config for a particular metric. type MetricConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ms) if err != nil { return err } ms.enabledSetByUser = parser.IsSet("enabled") return nil } // MetricsConfig provides config for sample metrics. type MetricsConfig struct { DefaultMetric MetricConfig `mapstructure:"default.metric"` DefaultMetricToBeRemoved MetricConfig `mapstructure:"default.metric.to_be_removed"` MetricInputType MetricConfig `mapstructure:"metric.input_type"` OptionalMetric MetricConfig `mapstructure:"optional.metric"` OptionalMetricEmptyUnit MetricConfig `mapstructure:"optional.metric.empty_unit"` SystemCPUTime MetricConfig `mapstructure:"system.cpu.time"` } func DefaultMetricsConfig() MetricsConfig { return MetricsConfig{ DefaultMetric: MetricConfig{ Enabled: true, }, DefaultMetricToBeRemoved: MetricConfig{ Enabled: true, }, MetricInputType: MetricConfig{ Enabled: true, }, OptionalMetric: MetricConfig{ Enabled: false, }, OptionalMetricEmptyUnit: MetricConfig{ Enabled: false, }, SystemCPUTime: MetricConfig{ Enabled: true, }, } } // ResourceAttributeConfig provides common config for a particular resource attribute. type ResourceAttributeConfig struct { Enabled bool `mapstructure:"enabled"` // Experimental: MetricsInclude defines a list of filters for attribute values. // If the list is not empty, only metrics with matching resource attribute values will be emitted. MetricsInclude []filter.Config `mapstructure:"metrics_include"` // Experimental: MetricsExclude defines a list of filters for attribute values. // If the list is not empty, metrics with matching resource attribute values will not be emitted. // MetricsInclude has higher priority than MetricsExclude. MetricsExclude []filter.Config `mapstructure:"metrics_exclude"` enabledSetByUser bool } func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(rac) if err != nil { return err } rac.enabledSetByUser = parser.IsSet("enabled") return nil } // ResourceAttributesConfig provides config for sample resource attributes. type ResourceAttributesConfig struct { MapResourceAttr ResourceAttributeConfig `mapstructure:"map.resource.attr"` OptionalResourceAttr ResourceAttributeConfig `mapstructure:"optional.resource.attr"` SliceResourceAttr ResourceAttributeConfig `mapstructure:"slice.resource.attr"` StringEnumResourceAttr ResourceAttributeConfig `mapstructure:"string.enum.resource.attr"` StringResourceAttr ResourceAttributeConfig `mapstructure:"string.resource.attr"` StringResourceAttrDisableWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_disable_warning"` StringResourceAttrRemoveWarning ResourceAttributeConfig `mapstructure:"string.resource.attr_remove_warning"` StringResourceAttrToBeRemoved ResourceAttributeConfig `mapstructure:"string.resource.attr_to_be_removed"` } func DefaultResourceAttributesConfig() ResourceAttributesConfig { return ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{ Enabled: true, }, OptionalResourceAttr: ResourceAttributeConfig{ Enabled: false, }, SliceResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringEnumResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttr: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrDisableWarning: ResourceAttributeConfig{ Enabled: true, }, StringResourceAttrRemoveWarning: ResourceAttributeConfig{ Enabled: false, }, StringResourceAttrToBeRemoved: ResourceAttributeConfig{ Enabled: true, }, } } // MetricsBuilderConfig is a configuration for sample metrics builder. type MetricsBuilderConfig struct { Metrics MetricsConfig `mapstructure:"metrics"` ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` } func DefaultMetricsBuilderConfig() MetricsBuilderConfig { return MetricsBuilderConfig{ Metrics: DefaultMetricsConfig(), ResourceAttributes: DefaultResourceAttributesConfig(), } } generated_config_test.go000066400000000000000000000131751511331344600357330ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestMetricsBuilderConfig(t *testing.T) { tests := []struct { name string want MetricsBuilderConfig }{ { name: "default", want: DefaultMetricsBuilderConfig(), }, { name: "all_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: true}, DefaultMetricToBeRemoved: MetricConfig{Enabled: true}, MetricInputType: MetricConfig{Enabled: true}, OptionalMetric: MetricConfig{Enabled: true}, OptionalMetricEmptyUnit: MetricConfig{Enabled: true}, SystemCPUTime: MetricConfig{Enabled: true}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, }, { name: "none_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ DefaultMetric: MetricConfig{Enabled: false}, DefaultMetricToBeRemoved: MetricConfig{Enabled: false}, MetricInputType: MetricConfig{Enabled: false}, OptionalMetric: MetricConfig{Enabled: false}, OptionalMetricEmptyUnit: MetricConfig{Enabled: false}, SystemCPUTime: MetricConfig{Enabled: false}, }, ResourceAttributes: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadMetricsBuilderConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(MetricConfig{}, ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadMetricsBuilderConfig(t *testing.T, name string) MetricsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultMetricsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } func TestResourceAttributesConfig(t *testing.T) { tests := []struct { name string want ResourceAttributesConfig }{ { name: "default", want: DefaultResourceAttributesConfig(), }, { name: "all_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: true}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: true}, SliceResourceAttr: ResourceAttributeConfig{Enabled: true}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttr: ResourceAttributeConfig{Enabled: true}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: true}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: true}, }, }, { name: "none_set", want: ResourceAttributesConfig{ MapResourceAttr: ResourceAttributeConfig{Enabled: false}, OptionalResourceAttr: ResourceAttributeConfig{Enabled: false}, SliceResourceAttr: ResourceAttributeConfig{Enabled: false}, StringEnumResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttr: ResourceAttributeConfig{Enabled: false}, StringResourceAttrDisableWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrRemoveWarning: ResourceAttributeConfig{Enabled: false}, StringResourceAttrToBeRemoved: ResourceAttributeConfig{Enabled: false}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadResourceAttributesConfig(t *testing.T, name string) ResourceAttributesConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) sub, err = sub.Sub("resource_attributes") require.NoError(t, err) cfg := DefaultResourceAttributesConfig() require.NoError(t, sub.Unmarshal(&cfg)) return cfg } generated_logs.go000066400000000000000000000065701511331344600343740ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( conventions "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/scraper" ) // LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations // required to produce log representation defined in metadata and user config. type LogsBuilder struct { logsBuffer plog.Logs logRecordsBuffer plog.LogRecordSlice buildInfo component.BuildInfo // contains version information. } // LogBuilderOption applies changes to default logs builder. type LogBuilderOption interface { apply(*LogsBuilder) } func NewLogsBuilder(settings scraper.Settings) *LogsBuilder { lb := &LogsBuilder{ logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, } return lb } // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted logs. func (lb *LogsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder(ResourceAttributesConfig{}) } // ResourceLogsOption applies changes to provided resource logs. type ResourceLogsOption interface { apply(plog.ResourceLogs) } type resourceLogsOptionFunc func(plog.ResourceLogs) func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { rlof(rl) } // WithLogsResource sets the provided resource on the emitted ResourceLogs. // It's recommended to use ResourceBuilder to create the resource. func WithLogsResource(res pcommon.Resource) ResourceLogsOption { return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { res.CopyTo(rl.Resource()) }) } // AppendLogRecord adds a log record to the logs builder. func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) } // EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for // recording another set of log records as part of another resource. This function can be helpful when one scraper // needs to emit logs from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceLogsOption arguments. func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { rl := plog.NewResourceLogs() rl.SetSchemaUrl(conventions.SchemaURL) ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) for _, op := range options { op.apply(rl) } if lb.logRecordsBuffer.Len() > 0 { lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) lb.logRecordsBuffer = plog.NewLogRecordSlice() } if ils.LogRecords().Len() > 0 { rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) } } // Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for // recording another set of logs. This function will be responsible for applying all the transformations required to // produce logs representation defined in metadata and user config. func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { lb.EmitForResource(options...) logs := lb.logsBuffer lb.logsBuffer = plog.NewLogs() return logs } generated_logs_test.go000066400000000000000000000050151511331344600354240ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "time" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/scraper/scrapertest" ) func TestLogsBuilderAppendLogRecord(t *testing.T) { observedZapCore, _ := observer.New(zap.WarnLevel) settings := scrapertest.NewNopSettings(scrapertest.NopType) settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder(settings) rb := lb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() // append the first log record lr := plog.NewLogRecord() lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr.Attributes().PutStr("type", "log") lr.Body().SetStr("the first log record") // append the second log record lr2 := plog.NewLogRecord() lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr2.Attributes().PutStr("type", "event") lr2.Body().SetStr("the second log record") lb.AppendLogRecord(lr) lb.AppendLogRecord(lr2) logs := lb.Emit(WithLogsResource(res)) assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, 1, rl.ScopeLogs().Len()) sl := rl.ScopeLogs().At(0) assert.Equal(t, ScopeName, sl.Scope().Name()) assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) assert.Equal(t, 2, sl.LogRecords().Len()) attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "log", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "event", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) } generated_metrics.go000066400000000000000000000677601511331344600351060ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "fmt" "strconv" "time" conventions "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/filter" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/scraper" ) // AttributeEnumAttr specifies the value enum_attr attribute. type AttributeEnumAttr int const ( _ AttributeEnumAttr = iota AttributeEnumAttrRed AttributeEnumAttrGreen AttributeEnumAttrBlue ) // String returns the string representation of the AttributeEnumAttr. func (av AttributeEnumAttr) String() string { switch av { case AttributeEnumAttrRed: return "red" case AttributeEnumAttrGreen: return "green" case AttributeEnumAttrBlue: return "blue" } return "" } // MapAttributeEnumAttr is a helper map of string to AttributeEnumAttr attribute value. var MapAttributeEnumAttr = map[string]AttributeEnumAttr{ "red": AttributeEnumAttrRed, "green": AttributeEnumAttrGreen, "blue": AttributeEnumAttrBlue, } var MetricsInfo = metricsInfo{ DefaultMetric: metricInfo{ Name: "default.metric", }, DefaultMetricToBeRemoved: metricInfo{ Name: "default.metric.to_be_removed", }, MetricInputType: metricInfo{ Name: "metric.input_type", }, OptionalMetric: metricInfo{ Name: "optional.metric", }, OptionalMetricEmptyUnit: metricInfo{ Name: "optional.metric.empty_unit", }, SystemCPUTime: metricInfo{ Name: "system.cpu.time", }, } type metricsInfo struct { DefaultMetric metricInfo DefaultMetricToBeRemoved metricInfo MetricInputType metricInfo OptionalMetric metricInfo OptionalMetricEmptyUnit metricInfo SystemCPUTime metricInfo } type metricInfo struct { Name string } type metricDefaultMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric metric with initial data. func (m *metricDefaultMetric) init() { m.data.SetName("default.metric") m.data.SetDescription("Monotonic cumulative sum int metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricDefaultMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetric) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetric(cfg MetricConfig) metricDefaultMetric { m := metricDefaultMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricDefaultMetricToBeRemoved struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills default.metric.to_be_removed metric with initial data. func (m *metricDefaultMetricToBeRemoved) init() { m.data.SetName("default.metric.to_be_removed") m.data.SetDescription("[DEPRECATED] Non-monotonic delta sum double metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(false) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityDelta) } func (m *metricDefaultMetricToBeRemoved) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricDefaultMetricToBeRemoved) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricDefaultMetricToBeRemoved) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricDefaultMetricToBeRemoved(cfg MetricConfig) metricDefaultMetricToBeRemoved { m := metricDefaultMetricToBeRemoved{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricMetricInputType struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills metric.input_type metric with initial data. func (m *metricMetricInputType) init() { m.data.SetName("metric.input_type") m.data.SetDescription("Monotonic cumulative sum int metric with string input_type enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) m.data.Sum().DataPoints().EnsureCapacity(m.capacity) } func (m *metricMetricInputType) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue string, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutInt("state", overriddenIntAttrAttributeValue) dp.Attributes().PutStr("enum_attr", enumAttrAttributeValue) dp.Attributes().PutEmptySlice("slice_attr").FromRaw(sliceAttrAttributeValue) dp.Attributes().PutEmptyMap("map_attr").FromRaw(mapAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricMetricInputType) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricMetricInputType) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricMetricInputType(cfg MetricConfig) metricMetricInputType { m := metricMetricInputType{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetric struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric metric with initial data. func (m *metricOptionalMetric) init() { m.data.SetName("optional.metric") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("1") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetric) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) dp.Attributes().PutBool("boolean_attr2", booleanAttr2AttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetric) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetric) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetric(cfg MetricConfig) metricOptionalMetric { m := metricOptionalMetric{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricOptionalMetricEmptyUnit struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills optional.metric.empty_unit metric with initial data. func (m *metricOptionalMetricEmptyUnit) init() { m.data.SetName("optional.metric.empty_unit") m.data.SetDescription("[DEPRECATED] Gauge double metric disabled by default.") m.data.SetUnit("") m.data.SetEmptyGauge() m.data.Gauge().DataPoints().EnsureCapacity(m.capacity) } func (m *metricOptionalMetricEmptyUnit) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { if !m.config.Enabled { return } dp := m.data.Gauge().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetDoubleValue(val) dp.Attributes().PutStr("string_attr", stringAttrAttributeValue) dp.Attributes().PutBool("boolean_attr", booleanAttrAttributeValue) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricOptionalMetricEmptyUnit) updateCapacity() { if m.data.Gauge().DataPoints().Len() > m.capacity { m.capacity = m.data.Gauge().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricOptionalMetricEmptyUnit) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Gauge().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricOptionalMetricEmptyUnit(cfg MetricConfig) metricOptionalMetricEmptyUnit { m := metricOptionalMetricEmptyUnit{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } type metricSystemCPUTime struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills system.cpu.time metric with initial data. func (m *metricSystemCPUTime) init() { m.data.SetName("system.cpu.time") m.data.SetDescription("Monotonic cumulative sum int metric enabled by default.") m.data.SetUnit("s") m.data.SetEmptySum() m.data.Sum().SetIsMonotonic(true) m.data.Sum().SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) } func (m *metricSystemCPUTime) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val int64) { if !m.config.Enabled { return } dp := m.data.Sum().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.SetIntValue(val) } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metricSystemCPUTime) updateCapacity() { if m.data.Sum().DataPoints().Len() > m.capacity { m.capacity = m.data.Sum().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metricSystemCPUTime) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.Sum().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetricSystemCPUTime(cfg MetricConfig) metricSystemCPUTime { m := metricSystemCPUTime{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } // MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations // required to produce metric representation defined in metadata and user config. type MetricsBuilder struct { config MetricsBuilderConfig // config of the metrics builder. startTime pcommon.Timestamp // start time that will be applied to all recorded data points. metricsCapacity int // maximum observed number of metrics per resource. metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. buildInfo component.BuildInfo // contains version information. resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter metricDefaultMetric metricDefaultMetric metricDefaultMetricToBeRemoved metricDefaultMetricToBeRemoved metricMetricInputType metricMetricInputType metricOptionalMetric metricOptionalMetric metricOptionalMetricEmptyUnit metricOptionalMetricEmptyUnit metricSystemCPUTime metricSystemCPUTime } // MetricBuilderOption applies changes to default metrics builder. type MetricBuilderOption interface { apply(*MetricsBuilder) } type metricBuilderOptionFunc func(mb *MetricsBuilder) func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { mbof(mb) } // WithStartTime sets startTime on the metrics builder. func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime }) } func NewMetricsBuilder(mbc MetricsBuilderConfig, settings scraper.Settings, options ...MetricBuilderOption) *MetricsBuilder { if !mbc.Metrics.DefaultMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.") } if mbc.Metrics.DefaultMetricToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetric.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.") } if mbc.Metrics.OptionalMetricEmptyUnit.enabledSetByUser { settings.Logger.Warn("[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.") } if !mbc.ResourceAttributes.StringResourceAttrDisableWarning.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.") } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.enabledSetByUser || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil || mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { settings.Logger.Warn("[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.") } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.Enabled { settings.Logger.Warn("[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.") } mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), metricsBuffer: pmetric.NewMetrics(), buildInfo: settings.BuildInfo, metricDefaultMetric: newMetricDefaultMetric(mbc.Metrics.DefaultMetric), metricDefaultMetricToBeRemoved: newMetricDefaultMetricToBeRemoved(mbc.Metrics.DefaultMetricToBeRemoved), metricMetricInputType: newMetricMetricInputType(mbc.Metrics.MetricInputType), metricOptionalMetric: newMetricOptionalMetric(mbc.Metrics.OptionalMetric), metricOptionalMetricEmptyUnit: newMetricOptionalMetricEmptyUnit(mbc.Metrics.OptionalMetricEmptyUnit), metricSystemCPUTime: newMetricSystemCPUTime(mbc.Metrics.SystemCPUTime), resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), } if mbc.ResourceAttributes.MapResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.MapResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["map.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.MapResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["optional.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.OptionalResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["slice.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.SliceResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.enum.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringEnumResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttr.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttr.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_disable_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrDisableWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_remove_warning"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrRemoveWarning.MetricsExclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsInclude) } if mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["string.resource.attr_to_be_removed"] = filter.CreateFilter(mbc.ResourceAttributes.StringResourceAttrToBeRemoved.MetricsExclude) } for _, op := range options { op.apply(mb) } return mb } // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted metrics. func (mb *MetricsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder(mb.config.ResourceAttributes) } // updateCapacity updates max length of metrics and resource attributes that will be used for the slice capacity. func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { if mb.metricsCapacity < rm.ScopeMetrics().At(0).Metrics().Len() { mb.metricsCapacity = rm.ScopeMetrics().At(0).Metrics().Len() } } // ResourceMetricsOption applies changes to provided resource metrics. type ResourceMetricsOption interface { apply(pmetric.ResourceMetrics) } type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { rmof(rm) } // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { switch metrics.At(i).Type() { case pmetric.MetricTypeGauge: dps = metrics.At(i).Gauge().DataPoints() case pmetric.MetricTypeSum: dps = metrics.At(i).Sum().DataPoints() } for j := 0; j < dps.Len(); j++ { dps.At(j).SetStartTimestamp(start) } } }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for // recording another set of data points as part of another resource. This function can be helpful when one scraper // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() rm.SetSchemaUrl(conventions.SchemaURL) ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(mb.buildInfo.Version) ils.Metrics().EnsureCapacity(mb.metricsCapacity) mb.metricDefaultMetric.emit(ils.Metrics()) mb.metricDefaultMetricToBeRemoved.emit(ils.Metrics()) mb.metricMetricInputType.emit(ils.Metrics()) mb.metricOptionalMetric.emit(ils.Metrics()) mb.metricOptionalMetricEmptyUnit.emit(ils.Metrics()) mb.metricSystemCPUTime.emit(ils.Metrics()) for _, op := range options { op.apply(rm) } for attr, filter := range mb.resourceAttributeIncludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { return } } for attr, filter := range mb.resourceAttributeExcludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { return } } if ils.Metrics().Len() > 0 { mb.updateCapacity(rm) rm.MoveTo(mb.metricsBuffer.ResourceMetrics().AppendEmpty()) } } // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics } // RecordDefaultMetricDataPoint adds a data point to default.metric metric. func (mb *MetricsBuilder) RecordDefaultMetricDataPoint(ts pcommon.Timestamp, val int64, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) { mb.metricDefaultMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) } // RecordDefaultMetricToBeRemovedDataPoint adds a data point to default.metric.to_be_removed metric. func (mb *MetricsBuilder) RecordDefaultMetricToBeRemovedDataPoint(ts pcommon.Timestamp, val float64) { mb.metricDefaultMetricToBeRemoved.recordDataPoint(mb.startTime, ts, val) } // RecordMetricInputTypeDataPoint adds a data point to metric.input_type metric. func (mb *MetricsBuilder) RecordMetricInputTypeDataPoint(ts pcommon.Timestamp, inputVal string, stringAttrAttributeValue string, overriddenIntAttrAttributeValue int64, enumAttrAttributeValue AttributeEnumAttr, sliceAttrAttributeValue []any, mapAttrAttributeValue map[string]any) error { val, err := strconv.ParseInt(inputVal, 10, 64) if err != nil { return fmt.Errorf("failed to parse int64 for MetricInputType, value was %s: %w", inputVal, err) } mb.metricMetricInputType.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, overriddenIntAttrAttributeValue, enumAttrAttributeValue.String(), sliceAttrAttributeValue, mapAttrAttributeValue) return nil } // RecordOptionalMetricDataPoint adds a data point to optional.metric metric. func (mb *MetricsBuilder) RecordOptionalMetricDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool, booleanAttr2AttributeValue bool) { mb.metricOptionalMetric.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue, booleanAttr2AttributeValue) } // RecordOptionalMetricEmptyUnitDataPoint adds a data point to optional.metric.empty_unit metric. func (mb *MetricsBuilder) RecordOptionalMetricEmptyUnitDataPoint(ts pcommon.Timestamp, val float64, stringAttrAttributeValue string, booleanAttrAttributeValue bool) { mb.metricOptionalMetricEmptyUnit.recordDataPoint(mb.startTime, ts, val, stringAttrAttributeValue, booleanAttrAttributeValue) } // RecordSystemCPUTimeDataPoint adds a data point to system.cpu.time metric. func (mb *MetricsBuilder) RecordSystemCPUTimeDataPoint(ts pcommon.Timestamp, val int64) { mb.metricSystemCPUTime.recordDataPoint(mb.startTime, ts, val) } // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { op.apply(mb) } } generated_metrics_test.go000066400000000000000000000313171511331344600361320ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/scraper/scrapertest" ) type testDataSet int const ( testDataSetDefault testDataSet = iota testDataSetAll testDataSetNone ) func TestMetricsBuilder(t *testing.T) { tests := []struct { name string metricsSet testDataSet resAttrsSet testDataSet expectEmpty bool }{ { name: "default", }, { name: "all_set", metricsSet: testDataSetAll, resAttrsSet: testDataSetAll, }, { name: "none_set", metricsSet: testDataSetNone, resAttrsSet: testDataSetNone, expectEmpty: true, }, { name: "filter_set_include", resAttrsSet: testDataSetAll, }, { name: "filter_set_exclude", resAttrsSet: testDataSetAll, expectEmpty: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) settings := scrapertest.NewNopSettings(scrapertest.NopType) settings.Logger = zap.New(observedZapCore) mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 if tt.metricsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `default.metric`: This metric will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetDefault || tt.metricsSet == testDataSetAll { assert.Equal(t, "[WARNING] `default.metric.to_be_removed` should not be enabled: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `optional.metric.empty_unit` should not be configured: This metric is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `string.resource.attr_disable_warning`: This resource_attribute will be disabled by default soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetAll || tt.resAttrsSet == testDataSetNone { assert.Equal(t, "[WARNING] `string.resource.attr_remove_warning` should not be configured: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } if tt.resAttrsSet == testDataSetDefault || tt.resAttrsSet == testDataSetAll { assert.Equal(t, "[WARNING] `string.resource.attr_to_be_removed` should not be enabled: This resource_attribute is deprecated and will be removed soon.", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } assert.Equal(t, expectedWarnings, observedLogs.Len()) defaultMetricsCount := 0 allMetricsCount := 0 defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricDataPoint(ts, 1, "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) defaultMetricsCount++ allMetricsCount++ mb.RecordDefaultMetricToBeRemovedDataPoint(ts, 1) defaultMetricsCount++ allMetricsCount++ mb.RecordMetricInputTypeDataPoint(ts, "1", "string_attr-val", 19, AttributeEnumAttrRed, []any{"slice_attr-item1", "slice_attr-item2"}, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}) allMetricsCount++ mb.RecordOptionalMetricDataPoint(ts, 1, "string_attr-val", true, false) allMetricsCount++ mb.RecordOptionalMetricEmptyUnitDataPoint(ts, 1, "string_attr-val", true) defaultMetricsCount++ allMetricsCount++ mb.RecordSystemCPUTimeDataPoint(ts, 1) rb := mb.NewResourceBuilder() rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() metrics := mb.Emit(WithResource(res)) if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } assert.Equal(t, 1, metrics.ResourceMetrics().Len()) rm := metrics.ResourceMetrics().At(0) assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) for i := 0; i < ms.Len(); i++ { switch ms.At(i).Name() { case "default.metric": assert.False(t, validatedMetrics["default.metric"], "Found a duplicate in the metrics slice: default.metric") validatedMetrics["default.metric"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "default.metric.to_be_removed": assert.False(t, validatedMetrics["default.metric.to_be_removed"], "Found a duplicate in the metrics slice: default.metric.to_be_removed") validatedMetrics["default.metric.to_be_removed"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Non-monotonic delta sum double metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.False(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityDelta, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) case "metric.input_type": assert.False(t, validatedMetrics["metric.input_type"], "Found a duplicate in the metrics slice: metric.input_type") validatedMetrics["metric.input_type"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric with string input_type enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("state") assert.True(t, ok) assert.EqualValues(t, 19, attrVal.Int()) attrVal, ok = dp.Attributes().Get("enum_attr") assert.True(t, ok) assert.Equal(t, "red", attrVal.Str()) attrVal, ok = dp.Attributes().Get("slice_attr") assert.True(t, ok) assert.Equal(t, []any{"slice_attr-item1", "slice_attr-item2"}, attrVal.Slice().AsRaw()) attrVal, ok = dp.Attributes().Get("map_attr") assert.True(t, ok) assert.Equal(t, map[string]any{"key1": "map_attr-val1", "key2": "map_attr-val2"}, attrVal.Map().AsRaw()) case "optional.metric": assert.False(t, validatedMetrics["optional.metric"], "Found a duplicate in the metrics slice: optional.metric") validatedMetrics["optional.metric"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Equal(t, "1", ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) attrVal, ok = dp.Attributes().Get("boolean_attr2") assert.True(t, ok) assert.False(t, attrVal.Bool()) case "optional.metric.empty_unit": assert.False(t, validatedMetrics["optional.metric.empty_unit"], "Found a duplicate in the metrics slice: optional.metric.empty_unit") validatedMetrics["optional.metric.empty_unit"] = true assert.Equal(t, pmetric.MetricTypeGauge, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Gauge().DataPoints().Len()) assert.Equal(t, "[DEPRECATED] Gauge double metric disabled by default.", ms.At(i).Description()) assert.Empty(t, ms.At(i).Unit()) dp := ms.At(i).Gauge().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeDouble, dp.ValueType()) assert.InDelta(t, float64(1), dp.DoubleValue(), 0.01) attrVal, ok := dp.Attributes().Get("string_attr") assert.True(t, ok) assert.Equal(t, "string_attr-val", attrVal.Str()) attrVal, ok = dp.Attributes().Get("boolean_attr") assert.True(t, ok) assert.True(t, attrVal.Bool()) case "system.cpu.time": assert.False(t, validatedMetrics["system.cpu.time"], "Found a duplicate in the metrics slice: system.cpu.time") validatedMetrics["system.cpu.time"] = true assert.Equal(t, pmetric.MetricTypeSum, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).Sum().DataPoints().Len()) assert.Equal(t, "Monotonic cumulative sum int metric enabled by default.", ms.At(i).Description()) assert.Equal(t, "s", ms.At(i).Unit()) assert.True(t, ms.At(i).Sum().IsMonotonic()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, ms.At(i).Sum().AggregationTemporality()) dp := ms.At(i).Sum().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueTypeInt, dp.ValueType()) assert.Equal(t, int64(1), dp.IntValue()) } } }) } } generated_resource.go000066400000000000000000000064261511331344600352570ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceBuilder is a helper struct to build resources predefined in metadata.yaml. // The ResourceBuilder is not thread-safe and must not to be used in multiple goroutines. type ResourceBuilder struct { config ResourceAttributesConfig res pcommon.Resource } // NewResourceBuilder creates a new ResourceBuilder. This method should be called on the start of the application. func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { return &ResourceBuilder{ config: rac, res: pcommon.NewResource(), } } // SetMapResourceAttr sets provided value as "map.resource.attr" attribute. func (rb *ResourceBuilder) SetMapResourceAttr(val map[string]any) { if rb.config.MapResourceAttr.Enabled { rb.res.Attributes().PutEmptyMap("map.resource.attr").FromRaw(val) } } // SetOptionalResourceAttr sets provided value as "optional.resource.attr" attribute. func (rb *ResourceBuilder) SetOptionalResourceAttr(val string) { if rb.config.OptionalResourceAttr.Enabled { rb.res.Attributes().PutStr("optional.resource.attr", val) } } // SetSliceResourceAttr sets provided value as "slice.resource.attr" attribute. func (rb *ResourceBuilder) SetSliceResourceAttr(val []any) { if rb.config.SliceResourceAttr.Enabled { rb.res.Attributes().PutEmptySlice("slice.resource.attr").FromRaw(val) } } // SetStringEnumResourceAttrOne sets "string.enum.resource.attr=one" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrOne() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "one") } } // SetStringEnumResourceAttrTwo sets "string.enum.resource.attr=two" attribute. func (rb *ResourceBuilder) SetStringEnumResourceAttrTwo() { if rb.config.StringEnumResourceAttr.Enabled { rb.res.Attributes().PutStr("string.enum.resource.attr", "two") } } // SetStringResourceAttr sets provided value as "string.resource.attr" attribute. func (rb *ResourceBuilder) SetStringResourceAttr(val string) { if rb.config.StringResourceAttr.Enabled { rb.res.Attributes().PutStr("string.resource.attr", val) } } // SetStringResourceAttrDisableWarning sets provided value as "string.resource.attr_disable_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrDisableWarning(val string) { if rb.config.StringResourceAttrDisableWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_disable_warning", val) } } // SetStringResourceAttrRemoveWarning sets provided value as "string.resource.attr_remove_warning" attribute. func (rb *ResourceBuilder) SetStringResourceAttrRemoveWarning(val string) { if rb.config.StringResourceAttrRemoveWarning.Enabled { rb.res.Attributes().PutStr("string.resource.attr_remove_warning", val) } } // SetStringResourceAttrToBeRemoved sets provided value as "string.resource.attr_to_be_removed" attribute. func (rb *ResourceBuilder) SetStringResourceAttrToBeRemoved(val string) { if rb.config.StringResourceAttrToBeRemoved.Enabled { rb.res.Attributes().PutStr("string.resource.attr_to_be_removed", val) } } // Emit returns the built resource and resets the internal builder state. func (rb *ResourceBuilder) Emit() pcommon.Resource { r := rb.res rb.res = pcommon.NewResource() return r } generated_resource_test.go000066400000000000000000000054211511331344600363100ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/assert" ) func TestResourceBuilder(t *testing.T) { for _, tt := range []string{"default", "all_set", "none_set"} { t.Run(tt, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt) rb := NewResourceBuilder(cfg) rb.SetMapResourceAttr(map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}) rb.SetOptionalResourceAttr("optional.resource.attr-val") rb.SetSliceResourceAttr([]any{"slice.resource.attr-item1", "slice.resource.attr-item2"}) rb.SetStringEnumResourceAttrOne() rb.SetStringResourceAttr("string.resource.attr-val") rb.SetStringResourceAttrDisableWarning("string.resource.attr_disable_warning-val") rb.SetStringResourceAttrRemoveWarning("string.resource.attr_remove_warning-val") rb.SetStringResourceAttrToBeRemoved("string.resource.attr_to_be_removed-val") res := rb.Emit() assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource switch tt { case "default": assert.Equal(t, 6, res.Attributes().Len()) case "all_set": assert.Equal(t, 8, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return default: assert.Failf(t, "unexpected test case: %s", tt) } val, ok := res.Attributes().Get("map.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, map[string]any{"key1": "map.resource.attr-val1", "key2": "map.resource.attr-val2"}, val.Map().AsRaw()) } val, ok = res.Attributes().Get("optional.resource.attr") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "optional.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("slice.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, []any{"slice.resource.attr-item1", "slice.resource.attr-item2"}, val.Slice().AsRaw()) } val, ok = res.Attributes().Get("string.enum.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "one", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_disable_warning") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_disable_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_remove_warning") assert.Equal(t, tt == "all_set", ok) if ok { assert.Equal(t, "string.resource.attr_remove_warning-val", val.Str()) } val, ok = res.Attributes().Get("string.resource.attr_to_be_removed") assert.True(t, ok) if ok { assert.Equal(t, "string.resource.attr_to_be_removed-val", val.Str()) } }) } } generated_status.go000066400000000000000000000005621511331344600347460ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("sample") ScopeName = "go.opentelemetry.io/collector/cmd/mdatagen/internal/samplescraper" ) const ( LogsStability = component.StabilityLevelDevelopment MetricsStability = component.StabilityLevelStable ) opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata/testdata/000077500000000000000000000000001511331344600327435ustar00rootroot00000000000000config.yaml000066400000000000000000000063401511331344600350200ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/internal/metadata/testdatadefault: all_set: metrics: default.metric: enabled: true default.metric.to_be_removed: enabled: true metric.input_type: enabled: true optional.metric: enabled: true optional.metric.empty_unit: enabled: true system.cpu.time: enabled: true resource_attributes: map.resource.attr: enabled: true optional.resource.attr: enabled: true slice.resource.attr: enabled: true string.enum.resource.attr: enabled: true string.resource.attr: enabled: true string.resource.attr_disable_warning: enabled: true string.resource.attr_remove_warning: enabled: true string.resource.attr_to_be_removed: enabled: true none_set: metrics: default.metric: enabled: false default.metric.to_be_removed: enabled: false metric.input_type: enabled: false optional.metric: enabled: false optional.metric.empty_unit: enabled: false system.cpu.time: enabled: false resource_attributes: map.resource.attr: enabled: false optional.resource.attr: enabled: false slice.resource.attr: enabled: false string.enum.resource.attr: enabled: false string.resource.attr: enabled: false string.resource.attr_disable_warning: enabled: false string.resource.attr_remove_warning: enabled: false string.resource.attr_to_be_removed: enabled: false filter_set_include: resource_attributes: map.resource.attr: enabled: true metrics_include: - regexp: ".*" optional.resource.attr: enabled: true metrics_include: - regexp: ".*" slice.resource.attr: enabled: true metrics_include: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_include: - regexp: ".*" string.resource.attr: enabled: true metrics_include: - regexp: ".*" string.resource.attr_disable_warning: enabled: true metrics_include: - regexp: ".*" string.resource.attr_remove_warning: enabled: true metrics_include: - regexp: ".*" string.resource.attr_to_be_removed: enabled: true metrics_include: - regexp: ".*" filter_set_exclude: resource_attributes: map.resource.attr: enabled: true metrics_exclude: - regexp: ".*" optional.resource.attr: enabled: true metrics_exclude: - strict: "optional.resource.attr-val" slice.resource.attr: enabled: true metrics_exclude: - regexp: ".*" string.enum.resource.attr: enabled: true metrics_exclude: - strict: "one" string.resource.attr: enabled: true metrics_exclude: - strict: "string.resource.attr-val" string.resource.attr_disable_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_disable_warning-val" string.resource.attr_remove_warning: enabled: true metrics_exclude: - strict: "string.resource.attr_remove_warning-val" string.resource.attr_to_be_removed: enabled: true metrics_exclude: - strict: "string.resource.attr_to_be_removed-val" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/samplescraper/metadata.yaml000066400000000000000000000120151511331344600302010ustar00rootroot00000000000000# Sample metadata file with all available configurations for a scraper. type: sample github_project: open-telemetry/opentelemetry-collector sem_conv_version: 1.37.0 status: disable_codecov_badge: true class: scraper stability: stable: [metrics] development: [logs] distributions: [] unsupported_platforms: [freebsd, illumos] codeowners: active: [dmitryax] warnings: - Any additional information that should be brought to the consumer's attention resource_attributes: map.resource.attr: description: Resource attribute with a map value. type: map enabled: true optional.resource.attr: description: Explicitly disabled ResourceAttribute. type: string enabled: false slice.resource.attr: description: Resource attribute with a slice value. type: slice enabled: true string.enum.resource.attr: description: Resource attribute with a known set of string values. type: string enum: [one, two] enabled: true string.resource.attr: description: Resource attribute with any string value. type: string enabled: true string.resource.attr_disable_warning: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled_not_set: This resource_attribute will be disabled by default soon. string.resource.attr_remove_warning: description: Resource attribute with any string value. type: string enabled: false warnings: if_configured: This resource_attribute is deprecated and will be removed soon. string.resource.attr_to_be_removed: description: Resource attribute with any string value. type: string enabled: true warnings: if_enabled: This resource_attribute is deprecated and will be removed soon. attributes: boolean_attr: description: Attribute with a boolean value. type: bool # This 2nd boolean attribute allows us to test both values for boolean attributes, # as test values are based on the parity of the attribute name length. boolean_attr2: description: Another attribute with a boolean value. type: bool enum_attr: description: Attribute with a known set of string values. type: string enum: [red, green, blue] map_attr: description: Attribute with a map value. type: map overridden_int_attr: name_override: state description: Integer attribute with overridden name. type: int slice_attr: description: Attribute with a slice value. type: slice string_attr: description: Attribute with any string value. type: string metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr] warnings: if_enabled_not_set: This metric will be disabled by default soon. default.metric.to_be_removed: enabled: true description: "[DEPRECATED] Non-monotonic delta sum double metric enabled by default." extended_documentation: The metric will be removed soon. stability: level: deprecated unit: s sum: value_type: double monotonic: false aggregation_temporality: delta warnings: if_enabled: This metric is deprecated and will be removed soon. metric.input_type: enabled: true stability: level: development description: Monotonic cumulative sum int metric with string input_type enabled by default. unit: s sum: value_type: int input_type: string monotonic: true aggregation_temporality: cumulative attributes: [string_attr, overridden_int_attr, enum_attr, slice_attr, map_attr] optional.metric: enabled: false description: "[DEPRECATED] Gauge double metric disabled by default." stability: level: deprecated unit: "1" gauge: value_type: double attributes: [string_attr, boolean_attr, boolean_attr2] warnings: if_configured: This metric is deprecated and will be removed soon. optional.metric.empty_unit: enabled: false description: "[DEPRECATED] Gauge double metric disabled by default." stability: level: deprecated unit: "" gauge: value_type: double attributes: [string_attr, boolean_attr] warnings: if_configured: This metric is deprecated and will be removed soon. system.cpu.time: enabled: true stability: level: beta description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative semantic_convention: ref: https://github.com/open-telemetry/semantic-conventions/blob/v1.37.0/docs/system/system-metrics.md#metric-systemcputime opentelemetry-collector-0.141.0/cmd/mdatagen/internal/status.go000066400000000000000000000122561511331344600245550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" import ( "errors" "fmt" "slices" "sort" "time" "go.opentelemetry.io/collector/component" ) // distroURL returns the collection of distributions that can be referenced in the metadata.yaml files. // The rules below apply to every distribution added to this list: // - The distribution is open source and maintained by the OpenTelemetry project. // - The link must point to a publicly accessible repository. func distroURL(name string) string { switch name { case "core": return "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol" case "contrib": return "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib" case "k8s": return "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-k8s" case "otlp": return "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp" default: return "" } } type Codeowners struct { // Active codeowners Active []string `mapstructure:"active"` // Emeritus codeowners Emeritus []string `mapstructure:"emeritus"` // Whether new codeowners are being sought SeekingNew bool `mapstructure:"seeking_new"` } type Status struct { Stability StabilityMap `mapstructure:"stability"` Distributions []string `mapstructure:"distributions"` Class string `mapstructure:"class"` Warnings []string `mapstructure:"warnings"` Codeowners *Codeowners `mapstructure:"codeowners"` UnsupportedPlatforms []string `mapstructure:"unsupported_platforms"` Deprecation DeprecationMap `mapstructure:"deprecation"` CodeCovComponentID string `mapstructure:"codecov_component_id"` DisableCodeCov bool `mapstructure:"disable_codecov_badge"` } type DeprecationMap map[string]DeprecationInfo type DeprecationInfo struct { Date string `mapstructure:"date"` Migration string `mapstructure:"migration"` } var validClasses = []string{ "cmd", "connector", "converter", "exporter", "extension", "pkg", "processor", "provider", "receiver", "scraper", } var validStabilityKeys = []string{ "converter", "extension", "logs", "logs_to_traces", "logs_to_metrics", "logs_to_logs", "logs_to_profiles", "metrics", "metrics_to_traces", "metrics_to_metrics", "metrics_to_logs", "metrics_to_profiles", "profiles", "profiles_to_profiles", "profiles_to_traces", "profiles_to_metrics", "profiles_to_logs", "provider", "traces_to_traces", "traces_to_metrics", "traces_to_logs", "traces_to_profiles", "traces", } func (s *Status) SortedDistributions() []string { sorted := s.Distributions sort.Slice(sorted, func(i, j int) bool { if s.Distributions[i] == "core" { return true } if s.Distributions[i] == "contrib" { return s.Distributions[j] != "core" } if s.Distributions[j] == "core" { return false } if s.Distributions[j] == "contrib" { return s.Distributions[i] == "core" } return s.Distributions[i] < s.Distributions[j] }) return sorted } func (s *Status) Validate() error { var errs error if s == nil { return errors.New("missing status") } if err := s.validateClass(); err != nil { errs = errors.Join(errs, err) } if err := s.Stability.Validate(); err != nil { errs = errors.Join(errs, err) } if err := s.Deprecation.Validate(s.Stability); err != nil { errs = errors.Join(errs, err) } return errs } func (s *Status) validateClass() error { if s.Class == "" { return errors.New("missing class") } if !slices.Contains(validClasses, s.Class) { return fmt.Errorf("invalid class: %v", s.Class) } return nil } type StabilityMap map[component.StabilityLevel][]string func (ms StabilityMap) Validate() error { var errs error if len(ms) == 0 { return errors.New("missing stability") } for stability, cmps := range ms { if len(cmps) == 0 { errs = errors.Join(errs, fmt.Errorf("missing component for stability: %v", stability)) } for _, c := range cmps { if !slices.Contains(validStabilityKeys, c) { errs = errors.Join(errs, fmt.Errorf("invalid component: %v", c)) } } } return errs } func (dm DeprecationMap) Validate(ms StabilityMap) error { var errs error for stability, cmps := range ms { if stability != component.StabilityLevelDeprecated { continue } for _, c := range cmps { depInfo, found := dm[c] if !found { errs = errors.Join(errs, fmt.Errorf("deprecated component missing deprecation date and migration guide for %v", c)) continue } if depInfo.Migration == "" { errs = errors.Join(errs, fmt.Errorf("deprecated component missing migration guide: %v", c)) } if depInfo.Date == "" { errs = errors.Join(errs, fmt.Errorf("deprecated component missing date in YYYY-MM-DD format: %v", c)) } else { _, err := time.Parse("2006-01-02", depInfo.Date) if err != nil { errs = errors.Join(errs, fmt.Errorf("deprecated component missing valid date in YYYY-MM-DD format: %v", c)) } } } } return errs } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/status_test.go000066400000000000000000000042171511331344600256120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" ) func TestDistroURL(t *testing.T) { tests := []struct { input string output string }{ { input: "core", output: "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol", }, { input: "contrib", output: "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib", }, { input: "k8s", output: "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-k8s", }, { input: "otlp", output: "https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp", }, { input: "not_found", output: "", }, } for _, test := range tests { t.Run(test.input, func(t *testing.T) { assert.Equal(t, test.output, distroURL(test.input)) }) } } func TestSortedDistributions(t *testing.T) { tests := []struct { name string s Status result []string }{ { "all combined", Status{Distributions: []string{"arm", "contrib", "core", "foo", "bar"}}, []string{"core", "contrib", "arm", "bar", "foo"}, }, { "core only", Status{Distributions: []string{"core"}}, []string{"core"}, }, { "core and contrib only", Status{Distributions: []string{"core", "contrib"}}, []string{"core", "contrib"}, }, { "core and contrib reversed", Status{Distributions: []string{"contrib", "core"}}, []string{"core", "contrib"}, }, { "neither core nor contrib", Status{Distributions: []string{"foo", "bar"}}, []string{"bar", "foo"}, }, { "no core, contrib, something else", Status{Distributions: []string{"foo", "contrib", "bar"}}, []string{"contrib", "bar", "foo"}, }, { "core, no contrib, something else", Status{Distributions: []string{"foo", "core", "bar"}}, []string{"core", "bar", "foo"}, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { assert.Equal(t, test.result, test.s.SortedDistributions()) }) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/telemetry.go000066400000000000000000000003631511331344600252400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" type Telemetry struct { Metrics map[MetricName]Metric `mapstructure:"metrics"` } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/000077500000000000000000000000001511331344600246735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/component_test.go.tmpl000066400000000000000000000474631511331344600312540ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. {{- if len .Status.UnsupportedPlatforms }} //go:build {{ range $i, $v := .Status.UnsupportedPlatforms }}{{ if $i }} && {{ end }}!{{ . }}{{ end }} {{- end }} package {{ .Package }} import ( {{- if not (and .Tests.SkipLifecycle .Tests.SkipShutdown) }} "context" {{- end }} "testing" {{- if and (not (and .Tests.SkipLifecycle .Tests.SkipShutdown)) (or isExporter isProcessor) }} "time" {{- end }} "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" {{- if not (and .Tests.SkipLifecycle .Tests.SkipShutdown) }} "go.opentelemetry.io/collector/confmap/confmaptest" {{- if isExporter }} "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" {{- end }} {{- if isProcessor }} "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" {{- end }} {{- if isReceiver }} "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" {{- end }} {{- if isScraper }} "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapertest" {{- end }} {{- if isExtension }} "go.opentelemetry.io/collector/extension/extensiontest" {{- end }} {{- if isConnector }} "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pipeline" {{- end }} {{- if or isExporter isProcessor }} "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" {{- end }} {{- end }} ) var typ = component.MustNewType("{{ .Type }}") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } {{ if not (and .Tests.SkipLifecycle .Tests.SkipShutdown) -}} {{ if isExporter -}} func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct{ createFn func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) name string }{ {{ if supportsLogs }} { name: "logs", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg) }, }, {{ end }} {{ if supportsMetrics }} { name: "metrics", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg) }, }, {{ end }} {{ if supportsTraces }} { name: "traces", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg) }, }, {{ end }} } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { {{- if not .Tests.SkipShutdown }} t.Run(tt.name + "-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} {{- if not .Tests.SkipLifecycle }} t.Run(tt.name + "-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := {{ .Tests.Host }} err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(exporter.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(exporter.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(exporter.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) {{ if not expectConsumerError }} require.NoError(t, err) {{ end }} err = c.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} } } {{ end }} {{ if isProcessor }} func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct{ createFn func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) name string }{ {{ if supportsLogs }} { name: "logs", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, {{ end }} {{ if supportsMetrics }} { name: "metrics", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, {{ end }} {{ if supportsTraces }} { name: "traces", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, {{ end }} } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { {{- if not .Tests.SkipShutdown }} t.Run(tt.name + "-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} {{- if not .Tests.SkipLifecycle }} t.Run(tt.name + "-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) host := {{ .Tests.Host }} err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(processor.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(processor.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(processor.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} } } {{ end }} {{ if isReceiver }} func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct{ createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) name string }{ {{ if supportsLogs }} { name: "logs", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, {{ end }} {{ if supportsMetrics }} { name: "metrics", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, {{ end }} {{ if supportsTraces }} { name: "traces", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, {{ end }} } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { {{- if not .Tests.SkipShutdown }} t.Run(tt.name + "-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} {{- if not .Tests.SkipLifecycle }} t.Run(tt.name + "-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := {{ .Tests.Host }} require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) {{- end }} } } {{ end }} {{ if isScraper }} func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct{ createFn func(ctx context.Context, set scraper.Settings, cfg component.Config) (component.Component, error) name string }{ {{ if supportsLogs }} { name: "logs", createFn: func(ctx context.Context, set scraper.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg) }, }, {{ end }} {{ if supportsMetrics }} { name: "metrics", createFn: func(ctx context.Context, set scraper.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg) }, }, {{ end }} {{ if supportsTraces }} { name: "traces", createFn: func(ctx context.Context, set scraper.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg) }, }, {{ end }} } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { {{- if not .Tests.SkipShutdown }} t.Run(tt.name + "-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), scrapertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} {{- if not .Tests.SkipLifecycle }} t.Run(tt.name + "-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), scrapertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := {{ .Tests.Host }} require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), scrapertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) {{- end }} } } {{ end }} {{ if isExtension }} func TestComponentLifecycle(t *testing.T) { factory := NewFactory() cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) {{- if not .Tests.SkipShutdown }} t.Run("shutdown", func(t *testing.T) { e, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) err = e.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} {{- if not .Tests.SkipLifecycle }} t.Run("lifecycle", func(t *testing.T) { firstExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, firstExt.Start(context.Background(), {{ .Tests.Host }})) require.NoError(t, firstExt.Shutdown(context.Background())) secondExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondExt.Start(context.Background(), {{ .Tests.Host }})) require.NoError(t, secondExt.Shutdown(context.Background())) }) {{- end }} } {{ end }} {{ if isConnector }} func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct{ createFn func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) name string }{ {{ if supportsLogsToLogs }} { name: "logs_to_logs", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewLogsRouter(map[pipeline.ID]consumer.Logs{pipeline.NewID(pipeline.SignalLogs): consumertest.NewNop()}) return factory.CreateLogsToLogs(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsLogsToMetrics }} { name: "logs_to_metrics", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewMetricsRouter(map[pipeline.ID]consumer.Metrics{pipeline.NewID(pipeline.SignalMetrics): consumertest.NewNop()}) return factory.CreateLogsToMetrics(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsLogsToTraces }} { name: "logs_to_traces", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewTracesRouter(map[pipeline.ID]consumer.Traces{pipeline.NewID(pipeline.SignalTraces): consumertest.NewNop()}) return factory.CreateLogsToTraces(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsMetricsToLogs }} { name: "metrics_to_logs", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewLogsRouter(map[pipeline.ID]consumer.Logs{pipeline.NewID(pipeline.SignalLogs): consumertest.NewNop()}) return factory.CreateMetricsToLogs(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsMetricsToMetrics }} { name: "metrics_to_metrics", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewMetricsRouter(map[pipeline.ID]consumer.Metrics{pipeline.NewID(pipeline.SignalMetrics): consumertest.NewNop()}) return factory.CreateMetricsToMetrics(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsMetricsToTraces }} { name: "metrics_to_traces", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewTracesRouter(map[pipeline.ID]consumer.Traces{pipeline.NewID(pipeline.SignalTraces): consumertest.NewNop()}) return factory.CreateMetricsToTraces(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsTracesToLogs }} { name: "traces_to_logs", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewLogsRouter(map[pipeline.ID]consumer.Logs{pipeline.NewID(pipeline.SignalLogs): consumertest.NewNop()}) return factory.CreateTracesToLogs(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsTracesToMetrics }} { name: "traces_to_metrics", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewMetricsRouter(map[pipeline.ID]consumer.Metrics{pipeline.NewID(pipeline.SignalMetrics): consumertest.NewNop()}) return factory.CreateTracesToMetrics(ctx, set, cfg, router) }, }, {{ end }} {{ if supportsTracesToTraces }} { name: "traces_to_traces", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewTracesRouter(map[pipeline.ID]consumer.Traces{pipeline.NewID(pipeline.SignalTraces): consumertest.NewNop()}) return factory.CreateTracesToTraces(ctx, set, cfg, router) }, }, {{ end }} } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { {{- if not .Tests.SkipShutdown }} t.Run(tt.name + "-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) {{- end }} {{- if not .Tests.SkipLifecycle }} t.Run(tt.name + "-lifecycle", func(t *testing.T) { firstConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) host := {{ .Tests.Host }} require.NoError(t, err) require.NoError(t, firstConnector.Start(context.Background(), host)) require.NoError(t, firstConnector.Shutdown(context.Background())) secondConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondConnector.Start(context.Background(), host)) require.NoError(t, secondConnector.Shutdown(context.Background())) }) {{- end }} } } {{ end }} {{ if or isExporter isProcessor -}} func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } {{- end }} {{- end }} {{- if not .Tests.SkipLifecycle }} var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/config.go.tmpl000066400000000000000000000117051511331344600274460ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "go.opentelemetry.io/collector/confmap" {{ if and .Metrics .ResourceAttributes -}} "go.opentelemetry.io/collector/filter" {{- end }} ) {{ if .Metrics -}} // MetricConfig provides common config for a particular metric. type MetricConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ms *MetricConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ms) if err != nil { return err } ms.enabledSetByUser = parser.IsSet("enabled") return nil } // MetricsConfig provides config for {{ .Type }} metrics. type MetricsConfig struct { {{- range $name, $metric := .Metrics }} {{ $name.Render }} MetricConfig `mapstructure:"{{ $name }}"` {{- end }} } func DefaultMetricsConfig() MetricsConfig { return MetricsConfig{ {{- range $name, $metric := .Metrics }} {{ $name.Render }}: MetricConfig{ Enabled: {{ $metric.Enabled }}, }, {{- end }} } } {{- end }} {{ if .Events }} // EventConfig provides common config for a particular event. type EventConfig struct { Enabled bool `mapstructure:"enabled"` enabledSetByUser bool } func (ec *EventConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(ec) if err != nil { return err } ec.enabledSetByUser = parser.IsSet("enabled") return nil } // EventsConfig provides config for {{ .Type }} events. type EventsConfig struct { {{- range $name, $event := .Events }} {{ $name.Render }} EventConfig `mapstructure:"{{ $name }}"` {{- end }} } func DefaultEventsConfig() EventsConfig { return EventsConfig{ {{- range $name, $event := .Events }} {{ $name.Render }}: EventConfig{ Enabled: {{ $event.Enabled }}, }, {{- end }} } } {{- end }} {{ if .ResourceAttributes -}} // ResourceAttributeConfig provides common config for a particular resource attribute. type ResourceAttributeConfig struct { Enabled bool `mapstructure:"enabled"` {{- if .Metrics }} // Experimental: MetricsInclude defines a list of filters for attribute values. // If the list is not empty, only metrics with matching resource attribute values will be emitted. MetricsInclude []filter.Config `mapstructure:"metrics_include"` // Experimental: MetricsExclude defines a list of filters for attribute values. // If the list is not empty, metrics with matching resource attribute values will not be emitted. // MetricsInclude has higher priority than MetricsExclude. MetricsExclude []filter.Config `mapstructure:"metrics_exclude"` {{- end }} {{- if .Events }} // Experimental: EventsInclude defines a list of filters for attribute values. // If the list is not empty, only events with matching resource attribute values will be emitted. EventsInclude []filter.Config `mapstructure:"events_include"` // Experimental: EventsExclude defines a list of filters for attribute values. // If the list is not empty, events with matching resource attribute values will not be emitted. // EventsInclude has higher priority than EventsExclude. EventsExclude []filter.Config `mapstructure:"events_exclude"` {{- end }} enabledSetByUser bool } func (rac *ResourceAttributeConfig) Unmarshal(parser *confmap.Conf) error { if parser == nil { return nil } err := parser.Unmarshal(rac) if err != nil { return err } rac.enabledSetByUser = parser.IsSet("enabled") return nil } // ResourceAttributesConfig provides config for {{ .Type }} resource attributes. type ResourceAttributesConfig struct { {{- range $name, $attr := .ResourceAttributes }} {{ $name.Render }} ResourceAttributeConfig `mapstructure:"{{ $name }}"` {{- end }} } func DefaultResourceAttributesConfig() ResourceAttributesConfig { return ResourceAttributesConfig{ {{- range $name, $attr := .ResourceAttributes }} {{ $name.Render }}: ResourceAttributeConfig { Enabled: {{ $attr.Enabled }}, }, {{- end }} } } {{- end }} {{ if .Metrics -}} // MetricsBuilderConfig is a configuration for {{ .Type }} metrics builder. type MetricsBuilderConfig struct { Metrics MetricsConfig `mapstructure:"metrics"` {{- if .ResourceAttributes }} ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` {{- end }} } func DefaultMetricsBuilderConfig() MetricsBuilderConfig { return MetricsBuilderConfig { Metrics: DefaultMetricsConfig(), {{- if .ResourceAttributes }} ResourceAttributes: DefaultResourceAttributesConfig(), {{- end }} } } {{- end }} {{ if .Events -}} // LogsBuilderConfig is a configuration for {{ .Type }} logs builder. type LogsBuilderConfig struct { Events EventsConfig `mapstructure:"events"` {{- if .ResourceAttributes }} ResourceAttributes ResourceAttributesConfig `mapstructure:"resource_attributes"` {{- end }} } func DefaultLogsBuilderConfig() LogsBuilderConfig { return LogsBuilderConfig { Events: DefaultEventsConfig(), {{- if .ResourceAttributes }} ResourceAttributes: DefaultResourceAttributesConfig(), {{- end }} } } {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/config_test.go.tmpl000066400000000000000000000073741511331344600305140ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "path/filepath" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) {{ if .Metrics }} func TestMetricsBuilderConfig(t *testing.T) { tests := []struct { name string want MetricsBuilderConfig }{ { name: "default", want: DefaultMetricsBuilderConfig(), }, { name: "all_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ {{- range $name, $_ := .Metrics }} {{ $name.Render }}: MetricConfig{Enabled: true}, {{- end }} }, {{- if .ResourceAttributes }} ResourceAttributes: ResourceAttributesConfig{ {{- range $name, $_ := .ResourceAttributes }} {{ $name.Render }}: ResourceAttributeConfig{Enabled: true}, {{- end }} }, {{- end }} }, }, { name: "none_set", want: MetricsBuilderConfig{ Metrics: MetricsConfig{ {{- range $name, $_ := .Metrics }} {{ $name.Render }}: MetricConfig{Enabled: false}, {{- end }} }, {{- if .ResourceAttributes }} ResourceAttributes: ResourceAttributesConfig{ {{- range $name, $_ := .ResourceAttributes }} {{ $name.Render }}: ResourceAttributeConfig{Enabled: false}, {{- end }} }, {{- end }} }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadMetricsBuilderConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(MetricConfig{} {{- if .ResourceAttributes }}, ResourceAttributeConfig{}{{ end }})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadMetricsBuilderConfig(t *testing.T, name string) MetricsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultMetricsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } {{- end }} {{ if .Events }} func loadLogsBuilderConfig(t *testing.T, name string) LogsBuilderConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) cfg := DefaultLogsBuilderConfig() require.NoError(t, sub.Unmarshal(&cfg, confmap.WithIgnoreUnused())) return cfg } {{- end }} {{ if .ResourceAttributes -}} func TestResourceAttributesConfig(t *testing.T) { tests := []struct { name string want ResourceAttributesConfig }{ { name: "default", want: DefaultResourceAttributesConfig(), }, { name: "all_set", want: ResourceAttributesConfig{ {{- range $name, $_ := .ResourceAttributes }} {{ $name.Render }}: ResourceAttributeConfig{Enabled: true}, {{- end }} }, }, { name: "none_set", want: ResourceAttributesConfig{ {{- range $name, $_ := .ResourceAttributes }} {{ $name.Render }}: ResourceAttributeConfig{Enabled: false}, {{- end }} }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt.name) diff := cmp.Diff(tt.want, cfg, cmpopts.IgnoreUnexported(ResourceAttributeConfig{})) require.Emptyf(t, diff, "Config mismatch (-expected +actual):\n%s", diff) }) } } func loadResourceAttributesConfig(t *testing.T, name string) ResourceAttributesConfig { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) sub, err := cm.Sub(name) require.NoError(t, err) sub, err = sub.Sub("resource_attributes") require.NoError(t, err) cfg := DefaultResourceAttributesConfig() require.NoError(t, sub.Unmarshal(&cfg)) return cfg } {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/documentation.md.tmpl000066400000000000000000000155311511331344600310460ustar00rootroot00000000000000{{- define "metric-documentation" -}} {{- $metricName := . }} {{- $metric := $metricName | metricInfo -}} ### {{ $metricName }} {{ $metric.Description }} {{- if $metric.ExtendedDocumentation }} {{ $metric.ExtendedDocumentation }} {{- end }} | Unit | Metric Type | Value Type |{{ if $metric.Data.HasAggregated }} Aggregation Temporality |{{ end }}{{ if $metric.Data.HasMonotonic }} Monotonic |{{ end }}{{ if $metric.Stability.Level }} Stability |{{ end }}{{ if $metric.SemanticConvention }} Semantic Convention |{{ end }} | ---- | ----------- | ---------- |{{ if $metric.Data.HasAggregated }} ----------------------- |{{ end }}{{ if $metric.Data.HasMonotonic }} --------- |{{ end }}{{ if $metric.Stability.Level }} --------- |{{ end }}{{ if $metric.SemanticConvention }} ------------------- |{{ end }} | {{ $metric.Unit }} | {{ $metric.Data.Type }} | {{ $metric.Data.MetricValueType }} | {{- if $metric.Data.HasAggregated }} {{ $metric.Data.AggregationTemporality }} |{{ end }} {{- if $metric.Data.HasMonotonic }} {{ $metric.Data.Monotonic }} |{{ end }} {{- if $metric.Stability.Level }} {{ $metric.Stability.Level }} |{{ end }} {{- if $metric.SemanticConvention }} [{{ $metricName }}]({{ $metric.SemanticConvention.SemanticConventionRef }}) |{{ end }} {{- if $metric.Attributes }} #### Attributes | Name | Description | Values | Requirement Level | | ---- | ----------- | ------ | -------- | {{- range $metric.Attributes }} {{- $attribute := . | attributeInfo }} | {{ $attribute.Name }} | {{ $attribute.Description }} | {{- if $attribute.Enum }} {{ $attribute.Type }}: ``{{ stringsJoin $attribute.Enum "``, ``" }}``{{ else }} Any {{ $attribute.Type }}{{ end }} | {{ $attribute.RequirementLevel }} | {{- end }} {{- end }} {{- end -}} {{- define "event-documentation" -}} {{- $eventName := . }} {{- $event := $eventName | eventInfo -}} ### {{ $eventName }} {{ $event.Description }} {{- if $event.ExtendedDocumentation }} {{ $event.ExtendedDocumentation }} {{- end }} {{- if $event.Attributes }} #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | {{- range $event.Attributes }} {{- $attribute := . | attributeInfo }} | {{ $attribute.Name }} | {{ $attribute.Description }} | {{- if $attribute.Enum }} {{ $attribute.Type }}: ``{{ stringsJoin $attribute.Enum "``, ``" }}``{{ else }} Any {{ $attribute.Type }}{{ end }} | {{- end }} {{- end }} {{- end -}} {{- define "telemetry-documentation" -}} {{- $metricName := . }} {{- $metric := $metricName | telemetryInfo -}} ### {{ if $metric.Prefix -}}{{ $metric.Prefix }}{{- else -}}otelcol_{{- end -}}{{ $metricName }} {{ $metric.Description }}{{ $metric.Stability }} {{- if $metric.ExtendedDocumentation }} {{ $metric.ExtendedDocumentation }} {{- end }} | Unit | Metric Type | Value Type |{{ if $metric.Data.HasMonotonic }} Monotonic |{{ end }}{{ if $metric.Stability.Level }} Stability |{{ end }}{{ if $metric.SemanticConvention }} Semantic Convention |{{ end }} | ---- | ----------- | ---------- |{{ if $metric.Data.HasMonotonic }} --------- |{{ end }}{{ if $metric.Stability.Level }} --------- |{{ end }}{{ if $metric.SemanticConvention }} ------------------- |{{ end }} | {{ $metric.Unit }} | {{ $metric.Data.Type }} | {{ $metric.Data.MetricValueType }} | {{- if $metric.Data.HasMonotonic }} {{ $metric.Data.Monotonic }} |{{ end }} {{- if $metric.Stability.Level }} {{ $metric.Stability.Level }} |{{ end }} {{- if $metric.SemanticConvention }} [{{ $metricName }}]({{ $metric.SemanticConvention.SemanticConventionRef }}) |{{ end }} {{- if $metric.Attributes }} #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | {{- range $metric.Attributes }} {{- $attribute := . | attributeInfo }} | {{ $attribute.Name }} | {{ $attribute.Description }} | {{- if $attribute.Enum }} {{ $attribute.Type }}: ``{{ stringsJoin $attribute.Enum "``, ``" }}``{{ else }} Any {{ $attribute.Type }}{{ end }} | {{- end }} {{- end }} {{- end -}} [comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # {{ .Type }} {{- if .Parent }} **Parent Component:** {{ .Parent }} {{- end }} {{- if .Metrics }} ## Default Metrics The following metrics are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml metrics: : enabled: false ``` {{- end }} {{- range $metricName, $metric := .Metrics }} {{- if $metric.Enabled }} {{ template "metric-documentation" $metricName }} {{- end }} {{- end }} {{- $optionalMetricSeen := false }} {{- range $metricName, $metric := .Metrics }} {{- if not $metric.Enabled }} {{- if not $optionalMetricSeen }} ## Optional Metrics The following metrics are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml metrics: : enabled: true ``` {{- end }} {{- $optionalMetricSeen = true }} {{ template "metric-documentation" $metricName }} {{- end }} {{- end }} {{- if .Events }} ## Default Events The following events are emitted by default. Each of them can be disabled by applying the following configuration: ```yaml events: : enabled: false ``` {{- range $eventName, $event := .Events }} {{- if $event.Enabled }} {{ template "event-documentation" $eventName }} {{- end }} {{- end }} {{- end }} {{- $optionalEventSeen := false }} {{- range $eventName, $event := .Events }} {{- if not $event.Enabled }} {{- if not $optionalEventSeen }} ## Optional Events The following events are not emitted by default. Each of them can be enabled by applying the following configuration: ```yaml events: : enabled: true ``` {{- end }} {{- $optionalEventSeen = true }} {{ template "event-documentation" $eventName }} {{- end }} {{- end }} {{- if .ResourceAttributes }} ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | {{- range $attributeName, $attribute := .ResourceAttributes }} | {{ $attributeName }} | {{ $attribute.Description }} | {{- if $attribute.Enum }} {{ $attribute.Type }}: ``{{ stringsJoin $attribute.Enum "``, ``" }}``{{ else }} Any {{ $attribute.Type }}{{ end }} | {{ $attribute.Enabled }} | {{- end }} {{- end }} {{- if .Entities }} ## Entities The following entities are defined for this component: {{- range $entity := .Entities }} ### {{ $entity.Type }} {{ $entity.Brief }} {{- if $entity.Stability }} **Stability:** {{ $entity.Stability }} {{- end }} {{- if $entity.Identity }} **Identity Attributes:** {{- range $entity.Identity }} - `{{ .Ref }}` {{- end }} {{- end }} {{- if $entity.Description }} **Description Attributes:** {{- range $entity.Description }} - `{{ .Ref }}` {{- end }} {{- end }} {{- end }} {{- end }} {{- if .Telemetry.Metrics }} ## Internal Telemetry The following telemetry is emitted by this component. {{- range $metricName, $metric := .Telemetry.Metrics }} {{- if $metric.Enabled }} {{ template "telemetry-documentation" $metricName }} {{- end }} {{- end }} {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/helper.tmpl000066400000000000000000000016101511331344600270460ustar00rootroot00000000000000{{- define "putAttribute" -}} {{- if eq (attributeInfo .).Type.Primitive "[]byte" }} dp.Attributes().PutEmptyBytes("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) {{- else if eq (attributeInfo .).Type.Primitive "[]any" }} dp.Attributes().PutEmptySlice("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) {{- else if eq (attributeInfo .).Type.Primitive "map[string]any" }} dp.Attributes().PutEmptyMap("{{ (attributeInfo .).Name }}").FromRaw({{ .RenderUnexported }}AttributeValue) {{- else }} dp.Attributes().Put{{ (attributeInfo .).Type }}("{{ (attributeInfo .).Name }}", {{ .RenderUnexported }}AttributeValue) {{- end }} {{- end -}} {{- define "getAttributeValue" -}} {{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ (index (attributeInfo .).Enum 0) | publicVar }}{{ else }}{{ (attributeInfo .).TestValue }}{{ end }} {{- end -}} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/logs.go.tmpl000066400000000000000000000243321511331344600271450ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" {{- if or isReceiver isScraper }} "go.opentelemetry.io/collector/{{ .Status.Class }}" {{- end }} {{- if .SemConvVersion }} conventions "go.opentelemetry.io/otel/semconv/v{{ .SemConvVersion }}" {{- end }} {{- if .Events }} "context" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/filter" {{- end }} ) {{ if getEventConditionalAttributes .Attributes }} type EventAttributeOption interface { apply(plog.LogRecord) } type eventAttributeOptionFunc func(plog.LogRecord) func (eaof eventAttributeOptionFunc) apply(lr plog.LogRecord) { eaof(lr) } {{ range getEventConditionalAttributes .Attributes }} func With{{ .Render }}EventAttribute({{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}) EventAttributeOption { return eventAttributeOptionFunc(func(dp plog.LogRecord) { {{- template "putAttribute" . }} }) } {{ end }} {{ end }} {{ range $name, $event := .Events -}} type event{{ $name.Render }} struct { data plog.LogRecordSlice // data buffer for generated log records. config EventConfig // event config provided by user. } func (e *event{{ $name.Render }}) recordEvent(ctx context.Context, timestamp pcommon.Timestamp {{- range $event.Attributes -}}{{- if not (attributeInfo .).IsConditional -}}, {{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}{{ end }}{{end}}{{- if $event.HasConditionalAttributes $.Attributes -}}, options ...EventAttributeOption{{- end -}}) { if !e.config.Enabled { return } dp := e.data.AppendEmpty() dp.SetEventName("{{ $name }}") dp.SetTimestamp(timestamp) if span := trace.SpanContextFromContext(ctx); span.IsValid() { dp.SetTraceID(pcommon.TraceID(span.TraceID())) dp.SetSpanID(pcommon.SpanID(span.SpanID())) } {{- range $event.Attributes }} {{- if not (attributeInfo .).IsConditional -}} {{- template "putAttribute" . }} {{- end }} {{- end }} {{ if $event.HasConditionalAttributes $.Attributes }} for _, op := range options { op.apply(dp) } {{- end }} } // emit appends recorded event data to a events slice and prepares it for recording another set of log records. func (e *event{{ $name.Render }}) emit(lrs plog.LogRecordSlice) { if e.config.Enabled && e.data.Len() > 0 { e.data.MoveAndAppendTo(lrs) } } func newEvent{{ $name.Render }}(cfg EventConfig) event{{ $name.Render }} { e := event{{ $name.Render }}{config: cfg} if cfg.Enabled { e.data = plog.NewLogRecordSlice() } return e } {{ end -}} // LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations // required to produce log representation defined in metadata and user config. type LogsBuilder struct { {{- if .Events }} config LogsBuilderConfig // config of the logs builder. {{- end }} logsBuffer plog.Logs logRecordsBuffer plog.LogRecordSlice buildInfo component.BuildInfo // contains version information. {{- if and .Events .ResourceAttributes }} resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter {{- end }} {{- range $name, $event := .Events }} event{{ $name.Render }} event{{ $name.Render }} {{- end }} } // LogBuilderOption applies changes to default logs builder. type LogBuilderOption interface { apply(*LogsBuilder) } {{- if or isReceiver isScraper }} func NewLogsBuilder({{ if .Events }}lbc LogsBuilderConfig, {{ end }}settings {{ .Status.Class }}.Settings) *LogsBuilder { {{- range $name, $event := .Events }} {{- if $event.Warnings.IfEnabled }} if lbc.Events.{{ $name.Render }}.Enabled { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be enabled: {{ $event.Warnings.IfEnabled }}") } {{- end }} {{- if $event.Warnings.IfEnabledNotSet }} if !lbc.Events.{{ $name.Render }}.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $event.Warnings.IfEnabledNotSet }}") } {{- end }} {{- if $event.Warnings.IfConfigured }} if lbc.Events.{{ $name.Render }}.enabledSetByUser { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be configured: {{ $event.Warnings.IfConfigured }}") } {{- end }} {{- end }} {{- if .Events }} {{- range $name, $attr := .ResourceAttributes }} {{- if $attr.Warnings.IfEnabled }} if lbc.ResourceAttributes.{{ $name.Render }}.Enabled { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be enabled: {{ $attr.Warnings.IfEnabled }}") } {{- end }} {{- if $attr.Warnings.IfEnabledNotSet }} if !lbc.ResourceAttributes.{{ $name.Render }}.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $attr.Warnings.IfEnabledNotSet }}") } {{- end }} {{- if $attr.Warnings.IfConfigured }} if lbc.ResourceAttributes.{{ $name.Render }}.enabledSetByUser || lbc.ResourceAttributes.{{ $name.Render }}.EventsInclude != nil || lbc.ResourceAttributes.{{ $name.Render }}.EventsExclude != nil { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be configured: {{ $attr.Warnings.IfConfigured }}") } {{- end }} {{- end }} {{- end }} lb := &LogsBuilder{ {{- if .Events }} config: lbc, {{- end }} logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, {{- range $name, $event := .Events }} event{{ $name.Render }}: newEvent{{ $name.Render }}(lbc.Events.{{ $name.Render }}), {{- end }} {{ if and .Events .ResourceAttributes -}} resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), {{- end }} } {{- if .Events }} {{- range $name, $attr := .ResourceAttributes }} if lbc.ResourceAttributes.{{ $name.Render }}.EventsInclude != nil { lb.resourceAttributeIncludeFilter["{{ $name }}"] = filter.CreateFilter(lbc.ResourceAttributes.{{ $name.Render }}.EventsInclude) } if lbc.ResourceAttributes.{{ $name.Render }}.EventsExclude != nil { lb.resourceAttributeExcludeFilter["{{ $name }}"] = filter.CreateFilter(lbc.ResourceAttributes.{{ $name.Render }}.EventsExclude) } {{- end }} {{- end }} return lb } {{- end }} {{- if .ResourceAttributes }} // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted logs. func (lb *LogsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder({{ if .Events }}lb.config.ResourceAttributes{{ else }}ResourceAttributesConfig{}{{ end }}) } {{- end }} // ResourceLogsOption applies changes to provided resource logs. type ResourceLogsOption interface { apply(plog.ResourceLogs) } type resourceLogsOptionFunc func(plog.ResourceLogs) func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { rlof(rl) } // WithLogsResource sets the provided resource on the emitted ResourceLogs. // It's recommended to use ResourceBuilder to create the resource. func WithLogsResource(res pcommon.Resource) ResourceLogsOption { return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { res.CopyTo(rl.Resource()) }) } // AppendLogRecord adds a log record to the logs builder. func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) } // EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for // recording another set of log records as part of another resource. This function can be helpful when one scraper // needs to emit logs from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceLogsOption arguments. func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { rl := plog.NewResourceLogs() {{- if .SemConvVersion }} rl.SetSchemaUrl(conventions.SchemaURL) {{- end }} ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) {{- range $name, $event := .Events }} lb.event{{- $name.Render }}.emit(ils.LogRecords()) {{- end }} for _, op := range options { op.apply(rl) } if lb.logRecordsBuffer.Len() > 0 { lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) lb.logRecordsBuffer = plog.NewLogRecordSlice() } {{ if and .Events .ResourceAttributes -}} for attr, filter := range lb.resourceAttributeIncludeFilter { if val, ok := rl.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { return } } for attr, filter := range lb.resourceAttributeExcludeFilter { if val, ok := rl.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { return } } {{- end }} if ils.LogRecords().Len() > 0 { rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) } } // Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for // recording another set of logs. This function will be responsible for applying all the transformations required to // produce logs representation defined in metadata and user config. func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { lb.EmitForResource(options...) logs := lb.logsBuffer lb.logsBuffer = plog.NewLogs() return logs } {{ range $name, $event := .Events -}} // Record{{ $name.Render }}Event adds a log record of {{ $name }} event. func (lb *LogsBuilder) Record{{ $name.Render }}Event(ctx context.Context, timestamp pcommon.Timestamp {{- range $event.Attributes -}} {{- if not (attributeInfo .).IsConditional -}} , {{ .RenderUnexported }}AttributeValue {{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ else }}{{ (attributeInfo .).Type.Primitive }}{{ end }} {{- end -}} {{- end -}} {{- if $event.HasConditionalAttributes $.Attributes -}} , options... EventAttributeOption {{- end -}}) { lb.event{{ $name.Render }}.recordEvent(ctx, timestamp {{- range $event.Attributes -}} {{- if not (attributeInfo .).IsConditional -}} , {{ .RenderUnexported }}AttributeValue{{ if (attributeInfo .).Enum }}.String(){{ end }} {{- end -}} {{- end -}} {{- if $event.HasConditionalAttributes $.Attributes -}} , options... {{- end -}}) } {{ end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/logs_test.go.tmpl000066400000000000000000000225401511331344600302030ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "time" "testing" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" {{- if or isReceiver isScraper }} "go.opentelemetry.io/collector/{{ .Status.Class }}/{{ .Status.Class }}test" {{- end }} {{- if .Events }} "context" "go.opentelemetry.io/otel/trace" {{- end }} ) {{- if .Events }} type eventsTestDataSet int const ( eventTestDataSetDefault eventsTestDataSet = iota eventTestDataSetAll eventTestDataSetNone ) {{- end }} func TestLogsBuilderAppendLogRecord(t *testing.T) { observedZapCore, _ := observer.New(zap.WarnLevel) {{- if or isReceiver isScraper }} settings := {{ .Status.Class }}test.NewNopSettings({{ .Status.Class }}test.NopType) {{- end }} settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder({{ if .Events }}loadLogsBuilderConfig(t, "all_set"), {{ end }}settings) {{ if .ResourceAttributes }} rb := lb.NewResourceBuilder() {{- range $name, $attr := .ResourceAttributes }} {{- if $attr.Enum }} rb.Set{{ $attr.Name.Render }}{{ index $attr.Enum 0 | publicVar }}() {{- else }} rb.Set{{ $attr.Name.Render }}({{ $attr.TestValue }}) {{- end }} {{- end }} res := rb.Emit() {{- else }} res := pcommon.NewResource() {{- end }} // append the first log record lr := plog.NewLogRecord() lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr.Attributes().PutStr("type", "log") lr.Body().SetStr("the first log record") // append the second log record lr2 := plog.NewLogRecord() lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr2.Attributes().PutStr("type", "event") lr2.Body().SetStr("the second log record") lb.AppendLogRecord(lr) lb.AppendLogRecord(lr2) logs := lb.Emit(WithLogsResource(res)) assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, 1, rl.ScopeLogs().Len()) sl := rl.ScopeLogs().At(0) assert.Equal(t, ScopeName,sl.Scope().Name()) assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) assert.Equal(t, 2, sl.LogRecords().Len()) attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "log", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "event", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) } {{- if .Events }} func TestLogsBuilder(t *testing.T) { tests := []struct { name string eventsSet eventsTestDataSet resAttrsSet eventsTestDataSet expectEmpty bool }{ { name: "default", }, { name: "all_set", eventsSet: eventTestDataSetAll, resAttrsSet: eventTestDataSetAll, }, { name: "none_set", eventsSet: eventTestDataSetNone, resAttrsSet: eventTestDataSetNone, expectEmpty: true, }, {{- if .ResourceAttributes }} { name: "filter_set_include", resAttrsSet: eventTestDataSetAll, }, { name: "filter_set_exclude", resAttrsSet: eventTestDataSetAll, expectEmpty: true, }, {{- end }} } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { timestamp := pcommon.Timestamp(1_000_001_000) traceID := [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} spanID := [8]byte{0, 1, 2, 3, 4, 5, 6, 7} ctx := trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ TraceID: trace.TraceID(traceID), SpanID: trace.SpanID(spanID), TraceFlags: trace.FlagsSampled, })) observedZapCore, observedLogs := observer.New(zap.WarnLevel) {{- if or isReceiver isScraper }} settings := {{ .Status.Class }}test.NewNopSettings({{ .Status.Class }}test.NopType) {{- end }} settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder(loadLogsBuilderConfig(t, tt.name), settings) expectedWarnings := 0 {{- range $name, $event := .Events }} {{- if and $event.Enabled $event.Warnings.IfEnabled }} if tt.eventsSet == eventTestDataSetDefault || tt.eventsSet == eventTestDataSetAll { assert.Equal(t, "[WARNING] `{{ $name }}` should not be enabled: {{ $event.Warnings.IfEnabled }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $event.Warnings.IfEnabledNotSet }} if tt.eventsSet == eventTestDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $event.Warnings.IfEnabledNotSet }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $event.Warnings.IfConfigured }} if tt.eventsSet == eventTestDataSetAll || tt.eventsSet == eventTestDataSetNone { assert.Equal(t, "[WARNING] `{{ $name }}` should not be configured: {{ $event.Warnings.IfConfigured }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- end }} {{- range $name, $attr := .ResourceAttributes }} {{- if and $attr.Enabled $attr.Warnings.IfEnabled }} if tt.resAttrsSet == eventTestDataSetDefault || tt.resAttrsSet == eventTestDataSetAll { assert.Equal(t, "[WARNING] `{{ $name }}` should not be enabled: {{ $attr.Warnings.IfEnabled }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $attr.Warnings.IfEnabledNotSet }} if tt.resAttrsSet == eventTestDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $attr.Warnings.IfEnabledNotSet }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $attr.Warnings.IfConfigured }} if tt.resAttrsSet == eventTestDataSetAll || tt.resAttrsSet == eventTestDataSetNone { assert.Equal(t, "[WARNING] `{{ $name }}` should not be configured: {{ $attr.Warnings.IfConfigured }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- end }} assert.Equal(t, expectedWarnings, observedLogs.Len()) defaultEventsCount := 0 allEventsCount := 0 {{- range $name, $event := .Events }} {{ if $event.Enabled }}defaultEventsCount++{{ end }} allEventsCount++ lb.Record{{ $name.Render }}Event(ctx, timestamp {{- range $event.Attributes -}} {{- if not (attributeInfo .).IsConditional -}} , {{- template "getAttributeValue" . -}} {{- end -}} {{- end -}} {{- range $event.Attributes -}} {{- if (attributeInfo .).IsConditional -}} , With{{ .Render }}EventAttribute({{- template "getAttributeValue" . -}}) {{- end -}} {{- end -}} ) {{- end }} {{ if .ResourceAttributes }} rb := lb.NewResourceBuilder() {{- range $name, $attr := .ResourceAttributes }} {{- if $attr.Enum }} rb.Set{{ $attr.Name.Render }}{{ index $attr.Enum 0 | publicVar }}() {{- else }} rb.Set{{ $attr.Name.Render }}({{ $attr.TestValue }}) {{- end }} {{- end }} res := rb.Emit() {{- else }} res := pcommon.NewResource() {{- end }} logs := lb.Emit(WithLogsResource(res)) if tt.expectEmpty || ((tt.name == "default" || tt.name == "filter_set_include") && defaultEventsCount == 0) { assert.Equal(t, 0, logs.ResourceLogs().Len()) return } assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, res, rl.Resource()) assert.Equal(t, 1, rl.ScopeLogs().Len()) lrs := rl.ScopeLogs().At(0).LogRecords() if tt.eventsSet == eventTestDataSetDefault { assert.Equal(t, defaultEventsCount, lrs.Len()) } if tt.eventsSet == eventTestDataSetAll { assert.Equal(t, allEventsCount, lrs.Len()) } validatedEvents := make(map[string]bool) for i := 0; i < lrs.Len(); i++ { switch lrs.At(i).EventName() { {{- range $name, $event := .Events }} case "{{ $name }}": assert.False(t, validatedEvents["{{ $name }}"], "Found a duplicate in the events slice: {{ $name }}") validatedEvents["{{ $name }}"] = true lr := lrs.At(i) assert.Equal(t, timestamp, lr.Timestamp()) assert.Equal(t, pcommon.TraceID(traceID), lr.TraceID()) assert.Equal(t, pcommon.SpanID(spanID), lr.SpanID()) {{- range $i, $attr := $event.Attributes }} attrVal, ok {{ if eq $i 0 }}:{{ end }}= lr.Attributes().Get("{{ (attributeInfo $attr).Name }}") assert.True(t, ok) {{- if eq (attributeInfo $attr).Type.String "Bool"}} assert.{{- if eq (attributeInfo $attr).TestValue "true" }}True{{ else }}False{{- end }}(t, attrVal.{{ (attributeInfo $attr).Type }}() {{- else if eq (attributeInfo $attr).Type.String "Int"}} assert.EqualValues(t, {{ (attributeInfo $attr).TestValue }}, attrVal.{{ (attributeInfo $attr).Type }}() {{- else }} assert.Equal(t, {{ (attributeInfo $attr).TestValue }}, attrVal.{{ (attributeInfo $attr).Type }}() {{- end }} {{- if or (eq (attributeInfo $attr).Type.String "Slice") (eq (attributeInfo $attr).Type.String "Map")}}.AsRaw(){{ end }}) {{- end }} {{- end }} } } }) } } {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/metrics.go.tmpl000066400000000000000000000362061511331344600276520ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( {{- if .Metrics | parseImportsRequired }} "strconv" "fmt" {{- end }} "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" {{- if or isReceiver isScraper isConnector }} "go.opentelemetry.io/collector/{{ .Status.Class }}" {{- end }} {{- if .SemConvVersion }} conventions "go.opentelemetry.io/otel/semconv/v{{ .SemConvVersion }}" {{- end }} {{ if .ResourceAttributes -}} "go.opentelemetry.io/collector/filter" {{- end }} ) {{ range $name, $info := .Attributes }} {{- if $info.Enum -}} // Attribute{{ $name.Render }} specifies the value {{ $name }} attribute. type Attribute{{ $name.Render }} int const ( _ Attribute{{ $name.Render }} = iota {{- range $info.Enum }} Attribute{{ $name.Render }}{{ . | publicVar }} {{- end }} ) // String returns the string representation of the Attribute{{ $name.Render }}. func (av Attribute{{ $name.Render }}) String() string { switch av { {{- range $info.Enum }} case Attribute{{ $name.Render }}{{ . | publicVar }}: return "{{ . }}" {{- end }} } return "" } // MapAttribute{{ $name.Render }} is a helper map of string to Attribute{{ $name.Render }} attribute value. var MapAttribute{{ $name.Render }} = map[string]Attribute{{ $name.Render }}{ {{- range $info.Enum }} "{{ . }}": Attribute{{ $name.Render }}{{ . | publicVar }}, {{- end }} } {{ end }} {{- end }} var MetricsInfo = metricsInfo{ {{- range $name, $metric := .Metrics }} {{ $name.Render }}: metricInfo{ Name: "{{ $name }}", }, {{- end }} } type metricsInfo struct { {{- range $name, $metric := .Metrics }} {{ $name.Render }} metricInfo {{- end }} } type metricInfo struct { Name string } {{ if getMetricConditionalAttributes .Attributes }} type MetricAttributeOption interface { apply(pmetric.NumberDataPoint) } type metricAttributeOptionFunc func(pmetric.NumberDataPoint) func (maof metricAttributeOptionFunc) apply(dp pmetric.NumberDataPoint) { maof(dp) } {{ range getMetricConditionalAttributes .Attributes }} func With{{ .Render }}MetricAttribute({{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}) MetricAttributeOption { return metricAttributeOptionFunc(func(dp pmetric.NumberDataPoint) { {{- template "putAttribute" . }} }) } {{ end }} {{ end }} {{ range $name, $metric := .Metrics -}} type metric{{ $name.Render }} struct { data pmetric.Metric // data buffer for generated metric. config MetricConfig // metric config provided by user. capacity int // max observed number of data points added to the metric. } // init fills {{ $name }} metric with initial data. func (m *metric{{ $name.Render }}) init() { m.data.SetName("{{ $name }}") m.data.SetDescription("{{ $metric.Description }}") m.data.SetUnit("{{ $metric.Unit }}") m.data.SetEmpty{{ $metric.Data.Type }}() {{- if $metric.Data.HasMonotonic }} m.data.{{ $metric.Data.Type }}().SetIsMonotonic({{ $metric.Data.Monotonic }}) {{- end }} {{- if $metric.Data.HasAggregated }} m.data.{{ $metric.Data.Type }}().SetAggregationTemporality(pmetric.AggregationTemporality{{ $metric.Data.AggregationTemporality }}) {{- end }} {{- if $metric.Attributes }} m.data.{{ $metric.Data.Type }}().DataPoints().EnsureCapacity(m.capacity) {{- end }} } func (m *metric{{ $name.Render }}) recordDataPoint(start pcommon.Timestamp, ts pcommon.Timestamp, val {{ $metric.Data.MetricValueType.BasicType }} {{- range $metric.Attributes -}}{{- if not (attributeInfo .).IsConditional -}}, {{ .RenderUnexported }}AttributeValue {{ (attributeInfo .).Type.Primitive }}{{ end }}{{ end }}{{- if $metric.HasConditionalAttributes $.Attributes -}}, options ...MetricAttributeOption{{- end -}}) { if !m.config.Enabled { return } dp := m.data.{{ $metric.Data.Type }}().DataPoints().AppendEmpty() dp.SetStartTimestamp(start) dp.SetTimestamp(ts) dp.Set{{ $metric.Data.MetricValueType }}Value(val) {{- range $metric.Attributes }} {{- if not (attributeInfo .).IsConditional -}} {{- template "putAttribute" . -}} {{- end }} {{- end }} {{- if $metric.HasConditionalAttributes $.Attributes }} for _, op := range options { op.apply(dp) } {{- end }} } // updateCapacity saves max length of data point slices that will be used for the slice capacity. func (m *metric{{ $name.Render }}) updateCapacity() { if m.data.{{ $metric.Data.Type }}().DataPoints().Len() > m.capacity { m.capacity = m.data.{{ $metric.Data.Type }}().DataPoints().Len() } } // emit appends recorded metric data to a metrics slice and prepares it for recording another set of data points. func (m *metric{{ $name.Render }}) emit(metrics pmetric.MetricSlice) { if m.config.Enabled && m.data.{{ $metric.Data.Type }}().DataPoints().Len() > 0 { m.updateCapacity() m.data.MoveTo(metrics.AppendEmpty()) m.init() } } func newMetric{{ $name.Render }}(cfg MetricConfig) metric{{ $name.Render }} { m := metric{{ $name.Render }}{config: cfg} if cfg.Enabled { m.data = pmetric.NewMetric() m.init() } return m } {{ end -}} // MetricsBuilder provides an interface for scrapers to report metrics while taking care of all the transformations // required to produce metric representation defined in metadata and user config. type MetricsBuilder struct { config MetricsBuilderConfig // config of the metrics builder. startTime pcommon.Timestamp // start time that will be applied to all recorded data points. metricsCapacity int // maximum observed number of metrics per resource. metricsBuffer pmetric.Metrics // accumulates metrics data before emitting. buildInfo component.BuildInfo // contains version information. {{- if .ResourceAttributes }} resourceAttributeIncludeFilter map[string]filter.Filter resourceAttributeExcludeFilter map[string]filter.Filter {{- end }} {{- range $name, $metric := .Metrics }} metric{{ $name.Render }} metric{{ $name.Render }} {{- end }} } // MetricBuilderOption applies changes to default metrics builder. type MetricBuilderOption interface { apply(*MetricsBuilder) } type metricBuilderOptionFunc func(mb *MetricsBuilder) func (mbof metricBuilderOptionFunc) apply(mb *MetricsBuilder) { mbof(mb) } // WithStartTime sets startTime on the metrics builder. func WithStartTime(startTime pcommon.Timestamp) MetricBuilderOption { return metricBuilderOptionFunc(func(mb *MetricsBuilder) { mb.startTime = startTime }) } {{- if or isReceiver isScraper isConnector }} func NewMetricsBuilder(mbc MetricsBuilderConfig, settings {{ .Status.Class }}.Settings, options ...MetricBuilderOption) *MetricsBuilder { {{- range $name, $metric := .Metrics }} {{- if $metric.Warnings.IfEnabled }} if mbc.Metrics.{{ $name.Render }}.Enabled { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be enabled: {{ $metric.Warnings.IfEnabled }}") } {{- end }} {{- if $metric.Warnings.IfEnabledNotSet }} if !mbc.Metrics.{{ $name.Render }}.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $metric.Warnings.IfEnabledNotSet }}") } {{- end }} {{- if $metric.Warnings.IfConfigured }} if mbc.Metrics.{{ $name.Render }}.enabledSetByUser { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be configured: {{ $metric.Warnings.IfConfigured }}") } {{- end }} {{- end }} {{- range $name, $attr := .ResourceAttributes }} {{- if $attr.Warnings.IfEnabled }} if mbc.ResourceAttributes.{{ $name.Render }}.Enabled { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be enabled: {{ $attr.Warnings.IfEnabled }}") } {{- end }} {{- if $attr.Warnings.IfEnabledNotSet }} if !mbc.ResourceAttributes.{{ $name.Render }}.enabledSetByUser { settings.Logger.Warn("[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $attr.Warnings.IfEnabledNotSet }}") } {{- end }} {{- if $attr.Warnings.IfConfigured }} if mbc.ResourceAttributes.{{ $name.Render }}.enabledSetByUser || mbc.ResourceAttributes.{{ $name.Render }}.MetricsInclude != nil || mbc.ResourceAttributes.{{ $name.Render }}.MetricsExclude != nil { settings.Logger.Warn("[WARNING] `{{ $name }}` should not be configured: {{ $attr.Warnings.IfConfigured }}") } {{- end }} {{- end }} mb := &MetricsBuilder{ config: mbc, startTime: pcommon.NewTimestampFromTime(time.Now()), metricsBuffer: pmetric.NewMetrics(), buildInfo: settings.BuildInfo, {{- range $name, $metric := .Metrics }} metric{{ $name.Render }}: newMetric{{ $name.Render }}(mbc.Metrics.{{ $name.Render }}), {{- end }} {{ if .ResourceAttributes -}} resourceAttributeIncludeFilter: make(map[string]filter.Filter), resourceAttributeExcludeFilter: make(map[string]filter.Filter), {{- end }} } {{- range $name, $attr := .ResourceAttributes }} if mbc.ResourceAttributes.{{ $name.Render }}.MetricsInclude != nil { mb.resourceAttributeIncludeFilter["{{ $name }}"] = filter.CreateFilter(mbc.ResourceAttributes.{{ $name.Render }}.MetricsInclude) } if mbc.ResourceAttributes.{{ $name.Render }}.MetricsExclude != nil { mb.resourceAttributeExcludeFilter["{{ $name }}"] = filter.CreateFilter(mbc.ResourceAttributes.{{ $name.Render }}.MetricsExclude) } {{- end }} for _, op := range options { op.apply(mb) } return mb } {{- end }} {{- if .ResourceAttributes }} // NewResourceBuilder returns a new resource builder that should be used to build a resource associated with for the emitted metrics. func (mb *MetricsBuilder) NewResourceBuilder() *ResourceBuilder { return NewResourceBuilder(mb.config.ResourceAttributes) } {{- end }} // updateCapacity updates max length of metrics and resource attributes that will be used for the slice capacity. func (mb *MetricsBuilder) updateCapacity(rm pmetric.ResourceMetrics) { if mb.metricsCapacity < rm.ScopeMetrics().At(0).Metrics().Len() { mb.metricsCapacity = rm.ScopeMetrics().At(0).Metrics().Len() } } // ResourceMetricsOption applies changes to provided resource metrics. type ResourceMetricsOption interface { apply(pmetric.ResourceMetrics) } type resourceMetricsOptionFunc func(pmetric.ResourceMetrics) func (rmof resourceMetricsOptionFunc) apply(rm pmetric.ResourceMetrics) { rmof(rm) } // WithResource sets the provided resource on the emitted ResourceMetrics. // It's recommended to use ResourceBuilder to create the resource. func WithResource(res pcommon.Resource) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { res.CopyTo(rm.Resource()) }) } // WithStartTimeOverride overrides start time for all the resource metrics data points. // This option should be only used if different start time has to be set on metrics coming from different resources. func WithStartTimeOverride(start pcommon.Timestamp) ResourceMetricsOption { return resourceMetricsOptionFunc(func(rm pmetric.ResourceMetrics) { var dps pmetric.NumberDataPointSlice metrics := rm.ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { switch metrics.At(i).Type() { case pmetric.MetricTypeGauge: dps = metrics.At(i).Gauge().DataPoints() case pmetric.MetricTypeSum: dps = metrics.At(i).Sum().DataPoints() } for j := 0; j < dps.Len(); j++ { dps.At(j).SetStartTimestamp(start) } } }) } // EmitForResource saves all the generated metrics under a new resource and updates the internal state to be ready for // recording another set of data points as part of another resource. This function can be helpful when one scraper // needs to emit metrics from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceMetricsOption arguments. func (mb *MetricsBuilder) EmitForResource(options ...ResourceMetricsOption) { rm := pmetric.NewResourceMetrics() {{- if .SemConvVersion }} rm.SetSchemaUrl(conventions.SchemaURL) {{- end }} ils := rm.ScopeMetrics().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(mb.buildInfo.Version) ils.Metrics().EnsureCapacity(mb.metricsCapacity) {{- range $name, $metric := .Metrics }} mb.metric{{- $name.Render }}.emit(ils.Metrics()) {{- end }} for _, op := range options { op.apply(rm) } {{ if .ResourceAttributes -}} for attr, filter := range mb.resourceAttributeIncludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && !filter.Matches(val.AsString()) { return } } for attr, filter := range mb.resourceAttributeExcludeFilter { if val, ok := rm.Resource().Attributes().Get(attr); ok && filter.Matches(val.AsString()) { return } } {{- end }} if ils.Metrics().Len() > 0 { mb.updateCapacity(rm) rm.MoveTo(mb.metricsBuffer.ResourceMetrics().AppendEmpty()) } } // Emit returns all the metrics accumulated by the metrics builder and updates the internal state to be ready for // recording another set of metrics. This function will be responsible for applying all the transformations required to // produce metric representation defined in metadata and user config, e.g. delta or cumulative. func (mb *MetricsBuilder) Emit(options ...ResourceMetricsOption) pmetric.Metrics { mb.EmitForResource(options...) metrics := mb.metricsBuffer mb.metricsBuffer = pmetric.NewMetrics() return metrics } {{ range $name, $metric := .Metrics -}} // Record{{ $name.Render }}DataPoint adds a data point to {{ $name }} metric. func (mb *MetricsBuilder) Record{{ $name.Render }}DataPoint(ts pcommon.Timestamp {{- if $metric.Data.HasMetricInputType }}, inputVal {{ $metric.Data.MetricInputType.String }} {{- else }}, val {{ $metric.Data.MetricValueType.BasicType }} {{- end }} {{- range $metric.Attributes -}} {{- if not (attributeInfo .).IsConditional -}} , {{ .RenderUnexported }}AttributeValue {{ if (attributeInfo .).Enum }}Attribute{{ .Render }}{{ else }}{{ (attributeInfo .).Type.Primitive }}{{ end }} {{- end -}} {{- end -}} {{- if $metric.HasConditionalAttributes $.Attributes -}} , options... MetricAttributeOption {{- end -}} ) {{- if $metric.Data.HasMetricInputType }} error{{ end }} { {{- if $metric.Data.HasMetricInputType }} {{- if eq $metric.Data.MetricValueType.BasicType "float64" }} val, err := strconv.ParseFloat(inputVal, 64) {{- else if eq $metric.Data.MetricValueType.BasicType "int64" }} val, err := strconv.ParseInt(inputVal, 10, 64) {{- end }} if err != nil { return fmt.Errorf("failed to parse {{ $metric.Data.MetricValueType.BasicType }} for {{ $name.Render }}, value was %s: %w", inputVal, err) } {{- end }} mb.metric{{ $name.Render }}.recordDataPoint(mb.startTime, ts, val {{- range $metric.Attributes -}} {{- if not (attributeInfo .).IsConditional -}} , {{ .RenderUnexported }}AttributeValue{{ if (attributeInfo .).Enum }}.String(){{ end }} {{- end -}} {{- end -}} {{- if $metric.HasConditionalAttributes $.Attributes -}} , options... {{- end -}} ) {{- if $metric.Data.HasMetricInputType }} return nil {{- end }} } {{ end }} // Reset resets metrics builder to its initial state. It should be used when external metrics source is restarted, // and metrics builder should update its startTime and reset it's internal state accordingly. func (mb *MetricsBuilder) Reset(options ...MetricBuilderOption) { mb.startTime = pcommon.NewTimestampFromTime(time.Now()) for _, op := range options { op.apply(mb) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/metrics_test.go.tmpl000066400000000000000000000176261511331344600307160ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" {{- if or isReceiver isScraper isConnector }} "go.opentelemetry.io/collector/{{ .Status.Class }}/{{ .Status.Class }}test" {{- end }} "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" ) type testDataSet int const ( testDataSetDefault testDataSet = iota testDataSetAll testDataSetNone ) func TestMetricsBuilder(t *testing.T) { tests := []struct { name string metricsSet testDataSet resAttrsSet testDataSet expectEmpty bool }{ { name: "default", }, { name: "all_set", metricsSet: testDataSetAll, resAttrsSet: testDataSetAll, }, { name: "none_set", metricsSet: testDataSetNone, resAttrsSet: testDataSetNone, expectEmpty: true, }, {{- if .ResourceAttributes }} { name: "filter_set_include", resAttrsSet: testDataSetAll, }, { name: "filter_set_exclude", resAttrsSet: testDataSetAll, expectEmpty: true, }, {{- end }} } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { start := pcommon.Timestamp(1_000_000_000) ts := pcommon.Timestamp(1_000_001_000) observedZapCore, observedLogs := observer.New(zap.WarnLevel) {{- if or isReceiver isScraper isConnector }} settings := {{ .Status.Class }}test.NewNopSettings({{ .Status.Class }}test.NopType) {{- end }} settings.Logger = zap.New(observedZapCore) mb := NewMetricsBuilder(loadMetricsBuilderConfig(t, tt.name), settings, WithStartTime(start)) expectedWarnings := 0 {{- range $name, $metric := .Metrics }} {{- if and $metric.Enabled $metric.Warnings.IfEnabled }} if tt.metricsSet == testDataSetDefault || tt.metricsSet == testDataSetAll { assert.Equal(t, "[WARNING] `{{ $name }}` should not be enabled: {{ $metric.Warnings.IfEnabled }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $metric.Warnings.IfEnabledNotSet }} if tt.metricsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $metric.Warnings.IfEnabledNotSet }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $metric.Warnings.IfConfigured }} if tt.metricsSet == testDataSetAll || tt.metricsSet == testDataSetNone { assert.Equal(t, "[WARNING] `{{ $name }}` should not be configured: {{ $metric.Warnings.IfConfigured }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- end }} {{- range $name, $attr := .ResourceAttributes }} {{- if and $attr.Enabled $attr.Warnings.IfEnabled }} if tt.resAttrsSet == testDataSetDefault || tt.resAttrsSet == testDataSetAll { assert.Equal(t, "[WARNING] `{{ $name }}` should not be enabled: {{ $attr.Warnings.IfEnabled }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $attr.Warnings.IfEnabledNotSet }} if tt.resAttrsSet == testDataSetDefault { assert.Equal(t, "[WARNING] Please set `enabled` field explicitly for `{{ $name }}`: {{ $attr.Warnings.IfEnabledNotSet }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- if $attr.Warnings.IfConfigured }} if tt.resAttrsSet == testDataSetAll || tt.resAttrsSet == testDataSetNone { assert.Equal(t, "[WARNING] `{{ $name }}` should not be configured: {{ $attr.Warnings.IfConfigured }}", observedLogs.All()[expectedWarnings].Message) expectedWarnings++ } {{- end }} {{- end }} assert.Equal(t, expectedWarnings, observedLogs.Len()) defaultMetricsCount := 0 allMetricsCount := 0 {{- range $name, $metric := .Metrics }} {{ if $metric.Enabled }}defaultMetricsCount++{{ end }} allMetricsCount++ mb.Record{{ $name.Render }}DataPoint(ts, {{ if $metric.Data.HasMetricInputType }}"1"{{ else }}1{{ end }} {{- range $metric.Attributes -}} {{- if not (attributeInfo .).IsConditional -}} , {{- template "getAttributeValue" . -}} {{- end -}} {{- end -}} {{- range $metric.Attributes -}} {{- if (attributeInfo .).IsConditional -}} , With{{ .Render }}MetricAttribute({{- template "getAttributeValue" . -}}) {{- end -}} {{- end -}} ) {{- end }} {{ if .ResourceAttributes }} rb := mb.NewResourceBuilder() {{- range $name, $attr := .ResourceAttributes }} {{- if $attr.Enum }} rb.Set{{ $attr.Name.Render }}{{ index $attr.Enum 0 | publicVar }}() {{- else }} rb.Set{{ $attr.Name.Render }}({{ $attr.TestValue }}) {{- end }} {{- end }} res := rb.Emit() {{- else }} res := pcommon.NewResource() {{- end }} metrics := mb.Emit(WithResource(res)) if tt.expectEmpty { assert.Equal(t, 0, metrics.ResourceMetrics().Len()) return } assert.Equal(t, 1, metrics.ResourceMetrics().Len()) rm := metrics.ResourceMetrics().At(0) assert.Equal(t, res, rm.Resource()) assert.Equal(t, 1, rm.ScopeMetrics().Len()) ms := rm.ScopeMetrics().At(0).Metrics() if tt.metricsSet == testDataSetDefault { assert.Equal(t, defaultMetricsCount, ms.Len()) } if tt.metricsSet == testDataSetAll { assert.Equal(t, allMetricsCount, ms.Len()) } validatedMetrics := make(map[string]bool) for i := 0; i < ms.Len(); i++ { switch ms.At(i).Name() { {{- range $name, $metric := .Metrics }} case "{{ $name }}": assert.False(t, validatedMetrics["{{ $name }}"], "Found a duplicate in the metrics slice: {{ $name }}") validatedMetrics["{{ $name }}"] = true assert.Equal(t, pmetric.MetricType{{ $metric.Data.Type }}, ms.At(i).Type()) assert.Equal(t, 1, ms.At(i).{{ $metric.Data.Type }}().DataPoints().Len()) assert.Equal(t, "{{ $metric.Description }}", ms.At(i).Description()) {{- if len $metric.Unit}} assert.Equal(t, "{{ $metric.Unit }}", ms.At(i).Unit()) {{- else }} assert.Empty(t, ms.At(i).Unit()) {{- end }} {{- if $metric.Data.HasMonotonic }} assert.{{- if $metric.Data.Monotonic }}True{{ else }}False{{ end }}(t, ms.At(i).{{ $metric.Data.Type }}().IsMonotonic()) {{- end }} {{- if $metric.Data.HasAggregated }} assert.Equal(t, pmetric.AggregationTemporality{{ $metric.Data.AggregationTemporality }}, ms.At(i).{{ $metric.Data.Type }}().AggregationTemporality()) {{- end }} dp := ms.At(i).{{ $metric.Data.Type }}().DataPoints().At(0) assert.Equal(t, start, dp.StartTimestamp()) assert.Equal(t, ts, dp.Timestamp()) assert.Equal(t, pmetric.NumberDataPointValueType{{ $metric.Data.MetricValueType }}, dp.ValueType()) {{- if eq $metric.Data.MetricValueType.BasicType "float64" }} assert.InDelta(t, {{ $metric.Data.MetricValueType.BasicType }}(1), dp.{{ $metric.Data.MetricValueType }}Value(), 0.01) {{- else }} assert.Equal(t, {{ $metric.Data.MetricValueType.BasicType }}(1), dp.{{ $metric.Data.MetricValueType }}Value()) {{- end }} {{- range $i, $attr := $metric.Attributes }} attrVal, ok {{ if eq $i 0 }}:{{ end }}= dp.Attributes().Get("{{ (attributeInfo $attr).Name }}") assert.True(t, ok) {{- if eq (attributeInfo $attr).Type.String "Bool"}} assert.{{- if eq (attributeInfo $attr).TestValue "true" }}True{{ else }}False{{- end }}(t, attrVal.{{ (attributeInfo $attr).Type }}() {{- else if eq (attributeInfo $attr).Type.String "Int"}} assert.EqualValues(t, {{ (attributeInfo $attr).TestValue }}, attrVal.{{ (attributeInfo $attr).Type }}() {{- else }} assert.Equal(t, {{ (attributeInfo $attr).TestValue }}, attrVal.{{ (attributeInfo $attr).Type }}() {{- end }} {{- if or (eq (attributeInfo $attr).Type.String "Slice") (eq (attributeInfo $attr).Type.String "Map")}}.AsRaw(){{ end }}) {{- end }} {{- end }} } } }) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/package_test.go.tmpl000066400000000000000000000014571511331344600306360ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ if isCommand -}}main{{ else }}{{ .Package }}{{- end }} import ( {{- if .Tests.GoLeak.Skip }} "os" {{- end }} "testing" {{- if not .Tests.GoLeak.Skip }} "go.uber.org/goleak" {{- end }} ) func TestMain(m *testing.M) { {{- if .Tests.GoLeak.Setup }} {{.Tests.GoLeak.Setup}} {{- end }} {{- if .Tests.GoLeak.Skip }} // skipping goleak test as per metadata.yml configuration os.Exit(m.Run()) {{- else }} goleak.VerifyTestMain(m {{- range $val := .Tests.GoLeak.Ignore.Top}}, goleak.IgnoreTopFunction("{{$val}}"){{end}}{{- range $val := .Tests.GoLeak.Ignore.Any}}, goleak.IgnoreAnyFunction("{{$val}}"){{end}} ) {{- end }} {{- if .Tests.GoLeak.Teardown }} {{.Tests.GoLeak.Teardown}} {{- end }} } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/readme.md.tmpl000066400000000000000000000104131511331344600274240ustar00rootroot00000000000000 {{- if len .Status.Stability }} | Status | | | ------------- |-----------| {{- $class := .Status.Class }} {{- $shortName := .ShortFolderName }} {{- if ne $class "connector" }} {{- $idx := 0 }} {{- range $stability, $value := .Status.Stability }} | {{ if not $idx }}Stability{{ else }} {{ end }} | [{{ toLowerCase $stability.String }}]{{ if and (ne $class "extension") (ne $class "converter") (ne $class "provider") }}: {{ stringsJoin $value ", " }} {{ end }} | {{- $idx = inc $idx }} {{- end }} {{- if .Status.Deprecation }} {{- range $deprecation, $value := .Status.Deprecation }} | Deprecation of {{ toLowerCase $deprecation }} | [Date]: {{ $value.Date }}{{ if and (ne $class "extension") (ne $class "converter") (ne $class "provider") }} {{ end }} | | | [Migration Note]: {{ $value.Migration }}{{ if ne $class "extension" }} {{ end }} | {{- end }} {{- end }} {{- end}} {{- if .Status.UnsupportedPlatforms }} | Unsupported Platforms | {{ stringsJoin .Status.UnsupportedPlatforms ", " }} | {{- end }} {{- if and (ne $class "cmd") (ne $class "pkg") }} | Distributions | [{{ stringsJoin .Status.SortedDistributions "], [" }}] | {{- end }} {{- if .Status.Warnings }} | Warnings | [{{ stringsJoin .Status.Warnings ", " }}](#warnings) | {{- end }} {{- if ne $class "" }} | Issues | [![Open issues](https://img.shields.io/github/issues-search/{{ .GithubProject }}?query=is%3Aissue%20is%3Aopen%20label%3A{{ $class }}%2F{{ $shortName }}%20&label=open&color=orange&logo=opentelemetry)](https://github.com/{{ .GithubProject }}/issues?q=is%3Aopen+is%3Aissue+label%3A{{ $class }}%2F{{ $shortName }}) [![Closed issues](https://img.shields.io/github/issues-search/{{ .GithubProject }}?query=is%3Aissue%20is%3Aclosed%20label%3A{{ $class }}%2F{{ $shortName }}%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/{{ .GithubProject }}/issues?q=is%3Aclosed+is%3Aissue+label%3A{{ $class }}%2F{{ $shortName }}) | {{- if not .Status.DisableCodeCov }} | Code coverage | [![codecov](https://codecov.io/github/{{ .GithubProject }}/graph/main/badge.svg?component={{ .GetCodeCovComponentID }})](https://app.codecov.io/gh/{{ .GithubProject}}/tree/main/?components%5B0%5D={{ .GetCodeCovComponentID }}&displayType=list) | {{- end }} {{- end }} {{- if .Status.Codeowners }} {{- $codeowners := userLinks .Status.Codeowners.Active }} {{- $emeritus := userLinks .Status.Codeowners.Emeritus }} | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | {{ stringsJoin $codeowners ", " }} {{ if .Status.Codeowners.SeekingNew }}\| Seeking more code owners! {{ end }}| {{- if $emeritus }} | Emeritus | {{ stringsJoin $emeritus ", " }} | {{- end }} {{- end }} {{range $stability, $val := .Status.Stability}} [{{ toLowerCase $stability.String }}]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#{{ toLowerCase $stability.String }} {{- end }} {{- if .Status.Deprecation }} [Date]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information [Migration Note]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information {{- end }} {{- range .Status.SortedDistributions }} [{{.}}]: {{ distroURL . }} {{- end }} {{- if eq $class "connector"}} ## Supported Pipeline Types | [Exporter Pipeline Type] | [Receiver Pipeline Type] | [Stability Level] | | ------------------------ | ------------------------ | ----------------- | {{- range $stability, $pipelines := .Status.Stability }} {{- range $pipeline := $pipelines }} {{- $parts := stringsSplit $pipeline "_to_" }} | {{index $parts 0}} | {{index $parts 1}} | [{{ toLowerCase $stability.String }}] | {{- end }} {{- end }} [Exporter Pipeline Type]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/connector/README.md#exporter-pipeline-type [Receiver Pipeline Type]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/connector/README.md#receiver-pipeline-type [Stability Level]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stability-levels {{- end }} {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/resource.go.tmpl000066400000000000000000000051241511331344600300260ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "go.opentelemetry.io/collector/pdata/pcommon" {{- if .HasEntities }} "go.opentelemetry.io/collector/pdata/xpdata/entity" {{- end }} ) // ResourceBuilder is a helper struct to build resources predefined in metadata.yaml. // The ResourceBuilder is not thread-safe and must not to be used in multiple goroutines. type ResourceBuilder struct { config ResourceAttributesConfig res pcommon.Resource } // NewResourceBuilder creates a new ResourceBuilder. This method should be called on the start of the application. func NewResourceBuilder(rac ResourceAttributesConfig) *ResourceBuilder { return &ResourceBuilder{ config: rac, res: pcommon.NewResource(), } } {{- range $name, $attr := .ResourceAttributes }} {{- range $attr.Enum }} // Set{{ $name.Render }}{{ . | publicVar }} sets "{{ $name }}={{ . }}" attribute. func (rb *ResourceBuilder) Set{{ $name.Render }}{{ . | publicVar }}() { if rb.config.{{ $name.Render }}.Enabled { rb.res.Attributes().PutStr("{{ $name }}", "{{ . }}") } } {{- else }} // Set{{ $name.Render }} sets provided value as "{{ $name }}" attribute. func (rb *ResourceBuilder) Set{{ $name.Render }}(val {{ $attr.Type.Primitive }}) { if rb.config.{{ $name.Render }}.Enabled { {{- if or (eq $attr.Type.String "Bytes") (eq $attr.Type.String "Slice") (eq $attr.Type.String "Map") }} rb.res.Attributes().PutEmpty{{ $attr.Type }}("{{ $name }}").FromRaw(val) {{- else }} rb.res.Attributes().Put{{ $attr.Type }}("{{ $name }}", val) {{- end }} } } {{- end }} {{ end }} {{- if .HasEntities }} {{ range $entity := .Entities }} // AssociateWith{{ $entity.Type | publicVar }} associates the resource with entity type "{{ $entity.Type }}". // This method is experimental and will be replaced with an entity builder pattern in the future. // However, for now, it allows associating resources with entities and producing correct entity references. func (rb *ResourceBuilder) AssociateWith{{ $entity.Type | publicVar }}() { entityRef := entity.ResourceEntityRefs(rb.res).AppendEmpty() entityRef.SetType("{{ $entity.Type }}") {{- if $entity.Identity }} idKeys := entityRef.IdKeys() {{- range $entity.Identity }} idKeys.Append("{{ .Ref }}") {{- end }} {{- end }} {{- if $entity.Description }} descKeys := entityRef.DescriptionKeys() {{- range $entity.Description }} descKeys.Append("{{ .Ref }}") {{- end }} {{- end }} } {{ end }} {{- end }} // Emit returns the built resource and resets the internal builder state. func (rb *ResourceBuilder) Emit() pcommon.Resource { r := rb.res rb.res = pcommon.NewResource() return r } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/resource_test.go.tmpl000066400000000000000000000035651511331344600310740ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "testing" "github.com/stretchr/testify/assert" ) {{- $enabledAttrCount := 0 }} {{- range $_, $attr := .ResourceAttributes }} {{- if $attr.Enabled }} {{- $enabledAttrCount = inc $enabledAttrCount }} {{- end }} {{- end }} func TestResourceBuilder(t *testing.T) { for _, tt := range []string{"default", "all_set", "none_set"} { t.Run(tt, func(t *testing.T) { cfg := loadResourceAttributesConfig(t, tt) rb := NewResourceBuilder(cfg) {{- range $name, $attr := .ResourceAttributes }} {{- if $attr.Enum }} rb.Set{{ $name.Render }}{{ index $attr.Enum 0 | publicVar }}() {{- else }} rb.Set{{ $name.Render }}({{ $attr.TestValue }}) {{- end }} {{- end }} res := rb.Emit() assert.Equal(t, 0, rb.Emit().Attributes().Len()) // Second call should return empty Resource switch tt { case "default": assert.Equal(t, {{ $enabledAttrCount }}, res.Attributes().Len()) case "all_set": assert.Equal(t, {{ len .ResourceAttributes }}, res.Attributes().Len()) case "none_set": assert.Equal(t, 0, res.Attributes().Len()) return default: assert.Failf(t, "unexpected test case: %s", tt) } {{ $assignSign := ":=" }} {{- range $name, $attr := .ResourceAttributes }} val, ok {{ $assignSign }} res.Attributes().Get("{{ $name }}") {{- if $attr.Enabled }} assert.True(t, ok) {{- else }} assert.Equal(t, tt == "all_set", ok) {{- end }} if ok { {{- if eq $attr.Type.String "Int" -}} assert.EqualValues(t, {{ $attr.TestValue }}, val.{{ $attr.Type }}() {{- else -}} assert.Equal(t, {{ $attr.TestValue }}, val.{{ $attr.Type }}() {{- end -}} {{- if or (eq $attr.Type.String "Bytes") (eq $attr.Type.String "Slice") (eq $attr.Type.String "Map") -}} .AsRaw() {{- end -}} ) } {{- $assignSign = "=" }} {{- end }} }) } } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/status.go.tmpl000066400000000000000000000006641511331344600275260ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("{{ .Type }}") ScopeName = "{{ .ScopeName }}" ) const ( {{- range $stability, $signals := .Status.Stability }} {{- range $signal := $signals }} {{ toCamelCase $signal }}Stability = component.StabilityLevel{{ casesTitle $stability.String }} {{- end }} {{- end }} ) opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/telemetry.go.tmpl000066400000000000000000000111401511331344600302040ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( {{- if .Telemetry.Metrics }} {{- range $_, $metric := .Telemetry.Metrics }} {{- if $metric.Data.Async }} "context" {{- break}} {{- end }} {{- end }} "errors" "sync" {{- end }} "go.opentelemetry.io/otel/metric" {{- if .Telemetry.Metrics }} {{- range $_, $metric := .Telemetry.Metrics }} {{- if $metric.Data.Async }} "go.opentelemetry.io/otel/metric/embedded" {{- break}} {{- end }} {{- end }} {{- end }} "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("{{ .ScopeName }}") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("{{ .ScopeName }}") } {{- if .Telemetry.Metrics }} // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration {{- range $name, $metric := .Telemetry.Metrics }} {{ $name.Render }} metric.{{ $metric.Data.Instrument }} {{- if and ($metric.Data.Async) (not $metric.Optional) }} {{- end }} {{- end }} } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } {{- range $name, $metric := .Telemetry.Metrics }} {{ if $metric.Data.Async -}} // Register{{ $name.Render }}Callback sets callback for observable {{ $name.Render }} metric. func (builder *TelemetryBuilder) Register{{ $name.Render }}Callback(cb metric.{{ casesTitle $metric.Data.BasicType }}Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observer{{ casesTitle $metric.Data.BasicType }}{inst : builder.{{ $name.Render }}, obs: o}) return nil }, builder.{{ $name.Render }}) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } {{- end }} {{- end }} {{- range $name, $metric := .Telemetry.Metrics }} {{- if $metric.Data.Async }} {{ if eq $metric.Data.BasicType "int64" -}} type observerInt64 struct { embedded.Int64Observer inst metric.Int64Observable obs metric.Observer } func (oi *observerInt64) Observe(value int64, opts ...metric.ObserveOption) { oi.obs.ObserveInt64(oi.inst, value, opts...) } {{ break }} {{- end }} {{- end }} {{- end }} {{- range $name, $metric := .Telemetry.Metrics }} {{- if $metric.Data.Async }} {{ if eq $metric.Data.BasicType "float64" -}} type observerFloat64 struct { embedded.Float64Observer inst metric.Float64Observable obs metric.Observer } func (oi *observerFloat64) Observe(value float64, opts ...metric.ObserveOption) { oi.obs.ObserveFloat64(oi.inst, value, opts...) } {{ break }} {{- end }} {{- end }} {{- end }} // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error {{- range $name, $metric := .Telemetry.Metrics }} builder.{{ $name.Render }}, err = builder.meter.{{ $metric.Data.Instrument }}( {{ if $metric.Prefix -}} "{{ $metric.Prefix }}{{ $name }}", {{ else -}} "otelcol_{{ $name }}", {{ end -}} metric.WithDescription("{{ $metric.Description }}{{ $metric.Stability }}"), metric.WithUnit("{{ $metric.Unit }}"), {{ if eq $metric.Data.Type "Histogram" -}} {{- if $metric.Data.Boundaries -}}metric.WithExplicitBucketBoundaries([]float64{ {{- range $metric.Data.Boundaries }} {{.}}, {{- end }} }...),{{- end }} {{- end }} ) errs = errors.Join(errs, err) {{- end }} return &builder, errs } {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/telemetry_test.go.tmpl000066400000000000000000000034451511331344600312540ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }} import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "{{ .ScopeName }}", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "{{ .ScopeName }}", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } {{- if .Telemetry.Metrics }} func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/telemetrytest.go.tmpl000066400000000000000000000042441511331344600311130ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }}test import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" {{- if or isConnector isExporter isExtension isProcessor isReceiver isScraper }} "go.opentelemetry.io/collector/component" {{- end }} "go.opentelemetry.io/collector/component/componenttest" {{- if or isConnector isExporter isExtension isProcessor isReceiver isScraper }} "go.opentelemetry.io/collector/{{ .Status.Class }}" "go.opentelemetry.io/collector/{{ .Status.Class }}/{{ .Status.Class }}test" {{- end }} ) {{ if or isConnector isExporter isExtension isProcessor isReceiver isScraper }} func NewSettings(tt *componenttest.Telemetry) {{ .Status.Class }}.Settings { set := {{ .Status.Class }}test.NewNopSettings({{ .Status.Class }}test.NopType) set.ID = component.NewID(component.MustNewType("{{ .Type }}")) set.TelemetrySettings = tt.NewTelemetrySettings() return set } {{- end }} {{ range $name, $metric := .Telemetry.Metrics }} func AssertEqual{{ $name.Render }}(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.{{- if eq $metric.Data.Type "Histogram" }} {{$metric.Data.Type}} {{- end }}DataPoint[{{ $metric.Data.BasicType }}], opts ...metricdatatest.Option) { want := metricdata.Metrics{ {{ if $metric.Prefix -}} Name: "{{ $metric.Prefix }}{{ $name }}", {{ else -}} Name: "otelcol_{{ $name }}", {{ end -}} Description: "{{ $metric.Description }}{{ $metric.Stability }}", Unit: "{{ $metric.Unit }}", Data: metricdata.{{ $metric.Data.Type }}[{{ $metric.Data.BasicType }}]{ {{- if $metric.Data.HasAggregated }} Temporality: metricdata.CumulativeTemporality, {{- end }} {{- if $metric.Data.HasMonotonic }} IsMonotonic: {{ $metric.Data.Monotonic }}, {{- end }} DataPoints: dps, }, } {{ if $metric.Prefix -}} got, err := tt.GetMetric("{{ $metric.Prefix }}{{ $name }}") {{ else -}} got, err := tt.GetMetric("otelcol_{{ $name }}") {{ end -}} require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/telemetrytest_test.go.tmpl000066400000000000000000000043421511331344600321510ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package {{ .Package }}test import ( "context" "testing" "github.com/stretchr/testify/require" {{- if .Telemetry.Metrics }} {{- range $_, $metric := .Telemetry.Metrics }} {{- if $metric.Data.Async }} "go.opentelemetry.io/otel/metric" {{- break}} {{- end }} {{- end }} {{- end }} "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "{{ .PackageName }}/internal/{{ .GeneratedPackageName }}" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := {{ .Package }}.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() {{- range $name, $metric := .Telemetry.Metrics }} {{- if $metric.Data.Async }} require.NoError(t, tb.Register{{ $name.Render }}Callback(func(_ context.Context, observer metric.{{ casesTitle $metric.Data.BasicType }}Observer) error { observer.Observe(1) return nil })) {{- end }} {{- end }} {{- range $name, $metric := .Telemetry.Metrics }} {{- if not $metric.Data.Async }} {{- if eq $metric.Data.Type "Sum" }} tb.{{ $name.Render }}.Add(context.Background(), 1) {{- else }} tb.{{ $name.Render }}.Record(context.Background(), 1) {{- end }} {{- end }} {{- end }} {{- range $name, $metric := .Telemetry.Metrics }} AssertEqual{{ $name.Render }}(t, testTel, {{ if eq $metric.Data.Type "Gauge" -}} []metricdata.DataPoint[{{ $metric.Gauge.MetricValueType.BasicType }}]{{"{{Value: 1}}"}}, {{- else if eq $metric.Data.Type "Sum" -}} []metricdata.DataPoint[{{ $metric.Sum.MetricValueType.BasicType }}]{{"{{Value: 1}}"}}, {{- else if eq $metric.Data.Type "Histogram" -}} []metricdata.HistogramDataPoint[{{ $metric.Histogram.MetricValueType.BasicType }}]{{"{{}}"}}, metricdatatest.IgnoreValue(), {{- end }} metricdatatest.IgnoreTimestamp()) {{- end }} require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/testdata/000077500000000000000000000000001511331344600265045ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/templates/testdata/config.yaml.tmpl000066400000000000000000000035201511331344600316100ustar00rootroot00000000000000default: all_set: {{- if .Metrics }} metrics: {{- range $name, $_ := .Metrics }} {{ $name }}: enabled: true {{- end }} {{- end }} {{- if .Events }} events: {{- range $name, $_ := .Events }} {{ $name }}: enabled: true {{- end }} {{- end }} {{- if .ResourceAttributes }} resource_attributes: {{- range $name, $_ := .ResourceAttributes }} {{ $name }}: enabled: true {{- end }} {{- end }} none_set: {{- if .Metrics }} metrics: {{- range $name, $_ := .Metrics }} {{ $name }}: enabled: false {{- end }} {{- end }} {{- if .Events }} events: {{- range $name, $_ := .Events }} {{ $name }}: enabled: false {{- end }} {{- end }} {{- if .ResourceAttributes }} resource_attributes: {{- range $name, $_ := .ResourceAttributes }} {{ $name }}: enabled: false {{- end }} {{- end }} {{- if and (or .Metrics .Events) .ResourceAttributes }} filter_set_include: resource_attributes: {{- range $name, $attr := .ResourceAttributes }} {{ $name }}: enabled: true {{- if $.Metrics }} metrics_include: - regexp: ".*" {{- end }} {{- if $.Events }} events_include: - regexp: ".*" {{- end }} {{- end }} filter_set_exclude: resource_attributes: {{- range $name, $attr := .ResourceAttributes }} {{ $name }}: enabled: true {{- if $.Metrics }} metrics_exclude: {{- if eq $attr.Type.String "Str" }} - strict: {{ $attr.TestValue }} {{- else }} - regexp: ".*" {{- end }} {{- end }} {{- if $.Events }} events_exclude: {{- if eq $attr.Type.String "Str" }} - strict: {{ $attr.TestValue }} {{- else }} - regexp: ".*" {{- end }} {{- end }} {{- end }} {{- end }} opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/000077500000000000000000000000001511331344600245065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/async_metric.yaml000066400000000000000000000007041511331344600300530ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: metric: enabled: true description: Description. stability: level: development unit: s gauge: value_type: double async: true tests: skip_lifecycle: true skip_shutdown: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/basic_connector.yaml000066400000000000000000000001201511331344600305160ustar00rootroot00000000000000type: test status: class: connector stability: beta: [traces_to_traces]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/basic_pkg.yaml000066400000000000000000000000761511331344600273170ustar00rootroot00000000000000type: test status: class: pkg stability: beta: [logs]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/basic_receiver.yaml000066400000000000000000000001031511331344600303310ustar00rootroot00000000000000type: test status: class: receiver stability: beta: [logs]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/custom_generated_package_name.yaml000066400000000000000000000005161511331344600333770ustar00rootroot00000000000000type: metricreceiver generated_package_name: custom status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention tests: skip_lifecycle: true skip_shutdown: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/deprecation_info_invalid_date.yaml000066400000000000000000000003151511331344600334040ustar00rootroot00000000000000type: file status: class: receiver stability: beta: [logs] stable: [metrics] deprecated: [traces] deprecation: traces: date: "05-09-2007" migration: "no migration needed" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/documentation.md000066400000000000000000000005221511331344600277000ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # sample ## Resource Attributes | Name | Description | Values | Enabled | | ---- | ----------- | ------ | ------- | | host.id | The unique host identifier | Any Str | true | | host.name | The hostname | Any Str | true | | process.pid | The process identifier | Any Int | true | opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/empty.go000066400000000000000000000002521511331344600261720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testdata // this file allows `go list -f` to run in tests and get the scope name. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/empty_test_config.yaml000066400000000000000000000001261511331344600311130ustar00rootroot00000000000000type: test status: class: receiver stability: beta: [logs] tests: config: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/entity_duplicate_attributes.yaml000066400000000000000000000012051511331344600332040ustar00rootroot00000000000000type: sample status: class: receiver stability: stable: [metrics] resource_attributes: host.id: description: The host identifier type: string enabled: true host.name: description: The hostname type: string enabled: true process.pid: description: The process identifier type: int enabled: true entities: - type: host brief: A host instance. stability: stable identity: - ref: host.id description: - ref: host.name - type: process brief: A process instance. stability: stable identity: - ref: process.pid description: - ref: host.name opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/entity_duplicate_types.yaml000066400000000000000000000007341511331344600321700ustar00rootroot00000000000000type: sample status: class: receiver stability: stable: [metrics] resource_attributes: host.id: description: The host identifier type: string enabled: true host.name: description: The hostname type: string enabled: true entities: - type: host brief: A host instance. stability: stable identity: - ref: host.id - type: host brief: Another host instance. stability: stable identity: - ref: host.name opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/entity_empty_id_attributes.yaml000066400000000000000000000004631511331344600330510ustar00rootroot00000000000000type: sample status: class: receiver stability: stable: [metrics] resource_attributes: host.name: description: The hostname type: string enabled: true entities: - type: host brief: A host instance. stability: stable identity: [] description: - ref: host.name entity_undefined_description_attribute.yaml000066400000000000000000000005151511331344600353370ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdatatype: sample status: class: receiver stability: stable: [metrics] resource_attributes: host.id: description: The host identifier type: string enabled: true entities: - type: host brief: A host instance. stability: stable identity: - ref: host.id description: - ref: host.missing opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/entity_undefined_id_attribute.yaml000066400000000000000000000005121511331344600334640ustar00rootroot00000000000000type: sample status: class: receiver stability: stable: [metrics] resource_attributes: host.name: description: The hostname type: string enabled: true entities: - type: host brief: A host instance. stability: stable identity: - ref: host.missing description: - ref: host.name opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/entity_valid.yaml000066400000000000000000000011441511331344600300650ustar00rootroot00000000000000type: sample status: class: receiver stability: stable: [metrics] resource_attributes: host.id: description: The unique host identifier type: string enabled: true host.name: description: The hostname type: string enabled: true process.pid: description: The process identifier type: int enabled: true entities: - type: host brief: A host instance. stability: stable identity: - ref: host.id description: - ref: host.name - type: process brief: A process instance. stability: stable identity: - ref: process.pid opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/events/000077500000000000000000000000001511331344600260125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/events/basic_event.yaml000066400000000000000000000004141511331344600311570ustar00rootroot00000000000000type: receiver status: class: receiver stability: development: [logs] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention events: event: enabled: true description: Description. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/events/empty.go000066400000000000000000000002501511331344600274740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package events // this file allows `go list -f` to run in tests and get the scope name. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/events/no_description.yaml000066400000000000000000000005271511331344600317210ustar00rootroot00000000000000type: file status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention events: default.event: enabled: true extended_documentation: The event will be renamed soon. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/events/no_enabled.yaml000066400000000000000000000003511511331344600307630ustar00rootroot00000000000000type: receiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] events: system.event: description: The system event collected by opentelemetry collector. attributes: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/events/unknown_attribute.yaml000066400000000000000000000004051511331344600324570ustar00rootroot00000000000000type: receiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] events: system.event: enabled: true description: The system event collected by opentelemetry collector. attributes: [missing] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/generated_component_test.go000066400000000000000000000051151511331344600321160ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package testdata import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" ) var typ = component.MustNewType("sample") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "metrics", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/generated_package_name.yaml000066400000000000000000000002311511331344600317770ustar00rootroot00000000000000type: custom generated_package_name: customname status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/generated_package_test.go000066400000000000000000000002471511331344600315100ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package testdata import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid.yaml000066400000000000000000000000071511331344600270150ustar00rootroot00000000000000invalidopentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_aggregation.yaml000066400000000000000000000011201511331344600313610ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int monotonic: true aggregation_temporality: invalidaggregation opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_class.yaml000066400000000000000000000001711511331344600302040ustar00rootroot00000000000000type: test status: class: incorrectclass stability: development: [logs] beta: [traces] stable: [metrics]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_input_type.yaml000066400000000000000000000006601511331344600313020ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] metrics: system.cpu.time: enabled: true description: Total CPU seconds broken down by different states. stability: level: development unit: s sum: value_type: double monotonic: true aggregation_temporality: cumulative input_type: double attributes: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_metric_semconvref.yaml000066400000000000000000000013751511331344600326200ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention sem_conv_version: 1.37.2 metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development semantic_convention: ref: https://github.com/open-telemetry/semantic-conventions/blob/v1.38.0/docs/system/system-metrics.md#metric-systemcputime unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_metric_stability.yaml000066400000000000000000000011121511331344600324420ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development42 unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_stability.yaml000066400000000000000000000001711511331344600311030ustar00rootroot00000000000000type: file status: class: receiver stability: incorrectstability: [logs] beta: [traces] stable: [metrics]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_stability_component.yaml000066400000000000000000000002001511331344600331560ustar00rootroot00000000000000type: file status: class: receiver stability: development: [incorrectcomponent] beta: [traces] stable: [metrics]invalid_telemetry_missing_value_type_for_histogram.yaml000066400000000000000000000004111511331344600377400ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdatatype: metric status: class: receiver stability: beta: [traces, logs, metrics] telemetry: metrics: sampling_decision_latency: description: Latency (in microseconds) of a given sampling policy unit: ยตs enabled: true histogram: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_type_attr.yaml000066400000000000000000000005651511331344600311210ustar00rootroot00000000000000type: metricreceiver sem_conv_version: 1.9.0 status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] attributes: used_attr: description: Used attribute. type: invalidtype metrics: metric: enabled: true description: Metric. unit: "1" gauge: value_type: double attributes: [used_attr] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/invalid_type_rattr.yaml000066400000000000000000000006311511331344600312750ustar00rootroot00000000000000type: file sem_conv_version: 1.9.0 status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention resource_attributes: string.resource.attr: description: Resource attribute with any string value. type: invalidtype enabled: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/metrics_and_type.yaml000066400000000000000000000006621511331344600307270ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: metric: enabled: true description: Description. stability: level: development unit: s gauge: value_type: double tests: skip_lifecycle: true skip_shutdown: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_aggregation.yaml000066400000000000000000000010251511331344600303530ustar00rootroot00000000000000type: file status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int monotonic: falseopentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_class.yaml000066400000000000000000000001411511331344600271670ustar00rootroot00000000000000type: test status: stability: development: [logs] beta: [traces] stable: [metrics]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_deprecation_date_info.yaml000066400000000000000000000002641511331344600323750ustar00rootroot00000000000000type: file status: class: receiver stability: beta: [logs] stable: [metrics] deprecated: [traces] deprecation: traces: migration: "no migration needed" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_deprecation_info.yaml000066400000000000000000000001621511331344600313750ustar00rootroot00000000000000type: file status: class: receiver stability: beta: [logs] stable: [metrics] deprecated: [traces] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_deprecation_migration_info.yaml000066400000000000000000000002461511331344600334510ustar00rootroot00000000000000type: file status: class: receiver stability: beta: [logs] stable: [metrics] deprecated: [traces] deprecation: traces: date: "2006-05-09" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_description_attr.yaml000066400000000000000000000014721511331344600314470ustar00rootroot00000000000000# Sample metric metadata file with all available configurations. type: file sem_conv_version: 1.9.0 status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention attributes: string_attr: type: string metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative attributes: [string_attr] warnings: if_enabled_not_set: This metric will be disabled by default soon. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_description_rattr.yaml000066400000000000000000000003041511331344600316220ustar00rootroot00000000000000type: file status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] resource_attributes: string.resource.attr: type: string enabled: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_enabled.yaml000066400000000000000000000006111511331344600274560ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] metrics: system.cpu.time: description: Total CPU seconds broken down by different states. stability: level: development unit: s sum: value_type: double monotonic: true aggregation_temporality: cumulative attributes: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_metric_description.yaml000066400000000000000000000007661511331344600317650ustar00rootroot00000000000000type: file status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: default.metric: enabled: true extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_metric_stability.yaml000066400000000000000000000010611511331344600314330ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: ~ unit: s sum: value_type: int monotonic: true aggregation_temporality: cumulative opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_metric_type.yaml000066400000000000000000000004631511331344600304150ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] metrics: system.cpu.time: enabled: true description: Total CPU seconds broken down by different states. stability: level: development unit: s attributes: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_metric_unit.yaml000066400000000000000000000010631511331344600304100ustar00rootroot00000000000000type: file status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development sum: value_type: int monotonic: true aggregation_temporality: cumulative opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_monotonic.yaml000066400000000000000000000010511511331344600300700ustar00rootroot00000000000000type: file status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: default.metric: enabled: true description: Monotonic cumulative sum int metric enabled by default. extended_documentation: The metric will be become optional soon. stability: level: development unit: s sum: value_type: int aggregation_temporality: cumulative opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_stability.yaml000066400000000000000000000000451511331344600300710ustar00rootroot00000000000000type: test status: class: receiveropentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_stability_component.yaml000066400000000000000000000001211511331344600321460ustar00rootroot00000000000000type: file status: class: receiver stability: beta: stable: [metrics]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_status.yaml000066400000000000000000000000121511331344600274020ustar00rootroot00000000000000type: testopentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_type.yaml000066400000000000000000000001471511331344600270510ustar00rootroot00000000000000status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_type_attr.yaml000066400000000000000000000006071511331344600301040ustar00rootroot00000000000000type: metricreceiver sem_conv_version: 1.9.0 status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] attributes: used_attr: description: Used attribute. metrics: metric: enabled: true description: Metric. stability: level: development unit: "1" gauge: value_type: double attributes: [used_attr] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_type_rattr.yaml000066400000000000000000000006021511331344600302610ustar00rootroot00000000000000type: file sem_conv_version: 1.9.0 status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention resource_attributes: string.resource.attr: description: Resource attribute with any string value. enabled: trueopentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/no_value_type.yaml000066400000000000000000000007721511331344600302510ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention metrics: system.cpu.time: enabled: true description: Total CPU seconds broken down by different states. stability: level: development unit: s sum: monotonic: true aggregation_temporality: cumulative attributes: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/parent.yaml000066400000000000000000000000531511331344600266610ustar00rootroot00000000000000type: subcomponent parent: parentComponentopentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_cmd_class.md000066400000000000000000000021631511331344600313320ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [alpha]: logs | | | [beta]: metrics | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Acmd%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Acmd%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Acmd%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Acmd%2Ffoo) | [alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha [beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_multiple_signals.md000066400000000000000000000011571511331344600327570ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [alpha]: logs | | | [beta]: metrics | | Distributions | [contrib] | [alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha [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 Some info about a component readme_with_multiple_signals_and_deprecation.md000066400000000000000000000022211511331344600360700ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata# Some component | Status | | | ------------- |-----------| | Stability | [deprecated]: traces | | | [alpha]: logs | | | [beta]: metrics | | Deprecation of traces | [Date]: 2025-02-05 | | | [Migration Note]: no migration needed | | Distributions | [contrib] | [deprecated]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecated [alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha [beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta [Date]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information [Migration Note]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information [contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_status.md000066400000000000000000000021501511331344600307210ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [beta]: metrics | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Ffoo) | [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 Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_status_codeowners.md000066400000000000000000000025721511331344600331610ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [beta]: metrics | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Ffoo) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@open-telemetry/collector-approvers](https://github.com/orgs/open-telemetry/teams/collector-approvers) | [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 Some info about a component readme_with_status_codeowners_and_emeritus.md000066400000000000000000000025541511331344600356410ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata# Some component | Status | | | ------------- |-----------| | Stability | [beta]: metrics | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Ffoo) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@foo](https://www.github.com/foo) | | Emeritus | [@bar](https://www.github.com/bar) | [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 Some info about a component readme_with_status_codeowners_and_seeking_new.md000066400000000000000000000025221511331344600362750ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata# Some component | Status | | | ------------- |-----------| | Stability | [beta]: metrics | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Ffoo) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@foo](https://www.github.com/foo) \| Seeking more code owners! | [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 Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_status_converter.md000066400000000000000000000022021511331344600330060ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [beta] | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aconverter%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aconverter%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aconverter%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aconverter%2Ffoo) | [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 Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_status_extension.md000066400000000000000000000022021511331344600330130ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [beta] | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Ffoo) | [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 Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_status_provider.md000066400000000000000000000021761511331344600326430ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [beta] | | Distributions | [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aopen%20label%3Aprovider%2Ffoo%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aopen+is%3Aissue+label%3Aprovider%2Ffoo) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector-contrib?query=is%3Aissue%20is%3Aclosed%20label%3Aprovider%2Ffoo%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues?q=is%3Aclosed+is%3Aissue+label%3Aprovider%2Ffoo) | [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 Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_with_warnings.md000066400000000000000000000010471511331344600312320ustar00rootroot00000000000000# Some component | Status | | | ------------- |-----------| | Stability | [beta]: metrics | | Distributions | [contrib] | | Warnings | [warning1](#warnings) | [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 Some info about a component ### warnings Some warning there. opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/readme_without_status.md000066400000000000000000000000561511331344600314540ustar00rootroot00000000000000# Some component Some info about a component opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/resource_attributes_only.yaml000066400000000000000000000006211511331344600325270ustar00rootroot00000000000000type: test status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] distributions: [contrib] warnings: - Any additional information that should be brought to the consumer's attention resource_attributes: res.attr1: description: Resource attribute 1. type: string enabled: true tests: skip_lifecycle: true skip_shutdown: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/status_only.yaml000066400000000000000000000002561511331344600277610ustar00rootroot00000000000000type: metricreceiver status: class: exporter stability: beta: [traces, metrics, logs] distributions: [contrib] tests: skip_lifecycle: true skip_shutdown: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/two_metric_types.yaml000066400000000000000000000006731511331344600310000ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] metrics: system.cpu.time: enabled: true description: Total CPU seconds broken down by different states. stability: level: development unit: s gauge: value_type: double sum: value_type: double monotonic: true aggregation_temporality: cumulative attributes: opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/twopackages.yaml000066400000000000000000000001761511331344600277060ustar00rootroot00000000000000type: sample github_project: open-telemetry/opentelemetry-collector status: class: receiver stability: beta: [traces]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/unknown_metric_attribute.yaml000066400000000000000000000006451511331344600325240ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] metrics: system.cpu.time: enabled: true description: Total CPU seconds broken down by different states. stability: level: development unit: s sum: value_type: double monotonic: true aggregation_temporality: cumulative attributes: [missing] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/unknown_value_type.yaml000066400000000000000000000006101511331344600313230ustar00rootroot00000000000000type: metricreceiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] metrics: system.cpu.time: enabled: true description: Total CPU seconds broken down by different states. stability: level: development unit: s sum: value_type: unknown monotonic: true aggregation_temporality: cumulative opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/unsorted_rattr.yaml000066400000000000000000000003711511331344600304520ustar00rootroot00000000000000type: sample status: class: receiver stability: beta: [logs] resource_attributes: cloud.region: description: region enabled: true type: string cloud.availability_zone: description: az enabled: true type: string opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/unused_attribute.yaml000066400000000000000000000015271511331344600307650ustar00rootroot00000000000000type: metricreceiver sem_conv_version: 1.9.0 status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] attributes: used_attr_in_metrics_section: description: Used attribute. type: string used_attr_in_telemetry_section: description: Used attribute. type: string unused_attr: name_override: state description: Unused attribute. type: string metrics: metric: enabled: true description: Metric. stability: level: development unit: "1" gauge: value_type: double attributes: [used_attr_in_metrics_section] telemetry: metrics: metric: enabled: true description: Metric. stability: level: development unit: "1" gauge: value_type: double attributes: [used_attr_in_telemetry_section]opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_conditional_attribute.yaml000066400000000000000000000012731511331344600330160ustar00rootroot00000000000000type: receiver status: class: receiver stability: development: [logs] beta: [traces] stable: [metrics] attributes: conditional_int_attr: description: Conditional int attr. type: string requirement_level: conditionally_required opt_in_string_attr: description: Opt-in string attr. type: string requirement_level: opt_in metrics: metric: enabled: true description: Metric. stability: level: development unit: "1" gauge: value_type: double attributes: [conditional_int_attr, opt_in_string_attr] events: event: enabled: true description: Event. attributes: [conditional_int_attr, opt_in_string_attr] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_goleak_ignores.yaml000066400000000000000000000005331511331344600314160ustar00rootroot00000000000000type: foobar status: disable_codecov_badge: true class: connector stability: beta: [traces_to_metrics, traces_to_traces, traces_to_logs, metrics_to_logs, metrics_to_metrics, metrics_to_traces, logs_to_logs, logs_to_metrics, logs_to_traces] tests: goleak: ignore: top: - "testfunc1" any: - "testfunc2" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_goleak_setup.yaml000066400000000000000000000004461511331344600311130ustar00rootroot00000000000000type: foobar status: disable_codecov_badge: true class: connector stability: beta: [traces_to_metrics, traces_to_traces, traces_to_logs, metrics_to_logs, metrics_to_metrics, metrics_to_traces, logs_to_logs, logs_to_metrics, logs_to_traces] tests: goleak: setup: "setupFunc()" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_goleak_skip.yaml000066400000000000000000000004341511331344600307160ustar00rootroot00000000000000type: foobar status: disable_codecov_badge: true class: connector stability: beta: [traces_to_metrics, traces_to_traces, traces_to_logs, metrics_to_logs, metrics_to_metrics, metrics_to_traces, logs_to_logs, logs_to_metrics, logs_to_traces] tests: goleak: skip: true opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_goleak_teardown.yaml000066400000000000000000000004541511331344600315750ustar00rootroot00000000000000type: foobar status: disable_codecov_badge: true class: connector stability: beta: [traces_to_metrics, traces_to_traces, traces_to_logs, metrics_to_logs, metrics_to_metrics, metrics_to_traces, logs_to_logs, logs_to_metrics, logs_to_traces] tests: goleak: teardown: "teardownFunc()" opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_telemetry.yaml000066400000000000000000000006601511331344600304410ustar00rootroot00000000000000type: metric status: class: receiver stability: beta: [traces, logs, metrics] attributes: name: description: Name of sampling decision type: string telemetry: metrics: sampling_decision_latency: description: Latency (in microseconds) of a given sampling policy unit: ยตs enabled: true stability: level: alpha histogram: value_type: int attributes: [name] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_tests_connector.yaml000066400000000000000000000003731511331344600316440ustar00rootroot00000000000000type: foobar status: disable_codecov_badge: true class: connector stability: beta: [traces_to_metrics, traces_to_traces, traces_to_logs, metrics_to_logs, metrics_to_metrics, metrics_to_traces, logs_to_logs, logs_to_metrics, logs_to_traces] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_tests_exporter.yaml000066400000000000000000000001271511331344600315170ustar00rootroot00000000000000type: metric status: class: exporter stability: beta: [traces, logs, metrics] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_tests_extension.yaml000066400000000000000000000001141511331344600316570ustar00rootroot00000000000000type: metric status: class: extension stability: beta: [extension] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_tests_processor.yaml000066400000000000000000000001301511331344600316600ustar00rootroot00000000000000type: metric status: class: processor stability: beta: [traces, logs, metrics] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/testdata/with_tests_receiver.yaml000066400000000000000000000001271511331344600314530ustar00rootroot00000000000000type: metric status: class: receiver stability: beta: [traces, logs, metrics] opentelemetry-collector-0.141.0/cmd/mdatagen/internal/tests.go000066400000000000000000000014441511331344600243710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/cmd/mdatagen/internal" type Ignore struct { Top []string `mapstructure:"top"` Any []string `mapstructure:"any"` } type GoLeak struct { Skip bool `mapstructure:"skip"` Ignore Ignore `mapstructure:"ignore"` Setup string `mapstructure:"setup"` Teardown string `mapstructure:"teardown"` } type Tests struct { Config any `mapstructure:"config"` SkipLifecycle bool `mapstructure:"skip_lifecycle"` SkipShutdown bool `mapstructure:"skip_shutdown"` GoLeak GoLeak `mapstructure:"goleak"` ExpectConsumerError bool `mapstructure:"expect_consumer_error"` Host string `mapstructure:"host"` } opentelemetry-collector-0.141.0/cmd/mdatagen/main.go000066400000000000000000000005101511331344600223300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package main //go:generate mdatagen metadata.yaml import ( "github.com/spf13/cobra" "go.opentelemetry.io/collector/cmd/mdatagen/internal" ) func main() { cmd, err := internal.NewCommand() cobra.CheckErr(err) cobra.CheckErr(cmd.Execute()) } opentelemetry-collector-0.141.0/cmd/mdatagen/metadata-schema.yaml000066400000000000000000000305421511331344600247670ustar00rootroot00000000000000# Required: The type of the component - Usually the name. The type and class combined uniquely identify the component (eg. receiver/otlp) or subcomponent (eg. receiver/hostmetricsreceiver/cpu) type: # Required for subcomponents: The type of the parent component. parent: string # Optional: Scope name for the telemetry generated by the component. If not set, name of the go package will be used. scope_name: string # Optional: The name of the package that mdatagen generates. If not set, the name "metadata" will be used. generated_package_name: string # Required for components (Optional for subcomponents): A high-level view of the development status and use of this component status: # Required: The class of the component (For example receiver) class: # Required: The stability of the component - See https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stability-levels stability: development: [] alpha: [] beta: [] stable: [] deprecated: [] unmaintained: [] # Required for deprecated components: The deprecation information for the deprecated components - See https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#deprecation-information deprecation: : date: string migration: string # Optional: The distributions that this component is bundled with (For example core or contrib). See statusdata.go for a list of common distros. distributions: [string] # Optional: A list of warnings that should be brought to the attention of users looking to use this component warnings: [string] # Optional: Metadata related to codeowners of the component codeowners: active: [string] emeritus: [string] unsupported_platforms: [] # Optional: OTel Semantic Conventions version that will be associated with the scraped metrics. # This attribute should be set for metrics compliant with OTel Semantic Conventions. sem_conv_version: 1.9.0 # Optional: map of resource attribute definitions with the key being the attribute name. resource_attributes: : # Required: whether the resource attribute is added the emitted metrics by default. enabled: bool # Required: description of the attribute. description: # Optional: array of attribute values if they are static values (currently, only string type is supported). enum: [string] # Required: attribute value type. type: # Optional: warnings that will be shown to user under specified conditions. warnings: # A warning that will be displayed if the resource_attribute is enabled in user config. # Should be used for deprecated default resource_attributes that will be removed soon. if_enabled: # A warning that will be displayed if `enabled` field is not set explicitly in user config. # Should be used for resource_attributes that will be turned from default to optional or vice versa. if_enabled_not_set: # A warning that will be displayed if the resource_attribute is configured by user in any way. # Should be used for deprecated optional resource_attributes that will be removed soon. if_configured: # Optional: array of entity definitions. Entities organize resource attributes into logical entities # with identity and description attributes. entities: - # Required: the type of the entity. type: string # Required: a brief description of the entity. brief: string # Optional: the stability level of the entity. stability: # Required: array of references to resource attributes that uniquely identify this entity. # All referenced attributes must be defined in the resource_attributes section. identity: - ref: string # Optional: array of references to resource attributes that describe this entity. # All referenced attributes must be defined in the resource_attributes section. description: - ref: string # Optional: map of attribute definitions with the key being the attribute name and value # being described below. attributes: : # Optional: this field can be used to override the actual attribute name defined by the key. # It should be used if multiple metrics have different attributes with the same name. name_override: # Required: description of the attribute. description: # Optional: array of attribute values if they are static values (currently, only string type is supported). enum: [string] # Required: attribute value type. type: # Optional: indicates requirement level of the attribute. # - required: the attribute is always included and cannot be excluded. # - conditionally_required: the attribute is included by default when certain conditions are met. # - recommended (default behavior): the attribute is included by default but can be disabled via configuration. # - opt_in: the attribute is not included unless explicitly enabled in user config. requirement_level: # Optional: map of metric names with the key being the metric name and value # being described below. metrics: : # Required: whether the metric is collected by default. enabled: bool # Required: metric description. description: # Optional: extended documentation of the metric. extended_documentation: # Optional: warnings that will be shown to user under specified conditions. warnings: # A warning that will be displayed if the metric is enabled in user config. # Should be used for deprecated default metrics that will be removed soon. if_enabled: # A warning that will be displayed if `enabled` field is not set explicitly in user config. # Should be used for metrics that will be turned from default to optional or vice versa. if_enabled_not_set: # A warning that will be displayed if the metrics is configured by user in any way. # Should be used for deprecated optional metrics that will be removed soon. if_configured: # Required: metric unit as defined by https://ucum.org/ucum.html. unit: # Required: metric type with its settings. : # Required for sum and gauge metrics: type of number data point values. value_type: # Required for sum metric: whether the metric is monotonic (no negative delta values). monotonic: bool # Required for sum metric: whether reported values incorporate previous measurements # (cumulative) or not (delta). aggregation_temporality: # Optional: Indicates the type the metric needs to be parsed from. If set, the generated # functions will parse the value from string to value_type. input_type: string # Optional: array of attributes that were defined in the attributes section that are emitted by this metric. attributes: [string] # Required: the metric stability stability: # Required: the level of stability level: # Optional: the version current stability was introduced from: # Optional: the reference to a semantic convention semantic_convention: ref: # Optional: map of event names with the key being the event name and value # being described below. events: : # Required: whether the event is collected by default. enabled: bool # Required: event description. description: # Optional: extended documentation of the event. extended_documentation: # Optional: warnings that will be shown to user under specified conditions. warnings: # A warning that will be displayed if the event is enabled in user config. # Should be used for deprecated default events that will be removed soon. if_enabled: # A warning that will be displayed if `enabled` field is not set explicitly in user config. if_enabled_not_set: # A warning that will be displayed if the event is configured by user in any way. if_configured: # Optional: array of attributes that were defined in the attributes section that are emitted by this event. attributes: [string] # Lifecycle tests generated for this component. tests: config: # {} by default, specific testing configuration for lifecycle tests. # Skip lifecycle tests for this component. Not recommended for components that are not in development. skip_lifecycle: false # false by default # Skip shutdown tests for this component. Not recommended for components that are not in development. skip_shutdown: false # false by default # Whether it's expected that the Consume[Logs|Metrics|Traces] method will return an error with the given configuration. expect_consumer_error: true # false by default goleak: # {} by default generates a package_test to enable check for leaks skip: false # set to true if goleak tests should be skipped setup: string # Optional: supports configuring a setup function that runs before goleak checks teardown: string # Optional: supports configuring a teardown function that runs before goleak checks ignore: top: [string] # Optional: array of strings representing functions that should be ignore via IgnoreTopFunction any: [string] # Optional: array of strings representing functions that should be ignore via IgnoreAnyFunction # Optional: map of metric names with the key being the metric name and value # being described below. telemetry: metrics: : # Required: whether the metric is collected by default. enabled: bool # Required: metric description. description: # Optional: the stability level of the metric. Set to alpha by default. stability: [alpha|stable|deprecated] # Optional: extended documentation of the metric. extended_documentation: # Optional: whether or not this metric is optional. Optional metrics may only be initialized # if certain features are enabled or configured. optional: bool # Optional: warnings that will be shown to user under specified conditions. warnings: # A warning that will be displayed if the metric is enabled in user config. # Should be used for deprecated default metrics that will be removed soon. if_enabled: # A warning that will be displayed if `enabled` field is not set explicitly in user config. # Should be used for metrics that will be turned from default to optional or vice versa. if_enabled_not_set: # A warning that will be displayed if the metrics is configured by user in any way. # Should be used for deprecated optional metrics that will be removed soon. if_configured: # Required: metric unit as defined by https://ucum.org/ucum.html. unit: # Required: metric type with its settings. : # Optional: Whether this metric is asynchronous. If async, a mechanism is required to be able to # pass in options to the callbacks that are called when the metric is observed. async: bool # Required: type of number data point values. value_type: # Required for sum metric: whether the metric is monotonic (no negative delta values). monotonic: bool # Bucket boundaries are only available to set for histogram metrics. bucket_boundaries: [double] # Optional: array of attributes that were defined in the attributes section that are emitted by this metric. # Note: Only the following attribute types are supported: attributes: [string] opentelemetry-collector-0.141.0/cmd/mdatagen/metadata.yaml000066400000000000000000000003011511331344600235170ustar00rootroot00000000000000type: mdatagen github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: cmd stability: alpha: [metrics] codeowners: active: [dmitryax] opentelemetry-collector-0.141.0/cmd/mdatagen/third_party/000077500000000000000000000000001511331344600234125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/third_party/golint/000077500000000000000000000000001511331344600247065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/mdatagen/third_party/golint/LICENSE000066400000000000000000000027071511331344600257210ustar00rootroot00000000000000Copyright (c) 2013 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. opentelemetry-collector-0.141.0/cmd/mdatagen/third_party/golint/golint.go000066400000000000000000000021701511331344600265310ustar00rootroot00000000000000// Copyright (c) 2013 The Go Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd. package golint // import "go.opentelemetry.io/collector/cmd/mdatagen/third_party/golint" // See https://github.com/golang/lint/blob/d0100b6bd8b389f0385611eb39152c4d7c3a7905/lint.go#L771 // Acronyms is a list of known acronyms that should not be formatted when linting. var Acronyms = map[string]bool{ "ACL": true, "API": true, "ASCII": true, "CPU": true, "CSS": true, "DNS": true, "EOF": true, "GUID": true, "HTML": true, "HTTP": true, "HTTPS": true, "ID": true, "IP": true, "JSON": true, "LHS": true, "QPS": true, "RAM": true, "RHS": true, "RPC": true, "SLA": true, "SMTP": true, "SQL": true, "SSH": true, "TCP": true, "TLS": true, "TTL": true, "UDP": true, "UI": true, "UID": true, "UUID": true, "URI": true, "URL": true, "UTF8": true, "VM": true, "XML": true, "XMPP": true, "XSRF": true, "XSS": true, } opentelemetry-collector-0.141.0/cmd/otelcorecol/000077500000000000000000000000001511331344600216135ustar00rootroot00000000000000opentelemetry-collector-0.141.0/cmd/otelcorecol/Makefile000066400000000000000000000000361511331344600232520ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/cmd/otelcorecol/README.md000066400000000000000000000011511511331344600230700ustar00rootroot00000000000000# `otelcorecol` test binary This folder contains the sources for the `otelcorecol` test binary. This binary is intended for internal **TEST PURPOSES ONLY**. The source files in this folder are **NOT** the ones used to build any official OpenTelemetry Collector releases. Check [open-telemetry/opentelemetry-collector-releases](https://github.com/open-telemetry/opentelemetry-collector-releases) for the official releases. Check the [**`otelcol` folder**](https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol) on that repository for the official Collector core manifest. opentelemetry-collector-0.141.0/cmd/otelcorecol/builder-config.yaml000066400000000000000000000211001511331344600253620ustar00rootroot00000000000000# NOTE: # This builder configuration is NOT used to build any official binary. # To see the builder manifests used for official binaries, # check https://github.com/open-telemetry/opentelemetry-collector-releases # # For the OpenTelemetry Collector Core official distribution sources, check # https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol dist: module: go.opentelemetry.io/collector/cmd/otelcorecol name: otelcorecol description: Local OpenTelemetry Collector binary, testing only. version: 0.141.0-dev receivers: - gomod: go.opentelemetry.io/collector/receiver/nopreceiver v0.141.0 - gomod: go.opentelemetry.io/collector/receiver/otlpreceiver v0.141.0 exporters: - gomod: go.opentelemetry.io/collector/exporter/debugexporter v0.141.0 - gomod: go.opentelemetry.io/collector/exporter/nopexporter v0.141.0 - gomod: go.opentelemetry.io/collector/exporter/otlpexporter v0.141.0 - gomod: go.opentelemetry.io/collector/exporter/otlphttpexporter v0.141.0 extensions: - gomod: go.opentelemetry.io/collector/extension/memorylimiterextension v0.141.0 - gomod: go.opentelemetry.io/collector/extension/zpagesextension v0.141.0 processors: - gomod: go.opentelemetry.io/collector/processor/batchprocessor v0.141.0 - gomod: go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.141.0 connectors: - gomod: go.opentelemetry.io/collector/connector/forwardconnector v0.141.0 providers: - gomod: go.opentelemetry.io/collector/confmap/provider/envprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/httpprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.47.0 - gomod: go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.47.0 replaces: - go.opentelemetry.io/collector => ../../ - go.opentelemetry.io/collector/client => ../../client - go.opentelemetry.io/collector/component => ../../component - go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest - go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus - go.opentelemetry.io/collector/config/configauth => ../../config/configauth - go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression - go.opentelemetry.io/collector/config/configgrpc => ../../config/configgrpc - go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp - go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware - go.opentelemetry.io/collector/config/confignet => ../../config/confignet - go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque - go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional - go.opentelemetry.io/collector/config/configretry => ../../config/configretry - go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry - go.opentelemetry.io/collector/config/configtls => ../../config/configtls - go.opentelemetry.io/collector/confmap => ../../confmap - go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap - go.opentelemetry.io/collector/confmap/provider/envprovider => ../../confmap/provider/envprovider - go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider - go.opentelemetry.io/collector/confmap/provider/httpprovider => ../../confmap/provider/httpprovider - go.opentelemetry.io/collector/confmap/provider/httpsprovider => ../../confmap/provider/httpsprovider - go.opentelemetry.io/collector/confmap/provider/yamlprovider => ../../confmap/provider/yamlprovider - go.opentelemetry.io/collector/consumer => ../../consumer - go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer - go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror - go.opentelemetry.io/collector/consumer/consumererror/xconsumererror => ../../consumer/consumererror/xconsumererror - go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest - go.opentelemetry.io/collector/connector => ../../connector - go.opentelemetry.io/collector/connector/connectortest => ../../connector/connectortest - go.opentelemetry.io/collector/connector/xconnector => ../../connector/xconnector - go.opentelemetry.io/collector/connector/forwardconnector => ../../connector/forwardconnector - go.opentelemetry.io/collector/exporter => ../../exporter - go.opentelemetry.io/collector/exporter/debugexporter => ../../exporter/debugexporter - go.opentelemetry.io/collector/exporter/exportertest => ../../exporter/exportertest - go.opentelemetry.io/collector/exporter/xexporter => ../../exporter/xexporter - go.opentelemetry.io/collector/exporter/exporterhelper => ../../exporter/exporterhelper - go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper => ../../exporter/exporterhelper/xexporterhelper - go.opentelemetry.io/collector/exporter/nopexporter => ../../exporter/nopexporter - go.opentelemetry.io/collector/exporter/otlpexporter => ../../exporter/otlpexporter - go.opentelemetry.io/collector/exporter/otlphttpexporter => ../../exporter/otlphttpexporter - go.opentelemetry.io/collector/extension => ../../extension - go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth - go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest - go.opentelemetry.io/collector/extension/extensioncapabilities => ../../extension/extensioncapabilities - go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware - go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest - go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest - go.opentelemetry.io/collector/extension/memorylimiterextension => ../../extension/memorylimiterextension - go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension - go.opentelemetry.io/collector/extension/zpagesextension => ../../extension/zpagesextension - go.opentelemetry.io/collector/featuregate => ../../featuregate - go.opentelemetry.io/collector/internal/memorylimiter => ../../internal/memorylimiter - go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer - go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry - go.opentelemetry.io/collector/internal/sharedcomponent => ../../internal/sharedcomponent - go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil - go.opentelemetry.io/collector/otelcol => ../../otelcol - go.opentelemetry.io/collector/pdata => ../../pdata - go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata - go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile - go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata - go.opentelemetry.io/collector/pipeline => ../../pipeline - go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline - go.opentelemetry.io/collector/processor => ../../processor - go.opentelemetry.io/collector/processor/processortest => ../../processor/processortest - go.opentelemetry.io/collector/processor/batchprocessor => ../../processor/batchprocessor - go.opentelemetry.io/collector/processor/memorylimiterprocessor => ../../processor/memorylimiterprocessor - go.opentelemetry.io/collector/processor/xprocessor => ../../processor/xprocessor - go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper => ../../processor/processorhelper/xprocessorhelper - go.opentelemetry.io/collector/processor/processorhelper => ../../processor/processorhelper - go.opentelemetry.io/collector/receiver => ../../receiver - go.opentelemetry.io/collector/receiver/nopreceiver => ../../receiver/nopreceiver - go.opentelemetry.io/collector/receiver/receiverhelper => ../../receiver/receiverhelper - go.opentelemetry.io/collector/receiver/otlpreceiver => ../../receiver/otlpreceiver - go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest - go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver - go.opentelemetry.io/collector/service => ../../service - go.opentelemetry.io/collector/service/hostcapabilities => ../../service/hostcapabilities - go.opentelemetry.io/collector/service/telemetry/telemetrytest => ../../service/telemetry/telemetrytest opentelemetry-collector-0.141.0/cmd/otelcorecol/components.go000066400000000000000000000104041511331344600243260ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. package main import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" forwardconnector "go.opentelemetry.io/collector/connector/forwardconnector" "go.opentelemetry.io/collector/exporter" debugexporter "go.opentelemetry.io/collector/exporter/debugexporter" nopexporter "go.opentelemetry.io/collector/exporter/nopexporter" otlpexporter "go.opentelemetry.io/collector/exporter/otlpexporter" otlphttpexporter "go.opentelemetry.io/collector/exporter/otlphttpexporter" "go.opentelemetry.io/collector/extension" memorylimiterextension "go.opentelemetry.io/collector/extension/memorylimiterextension" zpagesextension "go.opentelemetry.io/collector/extension/zpagesextension" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/processor" batchprocessor "go.opentelemetry.io/collector/processor/batchprocessor" memorylimiterprocessor "go.opentelemetry.io/collector/processor/memorylimiterprocessor" "go.opentelemetry.io/collector/receiver" nopreceiver "go.opentelemetry.io/collector/receiver/nopreceiver" otlpreceiver "go.opentelemetry.io/collector/receiver/otlpreceiver" "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" ) func components() (otelcol.Factories, error) { var err error factories := otelcol.Factories{ Telemetry: otelconftelemetry.NewFactory(), } factories.Extensions, err = otelcol.MakeFactoryMap[extension.Factory]( memorylimiterextension.NewFactory(), zpagesextension.NewFactory(), ) if err != nil { return otelcol.Factories{}, err } factories.ExtensionModules = make(map[component.Type]string, len(factories.Extensions)) factories.ExtensionModules[memorylimiterextension.NewFactory().Type()] = "go.opentelemetry.io/collector/extension/memorylimiterextension v0.141.0" factories.ExtensionModules[zpagesextension.NewFactory().Type()] = "go.opentelemetry.io/collector/extension/zpagesextension v0.141.0" factories.Receivers, err = otelcol.MakeFactoryMap[receiver.Factory]( nopreceiver.NewFactory(), otlpreceiver.NewFactory(), ) if err != nil { return otelcol.Factories{}, err } factories.ReceiverModules = make(map[component.Type]string, len(factories.Receivers)) factories.ReceiverModules[nopreceiver.NewFactory().Type()] = "go.opentelemetry.io/collector/receiver/nopreceiver v0.141.0" factories.ReceiverModules[otlpreceiver.NewFactory().Type()] = "go.opentelemetry.io/collector/receiver/otlpreceiver v0.141.0" factories.Exporters, err = otelcol.MakeFactoryMap[exporter.Factory]( debugexporter.NewFactory(), nopexporter.NewFactory(), otlpexporter.NewFactory(), otlphttpexporter.NewFactory(), ) if err != nil { return otelcol.Factories{}, err } factories.ExporterModules = make(map[component.Type]string, len(factories.Exporters)) factories.ExporterModules[debugexporter.NewFactory().Type()] = "go.opentelemetry.io/collector/exporter/debugexporter v0.141.0" factories.ExporterModules[nopexporter.NewFactory().Type()] = "go.opentelemetry.io/collector/exporter/nopexporter v0.141.0" factories.ExporterModules[otlpexporter.NewFactory().Type()] = "go.opentelemetry.io/collector/exporter/otlpexporter v0.141.0" factories.ExporterModules[otlphttpexporter.NewFactory().Type()] = "go.opentelemetry.io/collector/exporter/otlphttpexporter v0.141.0" factories.Processors, err = otelcol.MakeFactoryMap[processor.Factory]( batchprocessor.NewFactory(), memorylimiterprocessor.NewFactory(), ) if err != nil { return otelcol.Factories{}, err } factories.ProcessorModules = make(map[component.Type]string, len(factories.Processors)) factories.ProcessorModules[batchprocessor.NewFactory().Type()] = "go.opentelemetry.io/collector/processor/batchprocessor v0.141.0" factories.ProcessorModules[memorylimiterprocessor.NewFactory().Type()] = "go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.141.0" factories.Connectors, err = otelcol.MakeFactoryMap[connector.Factory]( forwardconnector.NewFactory(), ) if err != nil { return otelcol.Factories{}, err } factories.ConnectorModules = make(map[component.Type]string, len(factories.Connectors)) factories.ConnectorModules[forwardconnector.NewFactory().Type()] = "go.opentelemetry.io/collector/connector/forwardconnector v0.141.0" return factories, nil } opentelemetry-collector-0.141.0/cmd/otelcorecol/go.mod000066400000000000000000000425111511331344600227240ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. module go.opentelemetry.io/collector/cmd/otelcorecol go 1.24.0 require ( go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/provider/envprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/httpprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.47.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/connector/forwardconnector v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/debugexporter v0.141.0 go.opentelemetry.io/collector/exporter/nopexporter v0.141.0 go.opentelemetry.io/collector/exporter/otlpexporter v0.141.0 go.opentelemetry.io/collector/exporter/otlphttpexporter v0.141.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/memorylimiterextension v0.141.0 go.opentelemetry.io/collector/extension/zpagesextension v0.141.0 go.opentelemetry.io/collector/otelcol v0.141.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/batchprocessor v0.141.0 go.opentelemetry.io/collector/processor/memorylimiterprocessor v0.141.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/nopreceiver v0.141.0 go.opentelemetry.io/collector/receiver/otlpreceiver v0.141.0 go.opentelemetry.io/collector/service v0.141.0 golang.org/x/sys v0.38.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // 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-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.1 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/mostynb/go-grpc-compression v1.2.3 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/rs/cors v1.11.1 // indirect github.com/shirou/gopsutil/v4 v4.25.10 // indirect github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector v0.141.0 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/component/componentstatus v0.141.0 // indirect go.opentelemetry.io/collector/component/componenttest v0.141.0 // indirect go.opentelemetry.io/collector/config/configauth v1.47.0 // indirect go.opentelemetry.io/collector/config/configcompression v1.47.0 // indirect go.opentelemetry.io/collector/config/configgrpc v0.141.0 // indirect go.opentelemetry.io/collector/config/confighttp v0.141.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/config/confignet v1.47.0 // indirect go.opentelemetry.io/collector/config/configopaque v1.47.0 // indirect go.opentelemetry.io/collector/config/configoptional v1.47.0 // indirect go.opentelemetry.io/collector/config/configretry v1.47.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.141.0 // indirect go.opentelemetry.io/collector/config/configtls v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/connector/connectortest v0.141.0 // indirect go.opentelemetry.io/collector/connector/xconnector v0.141.0 // indirect go.opentelemetry.io/collector/consumer v1.47.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror/xconsumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumertest v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 // indirect go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper v0.141.0 // indirect go.opentelemetry.io/collector/exporter/exportertest v0.141.0 // indirect go.opentelemetry.io/collector/exporter/xexporter v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensioncapabilities v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensiontest v0.141.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 // indirect go.opentelemetry.io/collector/internal/memorylimiter v0.141.0 // indirect go.opentelemetry.io/collector/internal/sharedcomponent v0.141.0 // indirect go.opentelemetry.io/collector/internal/telemetry v0.141.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.141.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/processor/processorhelper v0.141.0 // indirect go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper v0.141.0 // indirect go.opentelemetry.io/collector/processor/processortest v0.141.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.141.0 // indirect go.opentelemetry.io/collector/receiver/receiverhelper v0.141.0 // indirect go.opentelemetry.io/collector/receiver/receivertest v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/collector/service/hostcapabilities v0.141.0 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.38.0 // indirect go.opentelemetry.io/contrib/zpages v0.63.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/text v0.31.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector => ../../ replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/config/configgrpc => ../../config/configgrpc replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/config/confignet => ../../config/confignet replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/confmap/provider/envprovider => ../../confmap/provider/envprovider replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider replace go.opentelemetry.io/collector/confmap/provider/httpprovider => ../../confmap/provider/httpprovider replace go.opentelemetry.io/collector/confmap/provider/httpsprovider => ../../confmap/provider/httpsprovider replace go.opentelemetry.io/collector/confmap/provider/yamlprovider => ../../confmap/provider/yamlprovider replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/consumer/consumererror/xconsumererror => ../../consumer/consumererror/xconsumererror replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/connector => ../../connector replace go.opentelemetry.io/collector/connector/connectortest => ../../connector/connectortest replace go.opentelemetry.io/collector/connector/xconnector => ../../connector/xconnector replace go.opentelemetry.io/collector/connector/forwardconnector => ../../connector/forwardconnector replace go.opentelemetry.io/collector/exporter => ../../exporter replace go.opentelemetry.io/collector/exporter/debugexporter => ../../exporter/debugexporter replace go.opentelemetry.io/collector/exporter/exportertest => ../../exporter/exportertest replace go.opentelemetry.io/collector/exporter/xexporter => ../../exporter/xexporter replace go.opentelemetry.io/collector/exporter/exporterhelper => ../../exporter/exporterhelper replace go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper => ../../exporter/exporterhelper/xexporterhelper replace go.opentelemetry.io/collector/exporter/nopexporter => ../../exporter/nopexporter replace go.opentelemetry.io/collector/exporter/otlpexporter => ../../exporter/otlpexporter replace go.opentelemetry.io/collector/exporter/otlphttpexporter => ../../exporter/otlphttpexporter replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../../extension/extensioncapabilities replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/extension/memorylimiterextension => ../../extension/memorylimiterextension replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/extension/zpagesextension => ../../extension/zpagesextension replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/memorylimiter => ../../internal/memorylimiter replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry replace go.opentelemetry.io/collector/internal/sharedcomponent => ../../internal/sharedcomponent replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil replace go.opentelemetry.io/collector/otelcol => ../../otelcol replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/processor => ../../processor replace go.opentelemetry.io/collector/processor/processortest => ../../processor/processortest replace go.opentelemetry.io/collector/processor/batchprocessor => ../../processor/batchprocessor replace go.opentelemetry.io/collector/processor/memorylimiterprocessor => ../../processor/memorylimiterprocessor replace go.opentelemetry.io/collector/processor/xprocessor => ../../processor/xprocessor replace go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper => ../../processor/processorhelper/xprocessorhelper replace go.opentelemetry.io/collector/processor/processorhelper => ../../processor/processorhelper replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/receiver/nopreceiver => ../../receiver/nopreceiver replace go.opentelemetry.io/collector/receiver/receiverhelper => ../../receiver/receiverhelper replace go.opentelemetry.io/collector/receiver/otlpreceiver => ../../receiver/otlpreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/service => ../../service replace go.opentelemetry.io/collector/service/hostcapabilities => ../../service/hostcapabilities replace go.opentelemetry.io/collector/service/telemetry/telemetrytest => ../../service/telemetry/telemetrytest opentelemetry-collector-0.141.0/cmd/otelcorecol/go.sum000066400000000000000000000513531511331344600227550ustar00rootroot00000000000000github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 h1:aBKdhLVieqvwWe9A79UHI/0vgp2t/s2euY8X59pGRlw= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0/go.mod h1:SYqtxLQE7iINgh6WFuVi2AI70148B8EI35DSk0Wr8m4= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo= go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU= go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLImUqiTPGnX4= go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= 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= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/cmd/otelcorecol/main.go000066400000000000000000000044641511331344600230760ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. // Program otelcorecol is an OpenTelemetry Collector binary. package main import ( "log" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" envprovider "go.opentelemetry.io/collector/confmap/provider/envprovider" fileprovider "go.opentelemetry.io/collector/confmap/provider/fileprovider" httpprovider "go.opentelemetry.io/collector/confmap/provider/httpprovider" httpsprovider "go.opentelemetry.io/collector/confmap/provider/httpsprovider" yamlprovider "go.opentelemetry.io/collector/confmap/provider/yamlprovider" "go.opentelemetry.io/collector/otelcol" ) func main() { info := component.BuildInfo{ Command: "otelcorecol", Description: "Local OpenTelemetry Collector binary, testing only.", Version: "0.141.0-dev", } set := otelcol.CollectorSettings{ BuildInfo: info, Factories: components, ConfigProviderSettings: otelcol.ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ ProviderFactories: []confmap.ProviderFactory{ envprovider.NewFactory(), fileprovider.NewFactory(), httpprovider.NewFactory(), httpsprovider.NewFactory(), yamlprovider.NewFactory(), }, }, }, ProviderModules: map[string]string{ envprovider.NewFactory().Create(confmap.ProviderSettings{}).Scheme(): "go.opentelemetry.io/collector/confmap/provider/envprovider v1.47.0", fileprovider.NewFactory().Create(confmap.ProviderSettings{}).Scheme(): "go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0", httpprovider.NewFactory().Create(confmap.ProviderSettings{}).Scheme(): "go.opentelemetry.io/collector/confmap/provider/httpprovider v1.47.0", httpsprovider.NewFactory().Create(confmap.ProviderSettings{}).Scheme(): "go.opentelemetry.io/collector/confmap/provider/httpsprovider v1.47.0", yamlprovider.NewFactory().Create(confmap.ProviderSettings{}).Scheme(): "go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.47.0", }, ConverterModules: []string{}, } if err := run(set); err != nil { log.Fatal(err) } } func runInteractive(params otelcol.CollectorSettings) error { cmd := otelcol.NewCommand(params) if err := cmd.Execute(); err != nil { log.Fatalf("collector server run finished with error: %v", err) } return nil } opentelemetry-collector-0.141.0/cmd/otelcorecol/main_others.go000066400000000000000000000003671511331344600244600ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. //go:build !windows package main import "go.opentelemetry.io/collector/otelcol" func run(params otelcol.CollectorSettings) error { return runInteractive(params) } opentelemetry-collector-0.141.0/cmd/otelcorecol/main_windows.go000066400000000000000000000015471511331344600246470ustar00rootroot00000000000000// Code generated by "go.opentelemetry.io/collector/cmd/builder". DO NOT EDIT. //go:build windows package main import ( "errors" "fmt" "golang.org/x/sys/windows" "golang.org/x/sys/windows/svc" "go.opentelemetry.io/collector/otelcol" ) func run(params otelcol.CollectorSettings) error { // No need to supply service name when startup is invoked through // the Service Control Manager directly. if err := svc.Run("", otelcol.NewSvcHandler(params)); err != nil { if errors.Is(err, windows.ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) { // Per https://learn.microsoft.com/en-us/windows/win32/api/winsvc/nf-winsvc-startservicectrldispatchera#return-value // this means that the process is not running as a service, so run interactively. return runInteractive(params) } return fmt.Errorf("failed to start collector server: %w", err) } return nil } opentelemetry-collector-0.141.0/component/000077500000000000000000000000001511331344600205405ustar00rootroot00000000000000opentelemetry-collector-0.141.0/component/Makefile000066400000000000000000000000331511331344600221740ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/component/build_info.go000066400000000000000000000014561511331344600232070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component // import "go.opentelemetry.io/collector/component" // BuildInfo is the information that is logged at the application start and // passed into each component. This information can be overridden in custom build. type BuildInfo struct { // Command is the executable file name, e.g. "otelcol". Command string // Description is the full name of the collector, e.g. "OpenTelemetry Collector". Description string // Version string. Version string // prevent unkeyed literal initialization _ struct{} } // NewDefaultBuildInfo returns a default BuildInfo. func NewDefaultBuildInfo() BuildInfo { return BuildInfo{ Command: "otelcol", Description: "OpenTelemetry Collector", Version: "latest", } } opentelemetry-collector-0.141.0/component/component.go000066400000000000000000000155561511331344600231050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package component outlines the abstraction of components within the OpenTelemetry Collector. It provides details on the component // lifecycle as well as defining the interface that components must fulfill. package component // import "go.opentelemetry.io/collector/component" import ( "context" "fmt" "strings" ) // Component is either a receiver, exporter, processor, connector, or an extension. // // A component's lifecycle has the following phases: // // 1. Creation: The component is created using its respective factory, via a Create* call. // 2. Start: The component's Start method is called. // 3. Running: The component is up and running. // 4. Shutdown: The component's Shutdown method is called and the lifecycle is complete. // // Once the lifecycle is complete it may be repeated, in which case a new component // is created, starts, runs and is shutdown again. type Component interface { // Start tells the component to start. Host parameter can be used for communicating // with the host after Start() has already returned. If an error is returned by // Start() then the collector startup will be aborted. // If this is an exporter component it may prepare for exporting // by connecting to the endpoint. // // If the component needs to perform a long-running starting operation then it is recommended // that Start() returns quickly and the long-running operation is performed in background. // In that case make sure that the long-running operation does not use the context passed // to Start() function since that context will be cancelled soon and can abort the long-running // operation. Create a new context from the context.Background() for long-running operations. Start(ctx context.Context, host Host) error // Shutdown is invoked during service shutdown. After Shutdown() is called, if the component // accepted data in any way, it should not accept it anymore. // // This method must be safe to call: // - without Start() having been called // - if the component is in a shutdown state already // // If there are any background operations running by the component they must be aborted before // this function returns. Remember that if you started any long-running background operations from // the Start() method, those operations must be also cancelled. If there are any buffers in the // component, they should be cleared and the data sent immediately to the next component. // // The component's lifecycle is completed once the Shutdown() method returns. No other // methods of the component are called after that. If necessary a new component with // the same or different configuration may be created and started (this may happen // for example if we want to restart the component). Shutdown(ctx context.Context) error } // StartFunc specifies the function invoked when the component.Component is being started. type StartFunc func(context.Context, Host) error // Start starts the component. func (f StartFunc) Start(ctx context.Context, host Host) error { if f == nil { return nil } return f(ctx, host) } // ShutdownFunc specifies the function invoked when the component.Component is being shutdown. type ShutdownFunc func(context.Context) error // Shutdown shuts down the component. func (f ShutdownFunc) Shutdown(ctx context.Context) error { if f == nil { return nil } return f(ctx) } // Kind represents component kinds. type Kind struct { name string } var ( KindReceiver = Kind{name: "Receiver"} KindProcessor = Kind{name: "Processor"} KindExporter = Kind{name: "Exporter"} KindExtension = Kind{name: "Extension"} KindConnector = Kind{name: "Connector"} ) func (k Kind) String() string { return k.name } // StabilityLevel represents the stability level of the component created by the factory. // The stability level is used to determine if the component should be used in production // or not. For more details see: // https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stability-levels type StabilityLevel int const ( StabilityLevelUndefined StabilityLevel = iota // skip 0, start types from 1. StabilityLevelUnmaintained StabilityLevelDeprecated StabilityLevelDevelopment StabilityLevelAlpha StabilityLevelBeta StabilityLevelStable ) func (sl *StabilityLevel) UnmarshalText(in []byte) error { str := strings.ToLower(string(in)) switch str { case "undefined": *sl = StabilityLevelUndefined case "unmaintained": *sl = StabilityLevelUnmaintained case "deprecated": *sl = StabilityLevelDeprecated case "development": *sl = StabilityLevelDevelopment case "alpha": *sl = StabilityLevelAlpha case "beta": *sl = StabilityLevelBeta case "stable": *sl = StabilityLevelStable default: return fmt.Errorf("unsupported stability level: %q", string(in)) } return nil } func (sl StabilityLevel) String() string { switch sl { case StabilityLevelUndefined: return "Undefined" case StabilityLevelUnmaintained: return "Unmaintained" case StabilityLevelDeprecated: return "Deprecated" case StabilityLevelDevelopment: return "Development" case StabilityLevelAlpha: return "Alpha" case StabilityLevelBeta: return "Beta" case StabilityLevelStable: return "Stable" } return "" } func (sl StabilityLevel) LogMessage() string { switch sl { case StabilityLevelUnmaintained: return "Unmaintained component. Actively looking for contributors. Component will become deprecated after 3 months of remaining unmaintained." case StabilityLevelDeprecated: return "Deprecated component. Will be removed in future releases." case StabilityLevelDevelopment: return "Development component. May change in the future." case StabilityLevelAlpha: return "Alpha component. May change in the future." case StabilityLevelBeta: return "Beta component. May change in the future." case StabilityLevelStable: return "Stable component." default: return "Stability level of component is undefined" } } // Factory is implemented by all Component factories. type Factory interface { // Type gets the type of the component created by this factory. Type() Type // CreateDefaultConfig creates the default configuration for the Component. // This method can be called multiple times depending on the pipeline // configuration and should not cause side effects that prevent the creation // of multiple instances of the Component. // The object returned by this method needs to pass the checks implemented by // 'componenttest.CheckConfigStruct'. It is recommended to have these checks in the // tests of any implementation of the Factory interface. CreateDefaultConfig() Config } // CreateDefaultConfigFunc is the equivalent of Factory.CreateDefaultConfig(). type CreateDefaultConfigFunc func() Config // CreateDefaultConfig implements Factory.CreateDefaultConfig(). func (f CreateDefaultConfigFunc) CreateDefaultConfig() Config { return f() } opentelemetry-collector-0.141.0/component/component_test.go000066400000000000000000000056311511331344600241350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component import ( "testing" "github.com/stretchr/testify/assert" ) func TestKindString(t *testing.T) { assert.Empty(t, Kind{}.String()) assert.Equal(t, "Receiver", KindReceiver.String()) assert.Equal(t, "Processor", KindProcessor.String()) assert.Equal(t, "Exporter", KindExporter.String()) assert.Equal(t, "Extension", KindExtension.String()) assert.Equal(t, "Connector", KindConnector.String()) } func TestStabilityLevelUnmarshal(t *testing.T) { tests := []struct { input string output StabilityLevel expectedErr string }{ { input: "Undefined", output: StabilityLevelUndefined, }, { input: "UnmaintaineD", output: StabilityLevelUnmaintained, }, { input: "DepreCated", output: StabilityLevelDeprecated, }, { input: "Development", output: StabilityLevelDevelopment, }, { input: "alpha", output: StabilityLevelAlpha, }, { input: "BETA", output: StabilityLevelBeta, }, { input: "sTABLe", output: StabilityLevelStable, }, { input: "notfound", expectedErr: "unsupported stability level: \"notfound\"", }, } for _, test := range tests { t.Run(test.input, func(t *testing.T) { var sl StabilityLevel err := sl.UnmarshalText([]byte(test.input)) if test.expectedErr != "" { assert.EqualError(t, err, test.expectedErr) } else { assert.Equal(t, test.output, sl) } }) } } func TestStabilityLevelString(t *testing.T) { assert.Equal(t, "Undefined", StabilityLevelUndefined.String()) assert.Equal(t, "Unmaintained", StabilityLevelUnmaintained.String()) assert.Equal(t, "Deprecated", StabilityLevelDeprecated.String()) assert.Equal(t, "Development", StabilityLevelDevelopment.String()) assert.Equal(t, "Alpha", StabilityLevelAlpha.String()) assert.Equal(t, "Beta", StabilityLevelBeta.String()) assert.Equal(t, "Stable", StabilityLevelStable.String()) assert.Empty(t, StabilityLevel(100).String()) } func TestStabilityLevelLogMessage(t *testing.T) { assert.Equal(t, "Stability level of component is undefined", StabilityLevelUndefined.LogMessage()) assert.Equal(t, "Unmaintained component. Actively looking for contributors. Component will become deprecated after 3 months of remaining unmaintained.", StabilityLevelUnmaintained.LogMessage()) assert.Equal(t, "Deprecated component. Will be removed in future releases.", StabilityLevelDeprecated.LogMessage()) assert.Equal(t, "Development component. May change in the future.", StabilityLevelDevelopment.LogMessage()) assert.Equal(t, "Alpha component. May change in the future.", StabilityLevelAlpha.LogMessage()) assert.Equal(t, "Beta component. May change in the future.", StabilityLevelBeta.LogMessage()) assert.Equal(t, "Stable component.", StabilityLevelStable.LogMessage()) assert.Equal(t, "Stability level of component is undefined", StabilityLevel(100).LogMessage()) } opentelemetry-collector-0.141.0/component/componentstatus/000077500000000000000000000000001511331344600240065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/component/componentstatus/Makefile000066400000000000000000000000361511331344600254450ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/component/componentstatus/go.mod000066400000000000000000000024311511331344600251140ustar00rootroot00000000000000module go.opentelemetry.io/collector/component/componentstatus go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../ replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/component/componentstatus/go.sum000066400000000000000000000124431511331344600251450ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/component/componentstatus/instance.go000066400000000000000000000047621511331344600261520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentstatus // import "go.opentelemetry.io/collector/component/componentstatus" import ( "slices" "sort" "strings" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pipeline" ) // pipelineDelim is the delimiter for internal representation of pipeline // component IDs. const pipelineDelim = byte(0x20) // InstanceID uniquely identifies a component instance // // TODO: consider moving this struct to a new package/module like `extension/statuswatcher` // https://github.com/open-telemetry/opentelemetry-collector/issues/10764 type InstanceID struct { componentID component.ID kind component.Kind pipelineIDs string // IDs encoded as a string so InstanceID is Comparable. } // NewInstanceID returns an ID that uniquely identifies a component. func NewInstanceID(componentID component.ID, kind component.Kind, pipelineIDs ...pipeline.ID) *InstanceID { instanceID := &InstanceID{ componentID: componentID, kind: kind, } instanceID.addPipelines(pipelineIDs) return instanceID } // ComponentID returns the ComponentID associated with this instance. func (id *InstanceID) ComponentID() component.ID { return id.componentID } // Kind returns the component Kind associated with this instance. func (id *InstanceID) Kind() component.Kind { return id.kind } // AllPipelineIDs calls f for each pipeline this instance is associated with. If // f returns false it will stop iteration. func (id *InstanceID) AllPipelineIDs(f func(pipeline.ID) bool) { var bs []byte for _, b := range []byte(id.pipelineIDs) { if b != pipelineDelim { bs = append(bs, b) continue } pipelineID := pipeline.ID{} err := pipelineID.UnmarshalText(bs) bs = bs[:0] if err != nil { continue } if !f(pipelineID) { break } } } // WithPipelines returns a new InstanceID updated to include the given // pipelineIDs. func (id *InstanceID) WithPipelines(pipelineIDs ...pipeline.ID) *InstanceID { instanceID := &InstanceID{ componentID: id.componentID, kind: id.kind, pipelineIDs: id.pipelineIDs, } instanceID.addPipelines(pipelineIDs) return instanceID } func (id *InstanceID) addPipelines(pipelineIDs []pipeline.ID) { delim := string(pipelineDelim) strIDs := strings.Split(id.pipelineIDs, delim) for _, pID := range pipelineIDs { strIDs = append(strIDs, pID.String()) } sort.Strings(strIDs) strIDs = slices.Compact(strIDs) id.pipelineIDs = strings.Join(strIDs, delim) + delim } opentelemetry-collector-0.141.0/component/componentstatus/instance_test.go000066400000000000000000000052151511331344600272030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentstatus import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pipeline" ) func TestInstanceID(t *testing.T) { traces := component.MustNewID("traces") tracesA := pipeline.NewIDWithName(pipeline.SignalTraces, "a") tracesB := pipeline.NewIDWithName(pipeline.SignalTraces, "b") tracesC := pipeline.NewIDWithName(pipeline.SignalTraces, "c") idTracesA := NewInstanceID(traces, component.KindReceiver, tracesA) idTracesAll := NewInstanceID(traces, component.KindReceiver, tracesA, tracesB, tracesC) assert.NotEqual(t, idTracesA, idTracesAll) assertHasPipelines := func(t *testing.T, instanceID *InstanceID, expectedPipelineIDs []pipeline.ID) { var pipelineIDs []pipeline.ID instanceID.AllPipelineIDs(func(id pipeline.ID) bool { pipelineIDs = append(pipelineIDs, id) return true }) assert.Equal(t, expectedPipelineIDs, pipelineIDs) } for _, tc := range []struct { name string id1 *InstanceID id2 *InstanceID pipelineIDs []pipeline.ID }{ { name: "equal instances", id1: idTracesA, id2: NewInstanceID(traces, component.KindReceiver, tracesA), pipelineIDs: []pipeline.ID{tracesA}, }, { name: "equal instances - out of order", id1: idTracesAll, id2: NewInstanceID(traces, component.KindReceiver, tracesC, tracesB, tracesA), pipelineIDs: []pipeline.ID{tracesA, tracesB, tracesC}, }, { name: "with pipelines", id1: idTracesAll, id2: idTracesA.WithPipelines(tracesB, tracesC), pipelineIDs: []pipeline.ID{tracesA, tracesB, tracesC}, }, { name: "with pipelines - out of order", id1: idTracesAll, id2: idTracesA.WithPipelines(tracesC, tracesB), pipelineIDs: []pipeline.ID{tracesA, tracesB, tracesC}, }, } { t.Run(tc.name, func(t *testing.T) { assert.Equal(t, tc.id1, tc.id2) assertHasPipelines(t, tc.id1, tc.pipelineIDs) assertHasPipelines(t, tc.id2, tc.pipelineIDs) }) } } func TestAllPipelineIDs(t *testing.T) { instanceID := NewInstanceID( component.MustNewID("traces"), component.KindReceiver, pipeline.NewIDWithName(pipeline.SignalTraces, "a"), pipeline.NewIDWithName(pipeline.SignalTraces, "b"), pipeline.NewIDWithName(pipeline.SignalTraces, "c"), ) count := 0 instanceID.AllPipelineIDs(func(pipeline.ID) bool { count++ return true }) assert.Equal(t, 3, count) count = 0 instanceID.AllPipelineIDs(func(pipeline.ID) bool { count++ return false }) assert.Equal(t, 1, count) } opentelemetry-collector-0.141.0/component/componentstatus/status.go000066400000000000000000000153011511331344600256600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package componentstatus is an experimental module that defines how components should // report health statues, how collector hosts should facilitate component status reporting, // and how extensions should watch for new component statuses. // // This package is currently under development and is exempt from the Collector SIG's // breaking change policy. package componentstatus // import "go.opentelemetry.io/collector/component/componentstatus" import ( "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" ) // Reporter is an extra interface for `component.Host` implementations. // A Reporter defines how to report a `componentstatus.Event`. type Reporter interface { // Report allows a component to report runtime changes in status. The service // will automatically report status for a component during startup and shutdown. Components can // use this method to report status after start and before shutdown. For more details about // component status reporting see: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-status.md Report(*Event) } // Watcher is an extra interface for Extension hosted by the OpenTelemetry // Collector that is to be implemented by extensions interested in changes to component // status. // // TODO: consider moving this interface to a new package/module like `extension/statuswatcher` // https://github.com/open-telemetry/opentelemetry-collector/issues/10764 type Watcher interface { // ComponentStatusChanged notifies about a change in the source component status. // Extensions that implement this interface must be ready that the ComponentStatusChanged // may be called before, after or concurrently with calls to Component.Start() and Component.Shutdown(). // The function may be called concurrently with itself. ComponentStatusChanged(source *InstanceID, event *Event) } type Status int32 // Enumeration of possible component statuses const ( // StatusNone indicates absence of component status. StatusNone Status = iota // StatusStarting indicates the component is starting. StatusStarting // StatusOK indicates the component is running without issues. StatusOK // StatusRecoverableError indicates that the component has experienced a transient error and may recover. StatusRecoverableError // StatusPermanentError indicates that the component has detected a condition at runtime that will need human intervention to fix. The collector will continue to run in a degraded mode. StatusPermanentError // StatusFatalError indicates that the collector has experienced a fatal runtime error and will shut down. StatusFatalError // StatusStopping indicates that the component is in the process of shutting down. StatusStopping // StatusStopped indicates that the component has completed shutdown. StatusStopped ) // String returns a string representation of a Status func (s Status) String() string { switch s { case StatusStarting: return "StatusStarting" case StatusOK: return "StatusOK" case StatusRecoverableError: return "StatusRecoverableError" case StatusPermanentError: return "StatusPermanentError" case StatusFatalError: return "StatusFatalError" case StatusStopping: return "StatusStopping" case StatusStopped: return "StatusStopped" } return "StatusNone" } // Event contains a status, a timestamp, optional error information, and additional attributes type Event struct { // attributes provides additional context or metadata for the event. attributes pcommon.Map status Status err error // TODO: consider if a timestamp is necessary in the default Event struct or is needed only for the healthcheckv2 extension // https://github.com/open-telemetry/opentelemetry-collector/issues/10763 timestamp time.Time } // Status returns the Status (enum) associated with the Event func (ev *Event) Status() Status { return ev.status } // Err returns the error associated with the Event. func (ev *Event) Err() error { return ev.err } // Attributes returns the attributes (pcommon.Map) associated with the Event. func (ev *Event) Attributes() pcommon.Map { return ev.attributes } // Timestamp returns the timestamp associated with the Event func (ev *Event) Timestamp() time.Time { return ev.timestamp } // EventBuilderOption is a sealed interface wrapping options for [NewEvent]. type EventBuilderOption interface { applyOption(*Event) } type eventOptionFunc func(*Event) func (f eventOptionFunc) applyOption(event *Event) { f(event) } // NewEvent creates and returns an Event with the specified options and sets the timestamp // time.Now(). To set an error on the event for an error status use the // WithError with one of the dedicated status (e.g. StatusRecoverableError, StatusPermanentError, StatusFatalError) func NewEvent(st Status, opts ...EventBuilderOption) *Event { event := &Event{ timestamp: time.Now(), attributes: pcommon.NewMap(), status: st, } for _, opt := range opts { opt.applyOption(event) } return event } // WithAttributes sets the Event attributes. func WithAttributes(attributes pcommon.Map) EventBuilderOption { return eventOptionFunc(func(e *Event) { e.attributes = attributes }) } // WithError sets the Event error. func WithError(err error) EventBuilderOption { return eventOptionFunc(func(e *Event) { e.err = err }) } // NewRecoverableErrorEvent wraps a transient error // passed as argument as a Event with a status StatusRecoverableError // and a timestamp set to time.Now(). func NewRecoverableErrorEvent(err error) *Event { return NewEvent(StatusRecoverableError, WithError(err)) } // NewPermanentErrorEvent wraps an error requiring human intervention to fix // passed as argument as a Event with a status StatusPermanentError // and a timestamp set to time.Now(). func NewPermanentErrorEvent(err error) *Event { return NewEvent(StatusPermanentError, WithError(err)) } // NewFatalErrorEvent wraps the fatal runtime error passed as argument as a Event // with a status StatusFatalError and a timestamp set to time.Now(). func NewFatalErrorEvent(err error) *Event { return NewEvent(StatusFatalError, WithError(err)) } // StatusIsError returns true for error statuses (e.g. StatusRecoverableError, // StatusPermanentError, or StatusFatalError) func StatusIsError(status Status) bool { return status == StatusRecoverableError || status == StatusPermanentError || status == StatusFatalError } // ReportStatus is a helper function that handles checking if the component.Host has implemented Reporter. // If it has, the Event is reported. Otherwise, nothing happens. func ReportStatus(host component.Host, e *Event) { statusReporter, ok := host.(Reporter) if ok { statusReporter.Report(e) } } opentelemetry-collector-0.141.0/component/componentstatus/status_test.go000066400000000000000000000063001511331344600267160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentstatus import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestNewStatusEvent(t *testing.T) { statuses := []Status{ StatusStarting, StatusOK, StatusRecoverableError, StatusPermanentError, StatusFatalError, StatusStopping, StatusStopped, } for _, status := range statuses { t.Run(fmt.Sprintf("%s without error", status), func(t *testing.T) { ev := NewEvent(status) require.Equal(t, status, ev.Status()) require.NoError(t, ev.Err()) require.False(t, ev.Timestamp().IsZero()) require.Equal(t, pcommon.NewMap(), ev.Attributes()) }) t.Run(fmt.Sprintf("%s without error and attributes", status), func(t *testing.T) { eventAttrs := pcommon.NewMap() require.NoError(t, eventAttrs.FromRaw(map[string]any{"test": "a"})) ev := NewEvent(status, WithAttributes(eventAttrs)) require.Equal(t, status, ev.Status()) require.NoError(t, ev.Err()) require.False(t, ev.Timestamp().IsZero()) require.Equal(t, eventAttrs, ev.Attributes()) }) } } func TestStatusEventsWithError(t *testing.T) { statusConstructorMap := map[Status]func(error) *Event{ StatusRecoverableError: NewRecoverableErrorEvent, StatusPermanentError: NewPermanentErrorEvent, StatusFatalError: NewFatalErrorEvent, } for status, newEvent := range statusConstructorMap { t.Run(fmt.Sprintf("error status constructor for: %s", status), func(t *testing.T) { ev := newEvent(assert.AnError) require.Equal(t, status, ev.Status()) require.Equal(t, assert.AnError, ev.Err()) require.False(t, ev.Timestamp().IsZero()) }) } } func TestStatusIsError(t *testing.T) { for _, tc := range []struct { status Status isError bool }{ { status: StatusStarting, isError: false, }, { status: StatusOK, isError: false, }, { status: StatusRecoverableError, isError: true, }, { status: StatusPermanentError, isError: true, }, { status: StatusFatalError, isError: true, }, { status: StatusStopping, isError: false, }, { status: StatusStopped, isError: false, }, } { name := fmt.Sprintf("StatusIsError(%s) is %t", tc.status, tc.isError) t.Run(name, func(t *testing.T) { assert.Equal(t, tc.isError, StatusIsError(tc.status)) }) } } func Test_ReportStatus(t *testing.T) { t.Run("Reporter implemented", func(t *testing.T) { r := &reporter{} ReportStatus(r, NewEvent(StatusOK)) require.True(t, r.reportStatusCalled) }) t.Run("Reporter not implemented", func(t *testing.T) { h := &host{} ReportStatus(h, NewEvent(StatusOK)) require.False(t, h.reportStatusCalled) }) } var ( _ = component.Host(nil) _ = Reporter(nil) ) type reporter struct { reportStatusCalled bool } func (r *reporter) GetExtensions() map[component.ID]component.Component { return nil } func (r *reporter) Report(_ *Event) { r.reportStatusCalled = true } var _ = component.Host(nil) type host struct { reportStatusCalled bool } func (h *host) GetExtensions() map[component.ID]component.Component { return nil } opentelemetry-collector-0.141.0/component/componenttest/000077500000000000000000000000001511331344600234425ustar00rootroot00000000000000opentelemetry-collector-0.141.0/component/componenttest/Makefile000066400000000000000000000000361511331344600251010ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/component/componenttest/configtest.go000066400000000000000000000077261511331344600261520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest // import "go.opentelemetry.io/collector/component/componenttest" import ( "fmt" "reflect" "regexp" "strings" "go.uber.org/multierr" ) // The regular expression for valid config field tag. var configFieldTagRegExp = regexp.MustCompile("^[a-z0-9][a-z0-9_]*$") // CheckConfigStruct enforces that given configuration object is following the patterns // used by the collector. This ensures consistency between different implementations // of components and extensions. It is recommended for implementers of components // to call this function on their tests passing the default configuration of the // component factory. func CheckConfigStruct(config any) error { t := reflect.TypeOf(config) if t.Kind() == reflect.Ptr { t = t.Elem() } if t.Kind() != reflect.Struct { return fmt.Errorf("config must be a struct or a pointer to one, the passed object is a %s", t.Kind()) } return validateConfigDataType(t) } // validateConfigDataType performs a descending validation of the given type. // If the type is a struct it goes to each of its fields to check for the proper // tags. func validateConfigDataType(t reflect.Type) error { var errs error switch t.Kind() { case reflect.Ptr: errs = multierr.Append(errs, validateConfigDataType(t.Elem())) case reflect.Struct: // Reflect on the pointed data and check each of its fields. nf := t.NumField() for i := range nf { f := t.Field(i) errs = multierr.Append(errs, checkStructFieldTags(f)) } default: // The config object can carry other types but they are not used when // reading the configuration via koanf so ignore them. Basically ignore: // reflect.Uintptr, reflect.Chan, reflect.Func, reflect.Interface, and // reflect.UnsafePointer. } if errs != nil { return fmt.Errorf("type %q from package %q has invalid config settings: %w", t.Name(), t.PkgPath(), errs) } return nil } // checkStructFieldTags inspects the tags of a struct field. func checkStructFieldTags(f reflect.StructField) error { tagValue, ok := f.Tag.Lookup("mapstructure") if !ok { // Ignore special types. switch f.Type.Kind() { case reflect.Interface, reflect.Chan, reflect.Func, reflect.Uintptr, reflect.UnsafePointer: // Allow the config to carry the types above, but since they are not read // when loading configuration, just ignore them. return nil } // Public fields of other types should be tagged. chars := []byte(f.Name) if len(chars) > 0 && chars[0] >= 'A' && chars[0] <= 'Z' { return fmt.Errorf("mapstructure tag not present on field %q", f.Name) } // Not public field, no need to have a tag. return nil } if tagValue == "" { return fmt.Errorf("mapstructure tag on field %q is empty", f.Name) } tagParts := strings.Split(tagValue, ",") if tagParts[0] != "" { if tagParts[0] == "-" { // Nothing to do, as mapstructure decode skips this field. return nil } } for _, tag := range tagParts[1:] { switch tag { case "squash": if (f.Type.Kind() != reflect.Struct) && (f.Type.Kind() != reflect.Ptr || f.Type.Elem().Kind() != reflect.Struct) { return fmt.Errorf( "attempt to squash non-struct type on field %q", f.Name) } case "remain": if f.Type.Kind() != reflect.Map && f.Type.Kind() != reflect.Interface { return fmt.Errorf(`attempt to use "remain" on non-map or interface type field %q`, f.Name) } } } switch f.Type.Kind() { case reflect.Struct: // It is another struct, continue down-level. return validateConfigDataType(f.Type) case reflect.Map, reflect.Slice, reflect.Array: // The element of map, array, or slice can be itself a configuration object. return validateConfigDataType(f.Type.Elem()) default: fieldTag := tagParts[0] if fieldTag != "" && !configFieldTagRegExp.MatchString(fieldTag) { return fmt.Errorf( "field %q has config tag %q which doesn't satisfy %q", f.Name, fieldTag, configFieldTagRegExp.String()) } } return nil } opentelemetry-collector-0.141.0/component/componenttest/configtest_test.go000066400000000000000000000120011511331344600271670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest import ( "io" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestCheckConfigStructPointerAndValue(t *testing.T) { config := struct { SomeFiled string `mapstructure:"test"` }{} assert.NoError(t, CheckConfigStruct(config)) assert.NoError(t, CheckConfigStruct(&config)) } func TestCheckConfigStruct(t *testing.T) { type BadConfigTag struct { BadTagField int `mapstructure:"test-dash"` } tests := []struct { name string config any wantErrMsgSubStr string }{ { name: "typical_config", config: struct { MyPublicString string `mapstructure:"string"` }{}, }, { name: "private_fields_ignored", config: struct { // A public type with proper tag. MyPublicString string `mapstructure:"string"` // A public type with proper tag. MyPublicInt string `mapstructure:"int"` // A public type that should be ignored. MyFunc func() error // A public type that should be ignored. Reader io.Reader // private type not tagged. myPrivateString string _someInt int }{}, }, { name: "remain_mapstructure_tag", config: struct { AdditionalProperties map[string]any `mapstructure:",remain"` }{}, }, { name: "remain_with_interface_type", config: struct { AdditionalProperties any `mapstructure:",remain"` }{}, }, { name: "omitempty_mapstructure_tag", config: struct { MyPublicString string `mapstructure:",omitempty"` }{}, }, { name: "named_omitempty_mapstructure_tag", config: struct { MyPublicString string `mapstructure:"my_public_string,omitempty"` }{}, }, { name: "not_struct_nor_pointer", config: func(x int) int { return x * x }, wantErrMsgSubStr: "config must be a struct or a pointer to one, the passed object is a func", }, { name: "squash_on_non_struct", config: struct { MyInt int `mapstructure:",squash"` }{}, wantErrMsgSubStr: "attempt to squash non-struct type on field \"MyInt\"", }, { name: "remain_on_non_map", config: struct { AdditionalProperties string `mapstructure:",remain"` }{}, wantErrMsgSubStr: `attempt to use "remain" on non-map or interface type field "AdditionalProperties"`, }, { name: "bad_custom_field_name", config: struct { AdditionalProperties any `mapstructure:"Additional_Properties"` }{}, wantErrMsgSubStr: `field "AdditionalProperties" has config tag "Additional_Properties" which doesn't satisfy "^[a-z0-9][a-z0-9_]*$"`, }, { name: "invalid_tag_detected", config: BadConfigTag{}, wantErrMsgSubStr: "field \"BadTagField\" has config tag \"test-dash\" which doesn't satisfy", }, { name: "public_field_must_have_tag", config: struct { PublicFieldWithoutMapstructureTag string }{}, wantErrMsgSubStr: "mapstructure tag not present on field \"PublicFieldWithoutMapstructureTag\"", }, { name: "public_field_must_have_nonempty_tag", config: struct { PublicFieldWithoutMapstructureTag string `mapstructure:""` }{}, wantErrMsgSubStr: "mapstructure tag on field \"PublicFieldWithoutMapstructureTag\" is empty", }, { name: "invalid_map_item", config: struct { Map map[string]BadConfigTag `mapstructure:"test_map"` }{}, wantErrMsgSubStr: "field \"BadTagField\" has config tag \"test-dash\" which doesn't satisfy", }, { name: "invalid_slice_item", config: struct { Slice []BadConfigTag `mapstructure:"test_slice"` }{}, wantErrMsgSubStr: "field \"BadTagField\" has config tag \"test-dash\" which doesn't satisfy", }, { name: "invalid_array_item", config: struct { Array [2]BadConfigTag `mapstructure:"test_array"` }{}, wantErrMsgSubStr: "field \"BadTagField\" has config tag \"test-dash\" which doesn't satisfy", }, { name: "invalid_map_item_ptr", config: struct { Map map[string]*BadConfigTag `mapstructure:"test_map"` }{}, wantErrMsgSubStr: "field \"BadTagField\" has config tag \"test-dash\" which doesn't satisfy", }, { name: "invalid_slice_item_ptr", config: struct { Slice []*BadConfigTag `mapstructure:"test_slice"` }{}, wantErrMsgSubStr: "field \"BadTagField\" has config tag \"test-dash\" which doesn't satisfy", }, { name: "invalid_array_item_ptr", config: struct { Array [2]*BadConfigTag `mapstructure:"test_array"` }{}, wantErrMsgSubStr: "field \"BadTagField\" has config tag \"test-dash\" which doesn't satisfy", }, { name: "valid_map_item", config: struct { Map map[string]int `mapstructure:"test_map"` }{}, }, { name: "valid_slice_item", config: struct { Slice []string `mapstructure:"test_slice"` }{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := CheckConfigStruct(tt.config) if tt.wantErrMsgSubStr == "" { assert.NoError(t, err) } else { require.ErrorContains(t, err, tt.wantErrMsgSubStr) } }) } } opentelemetry-collector-0.141.0/component/componenttest/doc.go000066400000000000000000000004501511331344600245350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package componenttest define types and functions used to help test packages // implementing the component package interfaces. package componenttest // import "go.opentelemetry.io/collector/component/componenttest" opentelemetry-collector-0.141.0/component/componenttest/go.mod000066400000000000000000000026751511331344600245620ustar00rootroot00000000000000module go.opentelemetry.io/collector/component/componenttest go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../ replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/component/componenttest/go.sum000066400000000000000000000140451511331344600246010ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/component/componenttest/nop_host.go000066400000000000000000000013521511331344600256230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest // import "go.opentelemetry.io/collector/component/componenttest" import ( "go.opentelemetry.io/collector/component" ) var _ component.Host = (*nopHost)(nil) // nopHost mocks a [component.Host] for testing purposes. type nopHost struct{} // NewNopHost returns a [component.Host] that returns empty values // from method calls. This host is intended to be used in tests // where a bare-minimum host is desired. func NewNopHost() component.Host { return &nopHost{} } // GetExtensions returns an empty extensions map. func (nh *nopHost) GetExtensions() map[component.ID]component.Component { return map[component.ID]component.Component{} } opentelemetry-collector-0.141.0/component/componenttest/nop_host_test.go000066400000000000000000000006351511331344600266650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewNopHost(t *testing.T) { nh := NewNopHost() require.NotNil(t, nh) require.IsType(t, &nopHost{}, nh) extensions := nh.GetExtensions() assert.NotNil(t, extensions) assert.Empty(t, extensions) } opentelemetry-collector-0.141.0/component/componenttest/nop_telemetry.go000066400000000000000000000013571511331344600266650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest // import "go.opentelemetry.io/collector/component/componenttest" import ( noopmetric "go.opentelemetry.io/otel/metric/noop" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" ) // NewNopTelemetrySettings returns a new nop telemetry settings for Create* functions. func NewNopTelemetrySettings() component.TelemetrySettings { return component.TelemetrySettings{ Logger: zap.NewNop(), TracerProvider: nooptrace.NewTracerProvider(), MeterProvider: noopmetric.NewMeterProvider(), Resource: pcommon.NewResource(), } } opentelemetry-collector-0.141.0/component/componenttest/nop_telemetry_test.go000066400000000000000000000010411511331344600277120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest import ( "testing" "github.com/stretchr/testify/assert" ) func TestNewNopTelemetrySettings(t *testing.T) { nts := NewNopTelemetrySettings() assert.NotNil(t, nts.Logger) assert.NotNil(t, nts.TracerProvider) assert.NotPanics(t, func() { nts.TracerProvider.Tracer("test") }) assert.NotNil(t, nts.MeterProvider) assert.NotPanics(t, func() { nts.MeterProvider.Meter("test") }) assert.Equal(t, 0, nts.Resource.Attributes().Len()) } opentelemetry-collector-0.141.0/component/componenttest/package_test.go000066400000000000000000000003161511331344600264230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/component/componenttest/telemetry.go000066400000000000000000000051201511331344600260010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest // import "go.opentelemetry.io/collector/component/componenttest" import ( "context" "errors" "fmt" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/collector/component" ) type TelemetryOption interface { apply(*telemetryOption) } type telemetryOption struct { metricOpts []sdkmetric.Option traceOpts []sdktrace.TracerProviderOption } type telemetryOptionFunc func(*telemetryOption) func (f telemetryOptionFunc) apply(o *telemetryOption) { f(o) } func WithMetricOptions(opts ...sdkmetric.Option) TelemetryOption { return telemetryOptionFunc(func(to *telemetryOption) { to.metricOpts = append(to.metricOpts, opts...) }) } func WithTraceOptions(opts ...sdktrace.TracerProviderOption) TelemetryOption { return telemetryOptionFunc(func(to *telemetryOption) { to.traceOpts = append(to.traceOpts, opts...) }) } type Telemetry struct { Reader *sdkmetric.ManualReader SpanRecorder *tracetest.SpanRecorder meterProvider *sdkmetric.MeterProvider traceProvider *sdktrace.TracerProvider } func NewTelemetry(opts ...TelemetryOption) *Telemetry { reader := sdkmetric.NewManualReader() spanRecorder := new(tracetest.SpanRecorder) tOpts := telemetryOption{ metricOpts: []sdkmetric.Option{sdkmetric.WithReader(reader)}, traceOpts: []sdktrace.TracerProviderOption{sdktrace.WithSpanProcessor(spanRecorder)}, } for _, opt := range opts { opt.apply(&tOpts) } return &Telemetry{ Reader: reader, SpanRecorder: spanRecorder, meterProvider: sdkmetric.NewMeterProvider(tOpts.metricOpts...), traceProvider: sdktrace.NewTracerProvider(tOpts.traceOpts...), } } func (tt *Telemetry) NewTelemetrySettings() component.TelemetrySettings { set := NewNopTelemetrySettings() set.MeterProvider = tt.meterProvider set.TracerProvider = tt.traceProvider return set } func (tt *Telemetry) GetMetric(name string) (metricdata.Metrics, error) { var rm metricdata.ResourceMetrics if err := tt.Reader.Collect(context.Background(), &rm); err != nil { return metricdata.Metrics{}, err } for _, sm := range rm.ScopeMetrics { for _, m := range sm.Metrics { if m.Name == name { return m, nil } } } return metricdata.Metrics{}, fmt.Errorf("metric '%s' not found", name) } func (tt *Telemetry) Shutdown(ctx context.Context) error { return errors.Join( tt.meterProvider.Shutdown(ctx), tt.traceProvider.Shutdown(ctx), ) } opentelemetry-collector-0.141.0/component/componenttest/telemetry_test.go000066400000000000000000000012251511331344600270420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componenttest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdkmetric "go.opentelemetry.io/otel/sdk/metric" sdktrace "go.opentelemetry.io/otel/sdk/trace" ) func TestNewTelemetry(t *testing.T) { tel := NewTelemetry() assert.NotNil(t, tel.Reader) assert.NotNil(t, tel.SpanRecorder) set := tel.NewTelemetrySettings() assert.IsType(t, &sdktrace.TracerProvider{}, set.TracerProvider) assert.IsType(t, &sdkmetric.MeterProvider{}, set.MeterProvider) require.NoError(t, tel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/component/config.go000066400000000000000000000011151511331344600223320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component // import "go.opentelemetry.io/collector/component" // Config defines the configuration for a component.Component. // // Implementations and/or any sub-configs (other types embedded or included in the Config implementation) // MUST implement xconfmap.Validator if any validation is required for that part of the configuration // (e.g. check if a required field is present). // // A valid implementation MUST pass the check componenttest.CheckConfigStruct (return nil error). type Config any opentelemetry-collector-0.141.0/component/doc.go000066400000000000000000000006141511331344600216350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package component outlines the components used in the collector // and provides a foundation for the componentโ€™s creation and // termination process. A component can be either a receiver, exporter, // processor, an extension, or a connector. package component // import "go.opentelemetry.io/collector/component" opentelemetry-collector-0.141.0/component/go.mod000066400000000000000000000023151511331344600216470ustar00rootroot00000000000000module go.opentelemetry.io/collector/component go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../pdata retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/component/go.sum000066400000000000000000000124431511331344600216770ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/component/host.go000066400000000000000000000022511511331344600220440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component // import "go.opentelemetry.io/collector/component" // Host represents the entity that is hosting a Component. It is used to allow communication // between the Component and its host (normally the service.Collector is the host). // // Components may require `component.Host` to implement additional interfaces to properly function. // The component is expected to cast the `component.Host` to the interface it needs and return // an error if the type assertion fails. type Host interface { // GetExtensions returns the map of extensions. Only enabled and created extensions will be returned. // Typically, it is used to find an extension by type or by full config name. Both cases // can be done by iterating the returned map. There are typically very few extensions, // so there are no performance implications due to iteration. // // GetExtensions can be called by the component anytime after Component.Start() begins and // until Component.Shutdown() ends. // // The returned map should only be nil if the host does not support extensions at all. GetExtensions() map[ID]Component } opentelemetry-collector-0.141.0/component/identifiable.go000066400000000000000000000121641511331344600235120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component // import "go.opentelemetry.io/collector/component" import ( "encoding" "errors" "fmt" "regexp" "strings" ) // typeAndNameSeparator is the separator that is used between type and name in type/name composite keys. const typeAndNameSeparator = "/" var ( // typeRegexp is used to validate the type of component. // A type must start with an ASCII alphabetic character and // can only contain ASCII alphanumeric characters and '_'. // This must be kept in sync with the regex in cmd/mdatagen/validate.go. typeRegexp = regexp.MustCompile(`^[a-zA-Z][0-9a-zA-Z_]{0,62}$`) // nameRegexp is used to validate the name of a component. A name can consist of // 1 to 1024 Unicode characters excluding whitespace, control characters, and // symbols. nameRegexp = regexp.MustCompile(`^[^\pZ\pC\pS]+$`) ) var _ fmt.Stringer = Type{} // Type is the component type as it is used in the config. type Type struct { name string } // String returns the string representation of the type. func (t Type) String() string { return t.name } // MarshalText marshals returns the Type name. func (t Type) MarshalText() ([]byte, error) { return []byte(t.name), nil } // NewType creates a type. It returns an error if the type is invalid. // A type must // - have at least one character, // - start with an ASCII alphabetic character and // - can only contain ASCII alphanumeric characters and '_'. func NewType(ty string) (Type, error) { if ty == "" { return Type{}, errors.New("id must not be empty") } if !typeRegexp.MatchString(ty) { return Type{}, fmt.Errorf("invalid character(s) in type %q", ty) } return Type{name: ty}, nil } // MustNewType creates a type. It panics if the type is invalid. // A type must // - have at least one character, // - start with an ASCII alphabetic character and // - can only contain ASCII alphanumeric characters and '_'. func MustNewType(strType string) Type { ty, err := NewType(strType) if err != nil { panic(err) } return ty } var ( _ fmt.Stringer = ID{} _ encoding.TextMarshaler = ID{} _ encoding.TextUnmarshaler = (*ID)(nil) ) // ID represents the identity for a component. It combines two values: // * type - the Type of the component. // * name - the name of that component. // The component ID (combination type + name) is unique for a given component.Kind. type ID struct { typeVal Type `mapstructure:"-"` nameVal string `mapstructure:"-"` } // NewID returns a new ID with the given Type and empty name. func NewID(typeVal Type) ID { return ID{typeVal: typeVal} } // MustNewID builds a Type and returns a new ID with the given Type and empty name. // This is equivalent to NewID(MustNewType(typeVal)). // See MustNewType to check the valid values of typeVal. func MustNewID(typeVal string) ID { return NewID(MustNewType(typeVal)) } // NewIDWithName returns a new ID with the given Type and name. func NewIDWithName(typeVal Type, nameVal string) ID { return ID{typeVal: typeVal, nameVal: nameVal} } // MustNewIDWithName builds a Type and returns a new ID with the given Type and name. // This is equivalent to NewIDWithName(MustNewType(typeVal), nameVal). // See MustNewType to check the valid values of typeVal. func MustNewIDWithName(typeVal, nameVal string) ID { return NewIDWithName(MustNewType(typeVal), nameVal) } // Type returns the type of the component. func (id ID) Type() Type { return id.typeVal } // Name returns the custom name of the component. func (id ID) Name() string { return id.nameVal } // MarshalText implements the encoding.TextMarshaler interface. // This marshals the type and name as one string in the config. func (id ID) MarshalText() ([]byte, error) { return []byte(id.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface. func (id *ID) UnmarshalText(text []byte) error { idStr := string(text) typeStr, nameStr, hasName := strings.Cut(idStr, typeAndNameSeparator) typeStr = strings.TrimSpace(typeStr) if typeStr == "" { if hasName { return fmt.Errorf("in %q id: the part before %s should not be empty", idStr, typeAndNameSeparator) } return errors.New("id must not be empty") } if hasName { // "name" part is present. nameStr = strings.TrimSpace(nameStr) if nameStr == "" { return fmt.Errorf("in %q id: the part after %s should not be empty", idStr, typeAndNameSeparator) } if err := validateName(nameStr); err != nil { return fmt.Errorf("in %q id: %w", nameStr, err) } } var err error if id.typeVal, err = NewType(typeStr); err != nil { return fmt.Errorf("in %q id: %w", idStr, err) } id.nameVal = nameStr return nil } // String returns the ID string representation as "type[/name]" format. func (id ID) String() string { if id.nameVal == "" { return id.typeVal.String() } return id.typeVal.String() + typeAndNameSeparator + id.nameVal } func validateName(nameStr string) error { if len(nameStr) > 1024 { return fmt.Errorf("name %q is longer than 1024 characters (%d characters)", nameStr, len(nameStr)) } if !nameRegexp.MatchString(nameStr) { return fmt.Errorf("invalid character(s) in name %q", nameStr) } return nil } opentelemetry-collector-0.141.0/component/identifiable_example_test.go000066400000000000000000000022101511331344600262530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component_test import ( "fmt" "go.opentelemetry.io/collector/component" ) func ExampleNewType() { t, err := component.NewType("exampleexporter") if err != nil { fmt.Println("error:", err) return } fmt.Println(t.String()) // Output: // exampleexporter } func ExampleMustNewType() { t := component.MustNewType("examplereceiver") fmt.Println(t.String()) // Output: // examplereceiver } func ExampleNewID() { t := component.MustNewType("exampleprocessor") id := component.NewID(t) fmt.Println(id.String()) // Output: // exampleprocessor } func ExampleMustNewID() { id := component.MustNewID("examplereceiver") fmt.Println(id.String()) // Output: // examplereceiver } func ExampleNewIDWithName() { t := component.MustNewType("exampleexporter") id := component.NewIDWithName(t, "customname") fmt.Println(id.String()) // Output: // exampleexporter/customname } func ExampleMustNewIDWithName() { id := component.MustNewIDWithName("exampleprocessor", "customproc") fmt.Println(id.String()) // Output: // exampleprocessor/customproc } opentelemetry-collector-0.141.0/component/identifiable_test.go000066400000000000000000000170131511331344600245470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestMarshalText(t *testing.T) { id := NewIDWithName(MustNewType("test"), "name") got, err := id.MarshalText() require.NoError(t, err) assert.Equal(t, id.String(), string(got)) } func TestUnmarshalText(t *testing.T) { validType := MustNewType("valid_type") testCases := []struct { name string expectedErr bool expectedID ID }{ { name: "valid_type", expectedID: ID{typeVal: validType, nameVal: ""}, }, { name: "valid_type/valid_name", expectedID: ID{typeVal: validType, nameVal: "valid_name"}, }, { name: " valid_type / valid_name ", expectedID: ID{typeVal: validType, nameVal: "valid_name"}, }, { name: "valid_type/ไธญๆ–‡ๅฅฝ", expectedID: ID{typeVal: validType, nameVal: "ไธญๆ–‡ๅฅฝ"}, }, { name: "valid_type/name-with-dashes", expectedID: ID{typeVal: validType, nameVal: "name-with-dashes"}, }, // issue 10816 { name: "valid_type/Linux-Messages-File_01J49HCH3SWFXRVASWFZFRT3J2__processor0__logs", expectedID: ID{typeVal: validType, nameVal: "Linux-Messages-File_01J49HCH3SWFXRVASWFZFRT3J2__processor0__logs"}, }, { name: "valid_type/1", expectedID: ID{typeVal: validType, nameVal: "1"}, }, { name: "/valid_name", expectedErr: true, }, { name: " /valid_name", expectedErr: true, }, { name: "valid_type/", expectedErr: true, }, { name: "valid_type/ ", expectedErr: true, }, { name: " ", expectedErr: true, }, { name: "valid_type/invalid name", expectedErr: true, }, { name: "valid_type/" + strings.Repeat("a", 1025), expectedErr: true, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { id := ID{} err := id.UnmarshalText([]byte(tt.name)) if tt.expectedErr { assert.Error(t, err) return } require.NoError(t, err) assert.Equal(t, tt.expectedID, id) assert.Equal(t, tt.expectedID.Type(), id.Type()) assert.Equal(t, tt.expectedID.Name(), id.Name()) assert.Equal(t, tt.expectedID.String(), id.String()) }) } } func TestNewType(t *testing.T) { tests := []struct { name string shouldErr bool }{ {name: "active_directory_ds"}, {name: "aerospike"}, {name: "alertmanager"}, {name: "alibabacloud_logservice"}, {name: "apache"}, {name: "apachespark"}, {name: "asapclient"}, {name: "attributes"}, {name: "awscloudwatch"}, {name: "awscloudwatchlogs"}, {name: "awscloudwatchmetrics"}, {name: "awscontainerinsightreceiver"}, {name: "awsecscontainermetrics"}, {name: "awsemf"}, {name: "awsfirehose"}, {name: "awskinesis"}, {name: "awsproxy"}, {name: "awss3"}, {name: "awsxray"}, {name: "azureblob"}, {name: "azuredataexplorer"}, {name: "azureeventhub"}, {name: "azuremonitor"}, {name: "basicauth"}, {name: "batch"}, {name: "bearertokenauth"}, {name: "bigip"}, {name: "carbon"}, {name: "cassandra"}, {name: "chrony"}, {name: "clickhouse"}, {name: "cloudflare"}, {name: "cloudfoundry"}, {name: "collectd"}, {name: "configschema"}, {name: "coralogix"}, {name: "couchdb"}, {name: "count"}, {name: "cumulativetodelta"}, {name: "datadog"}, {name: "dataset"}, {name: "db_storage"}, {name: "debug"}, {name: "deltatorate"}, {name: "demo"}, {name: "docker_observer"}, {name: "docker_stats"}, {name: "dynatrace"}, {name: "ecs_observer"}, {name: "ecs_task_observer"}, {name: "elasticsearch"}, {name: "exceptions"}, {name: "experimental_metricsgeneration"}, {name: "expvar"}, {name: "f5cloud"}, {name: "failover"}, {name: "file"}, {name: "filelog"}, {name: "filestats"}, {name: "file_storage"}, {name: "filter"}, {name: "flinkmetrics"}, {name: "fluentforward"}, {name: "forward"}, {name: "githubgen"}, {name: "gitprovider"}, {name: "golden"}, {name: "googlecloud"}, {name: "googlecloudpubsub"}, {name: "googlecloudspanner"}, {name: "googlemanagedprometheus"}, {name: "groupbyattrs"}, {name: "groupbytrace"}, {name: "haproxy"}, {name: "headers_setter"}, {name: "health_check"}, {name: "honeycombmarker"}, {name: "hostmetrics"}, {name: "host_observer"}, {name: "httpcheck"}, {name: "http_forwarder"}, {name: "iis"}, {name: "influxdb"}, {name: "instana"}, {name: "interval"}, {name: "jaeger"}, {name: "jaeger_encoding"}, {name: "jaegerremotesampling"}, {name: "jmx"}, {name: "journald"}, {name: "json_log_encoding"}, {name: "k8sattributes"}, {name: "k8s_cluster"}, {name: "k8s_events"}, {name: "k8sobjects"}, {name: "k8s_observer"}, {name: "kafka"}, {name: "kafkametrics"}, {name: "kinetica"}, {name: "kubeletstats"}, {name: "loadbalancing"}, {name: "logicmonitor"}, {name: "logstransform"}, {name: "logzio"}, {name: "loki"}, {name: "mdatagen"}, {name: "memcached"}, {name: "memory_limiter"}, {name: "metricstransform"}, {name: "mezmo"}, {name: "mongodb"}, {name: "mongodbatlas"}, {name: "mysql"}, {name: "namedpipe"}, {name: "nginx"}, {name: "nsxt"}, {name: "oauth2client"}, {name: "oidc"}, {name: "opamp"}, {name: "opampsupervisor"}, {name: "opencensus"}, {name: "opensearch"}, {name: "oracledb"}, {name: "osquery"}, {name: "otelarrow"}, {name: "otelcontribcol"}, {name: "oteltestbedcol"}, {name: "otlp"}, {name: "otlp_encoding"}, {name: "otlphttp"}, {name: "otlpjsonfile"}, {name: "ottl"}, {name: "podman_stats"}, {name: "postgresql"}, {name: "pprof"}, {name: "probabilistic_sampler"}, {name: "prometheus"}, {name: "prometheusremotewrite"}, {name: "prometheus_simple"}, {name: "pulsar"}, {name: "purefa"}, {name: "purefb"}, {name: "rabbitmq"}, {name: "receiver_creator"}, {name: "redaction"}, {name: "redis"}, {name: "remotetap"}, {name: "resource"}, {name: "resourcedetection"}, {name: "riak"}, {name: "routing"}, {name: "saphana"}, {name: "sapm"}, {name: "schema"}, {name: "sentry"}, {name: "servicegraph"}, {name: "signalfx"}, {name: "sigv4auth"}, {name: "skywalking"}, {name: "snmp"}, {name: "snowflake"}, {name: "solace"}, {name: "solarwindsapmsettings"}, {name: "span"}, {name: "spanmetrics"}, {name: "splunkenterprise"}, {name: "splunk_hec"}, {name: "sqlquery"}, {name: "sqlserver"}, {name: "sshcheck"}, {name: "statsd"}, {name: "sumologic"}, {name: "syslog"}, {name: "tail_sampling"}, {name: "tcplog"}, {name: "telemetrygen"}, {name: "tencentcloud_logservice"}, {name: "text_encoding"}, {name: "transform"}, {name: "udplog"}, {name: "vcenter"}, {name: "wavefront"}, {name: "webhookevent"}, {name: "windowseventlog"}, {name: "windowsperfcounters"}, {name: "zipkin"}, {name: "zipkin_encoding"}, {name: "zookeeper"}, {name: "zpages"}, {name: strings.Repeat("a", 63)}, {name: "", shouldErr: true}, {name: "contains spaces", shouldErr: true}, {name: "contains-dashes", shouldErr: true}, {name: "0startswithnumber", shouldErr: true}, {name: "contains/slash", shouldErr: true}, {name: "contains:colon", shouldErr: true}, {name: "contains#hash", shouldErr: true}, {name: strings.Repeat("a", 64), shouldErr: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ty, err := NewType(tt.name) if tt.shouldErr { assert.Error(t, err) } else { require.NoError(t, err) assert.Equal(t, tt.name, ty.String()) } }) } } opentelemetry-collector-0.141.0/component/package_test.go000066400000000000000000000003121511331344600235150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/component/telemetry.go000066400000000000000000000021751511331344600231060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package component // import "go.opentelemetry.io/collector/component" import ( "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.opentelemetry.io/collector/pdata/pcommon" ) // TelemetrySettings provides components with APIs to report telemetry. type TelemetrySettings struct { // Logger that the factory can use during creation and can pass to the created // component to be used later as well. Logger *zap.Logger // TracerProvider that the factory can pass to other instrumented third-party libraries. // // The service may wrap this provider for attribute injection. The wrapper may implement an // additional `Unwrap() trace.TracerProvider` method to grant access to the underlying SDK. TracerProvider trace.TracerProvider // MeterProvider that the factory can pass to other instrumented third-party libraries. MeterProvider metric.MeterProvider // Resource contains the resource attributes for the collector's telemetry. Resource pcommon.Resource // prevent unkeyed literal initialization _ struct{} } opentelemetry-collector-0.141.0/config/000077500000000000000000000000001511331344600200035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configauth/000077500000000000000000000000001511331344600221325ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configauth/Makefile000066400000000000000000000000361511331344600235710ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configauth/README.md000066400000000000000000000065461511331344600234240ustar00rootroot00000000000000# Authentication configuration This module defines necessary interfaces to implement server and client type authenticators: - Server type authenticators perform authentication for incoming HTTP/gRPC requests and are typically used in receivers. - Client type authenticators perform client-side authentication for outgoing HTTP/gRPC requests and are typically used in exporters. The currently known authenticators are listed below. ## Server Authenticators - [Basic Auth Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/basicauthextension) - [Bearer Token Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/bearertokenauthextension) - [OIDC Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/oidcauthextension) ## Client Authenticators - [ASAP Client Authentication Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/asapauthextension) - [Basic Auth Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/basicauthextension) - [Bearer Token Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/bearertokenauthextension) - [OAuth2 Client Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/oauth2clientauthextension) - [Sigv4 Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/sigv4authextension) Example: ```yaml extensions: oidc: # see the blog post on securing the otelcol for information # on how to setup an OIDC server and how to generate the TLS certs # required for this example # https://medium.com/opentelemetry/securing-your-opentelemetry-collector-1a4f9fa5bd6f issuer_url: http://localhost:8080/auth/realms/opentelemetry audience: account oauth2client: client_id: someclientid client_secret: someclientsecret token_url: https://example.com/oauth2/default/v1/token scopes: ["api.metrics"] # tls settings for the token client tls: insecure: true ca_file: /var/lib/mycert.pem cert_file: certfile key_file: keyfile # timeout for the token client timeout: 2s receivers: otlp/with_auth: protocols: grpc: endpoint: localhost:4318 tls: cert_file: /tmp/certs/cert.pem key_file: /tmp/certs/cert-key.pem auth: ## oidc is the extension name to use as the authenticator for this receiver authenticator: oidc otlphttp/withauth: endpoint: http://localhost:9000 auth: authenticator: oauth2client ``` ## Creating an authenticator New authenticators can be added by creating a new extension that also implements the appropriate interface (`configauth.ServerAuthenticator` or `configauth.ClientAuthenticator`). Generic authenticators that may be used by a good number of users might be accepted as part of the contrib distribution. If you have an interest in contributing an authenticator, open an issue with your proposal. For other cases, you'll need to include your custom authenticator as part of your custom OpenTelemetry Collector, perhaps being built using the [OpenTelemetry Collector Builder](https://github.com/open-telemetry/opentelemetry-collector/tree/main/cmd/builder). opentelemetry-collector-0.141.0/config/configauth/configauth.go000066400000000000000000000061651511331344600246200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package configauth implements the configuration settings to // ensure authentication on incoming requests, and allows // exporters to add authentication on outgoing requests. package configauth // import "go.opentelemetry.io/collector/config/configauth" import ( "context" "errors" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension/extensionauth" ) var ( errAuthenticatorNotFound = errors.New("authenticator not found") errNotHTTPClient = errors.New("requested authenticator is not a HTTP client authenticator") errNotGRPCClient = errors.New("requested authenticator is not a gRPC client authenticator") errNotServer = errors.New("requested authenticator is not a server authenticator") ) // Config defines the auth settings for the receiver. type Config struct { // AuthenticatorID specifies the name of the extension to use in order to authenticate the incoming data point. AuthenticatorID component.ID `mapstructure:"authenticator,omitempty"` // prevent unkeyed literal initialization _ struct{} } // GetServerAuthenticator attempts to select the appropriate extensionauth.Server from the list of extensions, // based on the requested extension name. If an authenticator is not found, an error is returned. func (a Config) GetServerAuthenticator(_ context.Context, extensions map[component.ID]component.Component) (extensionauth.Server, error) { if ext, found := extensions[a.AuthenticatorID]; found { if server, ok := ext.(extensionauth.Server); ok { return server, nil } return nil, errNotServer } return nil, fmt.Errorf("failed to resolve authenticator %q: %w", a.AuthenticatorID, errAuthenticatorNotFound) } // GetHTTPClientAuthenticator attempts to select the appropriate extensionauth.Client from the list of extensions, // based on the component id of the extension. If an authenticator is not found, an error is returned. // This should be only used by HTTP clients. func (a Config) GetHTTPClientAuthenticator(_ context.Context, extensions map[component.ID]component.Component) (extensionauth.HTTPClient, error) { if ext, found := extensions[a.AuthenticatorID]; found { if client, ok := ext.(extensionauth.HTTPClient); ok { return client, nil } return nil, errNotHTTPClient } return nil, fmt.Errorf("failed to resolve authenticator %q: %w", a.AuthenticatorID, errAuthenticatorNotFound) } // GetGRPCClientAuthenticator attempts to select the appropriate extensionauth.Client from the list of extensions, // based on the component id of the extension. If an authenticator is not found, an error is returned. // This should be only used by gRPC clients. func (a Config) GetGRPCClientAuthenticator(_ context.Context, extensions map[component.ID]component.Component) (extensionauth.GRPCClient, error) { if ext, found := extensions[a.AuthenticatorID]; found { if client, ok := ext.(extensionauth.GRPCClient); ok { return client, nil } return nil, errNotGRPCClient } return nil, fmt.Errorf("failed to resolve authenticator %q: %w", a.AuthenticatorID, errAuthenticatorNotFound) } opentelemetry-collector-0.141.0/config/configauth/configauth_test.go000066400000000000000000000055511511331344600256550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configauth import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest" ) var mockID = component.MustNewID("mock") func TestGetServer(t *testing.T) { testCases := []struct { name string authenticator extension.Extension expected error }{ { name: "obtain server authenticator", authenticator: extensionauthtest.NewNopServer(), expected: nil, }, { name: "not a server authenticator", authenticator: extensionauthtest.NewNopClient(), expected: errNotServer, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { // prepare cfg := &Config{ AuthenticatorID: mockID, } ext := map[component.ID]component.Component{ mockID: tt.authenticator, } authenticator, err := cfg.GetServerAuthenticator(context.Background(), ext) // verify if tt.expected != nil { require.ErrorIs(t, err, tt.expected) assert.Nil(t, authenticator) } else { require.NoError(t, err) assert.NotNil(t, authenticator) } }) } } func TestGetServerFails(t *testing.T) { cfg := &Config{ AuthenticatorID: component.MustNewID("does_not_exist"), } authenticator, err := cfg.GetServerAuthenticator(context.Background(), map[component.ID]component.Component{}) require.ErrorIs(t, err, errAuthenticatorNotFound) assert.Nil(t, authenticator) } func TestGetHTTPClient(t *testing.T) { testCases := []struct { name string authenticator extension.Extension expected error }{ { name: "obtain client authenticator", authenticator: extensionauthtest.NewNopClient(), expected: nil, }, { name: "not a client authenticator", authenticator: extensionauthtest.NewNopServer(), expected: errNotHTTPClient, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { // prepare cfg := &Config{ AuthenticatorID: mockID, } ext := map[component.ID]component.Component{ mockID: tt.authenticator, } authenticator, err := cfg.GetHTTPClientAuthenticator(context.Background(), ext) // verify if tt.expected != nil { require.ErrorIs(t, err, tt.expected) assert.Nil(t, authenticator) } else { require.NoError(t, err) assert.NotNil(t, authenticator) } }) } } func TestGetGRPCClientFails(t *testing.T) { cfg := &Config{ AuthenticatorID: component.MustNewID("does_not_exist"), } authenticator, err := cfg.GetGRPCClientAuthenticator(context.Background(), map[component.ID]component.Component{}) require.ErrorIs(t, err, errAuthenticatorNotFound) assert.Nil(t, authenticator) } opentelemetry-collector-0.141.0/config/configauth/go.mod000066400000000000000000000034311511331344600232410ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configauth go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensionauth v1.47.0 go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/config/configauth/go.sum000066400000000000000000000143221511331344600232670ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configauth/metadata.yaml000066400000000000000000000002031511331344600245710ustar00rootroot00000000000000type: config/configauth github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configauth/package_test.go000066400000000000000000000003131511331344600251100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configauth import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configcompression/000077500000000000000000000000001511331344600235325ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configcompression/Makefile000066400000000000000000000000361511331344600251710ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configcompression/compressiontype.go000066400000000000000000000036611511331344600273320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configcompression // import "go.opentelemetry.io/collector/config/configcompression" import ( "compress/zlib" "fmt" ) // Type represents a compression method type Type string type Level int type CompressionParams struct { Level Level `mapstructure:"level"` // prevent unkeyed literal initialization _ struct{} } const ( TypeGzip Type = "gzip" TypeZlib Type = "zlib" TypeDeflate Type = "deflate" TypeSnappy Type = "snappy" TypeSnappyFramed Type = "x-snappy-framed" TypeZstd Type = "zstd" TypeLz4 Type = "lz4" typeNone Type = "none" typeEmpty Type = "" DefaultCompressionLevel = zlib.DefaultCompression ) // IsCompressed returns false if CompressionType is nil, none, or empty. // Otherwise, returns true. func (ct *Type) IsCompressed() bool { return *ct != typeEmpty && *ct != typeNone } func (ct *Type) UnmarshalText(in []byte) error { typ := Type(in) if typ == TypeGzip || typ == TypeZlib || typ == TypeDeflate || typ == TypeSnappy || typ == TypeSnappyFramed || typ == TypeZstd || typ == TypeLz4 || typ == typeNone || typ == typeEmpty { *ct = typ return nil } return fmt.Errorf("unsupported compression type %q", typ) } func (ct *Type) ValidateParams(p CompressionParams) error { switch *ct { case TypeGzip, TypeZlib, TypeDeflate: if p.Level == zlib.DefaultCompression || p.Level == zlib.HuffmanOnly || p.Level == zlib.NoCompression || (p.Level >= zlib.BestSpeed && p.Level <= zlib.BestCompression) { return nil } case TypeZstd: // Supports arbitrary levels: zstd will map any given // level to the nearest internally supported level. return nil } if p.Level != 0 { return fmt.Errorf("unsupported parameters {Level:%+v} for compression type %q", p.Level, *ct) } return nil } opentelemetry-collector-0.141.0/config/configcompression/compressiontype_test.go000066400000000000000000000104041511331344600303620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configcompression import ( "compress/zlib" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestUnmarshalText(t *testing.T) { tests := []struct { name string compressionName []byte shouldError bool isCompressed bool }{ { name: "ValidGzip", compressionName: []byte("gzip"), shouldError: false, isCompressed: true, }, { name: "ValidZlib", compressionName: []byte("zlib"), shouldError: false, isCompressed: true, }, { name: "ValidDeflate", compressionName: []byte("deflate"), shouldError: false, isCompressed: true, }, { name: "ValidSnappy", compressionName: []byte("snappy"), shouldError: false, isCompressed: true, }, { name: "ValidSnappyFramed", compressionName: []byte("x-snappy-framed"), shouldError: false, isCompressed: true, }, { name: "ValidZstd", compressionName: []byte("zstd"), shouldError: false, isCompressed: true, }, { name: "ValidEmpty", compressionName: []byte(""), shouldError: false, }, { name: "ValidNone", compressionName: []byte("none"), shouldError: false, }, { name: "ValidLz4", compressionName: []byte("lz4"), isCompressed: true, shouldError: false, }, { name: "Invalid", compressionName: []byte("ggip"), shouldError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { temp := typeNone err := temp.UnmarshalText(tt.compressionName) if tt.shouldError { assert.Error(t, err) return } require.NoError(t, err) ct := Type(tt.compressionName) assert.Equal(t, temp, ct) assert.Equal(t, tt.isCompressed, ct.IsCompressed()) }) } } func TestValidateParams(t *testing.T) { tests := []struct { name string compressionName []byte compressionLevel Level shouldError bool }{ { name: "ValidGzip", compressionName: []byte("gzip"), compressionLevel: zlib.DefaultCompression, shouldError: false, }, { name: "InvalidGzip", compressionName: []byte("gzip"), compressionLevel: 99, shouldError: true, }, { name: "ValidZlib", compressionName: []byte("zlib"), compressionLevel: zlib.DefaultCompression, shouldError: false, }, { name: "ValidDeflate", compressionName: []byte("deflate"), compressionLevel: zlib.DefaultCompression, shouldError: false, }, { name: "ValidSnappy", compressionName: []byte("snappy"), shouldError: false, }, { name: "InvalidSnappy", compressionName: []byte("snappy"), compressionLevel: 1, shouldError: true, }, { name: "ValidSnappyFramed", compressionName: []byte("x-snappy-framed"), shouldError: false, }, { name: "InvalidSnappyFramed", compressionName: []byte("x-snappy-framed"), compressionLevel: 1, shouldError: true, }, { name: "ValidZstd", compressionName: []byte("zstd"), compressionLevel: zlib.DefaultCompression, shouldError: false, }, { name: "ValidEmpty", compressionName: []byte(""), shouldError: false, }, { name: "ValidNone", compressionName: []byte("none"), shouldError: false, }, { name: "ValidLz4", compressionName: []byte("lz4"), shouldError: false, }, { name: "InvalidLz4", compressionName: []byte("lz4"), compressionLevel: 1, shouldError: true, }, { name: "Invalid", compressionName: []byte("ggip"), compressionLevel: zlib.DefaultCompression, shouldError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { compressionParams := CompressionParams{Level: tt.compressionLevel} temp := Type(tt.compressionName) err := temp.ValidateParams(compressionParams) if tt.shouldError { assert.Error(t, err) return } require.NoError(t, err) }) } } opentelemetry-collector-0.141.0/config/configcompression/go.mod000066400000000000000000000007111511331344600246370ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configcompression go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/config/configcompression/go.sum000066400000000000000000000041771511331344600246760ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configcompression/metadata.yaml000066400000000000000000000002121511331344600261710ustar00rootroot00000000000000type: config/configcompression github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configcompression/package_test.go000066400000000000000000000003221511331344600265100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configcompression import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configgrpc/000077500000000000000000000000001511331344600221245ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configgrpc/Makefile000066400000000000000000000000361511331344600235630ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configgrpc/README.md000066400000000000000000000221701511331344600234050ustar00rootroot00000000000000# gRPC Configuration Settings gRPC exposes a [variety of settings](https://godoc.org/google.golang.org/grpc). Several of these settings are available for configuration within individual receivers or exporters. In general, none of these settings should need to be adjusted. ## Client Configuration [Exporters](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/README.md) leverage client configuration. Note that client configuration supports TLS configuration, the configuration parameters are also defined under `tls` like server configuration. For more information, see [configtls README](../configtls/README.md). - [`balancer_name`](https://github.com/grpc/grpc-go/blob/master/examples/features/load_balancing/README.md): Default before v0.103.0 is `pick_first`, default for v0.103.0 is `round_robin`. See [issue](https://github.com/open-telemetry/opentelemetry-collector/issues/10298). To restore the previous behavior, set `balancer_name` to `pick_first`. - `compression`: Compression type to use among `gzip`, `snappy`, `zstd`, and `none`. - `endpoint`: Valid value syntax available [here](https://github.com/grpc/grpc/blob/master/doc/naming.md) - [`tls`](../configtls/README.md) - `headers`: name/value pairs added to the request - [`keepalive`](https://godoc.org/google.golang.org/grpc/keepalive#ClientParameters) - `permit_without_stream` - `time` - `timeout` - [`read_buffer_size`](https://godoc.org/google.golang.org/grpc#ReadBufferSize) - [`write_buffer_size`](https://godoc.org/google.golang.org/grpc#WriteBufferSize) - [`auth`](../configauth/README.md) - [`middlewares`](../configmiddleware/README.md) Please note that [`per_rpc_auth`](https://pkg.go.dev/google.golang.org/grpc#PerRPCCredentials) which allows the credentials to send for every RPC is now moved to become an [extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/extension/bearertokenauthextension). Note that this feature isn't about sending the headers only during the initial connection as an `authorization` header under the `headers` would do: this is sent for every RPC performed during an established connection. Example: ```yaml exporters: otlp: endpoint: otelcol2:55690 auth: authenticator: some-authenticator-extension tls: ca_file: ca.pem cert_file: cert.pem key_file: key.pem headers: test1: "value1" "test 2": "value 2" ``` ### Compression Comparison [configgrpc_benchmark_test.go](./configgrpc_benchmark_test.go) contains benchmarks comparing the supported compression algorithms. It performs compression using `gzip`, `zstd`, and `snappy` compression on small, medium, and large sized log, trace, and metric payloads. Each test case outputs the uncompressed payload size, the compressed payload size, and the average nanoseconds spent on compression. The following table summarizes the results, including some additional columns computed from the raw data. The benchmarks were performed on an AWS m5.large EC2 instance with an Intel(R) Xeon(R) Platinum 8259CL CPU @ 2.50GHz. | Request | Compressor | Raw Bytes | Compressed bytes | Compression ratio | Ns / op | Mb compressed / second | Mb saved / second | |-------------------|------------|-----------|------------------|-------------------|---------|------------------------|-------------------| | lg_log_request | gzip | 5150 | 262 | 19.66 | 49231 | 104.61 | 99.29 | | lg_metric_request | gzip | 6800 | 201 | 33.83 | 51816 | 131.23 | 127.35 | | lg_trace_request | gzip | 9200 | 270 | 34.07 | 65174 | 141.16 | 137.02 | | md_log_request | gzip | 363 | 268 | 1.35 | 37609 | 9.65 | 2.53 | | md_metric_request | gzip | 320 | 145 | 2.21 | 30141 | 10.62 | 5.81 | | md_trace_request | gzip | 451 | 288 | 1.57 | 38270 | 11.78 | 4.26 | | sm_log_request | gzip | 166 | 168 | 0.99 | 30511 | 5.44 | -0.07 | | sm_metric_request | gzip | 185 | 142 | 1.30 | 29055 | 6.37 | 1.48 | | sm_trace_request | gzip | 233 | 205 | 1.14 | 33466 | 6.96 | 0.84 | | lg_log_request | snappy | 5150 | 475 | 10.84 | 1915 | 2,689.30 | 2,441.25 | | lg_metric_request | snappy | 6800 | 466 | 14.59 | 2266 | 3,000.88 | 2,795.23 | | lg_trace_request | snappy | 9200 | 644 | 14.29 | 3281 | 2,804.02 | 2,607.74 | | md_log_request | snappy | 363 | 300 | 1.21 | 770.0 | 471.43 | 81.82 | | md_metric_request | snappy | 320 | 162 | 1.98 | 588.6 | 543.66 | 268.43 | | md_trace_request | snappy | 451 | 330 | 1.37 | 907.7 | 496.86 | 133.30 | | sm_log_request | snappy | 166 | 184 | 0.90 | 551.8 | 300.83 | -32.62 | | sm_metric_request | snappy | 185 | 154 | 1.20 | 526.3 | 351.51 | 58.90 | | sm_trace_request | snappy | 233 | 251 | 0.93 | 682.1 | 341.59 | -26.39 | | lg_log_request | zstd | 5150 | 223 | 23.09 | 17998 | 286.14 | 273.75 | | lg_metric_request | zstd | 6800 | 144 | 47.22 | 14289 | 475.89 | 465.81 | | lg_trace_request | zstd | 9200 | 208 | 44.23 | 17160 | 536.13 | 524.01 | | md_log_request | zstd | 363 | 261 | 1.39 | 11216 | 32.36 | 9.09 | | md_metric_request | zstd | 320 | 145 | 2.21 | 9318 | 34.34 | 18.78 | | md_trace_request | zstd | 451 | 301 | 1.50 | 12583 | 35.84 | 11.92 | | sm_log_request | zstd | 166 | 165 | 1.01 | 12482 | 13.30 | 0.08 | | sm_metric_request | zstd | 185 | 139 | 1.33 | 8824 | 20.97 | 5.21 | | sm_trace_request | zstd | 233 | 203 | 1.15 | 10134 | 22.99 | 2.96 | Compression ratios will vary in practice as they are highly dependent on the data's information entropy. Compression rates are dependent on the speed of the CPU, and the size of payloads being compressed: smaller payloads compress at slower rates relative to larger payloads, which are able to amortize fixed computation costs over more bytes. `gzip` is the only required compression algorithm required for [OTLP servers](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#protocol-details), and is a natural first choice. It is not as fast as `snappy`, but achieves better compression ratios and has reasonable performance. If your collector is CPU bound and your OTLP server supports it, you may benefit from using `snappy` compression. If your collector is CPU bound and has a very fast network link, you may benefit from disabling compression, which is the default. ## Server Configuration [Receivers](https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/README.md) leverage server configuration. Note that transport configuration can also be configured. The default transport type is TCP. For more information, see [confignet README](../confignet/README.md). - [`keepalive`](https://godoc.org/google.golang.org/grpc/keepalive#ServerParameters) - [`enforcement_policy`](https://godoc.org/google.golang.org/grpc/keepalive#EnforcementPolicy) - `min_time` - `permit_without_stream` - [`server_parameters`](https://godoc.org/google.golang.org/grpc/keepalive#ServerParameters) - `max_connection_age` - `max_connection_age_grace` - `max_connection_idle` - `time` - `timeout` - [`max_concurrent_streams`](https://godoc.org/google.golang.org/grpc#MaxConcurrentStreams) - [`max_recv_msg_size_mib`](https://godoc.org/google.golang.org/grpc#MaxRecvMsgSize) - [`read_buffer_size`](https://godoc.org/google.golang.org/grpc#ReadBufferSize) - [`tls`](../configtls/README.md) - [`write_buffer_size`](https://godoc.org/google.golang.org/grpc#WriteBufferSize) - [`auth`](../configauth/README.md) - [`middlewares`](../configmiddleware/README.md) opentelemetry-collector-0.141.0/config/configgrpc/client_middleware_test.go000066400000000000000000000137001511331344600271660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configgrpc import ( "context" "errors" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/metadata" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionmiddleware" "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" ) // testlientMiddleware is a mock implementation of a middleware extension type testClientMiddleware struct { extension.Extension extensionmiddleware.GetGRPCClientOptionsFunc } func newTestMiddlewareConfig(name string) configmiddleware.Config { return configmiddleware.Config{ ID: component.MustNewID(name), } } func newTestClientMiddleware(name string) extension.Extension { return &testClientMiddleware{ Extension: extensionmiddlewaretest.NewNop(), GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { return []grpc.DialOption{ grpc.WithChainUnaryInterceptor( func( ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption, ) error { // Get existing metadata or create new metadata md, ok := metadata.FromOutgoingContext(ctx) if !ok { md = metadata.New(nil) } else { // Clone the metadata to avoid modifying the real metadata map md = md.Copy() } // Check if there's already a middleware sequence header sequence := "" if values := md.Get("middleware-sequence"); len(values) > 0 { sequence = values[0] } // Append this middleware's ID to the sequence if sequence == "" { sequence = name } else { sequence = fmt.Sprintf("%s,%s", sequence, name) } // Set the updated sequence md.Set("middleware-sequence", sequence) // Create a new context with the updated metadata newCtx := metadata.NewOutgoingContext(ctx, md) // Continue the call with our updated context return invoker(newCtx, method, req, reply, cc, opts...) }), }, nil }, } } // TestClientMiddlewareOrdering verifies that client middleware // interceptors are called in the right order. func TestClientMiddlewareOrdering(t *testing.T) { // Create a middleware tracking header that will be modified by our middleware interceptors const middlewareTrackingHeader = "middleware-sequence" // Create middleware extensions that will modify the metadata to track their execution order mockMiddleware1 := newTestClientMiddleware("middleware-1") mockMiddleware2 := newTestClientMiddleware("middleware-2") mockExt := map[component.ID]component.Component{ component.MustNewID("middleware1"): mockMiddleware1, component.MustNewID("middleware2"): mockMiddleware2, } // Start a gRPC server that will record the incoming metadata server := &grpcTraceServer{} srv, addr := server.startTestServer(t, configoptional.Some(ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:0", Transport: confignet.TransportTypeTCP, }, })) defer srv.Stop() // Create client config with middleware extensions clientConfig := ClientConfig{ Endpoint: addr, TLS: configtls.ClientConfig{ Insecure: true, }, Middlewares: []configmiddleware.Config{ newTestMiddlewareConfig("middleware1"), newTestMiddlewareConfig("middleware2"), }, } // Send a request using the client with middleware resp, err := sendTestRequestWithExtensions(t, clientConfig, mockExt) require.NoError(t, err) assert.NotNil(t, resp) // Verify that the middleware order was respected as recorded in the metadata ictx, ok := metadata.FromIncomingContext(server.recordedContext) require.True(t, ok, "middleware tracking header not found in metadata") md := ictx[middlewareTrackingHeader] require.Len(t, md, 1, "expected exactly one middleware tracking header value") // The sequence should be "middleware-1,middleware-2" as that's the order they were registered expectedSequence := "middleware-1,middleware-2" assert.Equal(t, expectedSequence, md[0]) } // TestClientMiddlewareToClientErrors tests failure cases for the ToClient method // specifically related to middleware resolution and API calls. func TestClientMiddlewareToClientErrors(t *testing.T) { tests := []struct { name string extensions map[component.ID]component.Component config ClientConfig errText string }{ { name: "extension_not_found", extensions: map[component.ID]component.Component{}, config: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: true, }, Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("nonexistent"), }, }, }, errText: "failed to resolve middleware \"nonexistent\": middleware not found", }, { name: "get_client_options_fails", extensions: map[component.ID]component.Component{ component.MustNewID("errormw"): extensionmiddlewaretest.NewErr(errors.New("get options failed")), }, config: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: true, }, Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("errormw"), }, }, }, errText: "get options failed", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { // Test creating the client with middleware errors _, err := tc.config.ToClientConn(context.Background(), tc.extensions, componenttest.NewNopTelemetrySettings()) require.Error(t, err) assert.Contains(t, err.Error(), tc.errText) }) } } opentelemetry-collector-0.141.0/config/configgrpc/configgrpc.go000066400000000000000000000577731511331344600246170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configgrpc // import "go.opentelemetry.io/collector/config/configgrpc" import ( "context" "crypto/tls" "errors" "fmt" "math" "strings" "time" "github.com/mostynb/go-grpc-compression/nonclobbering/snappy" "github.com/mostynb/go-grpc-compression/nonclobbering/zstd" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "go.opentelemetry.io/otel" "google.golang.org/grpc" "google.golang.org/grpc/balancer" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/encoding/gzip" "google.golang.org/grpc/keepalive" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/extension/extensionauth" ) var errMetadataNotFound = errors.New("no request metadata found") // KeepaliveClientConfig exposes the keepalive.ClientParameters to be used by the exporter. // Refer to the original data-structure for the meaning of each parameter: // https://godoc.org/google.golang.org/grpc/keepalive#ClientParameters type KeepaliveClientConfig struct { Time time.Duration `mapstructure:"time"` Timeout time.Duration `mapstructure:"timeout"` PermitWithoutStream bool `mapstructure:"permit_without_stream,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultKeepaliveClientConfig returns a new instance of KeepaliveClientConfig with default values. func NewDefaultKeepaliveClientConfig() KeepaliveClientConfig { return KeepaliveClientConfig{ Time: time.Second * 10, Timeout: time.Second * 10, } } // BalancerName returns a string with default load balancer value func BalancerName() string { return "round_robin" } // ClientConfig defines common settings for a gRPC client configuration. type ClientConfig struct { // The target to which the exporter is going to send traces or metrics, // using the gRPC protocol. The valid syntax is described at // https://github.com/grpc/grpc/blob/master/doc/naming.md. Endpoint string `mapstructure:"endpoint,omitempty"` // The compression key for supported compression types within collector. Compression configcompression.Type `mapstructure:"compression,omitempty"` // TLS struct exposes TLS client configuration. TLS configtls.ClientConfig `mapstructure:"tls,omitempty"` // The keepalive parameters for gRPC client. See grpc.WithKeepaliveParams. // (https://godoc.org/google.golang.org/grpc#WithKeepaliveParams). Keepalive configoptional.Optional[KeepaliveClientConfig] `mapstructure:"keepalive,omitempty"` // ReadBufferSize for gRPC client. See grpc.WithReadBufferSize. // (https://godoc.org/google.golang.org/grpc#WithReadBufferSize). ReadBufferSize int `mapstructure:"read_buffer_size,omitempty"` // WriteBufferSize for gRPC gRPC. See grpc.WithWriteBufferSize. // (https://godoc.org/google.golang.org/grpc#WithWriteBufferSize). WriteBufferSize int `mapstructure:"write_buffer_size,omitempty"` // WaitForReady parameter configures client to wait for ready state before sending data. // (https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md) WaitForReady bool `mapstructure:"wait_for_ready,omitempty"` // The headers associated with gRPC requests. Headers configopaque.MapList `mapstructure:"headers,omitempty"` // Sets the balancer in grpclb_policy to discover the servers. Default is pick_first. // https://github.com/grpc/grpc-go/blob/master/examples/features/load_balancing/README.md BalancerName string `mapstructure:"balancer_name"` // WithAuthority parameter configures client to rewrite ":authority" header // (godoc.org/google.golang.org/grpc#WithAuthority) Authority string `mapstructure:"authority,omitempty"` // Auth configuration for outgoing RPCs. Auth configoptional.Optional[configauth.Config] `mapstructure:"auth,omitempty"` // Middlewares for the gRPC client. Middlewares []configmiddleware.Config `mapstructure:"middlewares,omitempty"` } // NewDefaultClientConfig returns a new instance of ClientConfig with default values. func NewDefaultClientConfig() ClientConfig { return ClientConfig{ TLS: configtls.NewDefaultClientConfig(), Keepalive: configoptional.Some(NewDefaultKeepaliveClientConfig()), BalancerName: BalancerName(), } } // KeepaliveServerConfig is the configuration for keepalive. type KeepaliveServerConfig struct { ServerParameters configoptional.Optional[KeepaliveServerParameters] `mapstructure:"server_parameters,omitempty"` EnforcementPolicy configoptional.Optional[KeepaliveEnforcementPolicy] `mapstructure:"enforcement_policy,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultKeepaliveServerConfig returns a new instance of KeepaliveServerConfig with default values. func NewDefaultKeepaliveServerConfig() KeepaliveServerConfig { return KeepaliveServerConfig{ ServerParameters: configoptional.Some(NewDefaultKeepaliveServerParameters()), EnforcementPolicy: configoptional.Some(NewDefaultKeepaliveEnforcementPolicy()), } } // KeepaliveServerParameters allow configuration of the keepalive.ServerParameters. // The same default values as keepalive.ServerParameters are applicable and get applied by the server. // See https://godoc.org/google.golang.org/grpc/keepalive#ServerParameters for details. type KeepaliveServerParameters struct { MaxConnectionIdle time.Duration `mapstructure:"max_connection_idle,omitempty"` MaxConnectionAge time.Duration `mapstructure:"max_connection_age,omitempty"` MaxConnectionAgeGrace time.Duration `mapstructure:"max_connection_age_grace,omitempty"` Time time.Duration `mapstructure:"time,omitempty"` Timeout time.Duration `mapstructure:"timeout,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultKeepaliveServerParameters creates and returns a new instance of KeepaliveServerParameters with default settings. func NewDefaultKeepaliveServerParameters() KeepaliveServerParameters { return KeepaliveServerParameters{} } // KeepaliveEnforcementPolicy allow configuration of the keepalive.EnforcementPolicy. // The same default values as keepalive.EnforcementPolicy are applicable and get applied by the server. // See https://godoc.org/google.golang.org/grpc/keepalive#EnforcementPolicy for details. type KeepaliveEnforcementPolicy struct { MinTime time.Duration `mapstructure:"min_time,omitempty"` PermitWithoutStream bool `mapstructure:"permit_without_stream,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultKeepaliveEnforcementPolicy creates and returns a new instance of KeepaliveEnforcementPolicy with default settings. func NewDefaultKeepaliveEnforcementPolicy() KeepaliveEnforcementPolicy { return KeepaliveEnforcementPolicy{} } // ServerConfig defines common settings for a gRPC server configuration. type ServerConfig struct { // Server net.Addr config. For transport only "tcp" and "unix" are valid options. NetAddr confignet.AddrConfig `mapstructure:",squash"` // Configures the protocol to use TLS. // The default value is nil, which will cause the protocol to not use TLS. TLS configoptional.Optional[configtls.ServerConfig] `mapstructure:"tls,omitempty"` // MaxRecvMsgSizeMiB sets the maximum size (in MiB) of messages accepted by the server. MaxRecvMsgSizeMiB int `mapstructure:"max_recv_msg_size_mib,omitempty"` // MaxConcurrentStreams sets the limit on the number of concurrent streams to each ServerTransport. // It has effect only for streaming RPCs. MaxConcurrentStreams uint32 `mapstructure:"max_concurrent_streams,omitempty,omitempty"` // ReadBufferSize for gRPC server. See grpc.ReadBufferSize. // (https://godoc.org/google.golang.org/grpc#ReadBufferSize). ReadBufferSize int `mapstructure:"read_buffer_size,omitempty"` // WriteBufferSize for gRPC server. See grpc.WriteBufferSize. // (https://godoc.org/google.golang.org/grpc#WriteBufferSize). WriteBufferSize int `mapstructure:"write_buffer_size,omitempty"` // Keepalive anchor for all the settings related to keepalive. Keepalive configoptional.Optional[KeepaliveServerConfig] `mapstructure:"keepalive,omitempty"` // Auth for this receiver Auth configoptional.Optional[configauth.Config] `mapstructure:"auth,omitempty"` // Include propagates the incoming connection's metadata to downstream consumers. IncludeMetadata bool `mapstructure:"include_metadata,omitempty"` // Middlewares for the gRPC server. Middlewares []configmiddleware.Config `mapstructure:"middlewares,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultServerConfig returns a new instance of ServerConfig with default values. func NewDefaultServerConfig() ServerConfig { netAddr := confignet.NewDefaultAddrConfig() // We typically want to create a TCP server and listen over a network. netAddr.Transport = confignet.TransportTypeTCP return ServerConfig{ Keepalive: configoptional.Some(NewDefaultKeepaliveServerConfig()), NetAddr: netAddr, } } func (cc *ClientConfig) Validate() error { if cc.BalancerName != "" { if balancer.Get(cc.BalancerName) == nil { return fmt.Errorf("invalid balancer_name: %s", cc.BalancerName) } } return nil } // sanitizedEndpoint strips the prefix of either http:// or https:// from configgrpc.ClientConfig.Endpoint. func (cc *ClientConfig) sanitizedEndpoint() string { switch { case cc.isSchemeHTTP(): return strings.TrimPrefix(cc.Endpoint, "http://") case cc.isSchemeHTTPS(): return strings.TrimPrefix(cc.Endpoint, "https://") default: return cc.Endpoint } } func (cc *ClientConfig) isSchemeHTTP() bool { return strings.HasPrefix(cc.Endpoint, "http://") } func (cc *ClientConfig) isSchemeHTTPS() bool { return strings.HasPrefix(cc.Endpoint, "https://") } // ToClientConnOption is a sealed interface wrapping options for [ClientConfig.ToClientConn]. type ToClientConnOption interface { isToClientConnOption() } type grpcDialOptionWrapper struct { opt grpc.DialOption } // WithGrpcDialOption wraps a [grpc.DialOption] into a [ToClientConnOption]. func WithGrpcDialOption(opt grpc.DialOption) ToClientConnOption { return grpcDialOptionWrapper{opt: opt} } func (grpcDialOptionWrapper) isToClientConnOption() {} // ToClientConn creates a client connection to the given target. By default, it's // a non-blocking dial (the function won't wait for connections to be // established, and connecting happens in the background). To make it a blocking // dial, use the WithGrpcDialOption(grpc.WithBlock()) option. // // To allow the configuration to reference middleware or authentication extensions, // the `extensions` argument should be the output of `host.GetExtensions()`. // It may also be `nil` in tests where no such extension is expected to be used. func (cc *ClientConfig) ToClientConn( ctx context.Context, extensions map[component.ID]component.Component, settings component.TelemetrySettings, extraOpts ...ToClientConnOption, ) (*grpc.ClientConn, error) { grpcOpts, err := cc.getGrpcDialOptions(ctx, extensions, settings, extraOpts) if err != nil { return nil, err } //nolint:staticcheck // SA1019 see https://github.com/open-telemetry/opentelemetry-collector/pull/11575 return grpc.DialContext(ctx, cc.sanitizedEndpoint(), grpcOpts...) } func (cc *ClientConfig) addHeadersIfAbsent(ctx context.Context) context.Context { kv := make([]string, 0, 2*len(cc.Headers)) existingMd, _ := metadata.FromOutgoingContext(ctx) for k, v := range cc.Headers.Iter { if len(existingMd.Get(k)) == 0 { kv = append(kv, k, string(v)) } } return metadata.AppendToOutgoingContext(ctx, kv...) } func (cc *ClientConfig) getGrpcDialOptions( ctx context.Context, extensions map[component.ID]component.Component, settings component.TelemetrySettings, extraOpts []ToClientConnOption, ) ([]grpc.DialOption, error) { var opts []grpc.DialOption if cc.Compression.IsCompressed() { cp, err := getGRPCCompressionName(cc.Compression) if err != nil { return nil, err } opts = append(opts, grpc.WithDefaultCallOptions(grpc.UseCompressor(cp))) } tlsCfg, err := cc.TLS.LoadTLSConfig(ctx) if err != nil { return nil, err } cred := insecure.NewCredentials() if tlsCfg != nil { cred = credentials.NewTLS(tlsCfg) } else if cc.isSchemeHTTPS() { cred = credentials.NewTLS(&tls.Config{}) } opts = append(opts, grpc.WithTransportCredentials(cred)) if cc.ReadBufferSize > 0 { opts = append(opts, grpc.WithReadBufferSize(cc.ReadBufferSize)) } if cc.WriteBufferSize > 0 { opts = append(opts, grpc.WithWriteBufferSize(cc.WriteBufferSize)) } if cc.Keepalive.HasValue() { keepaliveConfig := cc.Keepalive.Get() keepAliveOption := grpc.WithKeepaliveParams(keepalive.ClientParameters{ Time: keepaliveConfig.Time, Timeout: keepaliveConfig.Timeout, PermitWithoutStream: keepaliveConfig.PermitWithoutStream, }) opts = append(opts, keepAliveOption) } if cc.Auth.HasValue() { if extensions == nil { return nil, errors.New("authentication was configured but this component or its host does not support extensions") } grpcAuthenticator, cerr := cc.Auth.Get().GetGRPCClientAuthenticator(ctx, extensions) if cerr != nil { return nil, cerr } perRPCCredentials, perr := grpcAuthenticator.PerRPCCredentials() if perr != nil { return nil, err } opts = append(opts, grpc.WithPerRPCCredentials(perRPCCredentials)) } if cc.BalancerName != "" { opts = append(opts, grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"loadBalancingPolicy":%q}`, cc.BalancerName))) } if cc.Authority != "" { opts = append(opts, grpc.WithAuthority(cc.Authority)) } otelOpts := []otelgrpc.Option{ otelgrpc.WithTracerProvider(settings.TracerProvider), otelgrpc.WithPropagators(otel.GetTextMapPropagator()), otelgrpc.WithMeterProvider(settings.MeterProvider), } // Enable OpenTelemetry observability plugin. opts = append(opts, grpc.WithStatsHandler(otelgrpc.NewClientHandler(otelOpts...))) if len(cc.Headers) > 0 { opts = append(opts, grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply any, gcc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { return invoker(cc.addHeadersIfAbsent(ctx), method, req, reply, gcc, opts...) }), grpc.WithStreamInterceptor(func(ctx context.Context, desc *grpc.StreamDesc, gcc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { return streamer(cc.addHeadersIfAbsent(ctx), desc, gcc, method, opts...) }), ) } // Apply middleware options. Note: OpenTelemetry could be registered as an extension. if len(cc.Middlewares) > 0 && extensions == nil { return nil, errors.New("middlewares were configured but this component or its host does not support extensions") } for _, middleware := range cc.Middlewares { middlewareOptions, err := middleware.GetGRPCClientOptions(ctx, extensions) if err != nil { return nil, fmt.Errorf("failed to get gRPC client options from middleware: %w", err) } opts = append(opts, middlewareOptions...) } for _, opt := range extraOpts { if wrapper, ok := opt.(grpcDialOptionWrapper); ok { opts = append(opts, wrapper.opt) } } return opts, nil } func (sc *ServerConfig) Validate() error { if sc.MaxRecvMsgSizeMiB*1024*1024 < 0 { return fmt.Errorf("invalid max_recv_msg_size_mib value, must be between 1 and %d: %d", math.MaxInt/1024/1024, sc.MaxRecvMsgSizeMiB) } if sc.ReadBufferSize < 0 { return fmt.Errorf("invalid read_buffer_size value: %d", sc.ReadBufferSize) } if sc.WriteBufferSize < 0 { return fmt.Errorf("invalid write_buffer_size value: %d", sc.WriteBufferSize) } return nil } // ToServerOption is a sealed interface wrapping options for [ServerConfig.ToServer]. type ToServerOption interface { isToServerOption() } type grpcServerOptionWrapper struct { opt grpc.ServerOption } // WithGrpcServerOption wraps a [grpc.ServerOption] into a [ToServerOption]. func WithGrpcServerOption(opt grpc.ServerOption) ToServerOption { return grpcServerOptionWrapper{opt: opt} } func (grpcServerOptionWrapper) isToServerOption() {} // ToServer returns a [grpc.Server] for the configuration. // // To allow the configuration to reference middleware or authentication extensions, // the `extensions` argument should be the output of `host.GetExtensions()`. // It may also be `nil` in tests where no such extension is expected to be used. func (sc *ServerConfig) ToServer( ctx context.Context, extensions map[component.ID]component.Component, settings component.TelemetrySettings, extraOpts ...ToServerOption, ) (*grpc.Server, error) { grpcOpts, err := sc.getGrpcServerOptions(ctx, extensions, settings, extraOpts) if err != nil { return nil, err } return grpc.NewServer(grpcOpts...), nil } func (sc *ServerConfig) getGrpcServerOptions( ctx context.Context, extensions map[component.ID]component.Component, settings component.TelemetrySettings, extraOpts []ToServerOption, ) ([]grpc.ServerOption, error) { var opts []grpc.ServerOption if sc.TLS.HasValue() { tlsCfg, err := sc.TLS.Get().LoadTLSConfig(ctx) if err != nil { return nil, err } opts = append(opts, grpc.Creds(credentials.NewTLS(tlsCfg))) } if sc.MaxRecvMsgSizeMiB > 0 && sc.MaxRecvMsgSizeMiB*1024*1024 > 0 { opts = append(opts, grpc.MaxRecvMsgSize(sc.MaxRecvMsgSizeMiB*1024*1024)) } if sc.MaxConcurrentStreams > 0 { opts = append(opts, grpc.MaxConcurrentStreams(sc.MaxConcurrentStreams)) } if sc.ReadBufferSize > 0 { opts = append(opts, grpc.ReadBufferSize(sc.ReadBufferSize)) } if sc.WriteBufferSize > 0 { opts = append(opts, grpc.WriteBufferSize(sc.WriteBufferSize)) } // The default values referenced in the GRPC docs are set within the server, so this code doesn't need // to apply them over zero/nil values before passing these as grpc.ServerOptions. // The following shows the server code for applying default grpc.ServerOptions. // https://github.com/grpc/grpc-go/blob/120728e1f775e40a2a764341939b78d666b08260/internal/transport/http2_server.go#L184-L200 if sc.Keepalive.HasValue() { keepaliveConfig := sc.Keepalive.Get() if keepaliveConfig.ServerParameters.HasValue() { svrParams := keepaliveConfig.ServerParameters.Get() opts = append(opts, grpc.KeepaliveParams(keepalive.ServerParameters{ MaxConnectionIdle: svrParams.MaxConnectionIdle, MaxConnectionAge: svrParams.MaxConnectionAge, MaxConnectionAgeGrace: svrParams.MaxConnectionAgeGrace, Time: svrParams.Time, Timeout: svrParams.Timeout, })) } // The default values referenced in the GRPC are set within the server, so this code doesn't need // to apply them over zero/nil values before passing these as grpc.ServerOptions. // The following shows the server code for applying default grpc.ServerOptions. // https://github.com/grpc/grpc-go/blob/120728e1f775e40a2a764341939b78d666b08260/internal/transport/http2_server.go#L202-L205 if keepaliveConfig.EnforcementPolicy.HasValue() { enfPol := keepaliveConfig.EnforcementPolicy.Get() opts = append(opts, grpc.KeepaliveEnforcementPolicy(keepalive.EnforcementPolicy{ MinTime: enfPol.MinTime, PermitWithoutStream: enfPol.PermitWithoutStream, })) } } var uInterceptors []grpc.UnaryServerInterceptor var sInterceptors []grpc.StreamServerInterceptor if sc.Auth.HasValue() { authenticator, err := sc.Auth.Get().GetServerAuthenticator(ctx, extensions) if err != nil { return nil, err } uInterceptors = append(uInterceptors, authUnaryServerInterceptor(authenticator)) sInterceptors = append(sInterceptors, authStreamServerInterceptor(authenticator)) //nolint:contextcheck // context already handled } otelOpts := []otelgrpc.Option{ otelgrpc.WithTracerProvider(settings.TracerProvider), otelgrpc.WithPropagators(otel.GetTextMapPropagator()), otelgrpc.WithMeterProvider(settings.MeterProvider), } // Enable OpenTelemetry observability plugin. uInterceptors = append(uInterceptors, enhanceWithClientInformation(sc.IncludeMetadata)) sInterceptors = append(sInterceptors, enhanceStreamWithClientInformation(sc.IncludeMetadata)) //nolint:contextcheck // context already handled opts = append(opts, grpc.StatsHandler(otelgrpc.NewServerHandler(otelOpts...)), grpc.ChainUnaryInterceptor(uInterceptors...), grpc.ChainStreamInterceptor(sInterceptors...)) // Apply middleware options. Note: OpenTelemetry could be registered as an extension. for _, middleware := range sc.Middlewares { middlewareOptions, err := middleware.GetGRPCServerOptions(ctx, extensions) if err != nil { return nil, fmt.Errorf("failed to get gRPC server options from middleware: %w", err) } opts = append(opts, middlewareOptions...) } for _, opt := range extraOpts { if wrapper, ok := opt.(grpcServerOptionWrapper); ok { opts = append(opts, wrapper.opt) } } return opts, nil } // getGRPCCompressionName returns compression name registered in grpc. func getGRPCCompressionName(compressionType configcompression.Type) (string, error) { switch compressionType { case configcompression.TypeGzip: return gzip.Name, nil case configcompression.TypeSnappy: return snappy.Name, nil case configcompression.TypeZstd: return zstd.Name, nil default: return "", fmt.Errorf("unsupported compression type %q", compressionType) } } // enhanceWithClientInformation intercepts the incoming RPC, replacing the incoming context with one that includes // a client.Info, potentially with the peer's address. func enhanceWithClientInformation(includeMetadata bool) grpc.UnaryServerInterceptor { return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { return handler(contextWithClient(ctx, includeMetadata), req) } } func enhanceStreamWithClientInformation(includeMetadata bool) grpc.StreamServerInterceptor { return func(srv any, ss grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error { return handler(srv, wrapServerStream(contextWithClient(ss.Context(), includeMetadata), ss)) } } // contextWithClient attempts to add the peer address to the client.Info from the context. When no // client.Info exists in the context, one is created. func contextWithClient(ctx context.Context, includeMetadata bool) context.Context { cl := client.FromContext(ctx) if p, ok := peer.FromContext(ctx); ok { cl.Addr = p.Addr } if includeMetadata { if md, ok := metadata.FromIncomingContext(ctx); ok { copiedMD := md.Copy() if len(md[client.MetadataHostName]) == 0 && len(md[":authority"]) > 0 { copiedMD[client.MetadataHostName] = md[":authority"] } cl.Metadata = client.NewMetadata(copiedMD) } } return client.NewContext(ctx, cl) } func authUnaryServerInterceptor(server extensionauth.Server) grpc.UnaryServerInterceptor { return func(ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { headers, ok := metadata.FromIncomingContext(ctx) if !ok { return nil, errMetadataNotFound } ctx, err := server.Authenticate(ctx, headers) if err != nil { if s, ok := status.FromError(err); ok { return nil, s.Err() } return nil, status.Error(codes.Unauthenticated, err.Error()) } return handler(ctx, req) } } func authStreamServerInterceptor(server extensionauth.Server) grpc.StreamServerInterceptor { return func(srv any, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error { ctx := stream.Context() headers, ok := metadata.FromIncomingContext(ctx) if !ok { return errMetadataNotFound } ctx, err := server.Authenticate(ctx, headers) if err != nil { if s, ok := status.FromError(err); ok { return s.Err() } return status.Error(codes.Unauthenticated, err.Error()) } return handler(srv, wrapServerStream(ctx, stream)) } } opentelemetry-collector-0.141.0/config/configgrpc/configgrpc_benchmark_test.go000066400000000000000000000105161511331344600276500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright 2014 gRPC authors. // SPDX-License-Identifier: Apache-2.0 package configgrpc import ( "bytes" "fmt" "testing" "github.com/mostynb/go-grpc-compression/nonclobbering/snappy" "github.com/mostynb/go-grpc-compression/nonclobbering/zstd" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/encoding" "google.golang.org/grpc/encoding/gzip" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) func BenchmarkCompressors(b *testing.B) { payloads := setupTestPayloads() compressors := make([]encoding.Compressor, 0) compressors = append(compressors, encoding.GetCompressor(gzip.Name), encoding.GetCompressor(zstd.Name), encoding.GetCompressor(snappy.Name)) for _, payload := range payloads { for _, compressor := range compressors { fmt.Println(payload.name) messageBytes, err := payload.marshaler.marshal(payload.message) require.NoError(b, err, "marshal(_) returned an error") compressedBytes, err := compress(compressor, messageBytes) require.NoError(b, err, "Compressor.Compress(_) returned an error") name := fmt.Sprintf("%v/raw_bytes_%v/compressed_bytes_%v/compressor_%v", payload.name, len(messageBytes), len(compressedBytes), compressor.Name()) b.Run(name, func(b *testing.B) { b.ResetTimer() for b.Loop() { require.NoError(b, err, "marshal(_) returned an error") _, err := compress(compressor, messageBytes) require.NoError(b, err, "compress(_) returned an error") } }) } } } func compress(compressor encoding.Compressor, in []byte) ([]byte, error) { if compressor == nil { return nil, nil } wrapErr := func(err error) error { return status.Errorf(codes.Internal, "error while compressing: %v", err.Error()) } cbuf := &bytes.Buffer{} z, err := compressor.Compress(cbuf) if err != nil { return nil, wrapErr(err) } if _, err := z.Write(in); err != nil { return nil, wrapErr(err) } if err := z.Close(); err != nil { return nil, wrapErr(err) } return cbuf.Bytes(), nil } type testPayload struct { name string message any marshaler marshaler } type marshaler interface { marshal(any) ([]byte, error) } type logMarshaler struct { plog.Marshaler } func (m *logMarshaler) marshal(e any) ([]byte, error) { return m.MarshalLogs(e.(plog.Logs)) } type traceMarshaler struct { ptrace.Marshaler } func (m *traceMarshaler) marshal(e any) ([]byte, error) { return m.MarshalTraces(e.(ptrace.Traces)) } type metricsMarshaler struct { pmetric.Marshaler } func (m *metricsMarshaler) marshal(e any) ([]byte, error) { return m.MarshalMetrics(e.(pmetric.Metrics)) } func setupTestPayloads() []testPayload { payloads := make([]testPayload, 0) // log payloads logMarshaler := &logMarshaler{Marshaler: &plog.ProtoMarshaler{}} payloads = append(payloads, testPayload{ name: "sm_log_request", message: testdata.GenerateLogs(1), marshaler: logMarshaler, }, testPayload{ name: "md_log_request", message: testdata.GenerateLogs(2), marshaler: logMarshaler, }, testPayload{ name: "lg_log_request", message: testdata.GenerateLogs(50), marshaler: logMarshaler, }) // trace payloads tracesMarshaler := &traceMarshaler{Marshaler: &ptrace.ProtoMarshaler{}} payloads = append(payloads, testPayload{ name: "sm_trace_request", message: testdata.GenerateTraces(1), marshaler: tracesMarshaler, }, testPayload{ name: "md_trace_request", message: testdata.GenerateTraces(2), marshaler: tracesMarshaler, }, testPayload{ name: "lg_trace_request", message: testdata.GenerateTraces(50), marshaler: tracesMarshaler, }) // metric payloads metricsMarshaler := &metricsMarshaler{Marshaler: &pmetric.ProtoMarshaler{}} payloads = append(payloads, testPayload{ name: "sm_metric_request", message: testdata.GenerateMetrics(1), marshaler: metricsMarshaler, }, testPayload{ name: "md_metric_request", message: testdata.GenerateMetrics(2), marshaler: metricsMarshaler, }, testPayload{ name: "lg_metric_request", message: testdata.GenerateMetrics(50), marshaler: metricsMarshaler, }) return payloads } opentelemetry-collector-0.141.0/config/configgrpc/configgrpc_test.go000066400000000000000000001075211511331344600256410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configgrpc import ( "context" "errors" "net" "os" "path/filepath" "runtime" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/peer" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionauth" "go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" ) var ( _ extension.Extension = (*mockAuthServer)(nil) _ extensionauth.Server = (*mockAuthServer)(nil) ) type mockAuthServer struct { component.StartFunc component.ShutdownFunc extensionauth.ServerAuthenticateFunc } func newMockAuthServer(auth func(ctx context.Context, sources map[string][]string) (context.Context, error)) extensionauth.Server { return &mockAuthServer{ServerAuthenticateFunc: auth} } func TestNewDefaultKeepaliveClientConfig(t *testing.T) { expectedKeepaliveClientConfig := KeepaliveClientConfig{ Time: time.Second * 10, Timeout: time.Second * 10, } keepaliveClientConfig := NewDefaultKeepaliveClientConfig() assert.Equal(t, expectedKeepaliveClientConfig, keepaliveClientConfig) } func TestNewDefaultClientConfig(t *testing.T) { keepalive := NewDefaultKeepaliveClientConfig() expected := ClientConfig{ TLS: configtls.NewDefaultClientConfig(), Keepalive: configoptional.Some(keepalive), BalancerName: BalancerName(), } result := NewDefaultClientConfig() assert.Equal(t, expected, result) } func TestNewDefaultKeepaliveServerParameters(t *testing.T) { expectedParams := KeepaliveServerParameters{} params := NewDefaultKeepaliveServerParameters() assert.Equal(t, expectedParams, params) } func TestNewDefaultKeepaliveEnforcementPolicy(t *testing.T) { expectedPolicy := KeepaliveEnforcementPolicy{} policy := NewDefaultKeepaliveEnforcementPolicy() assert.Equal(t, expectedPolicy, policy) } func TestNewDefaultKeepaliveServerConfig(t *testing.T) { expected := KeepaliveServerConfig{ ServerParameters: configoptional.Some(NewDefaultKeepaliveServerParameters()), EnforcementPolicy: configoptional.Some(NewDefaultKeepaliveEnforcementPolicy()), } result := NewDefaultKeepaliveServerConfig() assert.Equal(t, expected, result) } func TestNewDefaultServerConfig(t *testing.T) { expected := ServerConfig{ Keepalive: configoptional.Some(NewDefaultKeepaliveServerConfig()), NetAddr: confignet.AddrConfig{ Transport: confignet.TransportTypeTCP, }, } result := NewDefaultServerConfig() assert.Equal(t, expected, result) } var ( testAuthID = component.MustNewID("testauth") mockID = component.MustNewID("mock") doesntExistID = component.MustNewID("doesntexist") ) func TestDefaultGrpcClientSettings(t *testing.T) { cc := &ClientConfig{ TLS: configtls.ClientConfig{ Insecure: true, }, } opts, err := cc.getGrpcDialOptions(context.Background(), nil, componenttest.NewNopTelemetrySettings(), []ToClientConnOption{}) require.NoError(t, err) /* Expecting 2 DialOptions: * - WithTransportCredentials (TLS) * - WithStatsHandler (always, for self-telemetry) */ assert.Len(t, opts, 2) } func TestGrpcClientExtraOption(t *testing.T) { cc := &ClientConfig{ TLS: configtls.ClientConfig{ Insecure: true, }, } extraOpt := grpc.WithUserAgent("test-agent") opts, err := cc.getGrpcDialOptions( context.Background(), nil, componenttest.NewNopTelemetrySettings(), []ToClientConnOption{WithGrpcDialOption(extraOpt)}, ) require.NoError(t, err) /* Expecting 3 DialOptions: * - WithTransportCredentials (TLS) * - WithStatsHandler (always, for self-telemetry) * - extraOpt */ assert.Len(t, opts, 3) assert.Equal(t, opts[2], extraOpt) } func TestAllGrpcClientSettings(t *testing.T) { tests := []struct { settings ClientConfig name string extensions map[component.ID]component.Component }{ { name: "test all with gzip compression", settings: ClientConfig{ Headers: configopaque.MapList{ {Name: "test", Value: "test"}, }, Endpoint: "localhost:1234", Compression: configcompression.TypeGzip, TLS: configtls.ClientConfig{ Insecure: false, }, Keepalive: configoptional.Some(KeepaliveClientConfig{ Time: time.Second, Timeout: time.Second, PermitWithoutStream: true, }), ReadBufferSize: 1024, WriteBufferSize: 1024, WaitForReady: true, BalancerName: "round_robin", Authority: "pseudo-authority", Auth: configoptional.Some(configauth.Config{AuthenticatorID: testAuthID}), }, extensions: map[component.ID]component.Component{ testAuthID: extensionauthtest.NewNopClient(), }, }, { name: "test all with snappy compression", settings: ClientConfig{ Headers: configopaque.MapList{ {Name: "test", Value: "test"}, }, Endpoint: "localhost:1234", Compression: configcompression.TypeSnappy, TLS: configtls.ClientConfig{ Insecure: false, }, Keepalive: configoptional.Some(KeepaliveClientConfig{ Time: time.Second, Timeout: time.Second, PermitWithoutStream: true, }), ReadBufferSize: 1024, WriteBufferSize: 1024, WaitForReady: true, BalancerName: "round_robin", Authority: "pseudo-authority", Auth: configoptional.Some(configauth.Config{AuthenticatorID: testAuthID}), }, extensions: map[component.ID]component.Component{ testAuthID: extensionauthtest.NewNopClient(), }, }, { name: "test all with zstd compression", settings: ClientConfig{ Headers: configopaque.MapList{ {Name: "test", Value: "test"}, }, Endpoint: "localhost:1234", Compression: configcompression.TypeZstd, TLS: configtls.ClientConfig{ Insecure: false, }, Keepalive: configoptional.Some(KeepaliveClientConfig{ Time: time.Second, Timeout: time.Second, PermitWithoutStream: true, }), ReadBufferSize: 1024, WriteBufferSize: 1024, WaitForReady: true, BalancerName: "round_robin", Authority: "pseudo-authority", Auth: configoptional.Some(configauth.Config{AuthenticatorID: testAuthID}), }, extensions: map[component.ID]component.Component{ testAuthID: extensionauthtest.NewNopClient(), }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { opts, err := test.settings.getGrpcDialOptions(context.Background(), test.extensions, componenttest.NewNopTelemetrySettings(), []ToClientConnOption{}) require.NoError(t, err) /* Expecting 11 DialOptions: * - WithDefaultCallOptions (Compression) * - WithTransportCredentials (TLS) * - WithDefaultServiceConfig (BalancerName) * - WithAuthority (Authority) * - WithStatsHandler (always, for self-telemetry) * - WithReadBufferSize (ReadBufferSize) * - WithWriteBufferSize (WriteBufferSize) * - WithKeepaliveParams (Keepalive) * - WithPerRPCCredentials (Auth) * - WithUnaryInterceptor/WithStreamInterceptor (Headers) */ assert.Len(t, opts, 11) }) } } func TestHeaders(t *testing.T) { traceServer := &grpcTraceServer{} server, addr := traceServer.startTestServer(t, configoptional.Some(ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:0", Transport: confignet.TransportTypeTCP, }, })) defer server.Stop() // Create client and send request to server with headers resp, errResp := sendTestRequest(t, ClientConfig{ Endpoint: addr, TLS: configtls.ClientConfig{ Insecure: true, }, Headers: configopaque.MapList{ {Name: "testheader", Value: "testvalue"}, }, }) require.NoError(t, errResp) assert.NotNil(t, resp) // Check received headers md, ok := metadata.FromIncomingContext(traceServer.recordedContext) require.True(t, ok) assert.Equal(t, []string{"testvalue"}, md.Get("testheader")) } func TestDefaultGrpcServerSettings(t *testing.T) { gss := &ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "0.0.0.0:1234", }, } opts, err := gss.getGrpcServerOptions(context.Background(), nil, componenttest.NewNopTelemetrySettings(), []ToServerOption{}) require.NoError(t, err) assert.Len(t, opts, 3) } func TestGrpcServerExtraOption(t *testing.T) { gss := &ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "0.0.0.0:1234", }, } extraOpt := grpc.ConnectionTimeout(1_000_000_000) opts, err := gss.getGrpcServerOptions( context.Background(), nil, componenttest.NewNopTelemetrySettings(), []ToServerOption{WithGrpcServerOption(extraOpt)}, ) require.NoError(t, err) assert.Len(t, opts, 4) assert.Equal(t, opts[3], extraOpt) } func TestGrpcServerValidate(t *testing.T) { tests := []struct { gss *ServerConfig err string }{ { gss: &ServerConfig{ MaxRecvMsgSizeMiB: -1, NetAddr: confignet.AddrConfig{ Endpoint: "0.0.0.0:1234", }, }, err: "invalid max_recv_msg_size_mib value", }, { gss: &ServerConfig{ MaxRecvMsgSizeMiB: 9223372036854775807, NetAddr: confignet.AddrConfig{ Endpoint: "0.0.0.0:1234", }, }, err: "invalid max_recv_msg_size_mib value", }, { gss: &ServerConfig{ ReadBufferSize: -1, NetAddr: confignet.AddrConfig{ Endpoint: "0.0.0.0:1234", }, }, err: "invalid read_buffer_size value", }, { gss: &ServerConfig{ WriteBufferSize: -1, NetAddr: confignet.AddrConfig{ Endpoint: "0.0.0.0:1234", }, }, err: "invalid write_buffer_size value", }, } for _, tt := range tests { t.Run(tt.err, func(t *testing.T) { err := tt.gss.Validate() require.Error(t, err) assert.ErrorContains(t, err, tt.err) }) } } func TestAllGrpcServerSettingsExceptAuth(t *testing.T) { gss := &ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:1234", Transport: confignet.TransportTypeTCP, }, TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{}, ClientCAFile: "", }), MaxRecvMsgSizeMiB: 1, MaxConcurrentStreams: 1024, ReadBufferSize: 1024, WriteBufferSize: 1024, Keepalive: configoptional.Some(KeepaliveServerConfig{ ServerParameters: configoptional.Some(KeepaliveServerParameters{ MaxConnectionIdle: time.Second, MaxConnectionAge: time.Second, MaxConnectionAgeGrace: time.Second, Time: time.Second, Timeout: time.Second, }), EnforcementPolicy: configoptional.Some(KeepaliveEnforcementPolicy{ MinTime: time.Second, PermitWithoutStream: true, }), }), } opts, err := gss.getGrpcServerOptions(context.Background(), nil, componenttest.NewNopTelemetrySettings(), []ToServerOption{}) require.NoError(t, err) assert.Len(t, opts, 10) } func TestGrpcServerAuthSettings(t *testing.T) { gss := &ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "0.0.0.0:1234", }, } gss.Auth = configoptional.Some(configauth.Config{ AuthenticatorID: mockID, }) extensions := map[component.ID]component.Component{ mockID: extensionauthtest.NewNopServer(), } srv, err := gss.ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings()) require.NoError(t, err) assert.NotNil(t, srv) } func TestGrpcClientConfigInvalidBalancer(t *testing.T) { settings := ClientConfig{ Headers: configopaque.MapList{ {Name: "test", Value: "test"}, }, Endpoint: "localhost:1234", Compression: "gzip", TLS: configtls.ClientConfig{ Insecure: false, }, Keepalive: configoptional.Some(KeepaliveClientConfig{ Time: time.Second, Timeout: time.Second, PermitWithoutStream: true, }), ReadBufferSize: 1024, WriteBufferSize: 1024, WaitForReady: true, BalancerName: "test", } assert.ErrorContains(t, settings.Validate(), "invalid balancer_name: test") } func TestGRPCClientSettingsError(t *testing.T) { tests := []struct { settings ClientConfig err string extensions map[component.ID]component.Component }{ { err: "failed to load TLS config: failed to load CA CertPool File: failed to load cert /doesnt/exist:", settings: ClientConfig{ Headers: nil, Endpoint: "", Compression: "", TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: "/doesnt/exist", }, Insecure: false, ServerName: "", }, }, }, { err: "failed to load TLS config: failed to load TLS cert and key: for auth via TLS, provide both certificate and key, or neither", settings: ClientConfig{ Headers: nil, Endpoint: "", Compression: "", TLS: configtls.ClientConfig{ Config: configtls.Config{ CertFile: "/doesnt/exist", }, Insecure: false, ServerName: "", }, }, }, { err: "failed to resolve authenticator \"doesntexist\": authenticator not found", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: doesntExistID}), }, extensions: map[component.ID]component.Component{}, }, { err: "authentication was configured but this component or its host does not support extensions", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: doesntExistID}), }, }, { err: "unsupported compression type \"zlib\"", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: true, }, Compression: "zlib", }, }, { err: "unsupported compression type \"deflate\"", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: true, }, Compression: "deflate", }, }, { err: "unsupported compression type \"bad\"", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: true, }, Compression: "bad", }, }, } for _, test := range tests { t.Run(test.err, func(t *testing.T) { require.NoError(t, test.settings.Validate()) _, err := test.settings.ToClientConn(context.Background(), test.extensions, componenttest.NewNopTelemetrySettings()) require.Error(t, err) assert.ErrorContains(t, err, test.err) }) } } func TestUseSecure(t *testing.T) { cc := &ClientConfig{ Headers: nil, Endpoint: "", Compression: "", TLS: configtls.ClientConfig{}, } dialOpts, err := cc.getGrpcDialOptions(context.Background(), nil, componenttest.NewNopTelemetrySettings(), []ToClientConnOption{}) require.NoError(t, err) assert.Len(t, dialOpts, 2) } func TestGRPCServerSettingsError(t *testing.T) { tests := []struct { settings ServerConfig err string }{ { err: "failed to load TLS config: failed to load CA CertPool File: failed to load cert /doesnt/exist:", settings: ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "127.0.0.1:1234", Transport: confignet.TransportTypeTCP, }, TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: "/doesnt/exist", }, }), }, }, { err: "failed to load TLS config: failed to load TLS cert and key: for auth via TLS, provide both certificate and key, or neither", settings: ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "127.0.0.1:1234", Transport: confignet.TransportTypeTCP, }, TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CertFile: "/doesnt/exist", }, }), }, }, { err: "failed to load client CA CertPool: failed to load CA /doesnt/exist:", settings: ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "127.0.0.1:1234", Transport: confignet.TransportTypeTCP, }, TLS: configoptional.Some(configtls.ServerConfig{ ClientCAFile: "/doesnt/exist", }), }, }, } for _, test := range tests { t.Run(test.err, func(t *testing.T) { _, err := test.settings.ToServer(context.Background(), nil, componenttest.NewNopTelemetrySettings()) assert.ErrorContains(t, err, test.err) }) } } func TestGRPCServerSettings_ToListener_Error(t *testing.T) { settings := ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "127.0.0.1:1234567", Transport: confignet.TransportTypeTCP, }, } _, err := settings.NetAddr.Listen(context.Background()) assert.Error(t, err) } func TestHttpReception(t *testing.T) { tests := []struct { name string tlsServerCreds configoptional.Optional[configtls.ServerConfig] tlsClientCreds configoptional.Optional[configtls.ClientConfig] hasError bool }{ { name: "noTLS", tlsServerCreds: configoptional.None[configtls.ServerConfig](), tlsClientCreds: configoptional.Some(configtls.ClientConfig{ Insecure: true, }), }, { name: "TLS", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, }), tlsClientCreds: configoptional.Some(configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", }), }, { name: "NoServerCertificates", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, }), tlsClientCreds: configoptional.Some(configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", }), hasError: true, }, { name: "mTLS", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, ClientCAFile: filepath.Join("testdata", "ca.crt"), }), tlsClientCreds: configoptional.Some(configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "client.crt"), KeyFile: filepath.Join("testdata", "client.key"), }, ServerName: "localhost", }), }, { name: "NoClientCertificate", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, ClientCAFile: filepath.Join("testdata", "ca.crt"), }), tlsClientCreds: configoptional.Some(configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", }), hasError: true, }, { name: "WrongClientCA", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, ClientCAFile: filepath.Join("testdata", "server.crt"), }), tlsClientCreds: configoptional.Some(configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "client.crt"), KeyFile: filepath.Join("testdata", "client.key"), }, ServerName: "localhost", }), hasError: true, }, } // prepare for _, test := range tests { t.Run(test.name, func(t *testing.T) { s, addr := (&grpcTraceServer{}).startTestServer(t, configoptional.Some(ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:0", Transport: confignet.TransportTypeTCP, }, TLS: test.tlsServerCreds, })) defer s.Stop() resp, errResp := sendTestRequest(t, ClientConfig{ Endpoint: addr, TLS: *test.tlsClientCreds.Get(), }) if test.hasError { require.Error(t, errResp) } else { require.NoError(t, errResp) assert.NotNil(t, resp) } }) } } func TestReceiveOnUnixDomainSocket(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping test on windows") } socketName := tempSocketName(t) srv, addr := (&grpcTraceServer{}).startTestServer(t, configoptional.Some(ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: socketName, Transport: confignet.TransportTypeUnix, }, })) defer srv.Stop() resp, errResp := sendTestRequest(t, ClientConfig{ Endpoint: "unix://" + addr, TLS: configtls.ClientConfig{ Insecure: true, }, }) require.NoError(t, errResp) assert.NotNil(t, resp) } func TestContextWithClient(t *testing.T) { testCases := []struct { desc string input context.Context doMetadata bool expected client.Info }{ { desc: "no peer information, empty client", input: context.Background(), expected: client.Info{}, }, { desc: "existing client with IP, no peer information", input: client.NewContext(context.Background(), client.Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }), expected: client.Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }, }, { desc: "empty client, with peer information", input: peer.NewContext(context.Background(), &peer.Peer{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }), expected: client.Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }, }, { desc: "existing client, existing IP gets overridden with peer information", input: peer.NewContext(client.NewContext(context.Background(), client.Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }), &peer.Peer{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 5), }, }), expected: client.Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 5), }, }, }, { desc: "existing client with metadata", input: client.NewContext(context.Background(), client.Info{ Metadata: client.NewMetadata(map[string][]string{"test-metadata-key": {"test-value"}}), }), doMetadata: true, expected: client.Info{ Metadata: client.NewMetadata(map[string][]string{"test-metadata-key": {"test-value"}}), }, }, { desc: "existing client with metadata in context", input: metadata.NewIncomingContext( client.NewContext(context.Background(), client.Info{}), metadata.Pairs("test-metadata-key", "test-value"), ), doMetadata: true, expected: client.Info{ Metadata: client.NewMetadata(map[string][]string{"test-metadata-key": {"test-value"}}), }, }, { desc: "existing client with metadata in context, no metadata processing", input: metadata.NewIncomingContext( client.NewContext(context.Background(), client.Info{}), metadata.Pairs("test-metadata-key", "test-value"), ), expected: client.Info{}, }, { desc: "existing client with Host and metadata", input: metadata.NewIncomingContext( client.NewContext(context.Background(), client.Info{}), metadata.Pairs("test-metadata-key", "test-value", ":authority", "localhost:55443"), ), doMetadata: true, expected: client.Info{ Metadata: client.NewMetadata(map[string][]string{"test-metadata-key": {"test-value"}, ":authority": {"localhost:55443"}, "Host": {"localhost:55443"}}), }, }, } for _, tt := range testCases { t.Run(tt.desc, func(t *testing.T) { cl := client.FromContext(contextWithClient(tt.input, tt.doMetadata)) assert.Equal(t, tt.expected, cl) }) } } func TestStreamInterceptorEnhancesClient(t *testing.T) { // prepare inCtx := peer.NewContext(context.Background(), &peer.Peer{ Addr: &net.IPAddr{IP: net.IPv4(1, 1, 1, 1)}, }) stream := &mockedStream{ ctx: inCtx, } var handlerCalled bool handler := func(_ any, stream grpc.ServerStream) error { handlerCalled = true cl := client.FromContext(stream.Context()) assert.Equal(t, "1.1.1.1", cl.Addr.String()) return nil } // test err := enhanceStreamWithClientInformation(false)(nil, stream, nil, handler) // verify require.NoError(t, err) assert.True(t, handlerCalled, "the handler should have been called") } type mockedStream struct { ctx context.Context grpc.ServerStream } func (ms *mockedStream) Context() context.Context { return ms.ctx } func TestClientInfoInterceptors(t *testing.T) { testCases := []struct { name string tester func(ptraceotlp.ExportResponse, error) }{ { // we only have unary services, we don't have any clients we could use // to test with streaming services name: "unary", tester: func(resp ptraceotlp.ExportResponse, errResp error) { require.NoError(t, errResp) require.NotNil(t, resp) }, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { mock := &grpcTraceServer{} var addr string // prepare the server { var srv *grpc.Server srv, addr = mock.startTestServer(t, configoptional.Some(ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:0", Transport: confignet.TransportTypeTCP, }, })) defer srv.Stop() } // prepare the client and execute a RPC { resp, errResp := sendTestRequest(t, ClientConfig{ Endpoint: addr, TLS: configtls.ClientConfig{ Insecure: true, }, }) // test tt.tester(resp, errResp) } // verify cl := client.FromContext(mock.recordedContext) // the client address is something like 127.0.0.1:41086 assert.Contains(t, cl.Addr.String(), "127.0.0.1") }) } } func TestDefaultUnaryInterceptorAuthSucceeded(t *testing.T) { // prepare handlerCalled := false authCalled := false authFunc := func(context.Context, map[string][]string) (context.Context, error) { authCalled = true ctx := client.NewContext(context.Background(), client.Info{ Addr: &net.IPAddr{IP: net.IPv4(1, 2, 3, 4)}, }) return ctx, nil } handler := func(ctx context.Context, _ any) (any, error) { handlerCalled = true cl := client.FromContext(ctx) assert.Equal(t, "1.2.3.4", cl.Addr.String()) return nil, nil } ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "some-auth-data")) interceptor := authUnaryServerInterceptor(newMockAuthServer(authFunc)) // test res, err := interceptor(ctx, nil, &grpc.UnaryServerInfo{}, handler) // verify assert.Nil(t, res) require.NoError(t, err) assert.True(t, authCalled) assert.True(t, handlerCalled) } func TestDefaultUnaryInterceptorAuthFailure(t *testing.T) { // prepare authCalled := false expectedErr := errors.New("not authenticated") authFunc := func(context.Context, map[string][]string) (context.Context, error) { authCalled = true return context.Background(), expectedErr } handler := func(context.Context, any) (any, error) { assert.FailNow(t, "the handler should not have been called on auth failure!") return nil, nil } ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "some-auth-data")) interceptor := authUnaryServerInterceptor(newMockAuthServer(authFunc)) // test res, err := interceptor(ctx, nil, &grpc.UnaryServerInfo{}, handler) // verify assert.Nil(t, res) require.ErrorContains(t, err, expectedErr.Error()) assert.Equal(t, codes.Unauthenticated, status.Code(err)) assert.True(t, authCalled) } func TestDefaultUnaryInterceptorAuthFailureWithStatusErr(t *testing.T) { // prepare authCalled := false expectedStatusErr := status.New(codes.Unavailable, "unavailable") authFunc := func(context.Context, map[string][]string) (context.Context, error) { authCalled = true return context.Background(), expectedStatusErr.Err() } handler := func(context.Context, any) (any, error) { assert.FailNow(t, "the handler should not have been called on auth failure!") return nil, nil } ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "some-auth-data")) interceptor := authUnaryServerInterceptor(newMockAuthServer(authFunc)) // test res, err := interceptor(ctx, nil, &grpc.UnaryServerInfo{}, handler) // verify assert.Nil(t, res) require.ErrorContains(t, err, expectedStatusErr.Err().Error()) assert.Equal(t, codes.Unavailable, status.Code(err)) assert.True(t, authCalled) } func TestDefaultUnaryInterceptorMissingMetadata(t *testing.T) { // prepare authFunc := func(context.Context, map[string][]string) (context.Context, error) { assert.FailNow(t, "the auth func should not have been called!") return context.Background(), nil } handler := func(context.Context, any) (any, error) { assert.FailNow(t, "the handler should not have been called!") return nil, nil } interceptor := authUnaryServerInterceptor(newMockAuthServer(authFunc)) // test res, err := interceptor(context.Background(), nil, &grpc.UnaryServerInfo{}, handler) // verify assert.Nil(t, res) assert.Equal(t, errMetadataNotFound, err) } func TestDefaultStreamInterceptorAuthSucceeded(t *testing.T) { // prepare handlerCalled := false authCalled := false authFunc := func(context.Context, map[string][]string) (context.Context, error) { authCalled = true ctx := client.NewContext(context.Background(), client.Info{ Addr: &net.IPAddr{IP: net.IPv4(1, 2, 3, 4)}, }) return ctx, nil } handler := func(_ any, stream grpc.ServerStream) error { // ensure that the client information is propagated down to the underlying stream cl := client.FromContext(stream.Context()) assert.Equal(t, "1.2.3.4", cl.Addr.String()) handlerCalled = true return nil } streamServer := &mockServerStream{ ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "some-auth-data")), } interceptor := authStreamServerInterceptor(newMockAuthServer(authFunc)) // test err := interceptor(nil, streamServer, &grpc.StreamServerInfo{}, handler) // verify require.NoError(t, err) assert.True(t, authCalled) assert.True(t, handlerCalled) } func TestDefaultStreamInterceptorAuthFailureWithStatusErr(t *testing.T) { // prepare authCalled := false expectedStatusErr := status.New(codes.Unavailable, "unavailable") authFunc := func(context.Context, map[string][]string) (context.Context, error) { authCalled = true return context.Background(), expectedStatusErr.Err() } handler := func(any, grpc.ServerStream) error { assert.FailNow(t, "the handler should not have been called on auth failure!") return nil } streamServer := &mockServerStream{ ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "some-auth-data")), } interceptor := authStreamServerInterceptor(newMockAuthServer(authFunc)) // test err := interceptor(nil, streamServer, &grpc.StreamServerInfo{}, handler) // verify require.ErrorContains(t, err, expectedStatusErr.Err().Error()) // unfortunately, grpc errors don't wrap the original ones assert.Equal(t, codes.Unavailable, status.Code(err)) assert.True(t, authCalled) } func TestDefaultStreamInterceptorAuthFailure(t *testing.T) { // prepare authCalled := false expectedErr := errors.New("not authenticated") authFunc := func(context.Context, map[string][]string) (context.Context, error) { authCalled = true return context.Background(), expectedErr } handler := func(any, grpc.ServerStream) error { assert.FailNow(t, "the handler should not have been called on auth failure!") return nil } streamServer := &mockServerStream{ ctx: metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", "some-auth-data")), } interceptor := authStreamServerInterceptor(newMockAuthServer(authFunc)) // test err := interceptor(nil, streamServer, &grpc.StreamServerInfo{}, handler) // verify require.ErrorContains(t, err, expectedErr.Error()) // unfortunately, grpc errors don't wrap the original ones assert.Equal(t, codes.Unauthenticated, status.Code(err)) assert.True(t, authCalled) } func TestDefaultStreamInterceptorMissingMetadata(t *testing.T) { // prepare authFunc := func(context.Context, map[string][]string) (context.Context, error) { assert.FailNow(t, "the auth func should not have been called!") return context.Background(), nil } handler := func(any, grpc.ServerStream) error { assert.FailNow(t, "the handler should not have been called!") return nil } streamServer := &mockServerStream{ ctx: context.Background(), } interceptor := authStreamServerInterceptor(newMockAuthServer(authFunc)) // test err := interceptor(nil, streamServer, &grpc.StreamServerInfo{}, handler) // verify assert.Equal(t, errMetadataNotFound, err) } type mockServerStream struct { grpc.ServerStream ctx context.Context } func (m *mockServerStream) Context() context.Context { return m.ctx } type grpcTraceServer struct { ptraceotlp.UnimplementedGRPCServer recordedContext context.Context } func (gts *grpcTraceServer) Export(ctx context.Context, _ ptraceotlp.ExportRequest) (ptraceotlp.ExportResponse, error) { gts.recordedContext = ctx return ptraceotlp.NewExportResponse(), nil } func (gts *grpcTraceServer) startTestServer(t *testing.T, gss configoptional.Optional[ServerConfig]) (*grpc.Server, string) { return gts.startTestServerWithExtensions(t, gss, nil) } func (gts *grpcTraceServer) startTestServerWithExtensions(t *testing.T, gss configoptional.Optional[ServerConfig], extensions map[component.ID]component.Component, opts ...ToServerOption) (*grpc.Server, string) { listener, err := gss.Get().NetAddr.Listen(context.Background()) require.NoError(t, err) server, err := gss.Get().ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings(), opts...) require.NoError(t, err) ptraceotlp.RegisterGRPCServer(server, gts) go func() { _ = server.Serve(listener) }() return server, listener.Addr().String() } func (gts *grpcTraceServer) startTestServerWithExtensionsError(_ *testing.T, gss ServerConfig, extensions map[component.ID]component.Component, opts ...ToServerOption) (*grpc.Server, error) { listener, err := gss.NetAddr.Listen(context.Background()) if err != nil { return nil, err } defer listener.Close() server, err := gss.ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings(), opts...) if err != nil { return nil, err } ptraceotlp.RegisterGRPCServer(server, gts) return server, nil } // sendTestRequest issues a ptraceotlp export request and captures metadata. func sendTestRequest(t *testing.T, cc ClientConfig) (ptraceotlp.ExportResponse, error) { return sendTestRequestWithExtensions(t, cc, nil) } // sendTestRequestWithExtensions is similar to sendTestRequest but allows specifying the host func sendTestRequestWithExtensions(t *testing.T, cc ClientConfig, extensions map[component.ID]component.Component) (ptraceotlp.ExportResponse, error) { grpcClientConn, errClient := cc.ToClientConn(context.Background(), extensions, componenttest.NewNopTelemetrySettings()) require.NoError(t, errClient) defer func() { assert.NoError(t, grpcClientConn.Close()) }() c := ptraceotlp.NewGRPCClient(grpcClientConn) ctx, cancelFunc := context.WithTimeout(context.Background(), 2*time.Second) resp, errResp := c.Export(ctx, ptraceotlp.NewExportRequest(), grpc.WaitForReady(true)) cancelFunc() return resp, errResp } // tempSocketName provides a temporary Unix socket name for testing. func tempSocketName(t *testing.T) string { // The socket path length limit on macOS is 104 characters. Using `os.TempDir` to produce a shorter file path (#12639) tmpfile, err := os.CreateTemp(os.TempDir(), "sock") require.NoError(t, err) require.NoError(t, tmpfile.Close()) socket := tmpfile.Name() require.NoError(t, os.Remove(socket)) return socket } opentelemetry-collector-0.141.0/config/configgrpc/doc.go000066400000000000000000000006241511331344600232220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package configgrpc defines the configuration settings to create // a gRPC client and server. // // The configuration structs in this package may be shared across signals, but // assume each struct is used for a single protocol and component. package configgrpc // import "go.opentelemetry.io/collector/config/configgrpc" opentelemetry-collector-0.141.0/config/configgrpc/go.mod000066400000000000000000000124331511331344600232350ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configgrpc go 1.24.0 require ( github.com/mostynb/go-grpc-compression v1.2.3 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/client v1.47.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configauth v1.47.0 go.opentelemetry.io/collector/config/configcompression v1.47.0 go.opentelemetry.io/collector/config/configmiddleware v1.47.0 go.opentelemetry.io/collector/config/confignet v1.47.0 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/config/configtls v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensionauth v1.47.0 go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest v0.141.0 go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 go.opentelemetry.io/otel v1.38.0 go.uber.org/goleak v1.3.0 google.golang.org/grpc v1.77.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/confmap v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.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.45.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/config/configauth => ../configauth replace go.opentelemetry.io/collector/config/configcompression => ../configcompression replace go.opentelemetry.io/collector/config/confignet => ../confignet replace go.opentelemetry.io/collector/config/configopaque => ../configopaque replace go.opentelemetry.io/collector/config/configoptional => ../configoptional replace go.opentelemetry.io/collector/config/configtls => ../configtls replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/config/configmiddleware => ../configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/config/configgrpc/go.sum000066400000000000000000000246051511331344600232660ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configgrpc/gzip.go000066400000000000000000000004371511331344600234300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configgrpc // import "go.opentelemetry.io/collector/config/configgrpc" import ( // Import the gzip package which auto-registers the gzip gRPC compressor. _ "google.golang.org/grpc/encoding/gzip" ) opentelemetry-collector-0.141.0/config/configgrpc/metadata.yaml000066400000000000000000000002031511331344600245630ustar00rootroot00000000000000type: config/configgrpc github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configgrpc/package_test.go000066400000000000000000000003131511331344600251020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configgrpc import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configgrpc/server_middleware_test.go000066400000000000000000000111521511331344600272150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configgrpc import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionmiddleware" "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" ) // contextKey is a private type for keys defined in this test. type contextKey int // Key for the slice of middleware names in the context. const middlewareCallsKey contextKey = 0 // getMiddlewareCalls retrieves the middleware calls from context or returns an empty slice. func getMiddlewareCalls(ctx context.Context) []string { calls, ok := ctx.Value(middlewareCallsKey).([]string) if !ok { return []string{} } return calls } // testServerMiddleware is a test implementation of configmiddleware.Middleware type testServerMiddleware struct { extension.Extension extensionmiddleware.GetGRPCServerOptionsFunc } func newTestServerMiddleware(name string) extension.Extension { return &testServerMiddleware{ Extension: extensionmiddlewaretest.NewNop(), GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { return []grpc.ServerOption{grpc.ChainUnaryInterceptor( func( ctx context.Context, req any, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler, ) (any, error) { ctx = context.WithValue(ctx, middlewareCallsKey, append(getMiddlewareCalls(ctx), name)) return handler(ctx, req) })}, nil }, } } func TestGrpcServerUnaryInterceptor(t *testing.T) { // Register two test extensions extensions := map[component.ID]component.Component{ component.MustNewID("test1"): newTestServerMiddleware("test1"), component.MustNewID("test2"): newTestServerMiddleware("test2"), } // Setup the server with both middleware options server := &grpcTraceServer{} var addr string // Create the server with middleware interceptors { var srv *grpc.Server srv, addr = server.startTestServerWithExtensions(t, configoptional.Some(ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:0", Transport: confignet.TransportTypeTCP, }, Middlewares: []configmiddleware.Config{ newTestMiddlewareConfig("test1"), newTestMiddlewareConfig("test2"), }, }), extensions) defer srv.Stop() } // Send a request to trigger the interceptors resp, errResp := sendTestRequest(t, ClientConfig{ Endpoint: addr, TLS: configtls.ClientConfig{ Insecure: true, }, }) require.NoError(t, errResp) require.NotNil(t, resp) // Verify interceptors were called in the correct order assert.Equal(t, []string{"test1", "test2"}, getMiddlewareCalls(server.recordedContext)) } // TestServerMiddlewareToServerErrors tests failure cases for the ToServer method // specifically related to middleware resolution and API calls. func TestServerMiddlewareToServerErrors(t *testing.T) { tests := []struct { name string extensions map[component.ID]component.Component config ServerConfig errText string }{ { name: "extension_not_found", extensions: map[component.ID]component.Component{}, config: ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:0", Transport: confignet.TransportTypeTCP, }, Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("nonexistent"), }, }, }, errText: "failed to resolve middleware \"nonexistent\": middleware not found", }, { name: "get_server_options_fails", extensions: map[component.ID]component.Component{ component.MustNewID("errormw"): extensionmiddlewaretest.NewErr(errors.New("get server options failed")), }, config: ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:0", Transport: confignet.TransportTypeTCP, }, Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("errormw"), }, }, }, errText: "get server options failed", }, } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { // Test creating the server with middleware errors server := &grpcTraceServer{} srv, err := server.startTestServerWithExtensionsError(t, tc.config, tc.extensions) if srv != nil { srv.Stop() } require.Error(t, err) assert.Contains(t, err.Error(), tc.errText) }) } } opentelemetry-collector-0.141.0/config/configgrpc/testdata/000077500000000000000000000000001511331344600237355ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configgrpc/testdata/ca.crt000066400000000000000000000022301511331344600250270ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDNjCCAh4CCQC0I5IQT7eziDANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJB VTESMBAGA1UECAwJQXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoM CU15T3JnTmFtZTEVMBMGA1UEAwwMTXlDb21tb25OYW1lMB4XDTIyMDgwMzA0MTky MVoXDTMyMDczMTA0MTkyMVowXTELMAkGA1UEBhMCQVUxEjAQBgNVBAgMCUF1c3Ry YWxpYTEPMA0GA1UEBwwGU3lkbmV5MRIwEAYDVQQKDAlNeU9yZ05hbWUxFTATBgNV BAMMDE15Q29tbW9uTmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AMhGP0dy3zvkdx9zI+/XVjPOWlER0OUp7Sgzidc3nLOk42+bH4ofIVNtOFVqlNKi O1bImu238VdBhd6R5IZZ1ZdIMcCeDgSJYu2X9wA3m4PKz8IdXo5ly2OHghhmCvqG WxgqDj5wPXiczQwuf1EcDMtRWbXJ6Z/XH1U68R/kRdNLkiZ2LwtjoQpis5XYckLL CrdF+AL6GeDIe0Mh9QGs26Vux+2kvaOGNUWRPE6Wt4GkqyKqmzYfR9HbflJ4xHT2 I+jE1lg+jMBeom7z8Z90RE4GGcHjO+Vens/88r5EAjTnFj1Kb5gL2deSHY1m/++R Z/kRyg+zQJyw4fAzlAA4+VkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAM3gRdTKX eGwGYVmmKqA2vTxeigQYLHml7OSopcWj2wJfxfp49HXPRuvgpQn9iubxO3Zmhd83 2X1E+T0A8oy5CfxgpAhHb3lY0jm3TjKXm6m+dSODwL3uND8tX+SqR8sRTFxPvPuo pmvhdTZoRI3EzIiHLTgCuSU25JNP/vrVoKk0JvCkDYTU/WcVfj0v95DTMoWR4JGz mtBwrgD0EM2XRw5ZMc7sMPli1gqmCbCQUrDZ+rPB78WDCBILBd8Cz75qYTUp98BY akJyBckdJHAdyEQYDKa9HpmpexOO7IhSXCTEN1DEBgpZgEi/lBDRG/b0OzenUUgt LUABtWt3pNQ9HA== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configgrpc/testdata/client.crt000066400000000000000000000023001511331344600257200ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIJANt5fkUlfxyiMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxOTIxWhcNMzIwNzMxMDQxOTIxWjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAm/gURxkdWTDS0TyL2j920SfOtOZIo7DjubWLbZtNLrNCZNBsV+8c/ko/ wleWmUJQRHeiZkNFs8TK6d8Grks6ta9oNO4CiCCO1kz4QidA827cL5+WaKWEVn8Y Z8aiEMjDOnpYnb/ycsXpERN/P22jHpFD3DKSwLXoXQvasbSJsZro+AIaPAurFB7W rMagCptwzGQDzryqVKEmXo+eN4XRxsoE8yroHsGbQ8GCZ+neftgV3Jhi1qcXZ//A 3ApY5lg06n1A03fYBlXE5L9tYKpIRNl2kq45mJ8DX6Tdp4Z1Y15+keIIyQpx4LRf rtdbMQNJhBFOwpAajTmaKXxeICFRHQIDAQABoxgwFjAUBgNVHREEDTALgglsb2Nh bGhvc3QwDQYJKoZIhvcNAQELBQADggEBAKWrbMxms658R/wYwLxzWPrZVKFswOJX TpSkXGkyRnrhhZi3I8EhLZhlpZ9k8dplcvseVAUdX9hJu0BaDWBiW/VlPVUkWpWR QZzrssAKhmSYMgl3OiayU30vL9bxYsAX9KeOJfnJ4kWoBpnguToED7wrC1lbzrVK Vj1AiI3hBdKUdPNO0hyb8yfxbP3MOottMkk89DIebtOhqj2KEU7sKrhW9a5P5D7d 0A+0kf/IunUZ4IYFfha6qy0gRMyayfm9ttrPAY6q3faqtWR7nY87/T/7wHr1LQ1/ Q622p7v3j3y75lGN50kFnSd77ykag/8avEKxOTFoGOQc5VCRYJnJwb4= -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configgrpc/testdata/client.key000066400000000000000000000032131511331344600257240ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAm/gURxkdWTDS0TyL2j920SfOtOZIo7DjubWLbZtNLrNCZNBs V+8c/ko/wleWmUJQRHeiZkNFs8TK6d8Grks6ta9oNO4CiCCO1kz4QidA827cL5+W aKWEVn8YZ8aiEMjDOnpYnb/ycsXpERN/P22jHpFD3DKSwLXoXQvasbSJsZro+AIa PAurFB7WrMagCptwzGQDzryqVKEmXo+eN4XRxsoE8yroHsGbQ8GCZ+neftgV3Jhi 1qcXZ//A3ApY5lg06n1A03fYBlXE5L9tYKpIRNl2kq45mJ8DX6Tdp4Z1Y15+keII yQpx4LRfrtdbMQNJhBFOwpAajTmaKXxeICFRHQIDAQABAoIBAQCWxrT7omi/vzYd 9dUQ8Acx3LS0JmaUb71F2x3loJt1iO+nO+FxBIPXw/ltK3U3xWaJOcnx6Biq15R9 kBAKUEl6OA6aFHi4FhlfS9s3QHFGo6YSF8m0ckXDxGvYbqpfZWVt07Z1EYkUsQRF cL6zl454T1/1r6I0z+XIhVwuLGRsHt2+GCwSrLMnF9aTUJvPFy5G7YlxmL5q1BFu F70AK9FLZcYqa5nP1F1HbIQB/zsQ8admpKIy5tjaZiLgctXv2GTzzXDEwEnaJMrq SPr1dGDhdGs5iYRMOMT5Pp9dIG2+ZSSMHFAn4IRoB/cPJbNEUkgwQOPmDYETqSg5 tSjfIUw1AoGBAMjE6PlT1/orlHW4QvKmV73YtKPVfi1Coo/F8G45qFaHDkc6bI9W ySrnvqWcPs++xOZMoGtLuESw/LEluFo8vMX8aQYrVSz4Pb7AvuYbBRE0EVVui7YB 3B1O0c7QTabmfQYeATYD7qSShLccSpUE+FQa6NdrJOxddJLM0Z9K73q7AoGBAMbg I2+NYB6XME7tyStOS4pkA4y7brG/M8BCaY34nfOJT4Qh6pqZRnDJ4ReopGoXEqWg hwFRsBNhsji4GGejRBPnYcfJTSuMXSPromgoH1tR0OQbMJB0pCTavbI9j+endlv4 /P+KV3ZMYOLhL/gaaTG+o6Wh2ehnE/8/rmqGpoIHAoGAHXVG+c5jkkFytxMiP5hI p4J0ftWEff+Y+p+Ad6veF1QZtDnOU/nX6oO2ZXZXgQPswB3eK+AgWXPen994/USM LkCq6EzTYpXJ+YMuf3TXeX66TF68ASiks2gtQLsvqZ2IGq2sX9CT43HcJ0Hvb44b IbwRDgqakFPmFuQWndjQ6qECgYA9bOlFATOY/zWKi2NBHvOyEOYPx6yO9fF0Bo83 rHyMxfJra1Zc3c6l85S0jAAMTIgT5BsOyz5JHjm/zwyqpgDW7PaEkKZnNvllqNgG t63HtOOCMOu1EnHIeE9zCBS0hkLGcYcjHoWZIkoiiU8ZoH6xQKKm+/CkGYJRqkei 22f+bQKBgGHq2/ZzgxfblD3blKWp8mh5Kw7c/2VwJRvLEMlgzrnRgF7QNhEcH3Jm aD/pqzAkqHnLVVQ5ogMKrrLl11jQp4kX74+Ps2Yul7UgzXFYy020mQSpJF/FMjrl PEqwfCiOT2nLyE30x9VClUOGXy1CxH52Yn/g81ENq3jKTptwh+fI -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/configgrpc/testdata/server.crt000066400000000000000000000023001511331344600257500ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIJANt5fkUlfxyhMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxOTIxWhcNMzIwNzMxMDQxOTIxWjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAv1Pm2elKl/IpJlX5NqQjRTlA1rHws8F7v1IuaXB2qfk1MsDCt37OvlbR 4ARrY6zdUIrEQ/wrhQsZ2M5/yaj0rfeCgd/SDUKMAqDvXQXBY2AaLubTAIEMs4rF R5Zq/pcBNz1zu8kRvRgvVuOpTCPR1kRvKFWAp689lXZhUU/BrQQXhdA993xVMRM9 u4fZuJLxNGGR/EhqTec4Z65jAZiUfO7ID94PtaxTrzR/Kjr2CiceR5hwdY40Bcme D3IAd0J6nN1zIihe+Nqg/ImOG7YS+efQIEWJ8eHOoCK5knFBXRy6WwxeCyAPXyIb DTrqTy67eTDYc0XZ24F/5Q3GSvfMDwIDAQABoxgwFjAUBgNVHREEDTALgglsb2Nh bGhvc3QwDQYJKoZIhvcNAQELBQADggEBAKeFHP5rQasRS/XGbPkobfbFyTdGnLay 0Vr6+Rs5+4siKlAIhuUP9A/De61CEkFj8NFi2bmXYv8q3qP/z0lrjw7btrvD7Qc7 lth73k3U2sUVZoqbYQZz0GHCWfZm8yXjP63SKI+81LHbS40ArO0R44BLc9TbbRiR /LwO/x2+cxs28KdsEkU6jQ6Ly5jyoxw1ysoIeRfIk+FnQD4w29TyGgtX/G15/NN0 ytByIZ8wdbUciunQc3nPXoPc41N+hyi2GZaXMuJ4VlsNmgY+wPmp4y3pl4l0bgCb 1FR8Vvtsi8jLH8J15oAMWdmHQKcoJDE49llx+bQGpNekp6mlfX1DIPI= -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configgrpc/testdata/server.key000066400000000000000000000032171511331344600257600ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAv1Pm2elKl/IpJlX5NqQjRTlA1rHws8F7v1IuaXB2qfk1MsDC t37OvlbR4ARrY6zdUIrEQ/wrhQsZ2M5/yaj0rfeCgd/SDUKMAqDvXQXBY2AaLubT AIEMs4rFR5Zq/pcBNz1zu8kRvRgvVuOpTCPR1kRvKFWAp689lXZhUU/BrQQXhdA9 93xVMRM9u4fZuJLxNGGR/EhqTec4Z65jAZiUfO7ID94PtaxTrzR/Kjr2CiceR5hw dY40BcmeD3IAd0J6nN1zIihe+Nqg/ImOG7YS+efQIEWJ8eHOoCK5knFBXRy6Wwxe CyAPXyIbDTrqTy67eTDYc0XZ24F/5Q3GSvfMDwIDAQABAoIBAQC/BuxlAhKiJvyC 9DABKFy2zvU35y3mq/X8Dfec+tbf2pwM8nz3bLrLPDAMNR1rxbqqogJXxr1E9tJ1 r6fTFshFsewx8+DrsFfOgBS9kfOGXvuFfJ2L0U13LcTPNxXY37gtCUQ2aAk3/Z+2 Z1QvW0w1XNqHMOdlhQg95JZB8xnyvXs1niLT/I9d7KbPBmOWkB5Jp7+JaebmWqNS alxnNqYnhXcrNSAbuR4bgz0l4I+Jprms26C6sakmgCfeMjfWbd2k3tp06vKXmT6q qKa0855axP9wuSbKbscTDW5RFYTYnu/CSYJ4nZtzSS8a559iG3m61EgPOoVTnTX6 0t0I+kwRAoGBAN403NO4FfHG8k2bFpbATQkmC9UwjMbl5RIEL0fFhNVsuM5jTwHc 0wlFm9tMN8xqg66OFCimC/mUNPWX8nrb/MwrAw6/50rbyqOBFnmFKIfVf4ftpLzt BLhEg7a/FPgdDgldQD+C6XbMyBA1AF3nbpTnbnj5WVQTl672s9teegSzAoGBANxs 1y6Nfh2DyyU16p61376AAP3WfHvuBgJAC0xGCqoTrbyzl4/r06BTMl51PbWJLDjm FryTtgM7a8XO1jwfWJno71dnT7Bsy+wYnmJ5+9XHwgO9oZfSFUk+ELrEImI/4NZX dJLkc0SuCG/wa3Wa76+sFNlzAzBBs83RE2j432E1AoGAF+x5GhJnynAxBkn8VJ6/ rIx8GafwgDmgQCBTNtb9Rj0+aHoot3qe/hCQhzvdhhSxuMlzQi0efPCIAyko4jFt Nk4rNhtTO6wOVSxAzzSW+Ij0Ah6D7hNWvsAhrjtEdrIqILf5gt0FZdUGdTg/odyY +08vhbbS90pkumG1W5kAaiECgYEAqjk3eBD26u4jjIn1tTk5H9GUcnMYUVCAvW4e C3ovtCZcTlTW3+M73B1D0aRy0mWrjAlMV7cuoZJa6TiRQ37lmn5Dj1kONm3ekWZ1 shEIBZEtaFwila88lwJiQwlCkGNKS9zf/qyDw+8uPtwI8JqFLUIUG9VxCexDYddr SO6g+10CgYEAwUs2BRJb6Od+8XtH32+8DDOnpfWJARY0CwogN2k+D1dbAB8Wkda1 BMADasAcjDFRX6xvyyDlqxcDIoCI1JvpS82I/PTNHeT8pEr5Caln7OHD/BtnPwmI YR0bvKkoN0jdQdjifpMVXEbJS1VfFLdQYQ8iQMwZfkFmzIkYpvqWVtw= -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/configgrpc/wrappedstream.go000066400000000000000000000021661511331344600253360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright 2016 Michal Witkowski. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package configgrpc // import "go.opentelemetry.io/collector/config/configgrpc" import ( "context" "google.golang.org/grpc" ) // this functionality was originally copied from grpc-ecosystem/go-grpc-middleware project // wrappedServerStream is a thin wrapper around grpc.ServerStream that allows modifying context. type wrappedServerStream struct { grpc.ServerStream // wrappedContext is the wrapper's own Context. You can assign it. wrappedCtx context.Context } // Context returns the wrapper's wrappedContext, overwriting the nested grpc.ServerStream.Context() func (w *wrappedServerStream) Context() context.Context { return w.wrappedCtx } // wrapServerStream returns a ServerStream with the new context. func wrapServerStream(wrappedCtx context.Context, stream grpc.ServerStream) *wrappedServerStream { if existing, ok := stream.(*wrappedServerStream); ok { existing.wrappedCtx = wrappedCtx return existing } return &wrappedServerStream{ServerStream: stream, wrappedCtx: wrappedCtx} } opentelemetry-collector-0.141.0/config/configgrpc/wrappedstream_test.go000066400000000000000000000024511511331344600263720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // Copyright 2016 Michal Witkowski. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 package configgrpc // import "go.opentelemetry.io/collector/internal/middleware" import ( "context" "testing" "github.com/stretchr/testify/assert" "google.golang.org/grpc" ) type ctxKey struct{} var ( oneCtxKey = ctxKey{} otherCtxKey = ctxKey{} ) func TestWrapServerStream(t *testing.T) { ctx := context.WithValue(t.Context(), oneCtxKey, 1) fake := &fakeServerStream{ctx: ctx} assert.NotNil(t, fake.Context().Value(oneCtxKey), "values from fake must propagate to wrapper") wrapped := wrapServerStream(context.WithValue(fake.Context(), otherCtxKey, 2), fake) assert.NotNil(t, wrapped.Context().Value(oneCtxKey), "values from wrapper must be set") assert.NotNil(t, wrapped.Context().Value(otherCtxKey), "values from wrapper must be set") } func TestDoubleWrapping(t *testing.T) { fake := &fakeServerStream{ctx: context.Background()} wrapped := wrapServerStream(fake.Context(), fake) assert.Same(t, wrapped, wrapServerStream(wrapped.Context(), wrapped)) // should be noop assert.Equal(t, fake, wrapped.ServerStream) } type fakeServerStream struct { grpc.ServerStream ctx context.Context } func (f *fakeServerStream) Context() context.Context { return f.ctx } opentelemetry-collector-0.141.0/config/confighttp/000077500000000000000000000000001511331344600221505ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/confighttp/Makefile000066400000000000000000000000361511331344600236070ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/confighttp/README.md000066400000000000000000000156041511331344600234350ustar00rootroot00000000000000# HTTP Configuration Settings HTTP exposes a [variety of settings](https://golang.org/pkg/net/http/). Several of these settings are available for configuration within individual receivers or exporters. ## Client Configuration [Exporters](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/README.md) leverage client configuration. Note that client configuration supports TLS configuration, the configuration parameters are also defined under `tls` like server configuration. For more information, see [configtls README](../configtls/README.md). - `endpoint`: address:port - [`tls`](../configtls/README.md) - [`headers`](https://pkg.go.dev/net/http#Request): name/value pairs added to the HTTP request headers - certain headers such as Content-Length and Connection are automatically written when needed and values in Header may be ignored. - `Host` header is automatically derived from `endpoint` value. However, this automatic assignment can be overridden by explicitly setting the Host field in the headers field. - if `Host` header is provided then it overrides `Host` field in [Request](https://pkg.go.dev/net/http#Request) which results as an override of `Host` header value. - [`read_buffer_size`](https://golang.org/pkg/net/http/#Transport) - [`timeout`](https://golang.org/pkg/net/http/#Client) - [`write_buffer_size`](https://golang.org/pkg/net/http/#Transport) - `compression`: Compression type to use among `gzip`, `zstd`, `snappy`, `zlib`, `deflate`, and `lz4`. - look at the documentation for the server-side of the communication. - `none` will be treated as uncompressed, and any other inputs will cause an error. - `compression_params` : Configure advanced compression options - `level`: Configure compression level for `compression` type - The following are valid combinations of `compression` and `level` - `gzip` - BestSpeed: `1` - BestCompression: `9` - DefaultCompression: `-1` - `zlib` - BestSpeed: `1` - BestCompression: `9` - DefaultCompression: `-1` - `deflate` - BestSpeed: `1` - BestCompression: `9` - DefaultCompression: `-1` - `zstd` - SpeedFastest: `1` - SpeedDefault: `3` - SpeedBetterCompression: `6` - SpeedBestCompression: `11` - `snappy` No compression levels supported yet - `x-snappy-framed` (When feature gate `confighttp.framedSnappy` is enabled) No compression levels supported yet - [`max_idle_conns`](https://golang.org/pkg/net/http/#Transport) - [`max_idle_conns_per_host`](https://golang.org/pkg/net/http/#Transport) - [`max_conns_per_host`](https://golang.org/pkg/net/http/#Transport) - [`idle_conn_timeout`](https://golang.org/pkg/net/http/#Transport) - [`auth`](../configauth/README.md) - [`disable_keep_alives`](https://golang.org/pkg/net/http/#Transport) - [`force_attempt_http2`](https://golang.org/pkg/net/http/#Transport) - [`http2_read_idle_timeout`](https://pkg.go.dev/golang.org/x/net/http2#Transport) - [`http2_ping_timeout`](https://pkg.go.dev/golang.org/x/net/http2#Transport) - [`cookies`](https://pkg.go.dev/net/http#CookieJar) - [`enabled`] if enabled, the client will store cookies from server responses and reuse them in subsequent requests. - [`middlewares`](../configmiddleware/README.md) Example: ```yaml exporter: otlphttp: endpoint: otelcol2:55690 auth: authenticator: some-authenticator-extension tls: ca_file: ca.pem cert_file: cert.pem key_file: key.pem headers: test1: "value1" "test 2": "value 2" compression: gzip compression_params: level: 1 cookies: enabled: true ``` ## Server Configuration [Receivers](https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/README.md) leverage server configuration. - [`cors`](https://github.com/rs/cors#parameters): Configure [CORS][cors], allowing the receiver to accept traces from web browsers, even if the receiver is hosted at a different [origin][origin]. If left blank or set to `null`, CORS will not be enabled. - `allowed_origins`: A list of [origins][origin] allowed to send requests to the receiver. An origin may contain a wildcard (`*`) to replace 0 or more characters (e.g., `https://*.example.com`). **Do not use** a plain wildcard `["*"]`, as our CORS response includes `Access-Control-Allow-Credentials: true`, which makes browsers to **disallow a plain wildcard** (this is a security standard). To allow any origin, you can specify at least the protocol, for example `["https://*", "http://*"]`. If no origins are listed, CORS will not be enabled. - `allowed_headers`: Allow CORS requests to include headers outside the [default safelist][cors-headers]. By default, safelist headers and `X-Requested-With` will be allowed. To allow any request header, set to `["*"]`. - `max_age`: Sets the value of the [`Access-Control-Max-Age`][cors-cache] header, allowing clients to cache the response to CORS preflight requests. If not set, browsers use a default of 5 seconds. - `endpoint`: Valid value syntax available [here](https://github.com/grpc/grpc/blob/master/doc/naming.md) - `max_request_body_size`: configures the maximum allowed body size in bytes for a single request. Default: `20971520` (20MiB) - `compression_algorithms`: configures the list of compression algorithms the server can accept. Default: ["", "gzip", "zstd", "zlib", "snappy", "deflate", "lz4"] - `x-snappy-framed` can be used if feature gate `confighttp.snappyFramed` is enabled. - [`tls`](../configtls/README.md) - [`auth`](../configauth/README.md) - `request_params`: a list of query parameter names to add to the auth context, along with the HTTP headers - [`middlewares`](../configmiddleware/README.md) You can enable [`attribute processor`][attribute-processor] to append any http header to span's attribute using custom key. You also need to enable the "include_metadata" Example: ```yaml receivers: otlp: protocols: http: include_metadata: true auth: request_params: - token authenticator: some-authenticator-extension cors: allowed_origins: - https://foo.bar.com - https://*.test.com allowed_headers: - Example-Header max_age: 7200 endpoint: 0.0.0.0:55690 compression_algorithms: ["", "gzip"] processors: attributes: actions: - key: http.client_ip from_context: metadata.x-forwarded-for action: upsert ``` [cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS [cors-headers]: https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header [cors-cache]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age [origin]: https://developer.mozilla.org/en-US/docs/Glossary/Origin [attribute-processor]: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/attributesprocessor/README.md opentelemetry-collector-0.141.0/config/confighttp/client.go000066400000000000000000000264121511331344600237620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import ( "context" "errors" "fmt" "net/http" "net/http/cookiejar" "net/url" "time" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "golang.org/x/net/http2" "golang.org/x/net/publicsuffix" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" ) const ( headerContentEncoding = "Content-Encoding" ) // ClientConfig defines settings for creating an HTTP client. type ClientConfig struct { // The target URL to send data to (e.g.: http://some.url:9411/v1/traces). Endpoint string `mapstructure:"endpoint,omitempty"` // ProxyURL setting for the collector ProxyURL string `mapstructure:"proxy_url,omitempty"` // TLS struct exposes TLS client configuration. TLS configtls.ClientConfig `mapstructure:"tls,omitempty"` // ReadBufferSize for HTTP client. See http.Transport.ReadBufferSize. // Default is 0. ReadBufferSize int `mapstructure:"read_buffer_size,omitempty"` // WriteBufferSize for HTTP client. See http.Transport.WriteBufferSize. // Default is 0. WriteBufferSize int `mapstructure:"write_buffer_size,omitempty"` // Timeout parameter configures `http.Client.Timeout`. // Default is 0 (unlimited). Timeout time.Duration `mapstructure:"timeout,omitempty"` // Additional headers attached to each HTTP request sent by the client. // Existing header values are overwritten if collision happens. // Header values are opaque since they may be sensitive. Headers configopaque.MapList `mapstructure:"headers,omitempty"` // Auth configuration for outgoing HTTP calls. Auth configoptional.Optional[configauth.Config] `mapstructure:"auth,omitempty"` // The compression key for supported compression types within collector. Compression configcompression.Type `mapstructure:"compression,omitempty"` // Advanced configuration options for the Compression CompressionParams configcompression.CompressionParams `mapstructure:"compression_params,omitempty"` // MaxIdleConns is used to set a limit to the maximum idle HTTP connections the client can keep open. // By default, it is set to 100. Zero means no limit. MaxIdleConns int `mapstructure:"max_idle_conns"` // MaxIdleConnsPerHost is used to set a limit to the maximum idle HTTP connections the host can keep open. // If zero, [net/http.DefaultMaxIdleConnsPerHost] is used. MaxIdleConnsPerHost int `mapstructure:"max_idle_conns_per_host,omitempty"` // MaxConnsPerHost limits the total number of connections per host, including connections in the dialing, // active, and idle states. Default is 0 (unlimited). MaxConnsPerHost int `mapstructure:"max_conns_per_host,omitempty"` // IdleConnTimeout is the maximum amount of time a connection will remain open before closing itself. // By default, it is set to 90 seconds. IdleConnTimeout time.Duration `mapstructure:"idle_conn_timeout"` // DisableKeepAlives, if true, disables HTTP keep-alives and will only use the connection to the server // for a single HTTP request. // // WARNING: enabling this option can result in significant overhead establishing a new HTTP(S) // connection for every request. Before enabling this option please consider whether changes // to idle connection settings can achieve your goal. DisableKeepAlives bool `mapstructure:"disable_keep_alives,omitempty"` // This is needed in case you run into // https://github.com/golang/go/issues/59690 // https://github.com/golang/go/issues/36026 // HTTP2ReadIdleTimeout if the connection has been idle for the configured value send a ping frame for health check // 0s means no health check will be performed. HTTP2ReadIdleTimeout time.Duration `mapstructure:"http2_read_idle_timeout,omitempty"` // HTTP2PingTimeout if there's no response to the ping within the configured value, the connection will be closed. // If not set or set to 0, it defaults to 15s. HTTP2PingTimeout time.Duration `mapstructure:"http2_ping_timeout,omitempty"` // Cookies configures the cookie management of the HTTP client. Cookies configoptional.Optional[CookiesConfig] `mapstructure:"cookies,omitempty"` // Enabling ForceAttemptHTTP2 forces the HTTP transport to use the HTTP/2 protocol. // By default, this is set to true. // NOTE: HTTP/2 does not support settings such as MaxConnsPerHost, MaxIdleConnsPerHost and MaxIdleConns. ForceAttemptHTTP2 bool `mapstructure:"force_attempt_http2,omitempty"` // Middlewares are used to add custom functionality to the HTTP client. // Middleware handlers are called in the order they appear in this list, // with the first middleware becoming the outermost handler. Middlewares []configmiddleware.Config `mapstructure:"middlewares,omitempty"` } // CookiesConfig defines the configuration of the HTTP client regarding cookies served by the server. type CookiesConfig struct { _ struct{} } // NewDefaultClientConfig returns ClientConfig type object with // the default values of 'MaxIdleConns' and 'IdleConnTimeout', as well as [http.DefaultTransport] values. // Other config options are not added as they are initialized with 'zero value' by GoLang as default. // We encourage to use this function to create an object of ClientConfig. func NewDefaultClientConfig() ClientConfig { // The default values are taken from the values of 'DefaultTransport' of 'http' package. defaultTransport := http.DefaultTransport.(*http.Transport) return ClientConfig{ MaxIdleConns: defaultTransport.MaxIdleConns, IdleConnTimeout: defaultTransport.IdleConnTimeout, ForceAttemptHTTP2: true, } } func (cc *ClientConfig) Validate() error { if cc.Compression.IsCompressed() { if err := cc.Compression.ValidateParams(cc.CompressionParams); err != nil { return err } } return nil } // ToClientOption is an option to change the behavior of the HTTP client // returned by ClientConfig.ToClient(). // There are currently no available options. type ToClientOption interface { sealed() } // ToClient creates an HTTP client. // // To allow the configuration to reference middleware or authentication extensions, // the `extensions` argument should be the output of `host.GetExtensions()`. // It may also be `nil` in tests where no such extension is expected to be used. func (cc *ClientConfig) ToClient(ctx context.Context, extensions map[component.ID]component.Component, settings component.TelemetrySettings, _ ...ToClientOption) (*http.Client, error) { tlsCfg, err := cc.TLS.LoadTLSConfig(ctx) if err != nil { return nil, err } transport := http.DefaultTransport.(*http.Transport).Clone() if tlsCfg != nil { transport.TLSClientConfig = tlsCfg } if cc.ReadBufferSize > 0 { transport.ReadBufferSize = cc.ReadBufferSize } if cc.WriteBufferSize > 0 { transport.WriteBufferSize = cc.WriteBufferSize } transport.MaxIdleConns = cc.MaxIdleConns transport.MaxIdleConnsPerHost = cc.MaxIdleConnsPerHost transport.MaxConnsPerHost = cc.MaxConnsPerHost transport.IdleConnTimeout = cc.IdleConnTimeout transport.ForceAttemptHTTP2 = cc.ForceAttemptHTTP2 // Setting the Proxy URL if cc.ProxyURL != "" { proxyURL, parseErr := url.ParseRequestURI(cc.ProxyURL) if parseErr != nil { return nil, parseErr } transport.Proxy = http.ProxyURL(proxyURL) } transport.DisableKeepAlives = cc.DisableKeepAlives if cc.HTTP2ReadIdleTimeout > 0 { transport2, transportErr := http2.ConfigureTransports(transport) if transportErr != nil { return nil, fmt.Errorf("failed to configure http2 transport: %w", transportErr) } transport2.ReadIdleTimeout = cc.HTTP2ReadIdleTimeout transport2.PingTimeout = cc.HTTP2PingTimeout } clientTransport := http.RoundTripper(transport) // Apply middlewares in reverse order so they execute in // forward order. The first middleware runs after authentication. if len(cc.Middlewares) > 0 && extensions == nil { return nil, errors.New("middlewares were configured but this component or its host does not support extensions") } for i := len(cc.Middlewares) - 1; i >= 0; i-- { var wrapper func(http.RoundTripper) (http.RoundTripper, error) wrapper, err = cc.Middlewares[i].GetHTTPClientRoundTripper(ctx, extensions) // If we failed to get the middleware if err != nil { return nil, err } clientTransport, err = wrapper(clientTransport) // If we failed to construct a wrapper if err != nil { return nil, err } } // The Auth RoundTripper should always be the innermost to ensure that // request signing-based auth mechanisms operate after compression // and header middleware modifies the request if cc.Auth.HasValue() { if extensions == nil { return nil, errors.New("authentication was configured but this component or its host does not support extensions") } auth := cc.Auth.Get() httpCustomAuthRoundTripper, aerr := auth.GetHTTPClientAuthenticator(ctx, extensions) if aerr != nil { return nil, aerr } clientTransport, err = httpCustomAuthRoundTripper.RoundTripper(clientTransport) if err != nil { return nil, err } } if len(cc.Headers) > 0 { clientTransport = &headerRoundTripper{ transport: clientTransport, headers: cc.Headers, } } // Compress the body using specified compression methods if non-empty string is provided. // Supporting gzip, zlib, deflate, snappy, and zstd; none is treated as uncompressed. if cc.Compression.IsCompressed() { // If the compression level is not set, use the default level. if cc.CompressionParams.Level == 0 { cc.CompressionParams.Level = configcompression.DefaultCompressionLevel } clientTransport, err = newCompressRoundTripper(clientTransport, cc.Compression, cc.CompressionParams) if err != nil { return nil, err } } otelOpts := []otelhttp.Option{ otelhttp.WithTracerProvider(settings.TracerProvider), otelhttp.WithPropagators(otel.GetTextMapPropagator()), otelhttp.WithMeterProvider(settings.MeterProvider), } // wrapping http transport with otelhttp transport to enable otel instrumentation if settings.TracerProvider != nil && settings.MeterProvider != nil { clientTransport = otelhttp.NewTransport(clientTransport, otelOpts...) } var jar http.CookieJar if cc.Cookies.HasValue() { jar, err = cookiejar.New(&cookiejar.Options{PublicSuffixList: publicsuffix.List}) if err != nil { return nil, err } } return &http.Client{ Transport: clientTransport, Timeout: cc.Timeout, Jar: jar, }, nil } // Custom RoundTripper that adds headers. type headerRoundTripper struct { transport http.RoundTripper headers configopaque.MapList } // RoundTrip is a custom RoundTripper that adds headers to the request. func (interceptor *headerRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { // Set Host header if provided hostHeader, found := interceptor.headers.Get("Host") if found && hostHeader != "" { // `Host` field should be set to override default `Host` header value which is Endpoint req.Host = string(hostHeader) } for k, v := range interceptor.headers.Iter { req.Header.Set(k, string(v)) } // Send the request to next transport. return interceptor.transport.RoundTrip(req) } opentelemetry-collector-0.141.0/config/confighttp/client_middleware_test.go000066400000000000000000000154441511331344600272210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "context" "errors" "io" "net/http" "net/http/httptest" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionmiddleware" "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" ) // testClientMiddleware is a test middleware that appends a string to the response body type testClientMiddleware struct { extension.Extension extensionmiddleware.GetHTTPRoundTripperFunc } func newTestClientMiddleware(name string) component.Component { return &testClientMiddleware{ Extension: extensionmiddlewaretest.NewNop(), GetHTTPRoundTripperFunc: func(transport http.RoundTripper) (http.RoundTripper, error) { return extensionmiddlewaretest.RoundTripperFunc( func(req *http.Request) (*http.Response, error) { resp, err := transport.RoundTrip(req) if err != nil { return resp, err } // Read the original body body, err := io.ReadAll(resp.Body) if err != nil { return resp, err } _ = resp.Body.Close() // Create a new body with the appended text newBody := string(body) + "\r\noutput by " + name // Replace the response body resp.Body = io.NopCloser(strings.NewReader(newBody)) resp.ContentLength = int64(len(newBody)) return resp, nil }), nil }, } } func newTestClientConfig(name string) configmiddleware.Config { return configmiddleware.Config{ ID: component.MustNewID(name), } } func TestClientMiddlewares(t *testing.T) { // Create a test server that returns "OK" server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("OK")) })) defer server.Close() // Register two test extensions extensions := map[component.ID]component.Component{ component.MustNewID("test1"): newTestClientMiddleware("test1"), component.MustNewID("test2"): newTestClientMiddleware("test2"), } // Test with different middleware configurations testCases := []struct { name string middlewares []configmiddleware.Config expectedOutput string }{ { name: "no_middlewares", middlewares: nil, expectedOutput: "OK", }, { name: "single_middleware", middlewares: []configmiddleware.Config{ newTestClientConfig("test1"), }, expectedOutput: "OK\r\noutput by test1", }, { name: "multiple_middlewares", middlewares: []configmiddleware.Config{ newTestClientConfig("test1"), newTestClientConfig("test2"), }, expectedOutput: "OK\r\noutput by test2\r\noutput by test1", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // Create HTTP client config with the test middlewares clientConfig := ClientConfig{ Endpoint: server.URL, Middlewares: tc.middlewares, } // Create the client client, err := clientConfig.ToClient(context.Background(), extensions, componenttest.NewNopTelemetrySettings()) require.NoError(t, err) // Create a request to the test server req, err := http.NewRequest(http.MethodGet, server.URL, http.NoBody) require.NoError(t, err) // Send the request resp, err := client.Do(req) require.NoError(t, err) defer resp.Body.Close() // Check the response body, err := io.ReadAll(resp.Body) require.NoError(t, err) assert.Equal(t, tc.expectedOutput, string(body)) }) } } func TestClientMiddlewareErrors(t *testing.T) { // Create a test server that returns "OK" server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) _, _ = w.Write([]byte("OK")) })) defer server.Close() // Test cases for HTTP client middleware errors httpTests := []struct { name string extensions map[component.ID]component.Component config ClientConfig errText string }{ { name: "extension_not_found", extensions: map[component.ID]component.Component{}, config: ClientConfig{ Endpoint: server.URL, Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("nonexistent"), }, }, }, errText: "failed to resolve middleware \"nonexistent\": middleware not found", }, { name: "get_round_tripper_fails", extensions: map[component.ID]component.Component{ component.MustNewID("errormw"): extensionmiddlewaretest.NewErr(errors.New("http middleware error")), }, config: ClientConfig{ Endpoint: server.URL, Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("errormw"), }, }, }, errText: "http middleware error", }, } for _, tc := range httpTests { t.Run(tc.name, func(t *testing.T) { // Trying to create the client should fail _, err := tc.config.ToClient(context.Background(), tc.extensions, componenttest.NewNopTelemetrySettings()) require.Error(t, err) assert.Contains(t, err.Error(), tc.errText) }) } } // Test failures for gRPC client middlewares by creating a mock implementation // that can fail in similar ways to HTTP clients func TestGRPCClientMiddlewareErrors(t *testing.T) { // Test cases for gRPC client middleware errors grpcTests := []struct { name string extensions map[component.ID]component.Component config ClientConfig errText string }{ { name: "grpc_extension_not_found", extensions: map[component.ID]component.Component{}, config: ClientConfig{ Endpoint: "localhost:1234", Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("nonexistent"), }, }, }, errText: "failed to resolve middleware \"nonexistent\": middleware not found", }, { name: "grpc_get_client_options_fails", extensions: map[component.ID]component.Component{ component.MustNewID("errormw"): extensionmiddlewaretest.NewErr(errors.New("grpc middleware error")), }, config: ClientConfig{ Endpoint: "localhost:1234", Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("errormw"), }, }, }, errText: "grpc middleware error", }, } for _, tc := range grpcTests { t.Run(tc.name, func(t *testing.T) { // For gRPC, we need to use the configgrpc.ClientConfig structure // We'll test the middleware failure path here using the HTTP client approach, // as the middleware resolution logic is the same _, err := tc.config.ToClient(context.Background(), tc.extensions, componenttest.NewNopTelemetrySettings()) require.Error(t, err) assert.Contains(t, err.Error(), tc.errText) }) } } opentelemetry-collector-0.141.0/config/confighttp/client_test.go000066400000000000000000000537011511331344600250220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "context" "errors" "net" "net/http" "net/http/httptest" "net/url" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionauth" "go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest" ) var ( testAuthID = component.MustNewID("testauth") mockID = component.MustNewID("mock") dummyID = component.MustNewID("dummy") nonExistingID = component.MustNewID("nonexisting") // Omit TracerProvider and MeterProvider in TelemetrySettings as otelhttp.Transport cannot be introspected nilProvidersSettings = component.TelemetrySettings{Logger: zap.NewNop()} ) func TestAllHTTPClientSettings(t *testing.T) { extensions := map[component.ID]component.Component{ testAuthID: extensionauthtest.NewNopClient(), } maxIdleConns := 50 maxIdleConnsPerHost := 40 maxConnsPerHost := 45 idleConnTimeout := 30 * time.Second http2PingTimeout := 5 * time.Second tests := []struct { name string settings ClientConfig shouldError bool }{ { name: "all_valid_settings", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: false, }, ReadBufferSize: 1024, WriteBufferSize: 512, MaxIdleConns: maxIdleConns, MaxIdleConnsPerHost: maxIdleConnsPerHost, MaxConnsPerHost: maxConnsPerHost, IdleConnTimeout: idleConnTimeout, Compression: "", DisableKeepAlives: true, Cookies: configoptional.Some(CookiesConfig{}), HTTP2ReadIdleTimeout: idleConnTimeout, HTTP2PingTimeout: http2PingTimeout, }, shouldError: false, }, { name: "all_valid_settings_http2_enabled", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: false, }, ReadBufferSize: 1024, WriteBufferSize: 512, MaxIdleConns: maxIdleConns, MaxIdleConnsPerHost: maxIdleConnsPerHost, MaxConnsPerHost: maxConnsPerHost, ForceAttemptHTTP2: true, IdleConnTimeout: idleConnTimeout, Compression: "", DisableKeepAlives: true, Cookies: configoptional.Some(CookiesConfig{}), HTTP2ReadIdleTimeout: idleConnTimeout, HTTP2PingTimeout: http2PingTimeout, }, shouldError: false, }, { name: "all_valid_settings_with_none_compression", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: false, }, ReadBufferSize: 1024, WriteBufferSize: 512, MaxIdleConns: maxIdleConns, MaxIdleConnsPerHost: maxIdleConnsPerHost, MaxConnsPerHost: maxConnsPerHost, IdleConnTimeout: idleConnTimeout, Compression: "none", DisableKeepAlives: true, HTTP2ReadIdleTimeout: idleConnTimeout, HTTP2PingTimeout: http2PingTimeout, }, shouldError: false, }, { name: "all_valid_settings_with_gzip_compression", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: false, }, ReadBufferSize: 1024, WriteBufferSize: 512, MaxIdleConns: maxIdleConns, MaxIdleConnsPerHost: maxIdleConnsPerHost, MaxConnsPerHost: maxConnsPerHost, IdleConnTimeout: idleConnTimeout, Compression: "gzip", DisableKeepAlives: true, HTTP2ReadIdleTimeout: idleConnTimeout, HTTP2PingTimeout: http2PingTimeout, }, shouldError: false, }, { name: "all_valid_settings_http2_health_check", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: false, }, ReadBufferSize: 1024, WriteBufferSize: 512, MaxIdleConns: maxIdleConns, MaxIdleConnsPerHost: maxIdleConnsPerHost, MaxConnsPerHost: maxConnsPerHost, IdleConnTimeout: idleConnTimeout, Compression: "gzip", DisableKeepAlives: true, HTTP2ReadIdleTimeout: idleConnTimeout, HTTP2PingTimeout: http2PingTimeout, }, shouldError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tel := componenttest.NewNopTelemetrySettings() tel.TracerProvider = nil client, err := tt.settings.ToClient(context.Background(), extensions, tel) if tt.shouldError { assert.Error(t, err) return } require.NoError(t, err) switch transport := client.Transport.(type) { case *http.Transport: assert.Equal(t, 1024, transport.ReadBufferSize) assert.Equal(t, 512, transport.WriteBufferSize) assert.Equal(t, 50, transport.MaxIdleConns) assert.Equal(t, 40, transport.MaxIdleConnsPerHost) assert.Equal(t, 45, transport.MaxConnsPerHost) assert.Equal(t, 30*time.Second, transport.IdleConnTimeout) assert.True(t, transport.DisableKeepAlives) case *compressRoundTripper: assert.EqualValues(t, "gzip", transport.compressionType) } }) } } func TestPartialHTTPClientSettings(t *testing.T) { extensions := map[component.ID]component.Component{ testAuthID: extensionauthtest.NewNopClient(), } tests := []struct { name string settings ClientConfig shouldError bool }{ { name: "valid_partial_settings", settings: ClientConfig{ Endpoint: "localhost:1234", TLS: configtls.ClientConfig{ Insecure: false, }, ReadBufferSize: 1024, WriteBufferSize: 512, }, shouldError: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tel := componenttest.NewNopTelemetrySettings() tel.TracerProvider = nil client, err := tt.settings.ToClient(context.Background(), extensions, tel) require.NoError(t, err) transport := client.Transport.(*http.Transport) assert.Equal(t, 1024, transport.ReadBufferSize) assert.Equal(t, 512, transport.WriteBufferSize) assert.Equal(t, 0, transport.MaxIdleConns) assert.Equal(t, 0, transport.MaxIdleConnsPerHost) assert.Equal(t, 0, transport.MaxConnsPerHost) assert.EqualValues(t, 0, transport.IdleConnTimeout) assert.False(t, transport.DisableKeepAlives) }) } } func TestDefaultHTTPClientSettings(t *testing.T) { httpClientSettings := NewDefaultClientConfig() assert.Equal(t, 100, httpClientSettings.MaxIdleConns) assert.Equal(t, 90*time.Second, httpClientSettings.IdleConnTimeout) } func TestProxyURL(t *testing.T) { testCases := []struct { name string proxyURL string expectedURL *url.URL err bool }{ { name: "default config", expectedURL: nil, }, { name: "proxy is set", proxyURL: "http://proxy.example.com:8080", expectedURL: &url.URL{Scheme: "http", Host: "proxy.example.com:8080"}, }, { name: "proxy is invalid", proxyURL: "://example.com", err: true, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { s := NewDefaultClientConfig() s.ProxyURL = tt.proxyURL tel := componenttest.NewNopTelemetrySettings() tel.TracerProvider = nil client, err := s.ToClient(context.Background(), nil, tel) if tt.err { require.Error(t, err) } else { require.NoError(t, err) } if err == nil { transport := client.Transport.(*http.Transport) require.NotNil(t, transport.Proxy) url, err := transport.Proxy(&http.Request{URL: &url.URL{Scheme: "http", Host: "example.com"}}) require.NoError(t, err) if tt.expectedURL == nil { assert.Nil(t, url) } else { require.NotNil(t, url) assert.Equal(t, tt.expectedURL, url) } } }) } } func TestHTTPClientSettingsError(t *testing.T) { extensions := map[component.ID]component.Component{} tests := []struct { settings ClientConfig err string }{ { err: "^failed to load TLS config: failed to load CA CertPool File: failed to load cert /doesnt/exist:", settings: ClientConfig{ Endpoint: "", TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: "/doesnt/exist", }, Insecure: false, ServerName: "", }, }, }, { err: "^failed to load TLS config: failed to load TLS cert and key: for auth via TLS, provide both certificate and key, or neither", settings: ClientConfig{ Endpoint: "", TLS: configtls.ClientConfig{ Config: configtls.Config{ CertFile: "/doesnt/exist", }, Insecure: false, ServerName: "", }, }, }, { err: "failed to resolve authenticator \"dummy\": authenticator not found", settings: ClientConfig{ Endpoint: "https://localhost:1234/v1/traces", Auth: configoptional.Some(configauth.Config{AuthenticatorID: dummyID}), }, }, } for _, tt := range tests { t.Run(tt.err, func(t *testing.T) { _, err := tt.settings.ToClient(context.Background(), extensions, componenttest.NewNopTelemetrySettings()) assert.Regexp(t, tt.err, err) }) } } var _ http.RoundTripper = &customRoundTripper{} type customRoundTripper struct{} func (c *customRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, nil } var ( _ extensionauth.HTTPClient = (*mockClient)(nil) _ extension.Extension = (*mockClient)(nil) ) type mockClient struct { component.StartFunc component.ShutdownFunc } // RoundTripper implements extensionauth.HTTPClient. func (m *mockClient) RoundTripper(http.RoundTripper) (http.RoundTripper, error) { return &customRoundTripper{}, nil } func TestHTTPClientSettingWithAuthConfig(t *testing.T) { tests := []struct { name string shouldErr bool settings ClientConfig extensions map[component.ID]component.Component }{ { name: "no_auth_extension_enabled", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.None[configauth.Config](), }, shouldErr: false, extensions: map[component.ID]component.Component{ mockID: extensionauthtest.NewNopClient(), }, }, { name: "with_auth_configuration_and_no_extension", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: dummyID}), }, shouldErr: true, extensions: map[component.ID]component.Component{ mockID: extensionauthtest.NewNopClient(), }, }, { name: "with_auth_configuration_and_no_extension_map", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: dummyID}), }, shouldErr: true, }, { name: "with_auth_configuration_has_extension", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: mockID}), }, shouldErr: false, extensions: map[component.ID]component.Component{ mockID: &mockClient{}, }, }, { name: "with_auth_configuration_has_extension_and_headers", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: mockID}), Headers: configopaque.MapList{ {Name: "foo", Value: "bar"}, }, }, shouldErr: false, extensions: map[component.ID]component.Component{ mockID: &mockClient{}, }, }, { name: "with_auth_configuration_has_extension_and_compression", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: mockID}), Compression: configcompression.TypeGzip, }, shouldErr: false, extensions: map[component.ID]component.Component{ mockID: &mockClient{}, }, }, { name: "with_auth_configuration_has_err_extension", settings: ClientConfig{ Endpoint: "localhost:1234", Auth: configoptional.Some(configauth.Config{AuthenticatorID: mockID}), }, shouldErr: true, extensions: map[component.ID]component.Component{ mockID: extensionauthtest.NewErr(errors.New("error")), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Omit TracerProvider and MeterProvider in TelemetrySettings as otelhttp.Transport cannot be introspected client, err := tt.settings.ToClient(context.Background(), tt.extensions, nilProvidersSettings) if tt.shouldErr { assert.Error(t, err) return } require.NoError(t, err) assert.NotNil(t, client) transport := client.Transport // Compression should wrap Auth, unwrap it if tt.settings.Compression.IsCompressed() { ct, ok := transport.(*compressRoundTripper) assert.True(t, ok) assert.Equal(t, tt.settings.Compression, ct.compressionType) transport = ct.rt } // Headers should wrap Auth, unwrap it if tt.settings.Headers != nil { ht, ok := transport.(*headerRoundTripper) assert.True(t, ok) assert.Equal(t, tt.settings.Headers, ht.headers) transport = ht.transport } if tt.settings.Auth.HasValue() { _, ok := transport.(*customRoundTripper) assert.True(t, ok) } }) } } func TestHttpClientHeaders(t *testing.T) { tests := []struct { name string headers configopaque.MapList }{ { name: "with_headers", headers: configopaque.MapList{ {Name: "header1", Value: "value1"}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { for k, v := range tt.headers.Iter { assert.Equal(t, r.Header.Get(k), string(v)) } w.WriteHeader(http.StatusOK) })) defer server.Close() serverURL, _ := url.Parse(server.URL) setting := ClientConfig{ Endpoint: serverURL.String(), TLS: configtls.ClientConfig{}, ReadBufferSize: 0, WriteBufferSize: 0, Timeout: 0, Headers: tt.headers, } client, _ := setting.ToClient(context.Background(), nil, componenttest.NewNopTelemetrySettings()) req, err := http.NewRequest(http.MethodGet, setting.Endpoint, http.NoBody) require.NoError(t, err) _, err = client.Do(req) assert.NoError(t, err) }) } } func TestHttpClientHostHeader(t *testing.T) { hostHeader := "th" tt := struct { name string headers configopaque.MapList }{ name: "with_host_header", headers: configopaque.MapList{ {Name: "Host", Value: configopaque.String(hostHeader)}, }, } t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { assert.Equal(t, hostHeader, r.Host) w.WriteHeader(http.StatusOK) })) defer server.Close() serverURL, _ := url.Parse(server.URL) setting := ClientConfig{ Endpoint: serverURL.String(), TLS: configtls.ClientConfig{}, ReadBufferSize: 0, WriteBufferSize: 0, Timeout: 0, Headers: tt.headers, } client, _ := setting.ToClient(context.Background(), nil, componenttest.NewNopTelemetrySettings()) req, err := http.NewRequest(http.MethodGet, setting.Endpoint, http.NoBody) require.NoError(t, err) _, err = client.Do(req) assert.NoError(t, err) }) } func TestHttpTransportOptions(t *testing.T) { settings := componenttest.NewNopTelemetrySettings() // Disable OTel instrumentation so the *http.Transport object is directly accessible settings.MeterProvider = nil settings.TracerProvider = nil clientConfig := NewDefaultClientConfig() clientConfig.MaxIdleConns = 100 clientConfig.IdleConnTimeout = time.Duration(100) clientConfig.MaxConnsPerHost = 100 clientConfig.MaxIdleConnsPerHost = 100 client, err := clientConfig.ToClient(context.Background(), nil, settings) require.NoError(t, err) transport, ok := client.Transport.(*http.Transport) require.True(t, ok, "client.Transport is not an *http.Transport") require.Equal(t, 100, transport.MaxIdleConns) require.Equal(t, time.Duration(100), transport.IdleConnTimeout) require.Equal(t, 100, transport.MaxConnsPerHost) require.Equal(t, 100, transport.MaxIdleConnsPerHost) clientConfig = NewDefaultClientConfig() clientConfig.MaxIdleConns = 0 clientConfig.IdleConnTimeout = 0 clientConfig.MaxConnsPerHost = 0 clientConfig.IdleConnTimeout = time.Duration(0) client, err = clientConfig.ToClient(context.Background(), nil, settings) require.NoError(t, err) transport, ok = client.Transport.(*http.Transport) require.True(t, ok, "client.Transport is not an *http.Transport") require.Equal(t, 0, transport.MaxIdleConns) require.Equal(t, time.Duration(0), transport.IdleConnTimeout) require.Equal(t, 0, transport.MaxConnsPerHost) require.Equal(t, 0, transport.MaxIdleConnsPerHost) } func TestContextWithClient(t *testing.T) { testCases := []struct { name string input *http.Request doMetadata bool expected client.Info }{ { name: "request without client IP or headers", input: &http.Request{}, expected: client.Info{}, }, { name: "request with client IP", input: &http.Request{ RemoteAddr: "1.2.3.4:55443", }, expected: client.Info{ Addr: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }, }, { name: "request with client headers, no metadata processing", input: &http.Request{ Header: map[string][]string{"x-tt-header": {"tt-value"}}, }, doMetadata: false, expected: client.Info{}, }, { name: "request with client headers", input: &http.Request{ Header: map[string][]string{"x-tt-header": {"tt-value"}}, }, doMetadata: true, expected: client.Info{ Metadata: client.NewMetadata(map[string][]string{"x-tt-header": {"tt-value"}}), }, }, { name: "request with Host and client headers", input: &http.Request{ Header: map[string][]string{"x-tt-header": {"tt-value"}}, Host: "localhost:55443", }, doMetadata: true, expected: client.Info{ Metadata: client.NewMetadata(map[string][]string{"x-tt-header": {"tt-value"}, "Host": {"localhost:55443"}}), }, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { ctx := contextWithClient(tt.input, tt.doMetadata) assert.Equal(t, tt.expected, client.FromContext(ctx)) }) } } // TestUnmarshalYAMLWithMiddlewares tests that the "middlewares" field is correctly // parsed from YAML configurations (fixing the bug where "middleware" was used instead) func TestClientUnmarshalYAMLWithMiddlewares(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "middlewares.yaml")) require.NoError(t, err) // Test client configuration var clientConfig ClientConfig clientSub, err := cm.Sub("client") require.NoError(t, err) require.NoError(t, clientSub.Unmarshal(&clientConfig)) // Validate the client configuration using reflection-based validation require.NoError(t, xconfmap.Validate(&clientConfig), "Client configuration should be valid") assert.Equal(t, "http://localhost:4318/v1/traces", clientConfig.Endpoint) require.Len(t, clientConfig.Middlewares, 2) assert.Equal(t, component.MustNewID("fancy_middleware"), clientConfig.Middlewares[0].ID) assert.Equal(t, component.MustNewID("careful_middleware"), clientConfig.Middlewares[1].ID) } // TestUnmarshalYAMLComprehensiveConfig tests the complete configuration example // to ensure all fields including middlewares are parsed correctly func TestClientUnmarshalYAMLComprehensiveConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) // Test client configuration var clientConfig ClientConfig clientSub, err := cm.Sub("client") require.NoError(t, err) require.NoError(t, clientSub.Unmarshal(&clientConfig)) // Validate the client configuration using reflection-based validation require.NoError(t, xconfmap.Validate(&clientConfig), "Client configuration should be valid") // Verify basic fields assert.Equal(t, "http://example.com:4318/v1/traces", clientConfig.Endpoint) assert.Equal(t, "http://proxy.example.com:8080", clientConfig.ProxyURL) assert.Equal(t, 30*time.Second, clientConfig.Timeout) assert.Equal(t, 4096, clientConfig.ReadBufferSize) assert.Equal(t, 4096, clientConfig.WriteBufferSize) assert.Equal(t, configcompression.TypeGzip, clientConfig.Compression) // Verify TLS configuration assert.False(t, clientConfig.TLS.Insecure) assert.Equal(t, "/path/to/client.crt", clientConfig.TLS.CertFile) assert.Equal(t, "/path/to/client.key", clientConfig.TLS.KeyFile) assert.Equal(t, "/path/to/ca.crt", clientConfig.TLS.CAFile) assert.Equal(t, "example.com", clientConfig.TLS.ServerName) // Verify headers expectedHeaders := configopaque.MapList{ {Name: "User-Agent", Value: "OpenTelemetry-Collector/1.0"}, {Name: "X-Custom-Header", Value: "custom-value"}, } assert.Equal(t, expectedHeaders, clientConfig.Headers) // Verify middlewares require.Len(t, clientConfig.Middlewares, 2) assert.Equal(t, component.MustNewID("middleware1"), clientConfig.Middlewares[0].ID) assert.Equal(t, component.MustNewID("middleware2"), clientConfig.Middlewares[1].ID) } // TestMiddlewaresFieldCompatibility tests that the new "middlewares" field name // is used instead of the old "middleware" name, ensuring the bug is fixed func TestClientMiddlewaresFieldCompatibility(t *testing.T) { // Test that we can create a config with middlewares using the new field name clientConfig := ClientConfig{ Endpoint: "http://localhost:4318", Middlewares: []configmiddleware.Config{ {ID: component.MustNewID("test_middleware")}, }, } assert.Equal(t, "http://localhost:4318", clientConfig.Endpoint) assert.Len(t, clientConfig.Middlewares, 1) assert.Equal(t, component.MustNewID("test_middleware"), clientConfig.Middlewares[0].ID) } opentelemetry-collector-0.141.0/config/confighttp/clientinfohandler.go000066400000000000000000000035431511331344600261740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import ( "context" "net" "net/http" "go.opentelemetry.io/collector/client" ) // clientInfoHandler is an http.Handler that enhances the incoming request context with client.Info. type clientInfoHandler struct { next http.Handler // include client metadata or not includeMetadata bool } // ServeHTTP intercepts incoming HTTP requests, replacing the request's context with one that contains // a client.Info containing the client's IP address. func (h *clientInfoHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { req = req.WithContext(contextWithClient(req, h.includeMetadata)) //nolint:contextcheck //context already handled through contextWithClient h.next.ServeHTTP(w, req) } // contextWithClient attempts to add the client IP address to the client.Info from the context. When no // client.Info exists in the context, one is created. func contextWithClient(req *http.Request, includeMetadata bool) context.Context { cl := client.FromContext(req.Context()) ip := parseIP(req.RemoteAddr) if ip != nil { cl.Addr = ip } if includeMetadata { md := req.Header.Clone() if md.Get(client.MetadataHostName) == "" && req.Host != "" { md.Add(client.MetadataHostName, req.Host) } cl.Metadata = client.NewMetadata(md) } ctx := client.NewContext(req.Context(), cl) return ctx } // parseIP parses the given string for an IP address. The input string might contain the port, // but must not contain a protocol or path. Suitable for getting the IP part of a client connection. func parseIP(source string) *net.IPAddr { ipstr, _, err := net.SplitHostPort(source) if err == nil { source = ipstr } ip := net.ParseIP(source) if ip != nil { return &net.IPAddr{ IP: ip, } } return nil } opentelemetry-collector-0.141.0/config/confighttp/clientinfohandler_test.go000066400000000000000000000016771511331344600272410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import ( "net" "net/http" "testing" "github.com/stretchr/testify/assert" ) var _ http.Handler = (*clientInfoHandler)(nil) func TestParseIP(t *testing.T) { testCases := []struct { name string input string expected *net.IPAddr }{ { name: "addr", input: "1.2.3.4", expected: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }, { name: "addr:port", input: "1.2.3.4:33455", expected: &net.IPAddr{ IP: net.IPv4(1, 2, 3, 4), }, }, { name: "protocol://addr:port", input: "http://1.2.3.4:33455", expected: nil, }, { name: "addr/path", input: "1.2.3.4/orders", expected: nil, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { assert.Equal(t, tt.expected, parseIP(tt.input)) }) } } opentelemetry-collector-0.141.0/config/confighttp/compress_readcloser.go000066400000000000000000000011101511331344600265260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import "io" // compressReadCloser couples the original compressed reader // and the compression reader to ensure that the original body // is correctly closed to ensure resources are freed. type compressReadCloser struct { io.Reader orig io.ReadCloser } var ( _ io.Reader = (*compressReadCloser)(nil) _ io.Closer = (*compressReadCloser)(nil) ) func (crc *compressReadCloser) Close() error { return crc.orig.Close() } opentelemetry-collector-0.141.0/config/confighttp/compress_readcloser_test.go000066400000000000000000000026731511331344600276040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "bytes" "errors" "io" "testing" "testing/iotest" "github.com/stretchr/testify/require" ) type errorReadCloser struct { io.Reader err error } func (erc errorReadCloser) Close() error { return erc.err } func TestCompressReadCloser(t *testing.T) { t.Parallel() for _, tc := range []struct { name string wrapper func(r io.Reader) io.ReadCloser content []byte errVal string }{ { name: "non mutating wrapper", wrapper: func(r io.Reader) io.ReadCloser { return errorReadCloser{ Reader: r, err: nil, } }, content: []byte("hello world"), errVal: "", }, { name: "failed reader", wrapper: func(r io.Reader) io.ReadCloser { return errorReadCloser{ Reader: r, err: errors.New("failed to close reader"), } }, errVal: "failed to close reader", }, } { t.Run(tc.name, func(t *testing.T) { t.Parallel() orig := bytes.NewBuffer([]byte("hello world")) crc := &compressReadCloser{ Reader: orig, orig: tc.wrapper(orig), } require.NoError(t, iotest.TestReader(crc, orig.Bytes()), "Must be able to read original content") err := crc.Close() if tc.errVal != "" { require.EqualError(t, err, tc.errVal, "Must match the expected error message") } else { require.NoError(t, err, "Must not error when closing reader") } }) } } opentelemetry-collector-0.141.0/config/confighttp/compression.go000066400000000000000000000224541511331344600250470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // This file contains helper functions regarding compression/decompression for confighttp. package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import ( "bufio" "bytes" "compress/gzip" "compress/zlib" "errors" "fmt" "io" "maps" "net/http" "sync" "github.com/golang/snappy" "github.com/klauspost/compress/zstd" "github.com/pierrec/lz4/v4" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/featuregate" ) var enableFramedSnappy = featuregate.GlobalRegistry().MustRegister( "confighttp.framedSnappy", featuregate.StageBeta, featuregate.WithRegisterFromVersion("v0.125.0"), featuregate.WithRegisterDescription("Content encoding 'snappy' will compress/decompress block snappy format while 'x-snappy-framed' will compress/decompress framed snappy format."), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/issues/10584"), ) func defaultCompressionAlgorithms() []string { if enableFramedSnappy.IsEnabled() { return []string{"", "gzip", "zstd", "zlib", "snappy", "deflate", "lz4", "x-snappy-framed"} } return []string{"", "gzip", "zstd", "zlib", "snappy", "deflate", "lz4"} } type compressRoundTripper struct { rt http.RoundTripper compressionType configcompression.Type compressionParams configcompression.CompressionParams compressor *compressor } var zstdReaderPool sync.Pool type pooledZstdReadCloser struct { inner *zstd.Decoder } func (pzrc *pooledZstdReadCloser) Read(dst []byte) (int, error) { if pzrc.inner == nil { return 0, zstd.ErrDecoderClosed } return pzrc.inner.Read(dst) } func (pzrc *pooledZstdReadCloser) Close() error { if pzrc.inner != nil { err := pzrc.inner.Reset(nil) if err != nil { return err } zstdReaderPool.Put(pzrc.inner) pzrc.inner = nil } return nil } var availableDecoders = map[string]func(body io.ReadCloser) (io.ReadCloser, error){ "": func(io.ReadCloser) (io.ReadCloser, error) { // Not a compressed payload. Nothing to do. return nil, nil }, "gzip": func(body io.ReadCloser) (io.ReadCloser, error) { gr, err := gzip.NewReader(body) if err != nil { return nil, err } return gr, nil }, "zstd": func(body io.ReadCloser) (io.ReadCloser, error) { v := zstdReaderPool.Get() var zr *zstd.Decoder var err error if v == nil { // NOTE(tigrannajaryan): // Concurrency 1 disables async decoding. We don't need async decoding, it is pointless // for our use-case (a server accepting decoding http requests). // Disabling async improves performance (I benchmarked it previously when working // on https://github.com/open-telemetry/opentelemetry-collector-contrib/pull/23257). zr, err = zstd.NewReader(body, zstd.WithDecoderConcurrency(1)) } else { zr = v.(*zstd.Decoder) err = zr.Reset(body) } if err != nil { return nil, err } return &pooledZstdReadCloser{inner: zr}, nil }, "zlib": func(body io.ReadCloser) (io.ReadCloser, error) { zr, err := zlib.NewReader(body) if err != nil { return nil, err } return zr, nil }, "snappy": snappyHandler, //nolint:unparam // Ignoring the linter request to remove error return since it needs to match the method signature "lz4": func(body io.ReadCloser) (io.ReadCloser, error) { return &compressReadCloser{ Reader: lz4.NewReader(body), orig: body, }, nil }, //nolint:unparam // Ignoring the linter request to remove error return since it needs to match the method signature "x-snappy-framed": func(body io.ReadCloser) (io.ReadCloser, error) { return &compressReadCloser{ Reader: snappy.NewReader(body), orig: body, }, nil }, } // snappyFramingHeader is always the first 10 bytes of a snappy framed stream. var snappyFramingHeader = []byte{ 0xff, 0x06, 0x00, 0x00, 0x73, 0x4e, 0x61, 0x50, 0x70, 0x59, // "sNaPpY" } // snappyHandler returns an io.ReadCloser that auto-detects the snappy format. // This is necessary because the collector previously used "content-encoding: snappy" // but decompressed and compressed the payloads using the snappy framing format. // However, "content-encoding: snappy" is uses the block format, and "x-snappy-framed" // is the framing format. This handler is a (hopefully temporary) hack to // make this work in a backwards-compatible way. // // See https://github.com/google/snappy/blob/6af9287fbdb913f0794d0148c6aa43b58e63c8e3/framing_format.txt#L27-L36 // for more details on the framing format. func snappyHandler(body io.ReadCloser) (io.ReadCloser, error) { br := bufio.NewReader(body) peekBytes, err := br.Peek(len(snappyFramingHeader)) if err != nil && !errors.Is(err, io.EOF) { return nil, err } isFramed := len(peekBytes) >= len(snappyFramingHeader) && bytes.Equal(peekBytes[:len(snappyFramingHeader)], snappyFramingHeader) if isFramed { return &compressReadCloser{ Reader: snappy.NewReader(br), orig: body, }, nil } compressed, err := io.ReadAll(br) if err != nil { return nil, err } decoded, err := snappy.Decode(nil, compressed) if err != nil { return nil, err } return io.NopCloser(bytes.NewReader(decoded)), nil } func newCompressionParams(level configcompression.Level) configcompression.CompressionParams { return configcompression.CompressionParams{ Level: level, } } func newCompressRoundTripper(rt http.RoundTripper, compressionType configcompression.Type, compressionParams configcompression.CompressionParams) (*compressRoundTripper, error) { encoder, err := newCompressor(compressionType, compressionParams) if err != nil { return nil, err } return &compressRoundTripper{ rt: rt, compressionType: compressionType, compressionParams: compressionParams, compressor: encoder, }, nil } func (r *compressRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { if req.Header.Get(headerContentEncoding) != "" { // If the header already specifies a content encoding then skip compression // since we don't want to compress it again. This is a safeguard that normally // should not happen since CompressRoundTripper is not intended to be used // with http clients which already do their own compression. return r.rt.RoundTrip(req) } // Compress the body. buf := bytes.NewBuffer([]byte{}) if err := r.compressor.compress(buf, req.Body); err != nil { return nil, err } // Create a new request since the docs say that we cannot modify the "req" // (see https://golang.org/pkg/net/http/#RoundTripper). cReq, err := http.NewRequestWithContext(req.Context(), req.Method, req.URL.String(), buf) if err != nil { return nil, err } // Clone the headers and add the encoding header. cReq.Header = req.Header.Clone() cReq.Header.Add(headerContentEncoding, string(r.compressionType)) return r.rt.RoundTrip(cReq) } type decompressor struct { errHandler func(w http.ResponseWriter, r *http.Request, errorMsg string, statusCode int) base http.Handler decoders map[string]func(body io.ReadCloser) (io.ReadCloser, error) maxRequestBodySize int64 } // httpContentDecompressor offloads the task of handling compressed HTTP requests // by identifying the compression format in the "Content-Encoding" header and re-writing // request body so that the handlers further in the chain can work on decompressed data. func httpContentDecompressor(h http.Handler, maxRequestBodySize int64, eh func(w http.ResponseWriter, r *http.Request, errorMsg string, statusCode int), enableDecoders []string, decoders map[string]func(body io.ReadCloser) (io.ReadCloser, error)) http.Handler { errHandler := defaultErrorHandler if eh != nil { errHandler = eh } enabled := map[string]func(body io.ReadCloser) (io.ReadCloser, error){} for _, dec := range enableDecoders { if dec == "x-frame-snappy" && !enableFramedSnappy.IsEnabled() { continue } enabled[dec] = availableDecoders[dec] if dec == "deflate" { enabled["deflate"] = availableDecoders["zlib"] } } d := &decompressor{ maxRequestBodySize: maxRequestBodySize, errHandler: errHandler, base: h, decoders: enabled, } maps.Copy(d.decoders, decoders) return d } func (d *decompressor) ServeHTTP(w http.ResponseWriter, r *http.Request) { newBody, err := d.newBodyReader(r) if err != nil { d.errHandler(w, r, err.Error(), http.StatusBadRequest) return } if newBody != nil { defer newBody.Close() // "Content-Encoding" header is removed to avoid decompressing twice // in case the next handler(s) have implemented a similar mechanism. r.Header.Del("Content-Encoding") // "Content-Length" is set to -1 as the size of the decompressed body is unknown. r.Header.Del("Content-Length") r.ContentLength = -1 r.Body = http.MaxBytesReader(w, newBody, d.maxRequestBodySize) } d.base.ServeHTTP(w, r) } func (d *decompressor) newBodyReader(r *http.Request) (io.ReadCloser, error) { if len(d.decoders) == 0 { return nil, nil // Signal: don't replace r.Body } encoding := r.Header.Get(headerContentEncoding) decoder, ok := d.decoders[encoding] if !ok { return nil, fmt.Errorf("unsupported %s: %s", headerContentEncoding, encoding) } return decoder(r.Body) } // defaultErrorHandler writes the error message in plain text. func defaultErrorHandler(w http.ResponseWriter, _ *http.Request, errMsg string, statusCode int) { http.Error(w, errMsg, statusCode) } opentelemetry-collector-0.141.0/config/confighttp/compression_test.go000066400000000000000000000571041511331344600261060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "bytes" "compress/gzip" "compress/zlib" "context" "errors" "fmt" "io" "net/http" "net/http/httptest" "strings" "testing" "testing/iotest" "github.com/golang/snappy" "github.com/klauspost/compress/zstd" "github.com/pierrec/lz4/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/featuregate" ) func TestHTTPClientCompression(t *testing.T) { testBody := []byte("uncompressed_text") compressedGzipBody := compressGzip(t, testBody) compressedZlibBody := compressZlib(t, testBody) compressedDeflateBody := compressZlib(t, testBody) compressedSnappyFramedBody := compressSnappyFramed(t, testBody) compressedSnappyBody := compressSnappy(t, testBody) compressedZstdBody := compressZstd(t, testBody) compressedLz4Body := compressLz4(t, testBody) const invalidGzipLevel configcompression.Level = 100 tests := []struct { name string encoding configcompression.Type level configcompression.Level framedSnappyEnabled bool reqBody []byte shouldError bool }{ { name: "ValidEmpty", encoding: "", reqBody: testBody, shouldError: false, }, { name: "ValidNone", encoding: "none", reqBody: testBody, shouldError: false, }, { name: "ValidGzip", encoding: configcompression.TypeGzip, level: gzip.DefaultCompression, reqBody: compressedGzipBody.Bytes(), shouldError: false, }, { name: "ValidGzip-DefaultLevel", encoding: configcompression.TypeGzip, reqBody: compressedGzipBody.Bytes(), shouldError: false, }, { name: "InvalidGzip", encoding: configcompression.TypeGzip, level: invalidGzipLevel, reqBody: compressedGzipBody.Bytes(), shouldError: true, }, { name: "InvalidCompression", encoding: configcompression.Type("invalid"), level: invalidGzipLevel, reqBody: compressedGzipBody.Bytes(), shouldError: true, }, { name: "ValidZlib", encoding: configcompression.TypeZlib, level: gzip.DefaultCompression, reqBody: compressedZlibBody.Bytes(), shouldError: false, }, { name: "ValidDeflate", encoding: configcompression.TypeDeflate, level: gzip.DefaultCompression, reqBody: compressedDeflateBody.Bytes(), shouldError: false, }, { name: "ValidSnappy", encoding: configcompression.TypeSnappy, framedSnappyEnabled: true, reqBody: compressedSnappyBody.Bytes(), shouldError: false, }, { name: "InvalidSnappy", encoding: configcompression.TypeSnappy, level: gzip.DefaultCompression, reqBody: compressedSnappyBody.Bytes(), shouldError: true, }, { name: "ValidSnappyFramed", encoding: configcompression.TypeSnappyFramed, framedSnappyEnabled: true, reqBody: compressedSnappyFramedBody.Bytes(), shouldError: false, }, { name: "InvalidSnappyFramed", encoding: configcompression.TypeSnappyFramed, level: gzip.DefaultCompression, reqBody: compressedSnappyFramedBody.Bytes(), shouldError: true, }, { name: "ValidZstd", encoding: configcompression.TypeZstd, level: 99, reqBody: compressedZstdBody.Bytes(), shouldError: false, }, { name: "ValidLz4", encoding: configcompression.TypeLz4, reqBody: compressedLz4Body.Bytes(), shouldError: false, }, { name: "InvalidLz4", encoding: configcompression.TypeLz4, level: gzip.DefaultCompression, reqBody: compressedLz4Body.Bytes(), shouldError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { require.NoError(t, featuregate.GlobalRegistry().Set(enableFramedSnappy.ID(), tt.framedSnappyEnabled)) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) assert.NoError(t, err, "failed to read request body: %v", err) assert.Equal(t, tt.reqBody, body) w.WriteHeader(http.StatusOK) })) t.Cleanup(srv.Close) reqBody := bytes.NewBuffer(testBody) req, err := http.NewRequest(http.MethodGet, srv.URL, reqBody) require.NoError(t, err, "failed to create request to test handler") clientSettings := ClientConfig{ Endpoint: srv.URL, Compression: tt.encoding, CompressionParams: newCompressionParams(tt.level), } err = clientSettings.Validate() if tt.shouldError { require.Error(t, err) message := fmt.Sprintf("unsupported parameters {Level:%+v} for compression type %q", tt.level, tt.encoding) assert.Equal(t, message, err.Error()) return } require.NoError(t, err) client, err := clientSettings.ToClient(context.Background(), nil, componenttest.NewNopTelemetrySettings()) require.NoError(t, err) res, err := client.Do(req) if tt.shouldError { assert.Error(t, err) return } require.NoError(t, err) _, err = io.ReadAll(res.Body) require.NoError(t, err) require.NoError(t, res.Body.Close(), "failed to close request body: %v", err) }) } } func TestHTTPCustomDecompression(t *testing.T) { handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(err.Error())) return } assert.NoError(t, err, "failed to read request body: %v", err) assert.Equal(t, "decompressed body", string(body)) w.WriteHeader(http.StatusOK) }) decoders := map[string]func(io.ReadCloser) (io.ReadCloser, error){ "custom-encoding": func(io.ReadCloser) (io.ReadCloser, error) { //nolint:unparam return io.NopCloser(strings.NewReader("decompressed body")), nil }, } srv := httptest.NewServer(httpContentDecompressor(handler, defaultMaxRequestBodySize, defaultErrorHandler, defaultCompressionAlgorithms(), decoders)) t.Cleanup(srv.Close) req, err := http.NewRequest(http.MethodGet, srv.URL, bytes.NewBuffer([]byte("123decompressed body"))) require.NoError(t, err, "failed to create request to test handler") req.Header.Set("Content-Encoding", "custom-encoding") client := srv.Client() res, err := client.Do(req) require.NoError(t, err) assert.Equal(t, http.StatusOK, res.StatusCode, "test handler returned unexpected status code ") _, err = io.ReadAll(res.Body) require.NoError(t, res.Body.Close(), "failed to close request body: %v", err) } func TestHTTPContentDecompressionHandler(t *testing.T) { testBody := []byte("uncompressed_text") noDecoders := map[string]func(io.ReadCloser) (io.ReadCloser, error){} tests := []struct { name string encoding string reqBody *bytes.Buffer respCode int respBody string framedSnappyEnabled bool }{ { name: "NoCompression", encoding: "", reqBody: bytes.NewBuffer(testBody), respCode: http.StatusOK, }, { name: "ValidDeflate", encoding: "deflate", reqBody: compressZlib(t, testBody), respCode: http.StatusOK, }, { name: "ValidGzip", encoding: "gzip", reqBody: compressGzip(t, testBody), respCode: http.StatusOK, }, { name: "ValidZlib", encoding: "zlib", reqBody: compressZlib(t, testBody), respCode: http.StatusOK, }, { name: "ValidZstd", encoding: "zstd", reqBody: compressZstd(t, testBody), respCode: http.StatusOK, }, { name: "ValidSnappyFramed", encoding: "x-snappy-framed", framedSnappyEnabled: true, reqBody: compressSnappyFramed(t, testBody), respCode: http.StatusOK, }, { name: "ValidSnappy", encoding: "snappy", reqBody: compressSnappy(t, testBody), respCode: http.StatusOK, }, { // Should work even without the framed snappy feature gate enabled, // since during decompression we're peeking the compression header // and identifying which snappy encoding was used. name: "ValidSnappyFramedAsSnappy", encoding: "snappy", reqBody: compressSnappyFramed(t, testBody), respCode: http.StatusOK, }, { name: "ValidLz4", encoding: "lz4", reqBody: compressLz4(t, testBody), respCode: http.StatusOK, }, { name: "InvalidDeflate", encoding: "deflate", reqBody: bytes.NewBuffer(testBody), respCode: http.StatusBadRequest, respBody: "zlib: invalid header\n", }, { name: "InvalidGzip", encoding: "gzip", reqBody: bytes.NewBuffer(testBody), respCode: http.StatusBadRequest, respBody: "gzip: invalid header\n", }, { name: "InvalidZlib", encoding: "zlib", reqBody: bytes.NewBuffer(testBody), respCode: http.StatusBadRequest, respBody: "zlib: invalid header\n", }, { name: "InvalidZstd", encoding: "zstd", reqBody: bytes.NewBuffer(testBody), respCode: http.StatusBadRequest, respBody: "invalid input: magic number mismatch", }, { name: "InvalidSnappyFramed", encoding: "x-snappy-framed", framedSnappyEnabled: true, reqBody: bytes.NewBuffer(testBody), respCode: http.StatusBadRequest, respBody: "snappy: corrupt input", }, { name: "InvalidSnappy", encoding: "snappy", reqBody: bytes.NewBuffer(testBody), respCode: http.StatusBadRequest, respBody: "snappy: corrupt input\n", }, { name: "UnsupportedCompression", encoding: "nosuchcompression", reqBody: bytes.NewBuffer(testBody), respCode: http.StatusBadRequest, respBody: "unsupported Content-Encoding: nosuchcompression\n", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { require.NoError(t, featuregate.GlobalRegistry().Set(enableFramedSnappy.ID(), tt.framedSnappyEnabled)) srv := httptest.NewServer(httpContentDecompressor(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) _, _ = w.Write([]byte(err.Error())) return } assert.NoError(t, err, "failed to read request body: %v", err) assert.EqualValues(t, testBody, string(body)) w.WriteHeader(http.StatusOK) }), defaultMaxRequestBodySize, defaultErrorHandler, defaultCompressionAlgorithms(), noDecoders)) t.Cleanup(srv.Close) req, err := http.NewRequest(http.MethodGet, srv.URL, tt.reqBody) require.NoError(t, err, "failed to create request to test handler") req.Header.Set("Content-Encoding", tt.encoding) client := srv.Client() res, err := client.Do(req) require.NoError(t, err) assert.Equal(t, tt.respCode, res.StatusCode, "test handler returned unexpected status code ") if tt.respBody != "" { body, err := io.ReadAll(res.Body) require.NoError(t, res.Body.Close(), "failed to close request body: %v", err) assert.Equal(t, tt.respBody, string(body)) } }) } } // TestEmptyCompressionAlgorithmsAllowsUncompressed verifies that when CompressionAlgorithms // is set to an empty array, requests without Content-Encoding header are accepted. func TestEmptyCompressionAlgorithmsAllowsUncompressed(t *testing.T) { testBody := []byte(`{"message": "test data"}`) tests := []struct { name string compressionAlgorithms []string contentEncoding string // empty string means no header expectedStatus int expectedError string compressionBypassed bool // If true, don't compress the body (simulates bypass behavior) }{ // Case 1: Empty array should bypass decompression { name: "EmptyArray_NoContentEncoding_Accepted", compressionAlgorithms: []string{}, contentEncoding: "", expectedStatus: http.StatusOK, }, { name: "EmptyArray_Gzip_PassedThrough", compressionAlgorithms: []string{}, contentEncoding: "gzip", expectedStatus: http.StatusOK, compressionBypassed: true, // Empty array bypasses decompression }, { name: "EmptyArray_RandomEncoding_Accepted", compressionAlgorithms: []string{}, contentEncoding: "randomstuff", expectedStatus: http.StatusOK, }, // Case 2: Explicit list with only compressed formats should reject uncompressed { name: "OnlyZstd_NoContentEncoding_Rejected", compressionAlgorithms: []string{"zstd"}, contentEncoding: "", expectedStatus: http.StatusBadRequest, expectedError: "unsupported Content-Encoding", }, { name: "OnlyZstd_Zstd_Accepted", compressionAlgorithms: []string{"zstd"}, contentEncoding: "zstd", expectedStatus: http.StatusOK, }, { name: "OnlyZstd_GzipContentEncoding_Rejected", compressionAlgorithms: []string{"zstd"}, contentEncoding: "gzip", expectedStatus: http.StatusBadRequest, expectedError: "unsupported Content-Encoding", }, // Case 3: Explicit list including empty string should accept uncompressed { name: "WithEmptyString_NoContentEncoding_Accepted", compressionAlgorithms: []string{"", "gzip", "zstd"}, contentEncoding: "", expectedStatus: http.StatusOK, }, { name: "WithEmptyString_Gzip_Accepted", compressionAlgorithms: []string{"", "gzip"}, contentEncoding: "gzip", expectedStatus: http.StatusOK, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Create handler that echoes back the request body // If there's an error reading, it returns 500 which the test will catch handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "failed to read body", http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) _, _ = w.Write(body) }) // Create ServerConfig with the specified CompressionAlgorithms serverConfig := &ServerConfig{ Endpoint: "localhost:0", CompressionAlgorithms: tt.compressionAlgorithms, } srv, err := serverConfig.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), handler, ) require.NoError(t, err) // Create test server testSrv := httptest.NewServer(srv.Handler) defer testSrv.Close() // Compress the body if needed for the test requestBody := testBody if !tt.compressionBypassed && tt.expectedStatus == http.StatusOK { switch tt.contentEncoding { case "gzip": requestBody = compressGzip(t, testBody).Bytes() case "zstd": requestBody = compressZstd(t, testBody).Bytes() } } // Create request req, err := http.NewRequest(http.MethodPost, testSrv.URL, bytes.NewReader(requestBody)) require.NoError(t, err) req.Header.Set("Content-Type", "application/json") // Set Content-Encoding header if specified if tt.contentEncoding != "" { req.Header.Set("Content-Encoding", tt.contentEncoding) } // Send request client := &http.Client{} resp, err := client.Do(req) require.NoError(t, err) defer resp.Body.Close() // Verify response assert.Equal(t, tt.expectedStatus, resp.StatusCode, "Unexpected status code") body, err := io.ReadAll(resp.Body) require.NoError(t, err) if tt.expectedError != "" { assert.Contains(t, string(body), tt.expectedError, "Expected error message not found") } else { // For successful requests, body should be echoed back assert.Equal(t, testBody, body, "Response body should match request body") } }) } } func TestHTTPContentCompressionRequestWithNilBody(t *testing.T) { compressedGzipBody := compressGzip(t, []byte{}) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) body, err := io.ReadAll(r.Body) assert.NoError(t, err, "failed to read request body: %v", err) assert.Equal(t, compressedGzipBody.Bytes(), body) })) defer srv.Close() req, err := http.NewRequest(http.MethodGet, srv.URL, http.NoBody) require.NoError(t, err, "failed to create request to test handler") client := srv.Client() compressionParams := newCompressionParams(gzip.DefaultCompression) client.Transport, err = newCompressRoundTripper(http.DefaultTransport, configcompression.TypeGzip, compressionParams) require.NoError(t, err) res, err := client.Do(req) require.NoError(t, err) _, err = io.ReadAll(res.Body) require.NoError(t, err) require.NoError(t, res.Body.Close(), "failed to close request body: %v", err) } func TestHTTPContentCompressionCopyError(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })) t.Cleanup(srv.Close) req, err := http.NewRequest(http.MethodGet, srv.URL, iotest.ErrReader(errors.New("read failed"))) require.NoError(t, err) client := srv.Client() compressionParams := newCompressionParams(gzip.DefaultCompression) client.Transport, err = newCompressRoundTripper(http.DefaultTransport, configcompression.TypeGzip, compressionParams) require.NoError(t, err) _, err = client.Do(req) require.Error(t, err) } type closeFailBody struct { *bytes.Buffer } func (*closeFailBody) Close() error { return errors.New("close failed") } func TestHTTPContentCompressionRequestBodyCloseError(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })) t.Cleanup(srv.Close) req, err := http.NewRequest(http.MethodGet, srv.URL, &closeFailBody{Buffer: bytes.NewBuffer([]byte("blank"))}) require.NoError(t, err) client := srv.Client() compressionParams := newCompressionParams(gzip.DefaultCompression) client.Transport, err = newCompressRoundTripper(http.DefaultTransport, configcompression.TypeGzip, compressionParams) require.NoError(t, err) _, err = client.Do(req) require.Error(t, err) } func TestOverrideCompressionList(t *testing.T) { // prepare configuredDecoders := []string{"none", "zlib"} srv := httptest.NewServer(httpContentDecompressor(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }), defaultMaxRequestBodySize, defaultErrorHandler, configuredDecoders, nil)) t.Cleanup(srv.Close) req, err := http.NewRequest(http.MethodGet, srv.URL, compressSnappyFramed(t, []byte("123decompressed body"))) require.NoError(t, err, "failed to create request to test handler") req.Header.Set("Content-Encoding", "snappy") client := srv.Client() // test res, err := client.Do(req) require.NoError(t, err) // verify assert.Equal(t, http.StatusBadRequest, res.StatusCode, "test handler returned unexpected status code ") _, err = io.ReadAll(res.Body) require.NoError(t, res.Body.Close(), "failed to close request body: %v", err) } func TestDecompressorAvoidDecompressionBomb(t *testing.T) { t.Parallel() for _, tc := range []struct { name string encoding string compress func(tb testing.TB, payload []byte) *bytes.Buffer framedSnappyEnabled bool }{ // None encoding is ignored since it does not // enforce the max body size if content encoding header is not set { name: "gzip", encoding: "gzip", compress: compressGzip, }, { name: "zstd", encoding: "zstd", compress: compressZstd, }, { name: "zlib", encoding: "zlib", compress: compressZlib, }, { name: "x-snappy-framed", encoding: "x-snappy-framed", compress: compressSnappyFramed, }, { name: "x-snappy-not-framed", encoding: "x-snappy-framed", compress: compressSnappyFramed, framedSnappyEnabled: false, }, { name: "snappy", encoding: "snappy", compress: compressSnappy, }, { name: "lz4", encoding: "lz4", compress: compressLz4, }, } { t.Run(tc.name, func(t *testing.T) { // t.Parallel() // TODO: Re-enable parallel tests once feature gate is removed. We can't parallelize since registry is shared. require.NoError(t, featuregate.GlobalRegistry().Set(enableFramedSnappy.ID(), tc.framedSnappyEnabled)) h := httpContentDecompressor( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { n, err := io.Copy(io.Discard, r.Body) assert.Equal(t, int64(1024), n, "Must have only read the limited value of bytes") assert.EqualError(t, err, "http: request body too large") w.WriteHeader(http.StatusBadRequest) }), 1024, defaultErrorHandler, defaultCompressionAlgorithms(), availableDecoders, ) payload := tc.compress(t, make([]byte, 2*1024)) // 2KB uncompressed payload assert.NotEmpty(t, payload.Bytes(), "Must have data available") req := httptest.NewRequest(http.MethodPost, "/", payload) req.Header.Set("Content-Encoding", tc.encoding) resp := httptest.NewRecorder() h.ServeHTTP(resp, req) assert.Equal(t, http.StatusBadRequest, resp.Code, "Must match the expected code") assert.Empty(t, resp.Body.String(), "Must match the returned string") }) } } func TestPooledZstdReadCloserReadAfterClose(t *testing.T) { h := httpContentDecompressor( http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { buf := make([]byte, 1024) _, err := r.Body.Read(buf) assert.NoError(t, err) err = r.Body.Close() assert.NoError(t, err) _, err = r.Body.Read(buf) assert.ErrorIs(t, err, zstd.ErrDecoderClosed) w.WriteHeader(http.StatusBadRequest) }), defaultMaxRequestBodySize, defaultErrorHandler, defaultCompressionAlgorithms(), availableDecoders, ) payload := compressZstd(t, make([]byte, 2*1024)) // 2KB uncompressed payload assert.NotEmpty(t, payload.Bytes(), "Must have data available") req := httptest.NewRequest(http.MethodPost, "/", payload) req.Header.Set("Content-Encoding", "zstd") resp := httptest.NewRecorder() h.ServeHTTP(resp, req) assert.Equal(t, http.StatusBadRequest, resp.Code, "Must match the expected code") assert.Empty(t, resp.Body.String(), "Must match the returned string") } func compressGzip(tb testing.TB, body []byte) *bytes.Buffer { var buf bytes.Buffer gw, _ := gzip.NewWriterLevel(&buf, gzip.DefaultCompression) _, err := gw.Write(body) require.NoError(tb, err) require.NoError(tb, gw.Close()) return &buf } func compressZlib(tb testing.TB, body []byte) *bytes.Buffer { var buf bytes.Buffer zw, _ := zlib.NewWriterLevel(&buf, zlib.DefaultCompression) _, err := zw.Write(body) require.NoError(tb, err) require.NoError(tb, zw.Close()) return &buf } func compressSnappyFramed(tb testing.TB, body []byte) *bytes.Buffer { var buf bytes.Buffer sw := snappy.NewBufferedWriter(&buf) _, err := sw.Write(body) require.NoError(tb, err) require.NoError(tb, sw.Close()) return &buf } func compressSnappy(tb testing.TB, body []byte) *bytes.Buffer { var buf bytes.Buffer compressed := snappy.Encode(nil, body) _, err := buf.Write(compressed) require.NoError(tb, err) return &buf } func compressZstd(tb testing.TB, body []byte) *bytes.Buffer { var buf bytes.Buffer compression := zstd.SpeedFastest encoderLevel := zstd.WithEncoderLevel(compression) zw, _ := zstd.NewWriter(&buf, encoderLevel) _, err := zw.Write(body) require.NoError(tb, err) require.NoError(tb, zw.Close()) return &buf } func compressLz4(tb testing.TB, body []byte) *bytes.Buffer { var buf bytes.Buffer lz := lz4.NewWriter(&buf) _, err := lz.Write(body) require.NoError(tb, err) require.NoError(tb, lz.Close()) return &buf } opentelemetry-collector-0.141.0/config/confighttp/compressor.go000066400000000000000000000110001511331344600246630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import ( "bytes" "compress/gzip" "compress/zlib" "errors" "io" "sync" "github.com/golang/snappy" "github.com/klauspost/compress/zstd" "github.com/pierrec/lz4/v4" "go.opentelemetry.io/collector/config/configcompression" ) type writeCloserReset interface { io.WriteCloser Reset(w io.Writer) } type compressor struct { pool sync.Pool } type compressorMap map[compressionMapKey]*compressor type compressionMapKey struct { compressionType configcompression.Type compressionParams configcompression.CompressionParams } var ( compressorPools = make(compressorMap) compressorPoolsMu sync.Mutex ) // writerFactory defines writer field in CompressRoundTripper. // The validity of input is already checked when NewCompressRoundTripper was called in confighttp, func newCompressor(compressionType configcompression.Type, compressionParams configcompression.CompressionParams) (*compressor, error) { compressorPoolsMu.Lock() defer compressorPoolsMu.Unlock() mapKey := compressionMapKey{compressionType, compressionParams} c, ok := compressorPools[mapKey] if ok { return c, nil } f, err := newWriteCloserResetFunc(compressionType, compressionParams) if err != nil { return nil, err } c = &compressor{pool: sync.Pool{New: func() any { return f() }}} compressorPools[mapKey] = c return c, nil } func newWriteCloserResetFunc(compressionType configcompression.Type, compressionParams configcompression.CompressionParams) (func() writeCloserReset, error) { switch compressionType { case configcompression.TypeGzip: return func() writeCloserReset { w, _ := gzip.NewWriterLevel(nil, int(compressionParams.Level)) return w }, nil case configcompression.TypeSnappyFramed: if !enableFramedSnappy.IsEnabled() { return nil, errors.New("x-snappy-framed is not enabled") } return func() writeCloserReset { return snappy.NewBufferedWriter(nil) }, nil case configcompression.TypeSnappy: if !enableFramedSnappy.IsEnabled() { // If framed snappy feature gate is not enabled, we keep the current behavior // where the 'Content-Encoding: snappy' is compressed as the framed snappy format. return func() writeCloserReset { return snappy.NewBufferedWriter(nil) }, nil } return func() writeCloserReset { // If framed snappy feature gate is enabled, we use the correct behavior // where the 'Content-Encoding: snappy' is compressed as the block snappy format. return &rawSnappyWriter{} }, nil case configcompression.TypeZstd: level := zstd.WithEncoderLevel(zstd.EncoderLevelFromZstd(int(compressionParams.Level))) return func() writeCloserReset { zw, _ := zstd.NewWriter(nil, zstd.WithEncoderConcurrency(1), level) return zw }, nil case configcompression.TypeZlib, configcompression.TypeDeflate: return func() writeCloserReset { w, _ := zlib.NewWriterLevel(nil, int(compressionParams.Level)) return w }, nil case configcompression.TypeLz4: return func() writeCloserReset { lz := lz4.NewWriter(nil) _ = lz.Apply(lz4.ConcurrencyOption(1)) return lz }, nil } return nil, errors.New("unsupported compression type") } func (p *compressor) compress(buf *bytes.Buffer, body io.ReadCloser) error { writer := p.pool.Get().(writeCloserReset) defer p.pool.Put(writer) writer.Reset(buf) if body != nil { _, copyErr := io.Copy(writer, body) closeErr := body.Close() if copyErr != nil { return copyErr } if closeErr != nil { return closeErr } } return writer.Close() } // rawSnappyWriter buffers all writes and, on Close, // compresses the data as a raw snappy block (non-framed) // and writes the compressed bytes to the underlying writer. type rawSnappyWriter struct { buffer bytes.Buffer w io.Writer closed bool } // Write buffers the data. func (w *rawSnappyWriter) Write(p []byte) (int, error) { return w.buffer.Write(p) } // Close compresses the buffered data in one shot using snappy.Encode, // writes the compressed block to the underlying writer, and marks the writer as closed. func (w *rawSnappyWriter) Close() error { if w.closed { return nil } w.closed = true // Compress the buffered uncompressed bytes. compressed := snappy.Encode(nil, w.buffer.Bytes()) _, err := w.w.Write(compressed) return err } // Reset sets a new underlying writer, resets the buffer and the closed flag. func (w *rawSnappyWriter) Reset(newWriter io.Writer) { w.buffer.Reset() w.w = newWriter w.closed = false } opentelemetry-collector-0.141.0/config/confighttp/compressor_test.go000066400000000000000000000044001511331344600257300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // This file contains helper functions regarding compression/decompression for confighttp. package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import ( "bytes" "fmt" "io" "strings" "testing" "github.com/klauspost/compress/zstd" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configcompression" ) func BenchmarkCompression(b *testing.B) { benchmarks := []struct { codec configcompression.Type name string function func(*testing.B, configcompression.Type, *bytes.Buffer, []byte) }{ { codec: configcompression.TypeZstd, name: "zstdWithConcurrency", function: benchmarkCompression, }, { codec: configcompression.TypeZstd, name: "zstdNoConcurrency", function: benchmarkCompressionNoConcurrency, }, } payload := make([]byte, 10<<22) buffer := bytes.Buffer{} buffer.Grow(len(payload)) ts := &bytes.Buffer{} defer func() { fmt.Printf("input => %.2f MB\n", float64(len(payload))/(1024*1024)) fmt.Println(ts) }() for i := range benchmarks { benchmark := &benchmarks[i] b.Run(benchmark.name, func(b *testing.B) { benchmark.function(b, benchmark.codec, &buffer, payload) }) } } func benchmarkCompression(b *testing.B, _ configcompression.Type, buf *bytes.Buffer, payload []byte) { // Concurrency Enabled stringReader := strings.NewReader(string(payload)) stringReadCloser := io.NopCloser(stringReader) var enc io.Writer b.ResetTimer() b.ReportAllocs() b.SetBytes(int64(len(payload))) for b.Loop() { enc, _ = zstd.NewWriter(nil, zstd.WithEncoderConcurrency(5)) enc.(writeCloserReset).Reset(buf) _, copyErr := io.Copy(enc, stringReadCloser) require.NoError(b, copyErr) } } func benchmarkCompressionNoConcurrency(b *testing.B, _ configcompression.Type, buf *bytes.Buffer, payload []byte) { stringReader := strings.NewReader(string(payload)) stringReadCloser := io.NopCloser(stringReader) var enc io.Writer b.ResetTimer() b.ReportAllocs() b.SetBytes(int64(len(payload))) for b.Loop() { enc, _ = zstd.NewWriter(nil, zstd.WithEncoderConcurrency(1)) enc.(writeCloserReset).Reset(buf) _, copyErr := io.Copy(enc, stringReadCloser) require.NoError(b, copyErr) } } opentelemetry-collector-0.141.0/config/confighttp/confighttp_example_test.go000066400000000000000000000013601511331344600274160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "context" "net/http" "go.opentelemetry.io/collector/component/componenttest" ) func ExampleServerConfig() { settings := NewDefaultServerConfig() settings.Endpoint = "localhost:443" // Typically obtained as an argument of Component.Start() host := componenttest.NewNopHost() s, err := settings.ToServer( context.Background(), host.GetExtensions(), componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) if err != nil { panic(err) } l, err := settings.ToListener(context.Background()) if err != nil { panic(err) } if err = s.Serve(l); err != nil { panic(err) } } opentelemetry-collector-0.141.0/config/confighttp/doc.go000066400000000000000000000006271511331344600232510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package confighttp defines the configuration settings // for creating an HTTP client and server. // // The configuration structs in this package may be shared across signals, but // assume each struct is used for a single protocol and component. package confighttp // import "go.opentelemetry.io/collector/config/confighttp" opentelemetry-collector-0.141.0/config/confighttp/go.mod000066400000000000000000000115741511331344600232660ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/confighttp go 1.24.0 require ( github.com/golang/snappy v1.0.0 github.com/klauspost/compress v1.18.1 github.com/pierrec/lz4/v4 v4.1.22 github.com/rs/cors v1.11.1 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/client v1.47.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configauth v1.47.0 go.opentelemetry.io/collector/config/configcompression v1.47.0 go.opentelemetry.io/collector/config/configmiddleware v1.47.0 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/config/configtls v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensionauth v1.47.0 go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest v0.141.0 go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest v0.141.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 go.opentelemetry.io/otel v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 golang.org/x/net v0.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/config/configauth => ../configauth replace go.opentelemetry.io/collector/config/configcompression => ../configcompression replace go.opentelemetry.io/collector/config/configmiddleware => ../configmiddleware replace go.opentelemetry.io/collector/config/configopaque => ../configopaque replace go.opentelemetry.io/collector/config/configoptional => ../configoptional replace go.opentelemetry.io/collector/config/configtls => ../configtls replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/config/confighttp/go.sum000066400000000000000000000252351511331344600233120ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/confighttp/internal/000077500000000000000000000000001511331344600237645ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/confighttp/internal/options.go000066400000000000000000000020621511331344600260060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/config/confighttp/internal" import ( "io" "net/http" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" ) // ToServerOptions has options that change the behavior of the HTTP server // returned by ServerConfig.ToServer(). type ToServerOptions struct { ErrHandler func(w http.ResponseWriter, r *http.Request, errorMsg string, statusCode int) Decoders map[string]func(body io.ReadCloser) (io.ReadCloser, error) OtelhttpOpts []otelhttp.Option } func (tso *ToServerOptions) Apply(opts ...ToServerOption) { for _, o := range opts { o.apply(tso) } } // ToServerOption is an option to change the behavior of the HTTP server // returned by ServerConfig.ToServer(). type ToServerOption interface { apply(*ToServerOptions) } // ToServerOptionFunc converts a function into ToServerOption interface. type ToServerOptionFunc func(*ToServerOptions) func (of ToServerOptionFunc) apply(e *ToServerOptions) { of(e) } opentelemetry-collector-0.141.0/config/confighttp/metadata.yaml000066400000000000000000000002031511331344600246070ustar00rootroot00000000000000type: config/confighttp github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/confighttp/package_test.go000066400000000000000000000003131511331344600251260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/confighttp/server.go000066400000000000000000000324151511331344600240120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp // import "go.opentelemetry.io/collector/config/confighttp" import ( "context" "crypto/tls" "errors" "io" "net" "net/http" "time" "github.com/rs/cors" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/otel" "go.uber.org/zap" "go.uber.org/zap/zapcore" "golang.org/x/net/http2" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/confighttp/internal" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/extension/extensionauth" ) const defaultMaxRequestBodySize = 20 * 1024 * 1024 // 20MiB // ServerConfig defines settings for creating an HTTP server. type ServerConfig struct { // Endpoint configures the listening address for the server. Endpoint string `mapstructure:"endpoint,omitempty"` // TLS struct exposes TLS client configuration. TLS configoptional.Optional[configtls.ServerConfig] `mapstructure:"tls"` // CORS configures the server for HTTP cross-origin resource sharing (CORS). CORS configoptional.Optional[CORSConfig] `mapstructure:"cors"` // Auth for this receiver Auth configoptional.Optional[AuthConfig] `mapstructure:"auth,omitempty"` // MaxRequestBodySize sets the maximum request body size in bytes. Default: 20MiB. MaxRequestBodySize int64 `mapstructure:"max_request_body_size,omitempty"` // IncludeMetadata propagates the client metadata from the incoming requests to the downstream consumers IncludeMetadata bool `mapstructure:"include_metadata,omitempty"` // Additional headers attached to each HTTP response sent to the client. // Header values are opaque since they may be sensitive. ResponseHeaders configopaque.MapList `mapstructure:"response_headers,omitempty"` // CompressionAlgorithms configures the list of compression algorithms the server can accept. Default: ["", "gzip", "zstd", "zlib", "snappy", "deflate"] CompressionAlgorithms []string `mapstructure:"compression_algorithms,omitempty"` // ReadTimeout is the maximum duration for reading the entire // request, including the body. A zero or negative value means // there will be no timeout. // // Because ReadTimeout does not let Handlers make per-request // decisions on each request body's acceptable deadline or // upload rate, most users will prefer to use // ReadHeaderTimeout. It is valid to use them both. ReadTimeout time.Duration `mapstructure:"read_timeout,omitempty"` // ReadHeaderTimeout is the amount of time allowed to read // request headers. The connection's read deadline is reset // after reading the headers and the Handler can decide what // is considered too slow for the body. If ReadHeaderTimeout // is zero, the value of ReadTimeout is used. If both are // zero, there is no timeout. ReadHeaderTimeout time.Duration `mapstructure:"read_header_timeout"` // WriteTimeout is the maximum duration before timing out // writes of the response. It is reset whenever a new // request's header is read. Like ReadTimeout, it does not // let Handlers make decisions on a per-request basis. // A zero or negative value means there will be no timeout. WriteTimeout time.Duration `mapstructure:"write_timeout"` // IdleTimeout is the maximum amount of time to wait for the // next request when keep-alives are enabled. If IdleTimeout // is zero, the value of ReadTimeout is used. If both are // zero, there is no timeout. IdleTimeout time.Duration `mapstructure:"idle_timeout"` // Middlewares are used to add custom functionality to the HTTP server. // Middleware handlers are called in the order they appear in this list, // with the first middleware becoming the outermost handler. Middlewares []configmiddleware.Config `mapstructure:"middlewares,omitempty"` // KeepAlivesEnabled controls whether HTTP keep-alives are enabled. // By default, keep-alives are always enabled. Only very resource-constrained environments should disable them. KeepAlivesEnabled bool `mapstructure:"keep_alives_enabled,omitempty"` } // NewDefaultServerConfig returns ServerConfig type object with default values. // We encourage to use this function to create an object of ServerConfig. func NewDefaultServerConfig() ServerConfig { return ServerConfig{ WriteTimeout: 30 * time.Second, ReadHeaderTimeout: 1 * time.Minute, IdleTimeout: 1 * time.Minute, KeepAlivesEnabled: true, } } type AuthConfig struct { // Auth for this receiver. configauth.Config `mapstructure:",squash"` // RequestParameters is a list of parameters that should be extracted from the request and added to the context. // When a parameter is found in both the query string and the header, the value from the query string will be used. RequestParameters []string `mapstructure:"request_params,omitempty"` // prevent unkeyed literal initialization _ struct{} } // ToListener creates a net.Listener. func (sc *ServerConfig) ToListener(ctx context.Context) (net.Listener, error) { listener, err := net.Listen("tcp", sc.Endpoint) if err != nil { return nil, err } if sc.TLS.HasValue() { var tlsCfg *tls.Config tlsCfg, err = sc.TLS.Get().LoadTLSConfig(ctx) if err != nil { return nil, err } tlsCfg.NextProtos = []string{http2.NextProtoTLS, "http/1.1"} listener = tls.NewListener(listener, tlsCfg) } return listener, nil } // toServerOptions has options that change the behavior of the HTTP server // returned by ServerConfig.ToServer(). type toServerOptions = internal.ToServerOptions // ToServerOption is an option to change the behavior of the HTTP server // returned by ServerConfig.ToServer(). type ToServerOption = internal.ToServerOption // WithErrorHandler overrides the HTTP error handler that gets invoked // when there is a failure inside httpContentDecompressor. func WithErrorHandler(e func(w http.ResponseWriter, r *http.Request, errorMsg string, statusCode int)) ToServerOption { return internal.ToServerOptionFunc(func(opts *toServerOptions) { opts.ErrHandler = e }) } // WithDecoder provides support for additional decoders to be configured // by the caller. func WithDecoder(key string, dec func(body io.ReadCloser) (io.ReadCloser, error)) ToServerOption { return internal.ToServerOptionFunc(func(opts *toServerOptions) { if opts.Decoders == nil { opts.Decoders = map[string]func(body io.ReadCloser) (io.ReadCloser, error){} } opts.Decoders[key] = dec }) } // ToServer creates an http.Server from settings object. // // To allow the configuration to reference middleware or authentication extensions, // the `extensions` argument should be the output of `host.GetExtensions()`. // It may also be `nil` in tests where no such extension is expected to be used. func (sc *ServerConfig) ToServer(ctx context.Context, extensions map[component.ID]component.Component, settings component.TelemetrySettings, handler http.Handler, opts ...ToServerOption) (*http.Server, error) { serverOpts := &toServerOptions{} serverOpts.Apply(opts...) if sc.MaxRequestBodySize <= 0 { sc.MaxRequestBodySize = defaultMaxRequestBodySize } if sc.CompressionAlgorithms == nil { sc.CompressionAlgorithms = defaultCompressionAlgorithms() } // Apply middlewares in reverse order so they execute in // forward order. The first middleware runs after // decompression, below, preceded by Auth, CORS, etc. if len(sc.Middlewares) > 0 && extensions == nil { return nil, errors.New("middlewares were configured but this component or its host does not support extensions") } for i := len(sc.Middlewares) - 1; i >= 0; i-- { wrapper, err := sc.Middlewares[i].GetHTTPServerHandler(ctx, extensions) // If we failed to get the middleware if err != nil { return nil, err } handler, err = wrapper(handler) // If we failed to construct a wrapper if err != nil { return nil, err } } handler = httpContentDecompressor( handler, sc.MaxRequestBodySize, serverOpts.ErrHandler, sc.CompressionAlgorithms, serverOpts.Decoders, ) if sc.MaxRequestBodySize > 0 { handler = maxRequestBodySizeInterceptor(handler, sc.MaxRequestBodySize) } if sc.Auth.HasValue() { if extensions == nil { return nil, errors.New("authentication was configured but this component or its host does not support extensions") } auth := sc.Auth.Get() server, err := auth.GetServerAuthenticator(ctx, extensions) if err != nil { return nil, err } handler = authInterceptor(handler, server, auth.RequestParameters, serverOpts) } if sc.CORS.HasValue() && len(sc.CORS.Get().AllowedOrigins) > 0 { corsConfig := sc.CORS.Get() co := cors.Options{ AllowedOrigins: corsConfig.AllowedOrigins, AllowCredentials: true, AllowedHeaders: corsConfig.AllowedHeaders, MaxAge: corsConfig.MaxAge, } handler = cors.New(co).Handler(handler) } if sc.CORS.HasValue() && len(sc.CORS.Get().AllowedOrigins) == 0 && len(sc.CORS.Get().AllowedHeaders) > 0 { settings.Logger.Warn("The CORS configuration specifies allowed headers but no allowed origins, and is therefore ignored.") } if sc.ResponseHeaders != nil { handler = responseHeadersHandler(handler, sc.ResponseHeaders) } otelOpts := append( []otelhttp.Option{ otelhttp.WithTracerProvider(settings.TracerProvider), otelhttp.WithPropagators(otel.GetTextMapPropagator()), otelhttp.WithSpanNameFormatter(func(_ string, r *http.Request) string { // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#name: // // "HTTP span names SHOULD be {method} {target} if there is a (low-cardinality) target available. // If there is no (low-cardinality) {target} available, HTTP span names SHOULD be {method}. // ... // Instrumentation MUST NOT default to using URI path as a {target}." // if r.Pattern != "" { return r.Method + " " + r.Pattern } return r.Method }), otelhttp.WithMeterProvider(settings.MeterProvider), }, serverOpts.OtelhttpOpts...) // Enable OpenTelemetry observability plugin. handler = otelhttp.NewHandler(handler, "", otelOpts...) // wrap the current handler in an interceptor that will add client.Info to the request's context handler = &clientInfoHandler{ next: handler, includeMetadata: sc.IncludeMetadata, } errorLog, err := zap.NewStdLogAt(settings.Logger, zapcore.ErrorLevel) if err != nil { return nil, err // If an error occurs while creating the logger, return nil and the error } server := &http.Server{ Handler: handler, ReadTimeout: sc.ReadTimeout, ReadHeaderTimeout: sc.ReadHeaderTimeout, WriteTimeout: sc.WriteTimeout, IdleTimeout: sc.IdleTimeout, ErrorLog: errorLog, } // Set keep-alives enabled/disabled server.SetKeepAlivesEnabled(sc.KeepAlivesEnabled) return server, err } func responseHeadersHandler(handler http.Handler, headers configopaque.MapList) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { h := w.Header() for k, v := range headers.Iter { h.Set(k, string(v)) } handler.ServeHTTP(w, r) }) } // CORSConfig configures a receiver for HTTP cross-origin resource sharing (CORS). // See the underlying https://github.com/rs/cors package for details. type CORSConfig struct { // AllowedOrigins sets the allowed values of the Origin header for // HTTP/JSON requests to an OTLP receiver. An origin may contain a // wildcard (*) to replace 0 or more characters (e.g., // "http://*.domain.com", or "*" to allow any origin). AllowedOrigins []string `mapstructure:"allowed_origins,omitempty"` // AllowedHeaders sets what headers will be allowed in CORS requests. // The Accept, Accept-Language, Content-Type, and Content-Language // headers are implicitly allowed. If no headers are listed, // X-Requested-With will also be accepted by default. Include "*" to // allow any request header. AllowedHeaders []string `mapstructure:"allowed_headers,omitempty"` // MaxAge sets the value of the Access-Control-Max-Age response header. // Set it to the number of seconds that browsers should cache a CORS // preflight response for. MaxAge int `mapstructure:"max_age,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultCORSConfig creates a default cross-origin resource sharing (CORS) configuration. func NewDefaultCORSConfig() CORSConfig { return CORSConfig{} } func authInterceptor(next http.Handler, server extensionauth.Server, requestParams []string, serverOpts *internal.ToServerOptions) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { sources := r.Header query := r.URL.Query() for _, param := range requestParams { if val, ok := query[param]; ok { sources[param] = val } } ctx, err := server.Authenticate(r.Context(), sources) if err != nil { if serverOpts.ErrHandler != nil { serverOpts.ErrHandler(w, r, err.Error(), http.StatusUnauthorized) } else { http.Error(w, err.Error(), http.StatusUnauthorized) } return } next.ServeHTTP(w, r.WithContext(ctx)) }) } func maxRequestBodySizeInterceptor(next http.Handler, maxRecvSize int64) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Body = http.MaxBytesReader(w, r.Body, maxRecvSize) next.ServeHTTP(w, r) }) } opentelemetry-collector-0.141.0/config/confighttp/server_middleware_test.go000066400000000000000000000142251511331344600272450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "context" "errors" "io" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionmiddleware" "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" ) // testServerMiddleware is a test implementation of configmiddleware.Config type testServerMiddleware struct { extension.Extension extensionmiddleware.GetHTTPHandlerFunc } func newTestServerMiddleware(name string) component.Component { return &testServerMiddleware{ Extension: extensionmiddlewaretest.NewNop(), GetHTTPHandlerFunc: func(handler http.Handler) (http.Handler, error) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Append middleware name to the URL path r.URL.Path += name + "/" // Call the next handler in the chain handler.ServeHTTP(w, r) // Add middleware name to the response _, _ = w.Write([]byte("\r\nserved by " + name)) }), nil }, } } func newTestServerConfig(name string) configmiddleware.Config { return configmiddleware.Config{ ID: component.MustNewID(name), } } func TestServerMiddleware(t *testing.T) { // Register two test extensions extensions := map[component.ID]component.Component{ component.MustNewID("test1"): newTestServerMiddleware("test1"), component.MustNewID("test2"): newTestServerMiddleware("test2"), } // Test with different middleware configurations testCases := []struct { name string middlewares []configmiddleware.Config expectedOutput string }{ { name: "no_middlewares", middlewares: nil, expectedOutput: "OK{/}", }, { name: "single_middleware", middlewares: []configmiddleware.Config{ newTestServerConfig("test1"), }, expectedOutput: "OK{/test1/}\r\nserved by test1", }, { name: "multiple_middlewares", middlewares: []configmiddleware.Config{ newTestServerConfig("test1"), newTestServerConfig("test2"), }, expectedOutput: "OK{/test1/test2/}\r\nserved by test2\r\nserved by test1", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // Create server config with the test middlewares cfg := ServerConfig{ Endpoint: "localhost:0", Middlewares: tc.middlewares, } // Create a test handler that responds with the request path handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { _, _ = w.Write([]byte("OK{" + r.URL.Path + "}")) }) // Create the server srv, err := cfg.ToServer( context.Background(), extensions, componenttest.NewNopTelemetrySettings(), handler, ) require.NoError(t, err) // Create a test request req := httptest.NewRequest(http.MethodGet, "/", http.NoBody) // Create a response recorder rec := httptest.NewRecorder() // Serve the request srv.Handler.ServeHTTP(rec, req) // Get the response resp := rec.Result() defer resp.Body.Close() // Check the response body, err := io.ReadAll(resp.Body) require.NoError(t, err) assert.Equal(t, tc.expectedOutput, string(body)) }) } } func TestServerMiddlewareErrors(t *testing.T) { // Create a basic handler for testing handler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, _ = w.Write([]byte("OK")) }) // Test cases for HTTP server middleware errors httpTests := []struct { name string extensions map[component.ID]component.Component config ServerConfig errText string }{ { name: "extension_not_found", extensions: map[component.ID]component.Component{}, config: ServerConfig{ Endpoint: "localhost:0", Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("nonexistent"), }, }, }, errText: "failed to resolve middleware \"nonexistent\": middleware not found", }, { name: "get_http_handler_fails", extensions: map[component.ID]component.Component{ component.MustNewID("errormw"): extensionmiddlewaretest.NewErr(errors.New("http middleware error")), }, config: ServerConfig{ Endpoint: "localhost:0", Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("errormw"), }, }, }, errText: "http middleware error", }, } for _, tc := range httpTests { t.Run(tc.name, func(t *testing.T) { // Trying to create the server should fail _, err := tc.config.ToServer( context.Background(), tc.extensions, componenttest.NewNopTelemetrySettings(), handler, ) require.Error(t, err) assert.Contains(t, err.Error(), tc.errText) }) } // Test cases for gRPC server middleware errors grpcTests := []struct { name string extensions map[component.ID]component.Component config ServerConfig errText string }{ { name: "grpc_extension_not_found", extensions: map[component.ID]component.Component{}, config: ServerConfig{ Endpoint: "localhost:0", Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("nonexistent"), }, }, }, errText: "failed to resolve middleware \"nonexistent\": middleware not found", }, { name: "get_grpc_handler_fails", extensions: map[component.ID]component.Component{ component.MustNewID("errormw"): extensionmiddlewaretest.NewErr(errors.New("grpc middleware error")), }, config: ServerConfig{ Endpoint: "localhost:0", Middlewares: []configmiddleware.Config{ { ID: component.MustNewID("errormw"), }, }, }, errText: "grpc middleware error", }, } for _, tc := range grpcTests { t.Run(tc.name, func(t *testing.T) { // Trying to create the server should fail _, err := tc.config.ToServer( context.Background(), tc.extensions, componenttest.NewNopTelemetrySettings(), handler, ) require.Error(t, err) assert.Contains(t, err.Error(), tc.errText) }) } } opentelemetry-collector-0.141.0/config/confighttp/server_test.go000066400000000000000000001016321511331344600250470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confighttp import ( "bytes" "context" "errors" "fmt" "io" "net/http" "net/http/httptest" "path/filepath" "strconv" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configmiddleware" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionauth" ) var ( _ extension.Extension = (*mockAuthServer)(nil) _ extensionauth.Server = (*mockAuthServer)(nil) ) type mockAuthServer struct { component.StartFunc component.ShutdownFunc extensionauth.ServerAuthenticateFunc } func newMockAuthServer(auth func(ctx context.Context, sources map[string][]string) (context.Context, error)) extension.Extension { return &mockAuthServer{ServerAuthenticateFunc: auth} } func TestHTTPServerSettingsError(t *testing.T) { tests := []struct { settings ServerConfig err string }{ { err: "^failed to load TLS config: failed to load CA CertPool File: failed to load cert /doesnt/exist:", settings: ServerConfig{ Endpoint: "localhost:0", TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: "/doesnt/exist", }, }), }, }, { err: "^failed to load TLS config: failed to load TLS cert and key: for auth via TLS, provide both certificate and key, or neither", settings: ServerConfig{ Endpoint: "localhost:0", TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CertFile: "/doesnt/exist", }, }), }, }, { err: "failed to load client CA CertPool: failed to load CA /doesnt/exist:", settings: ServerConfig{ Endpoint: "localhost:0", TLS: configoptional.Some(configtls.ServerConfig{ ClientCAFile: "/doesnt/exist", }), }, }, } for _, tt := range tests { t.Run(tt.err, func(t *testing.T) { _, err := tt.settings.ToListener(context.Background()) assert.Regexp(t, tt.err, err) }) } } func TestHttpReception(t *testing.T) { tests := []struct { name string tlsServerCreds configoptional.Optional[configtls.ServerConfig] tlsClientCreds *configtls.ClientConfig hasError bool forceHTTP1 bool }{ { name: "noTLS", tlsServerCreds: configoptional.None[configtls.ServerConfig](), tlsClientCreds: &configtls.ClientConfig{ Insecure: true, }, }, { name: "TLS", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, }), tlsClientCreds: &configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", }, }, { name: "TLS (HTTP/1.1)", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, }), tlsClientCreds: &configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", }, forceHTTP1: true, }, { name: "NoServerCertificates", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, }), tlsClientCreds: &configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", }, hasError: true, }, { name: "mTLS", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, ClientCAFile: filepath.Join("testdata", "ca.crt"), }), tlsClientCreds: &configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "client.crt"), KeyFile: filepath.Join("testdata", "client.key"), }, ServerName: "localhost", }, }, { name: "NoClientCertificate", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, ClientCAFile: filepath.Join("testdata", "ca.crt"), }), tlsClientCreds: &configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", }, hasError: true, }, { name: "WrongClientCA", tlsServerCreds: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, ClientCAFile: filepath.Join("testdata", "server.crt"), }), tlsClientCreds: &configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "client.crt"), KeyFile: filepath.Join("testdata", "client.key"), }, ServerName: "localhost", }, hasError: true, }, } // prepare for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sc := &ServerConfig{ Endpoint: "localhost:0", TLS: tt.tlsServerCreds, } ln, err := sc.ToListener(context.Background()) require.NoError(t, err) s, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, errWrite := fmt.Fprint(w, "tt") assert.NoError(t, errWrite) })) require.NoError(t, err) go func() { _ = s.Serve(ln) }() prefix := "https://" expectedProto := "HTTP/2.0" if tt.tlsClientCreds.Insecure { prefix = "http://" expectedProto = "HTTP/1.1" } cc := &ClientConfig{ Endpoint: prefix + ln.Addr().String(), TLS: *tt.tlsClientCreds, ForceAttemptHTTP2: true, } client, errClient := cc.ToClient(context.Background(), nil, nilProvidersSettings) require.NoError(t, errClient) if tt.forceHTTP1 { expectedProto = "HTTP/1.1" client.Transport.(*http.Transport).ForceAttemptHTTP2 = false } resp, errResp := client.Get(cc.Endpoint) if tt.hasError { require.Error(t, errResp) } else { require.NoError(t, errResp) body, errRead := io.ReadAll(resp.Body) require.NoError(t, errRead) assert.Equal(t, "tt", string(body)) assert.Equal(t, expectedProto, resp.Proto) } require.NoError(t, s.Close()) }) } } func TestHttpCors(t *testing.T) { tests := []struct { name string CORSConfig configoptional.Optional[CORSConfig] allowedWorks bool disallowedWorks bool extraHeaderWorks bool }{ { name: "noCORS", allowedWorks: false, disallowedWorks: false, extraHeaderWorks: false, }, { name: "emptyCORS", CORSConfig: configoptional.Some(NewDefaultCORSConfig()), allowedWorks: false, disallowedWorks: false, extraHeaderWorks: false, }, { name: "OriginCORS", CORSConfig: configoptional.Some(CORSConfig{ AllowedOrigins: []string{"allowed-*.com"}, }), allowedWorks: true, disallowedWorks: false, extraHeaderWorks: false, }, { name: "CacheableCORS", CORSConfig: configoptional.Some(CORSConfig{ AllowedOrigins: []string{"allowed-*.com"}, MaxAge: 360, }), allowedWorks: true, disallowedWorks: false, extraHeaderWorks: false, }, { name: "HeaderCORS", CORSConfig: configoptional.Some(CORSConfig{ AllowedOrigins: []string{"allowed-*.com"}, AllowedHeaders: []string{"ExtraHeader"}, }), allowedWorks: true, disallowedWorks: false, extraHeaderWorks: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sc := &ServerConfig{ Endpoint: "localhost:0", CORS: tt.CORSConfig, } ln, err := sc.ToListener(context.Background()) require.NoError(t, err) s, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })) require.NoError(t, err) go func() { _ = s.Serve(ln) }() url := "http://" + ln.Addr().String() expectedStatus := http.StatusNoContent if !tt.CORSConfig.HasValue() || len(tt.CORSConfig.Get().AllowedOrigins) == 0 { expectedStatus = http.StatusOK } // Verify allowed domain gets responses that allow CORS. verifyCorsResp(t, url, "allowed-origin.com", tt.CORSConfig, false, expectedStatus, tt.allowedWorks) // Verify allowed domain and extra headers gets responses that allow CORS. verifyCorsResp(t, url, "allowed-origin.com", tt.CORSConfig, true, expectedStatus, tt.extraHeaderWorks) // Verify disallowed domain gets responses that disallow CORS. verifyCorsResp(t, url, "disallowed-origin.com", tt.CORSConfig, false, expectedStatus, tt.disallowedWorks) require.NoError(t, s.Close()) }) } } func TestHttpCorsInvalidSettings(t *testing.T) { sc := &ServerConfig{ Endpoint: "localhost:0", CORS: configoptional.Some(CORSConfig{AllowedHeaders: []string{"some-header"}}), } // This effectively does not enable CORS but should also not cause an error s, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) require.NoError(t, err) require.NotNil(t, s) require.NoError(t, s.Close()) } func TestHttpCorsWithSettings(t *testing.T) { sc := &ServerConfig{ Endpoint: "localhost:0", CORS: configoptional.Some(CORSConfig{ AllowedOrigins: []string{"*"}, }), Auth: configoptional.Some(AuthConfig{ Config: configauth.Config{ AuthenticatorID: mockID, }, }), } extensions := map[component.ID]component.Component{ mockID: newMockAuthServer(func(ctx context.Context, _ map[string][]string) (context.Context, error) { return ctx, errors.New("Settings failed") }), } srv, err := sc.ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings(), nil) require.NoError(t, err) require.NotNil(t, srv) rec := httptest.NewRecorder() req := httptest.NewRequest(http.MethodOptions, "/", http.NoBody) req.Header.Set("Origin", "http://localhost") req.Header.Set("Access-Control-Request-Method", http.MethodPost) srv.Handler.ServeHTTP(rec, req) assert.Equal(t, http.StatusNoContent, rec.Result().StatusCode) assert.Equal(t, "*", rec.Header().Get("Access-Control-Allow-Origin")) } func TestHttpServerHeaders(t *testing.T) { tests := []struct { name string headers configopaque.MapList }{ { name: "noHeaders", headers: nil, }, { name: "withHeaders", headers: configopaque.MapList{ {Name: "x-new-header-1", Value: "value1"}, {Name: "x-new-header-2", Value: "value2"}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sc := &ServerConfig{ Endpoint: "localhost:0", ResponseHeaders: tt.headers, } ln, err := sc.ToListener(context.Background()) require.NoError(t, err) s, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })) require.NoError(t, err) go func() { _ = s.Serve(ln) }() url := "http://" + ln.Addr().String() // Verify allowed domain gets responses that allow CORS. verifyHeadersResp(t, url, tt.headers) require.NoError(t, s.Close()) }) } } func verifyCorsResp(t *testing.T, url, origin string, set configoptional.Optional[CORSConfig], extraHeader bool, wantStatus int, wantAllowed bool) { req, err := http.NewRequest(http.MethodOptions, url, http.NoBody) require.NoError(t, err, "Error creating trace OPTIONS request: %v", err) req.Header.Set("Origin", origin) if extraHeader { req.Header.Set("ExtraHeader", "foo") req.Header.Set("Access-Control-Request-Headers", "extraheader") } req.Header.Set("Access-Control-Request-Method", "POST") resp, err := http.DefaultClient.Do(req) require.NoError(t, err, "Error sending OPTIONS to http server") require.NotNil(t, resp.Body) require.NoError(t, resp.Body.Close(), "Error closing OPTIONS response body") assert.Equal(t, wantStatus, resp.StatusCode) gotAllowOrigin := resp.Header.Get("Access-Control-Allow-Origin") gotAllowMethods := resp.Header.Get("Access-Control-Allow-Methods") wantAllowOrigin := "" wantAllowMethods := "" wantMaxAge := "" if wantAllowed { wantAllowOrigin = origin wantAllowMethods = "POST" if set.HasValue() && set.Get().MaxAge != 0 { wantMaxAge = strconv.Itoa(set.Get().MaxAge) } } assert.Equal(t, wantAllowOrigin, gotAllowOrigin) assert.Equal(t, wantAllowMethods, gotAllowMethods) assert.Equal(t, wantMaxAge, resp.Header.Get("Access-Control-Max-Age")) } func verifyHeadersResp(t *testing.T, url string, expected configopaque.MapList) { req, err := http.NewRequest(http.MethodGet, url, http.NoBody) require.NoError(t, err, "Error creating request") resp, err := http.DefaultClient.Do(req) require.NoError(t, err, "Error sending request to http server") require.NotNil(t, resp.Body) require.NoError(t, resp.Body.Close(), "Error closing response body") assert.Equal(t, http.StatusOK, resp.StatusCode) for k, v := range expected.Iter { assert.Equal(t, string(v), resp.Header.Get(k)) } } func TestServerAuth(t *testing.T) { // prepare authCalled := false sc := ServerConfig{ Endpoint: "localhost:0", Auth: configoptional.Some(AuthConfig{ Config: configauth.Config{ AuthenticatorID: mockID, }, }), } extensions := map[component.ID]component.Component{ mockID: newMockAuthServer(func(ctx context.Context, _ map[string][]string) (context.Context, error) { authCalled = true return ctx, nil }), } handlerCalled := false handler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { handlerCalled = true }) srv, err := sc.ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings(), handler) require.NoError(t, err) // tt srv.Handler.ServeHTTP(&httptest.ResponseRecorder{}, httptest.NewRequest(http.MethodGet, "/", http.NoBody)) // verify assert.True(t, handlerCalled) assert.True(t, authCalled) } func TestInvalidServerAuth(t *testing.T) { sc := ServerConfig{ Auth: configoptional.Some(AuthConfig{ Config: configauth.Config{ AuthenticatorID: nonExistingID, }, }), } srv, err := sc.ToServer(context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.NewServeMux()) require.Error(t, err) require.Nil(t, srv) } func TestFailedServerAuth(t *testing.T) { // prepare sc := ServerConfig{ Endpoint: "localhost:0", Auth: configoptional.Some(AuthConfig{ Config: configauth.Config{ AuthenticatorID: mockID, }, }), } extensions := map[component.ID]component.Component{ mockID: newMockAuthServer(func(ctx context.Context, _ map[string][]string) (context.Context, error) { return ctx, errors.New("invalid authorization") }), } srv, err := sc.ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) require.NoError(t, err) // tt response := &httptest.ResponseRecorder{} srv.Handler.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/", http.NoBody)) // verify assert.Equal(t, http.StatusUnauthorized, response.Result().StatusCode) assert.Equal(t, fmt.Sprintf("%v %s", http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)), response.Result().Status) } func TestFailedServerAuthWithErrorHandler(t *testing.T) { // prepare sc := ServerConfig{ Endpoint: "localhost:0", Auth: configoptional.Some(AuthConfig{ Config: configauth.Config{ AuthenticatorID: mockID, }, }), } extensions := map[component.ID]component.Component{ mockID: newMockAuthServer(func(ctx context.Context, _ map[string][]string) (context.Context, error) { return ctx, errors.New("invalid authorization") }), } eh := func(w http.ResponseWriter, _ *http.Request, err string, statusCode int) { assert.Equal(t, http.StatusUnauthorized, statusCode) // custom error handler uses real error string assert.Equal(t, "invalid authorization", err) // custom error handler changes returned status code http.Error(w, err, http.StatusInternalServerError) } srv, err := sc.ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}), WithErrorHandler(eh)) require.NoError(t, err) // tt response := &httptest.ResponseRecorder{} srv.Handler.ServeHTTP(response, httptest.NewRequest(http.MethodGet, "/", http.NoBody)) // verify assert.Equal(t, http.StatusInternalServerError, response.Result().StatusCode) assert.Equal(t, fmt.Sprintf("%v %s", http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)), response.Result().Status) } func TestServerWithErrorHandler(t *testing.T) { // prepare sc := ServerConfig{ Endpoint: "localhost:0", } eh := func(w http.ResponseWriter, _ *http.Request, _ string, statusCode int) { assert.Equal(t, http.StatusBadRequest, statusCode) // custom error handler changes returned status code http.Error(w, "invalid request", http.StatusInternalServerError) } srv, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}), WithErrorHandler(eh), ) require.NoError(t, err) // tt response := &httptest.ResponseRecorder{} req, err := http.NewRequest(http.MethodGet, srv.Addr, http.NoBody) require.NoError(t, err, "Error creating request: %v", err) req.Header.Set("Content-Encoding", "something-invalid") srv.Handler.ServeHTTP(response, req) // verify assert.Equal(t, http.StatusInternalServerError, response.Result().StatusCode) } func TestServerWithDecoder(t *testing.T) { // prepare sc := NewDefaultServerConfig() sc.Endpoint = "localhost:0" decoder := func(body io.ReadCloser) (io.ReadCloser, error) { return body, nil } srv, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}), WithDecoder("something-else", decoder), ) require.NoError(t, err) // tt response := &httptest.ResponseRecorder{} req, err := http.NewRequest(http.MethodGet, srv.Addr, bytes.NewBuffer([]byte("something"))) require.NoError(t, err, "Error creating request: %v", err) req.Header.Set("Content-Encoding", "something-else") srv.Handler.ServeHTTP(response, req) // verify assert.Equal(t, http.StatusOK, response.Result().StatusCode) } func TestServerWithDecompression(t *testing.T) { // prepare sc := ServerConfig{ MaxRequestBodySize: 1000, // 1 KB } body := []byte(strings.Repeat("a", 1000*1000)) // 1 MB srv, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(resp http.ResponseWriter, req *http.Request) { actualBody, err := io.ReadAll(req.Body) assert.ErrorContains(t, err, "http: request body too large") assert.Len(t, actualBody, 1000) if err != nil { resp.WriteHeader(http.StatusBadRequest) } else { resp.WriteHeader(http.StatusOK) } }), ) require.NoError(t, err) testSrv := httptest.NewServer(srv.Handler) defer testSrv.Close() req, err := http.NewRequest(http.MethodGet, testSrv.URL, compressZstd(t, body)) require.NoError(t, err, "Error creating request: %v", err) req.Header.Set("Content-Encoding", "zstd") // tt c := http.Client{} resp, err := c.Do(req) require.NoError(t, err, "Error sending request: %v", err) _, err = io.ReadAll(resp.Body) require.NoError(t, err, "Error reading response body: %v", err) // verifications is done mostly within the tt, but this is only a sanity check // that we got into the tt handler assert.Equal(t, http.StatusBadRequest, resp.StatusCode) } func TestDefaultMaxRequestBodySize(t *testing.T) { tests := []struct { name string settings ServerConfig expected int64 }{ { name: "default", settings: ServerConfig{}, expected: defaultMaxRequestBodySize, }, { name: "zero", settings: ServerConfig{MaxRequestBodySize: 0}, expected: defaultMaxRequestBodySize, }, { name: "negative", settings: ServerConfig{MaxRequestBodySize: -1}, expected: defaultMaxRequestBodySize, }, { name: "custom", settings: ServerConfig{MaxRequestBodySize: 100}, expected: 100, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := tt.settings.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}), ) require.NoError(t, err) assert.Equal(t, tt.expected, tt.settings.MaxRequestBodySize) }) } } func TestAuthWithQueryParams(t *testing.T) { // prepare authCalled := false sc := ServerConfig{ Endpoint: "localhost:0", Auth: configoptional.Some(AuthConfig{ RequestParameters: []string{"auth"}, Config: configauth.Config{ AuthenticatorID: mockID, }, }), } extensions := map[component.ID]component.Component{ mockID: newMockAuthServer(func(ctx context.Context, sources map[string][]string) (context.Context, error) { require.Len(t, sources, 1) assert.Equal(t, "1", sources["auth"][0]) authCalled = true return ctx, nil }), } handlerCalled := false handler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) { handlerCalled = true }) srv, err := sc.ToServer(context.Background(), extensions, componenttest.NewNopTelemetrySettings(), handler) require.NoError(t, err) // tt srv.Handler.ServeHTTP(&httptest.ResponseRecorder{}, httptest.NewRequest(http.MethodGet, "/?auth=1", http.NoBody)) // verify assert.True(t, handlerCalled) assert.True(t, authCalled) } func BenchmarkHttpRequest(b *testing.B) { tests := []struct { name string forceHTTP1 bool clientPerThread bool }{ { name: "HTTP/2.0, shared client (like load balancer)", forceHTTP1: false, clientPerThread: false, }, { name: "HTTP/1.1, shared client (like load balancer)", forceHTTP1: true, clientPerThread: false, }, { name: "HTTP/2.0, client per thread (like single app)", forceHTTP1: false, clientPerThread: true, }, { name: "HTTP/1.1, client per thread (like single app)", forceHTTP1: true, clientPerThread: true, }, } tlsServerCreds := configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), CertFile: filepath.Join("testdata", "server.crt"), KeyFile: filepath.Join("testdata", "server.key"), }, }) tlsClientCreds := &configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "ca.crt"), }, ServerName: "localhost", } sc := &ServerConfig{ Endpoint: "localhost:0", TLS: tlsServerCreds, } s, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { _, errWrite := fmt.Fprint(w, "tt") assert.NoError(b, errWrite) })) require.NoError(b, err) ln, err := sc.ToListener(context.Background()) require.NoError(b, err) go func() { _ = s.Serve(ln) }() defer func() { _ = s.Close() }() for _, bb := range tests { cc := &ClientConfig{ Endpoint: "https://" + ln.Addr().String(), TLS: *tlsClientCreds, } b.Run(bb.name, func(b *testing.B) { var c *http.Client if !bb.clientPerThread { c, err = cc.ToClient(context.Background(), nil, nilProvidersSettings) require.NoError(b, err) } b.RunParallel(func(pb *testing.PB) { if c == nil { c, err = cc.ToClient(context.Background(), nil, nilProvidersSettings) require.NoError(b, err) } if bb.forceHTTP1 { c.Transport.(*http.Transport).ForceAttemptHTTP2 = false } for pb.Next() { resp, errResp := c.Get(cc.Endpoint) require.NoError(b, errResp) body, errRead := io.ReadAll(resp.Body) _ = resp.Body.Close() require.NoError(b, errRead) require.Equal(b, "tt", string(body)) } c.CloseIdleConnections() }) // Wait for connections to close before closing server to prevent log spam <-time.After(10 * time.Millisecond) }) } } func TestDefaultHTTPServerSettings(t *testing.T) { httpServerSettings := NewDefaultServerConfig() assert.NotNil(t, httpServerSettings.CORS) assert.NotNil(t, httpServerSettings.TLS) assert.Equal(t, 1*time.Minute, httpServerSettings.IdleTimeout) assert.Equal(t, 30*time.Second, httpServerSettings.WriteTimeout) assert.Equal(t, time.Duration(0), httpServerSettings.ReadTimeout) assert.Equal(t, 1*time.Minute, httpServerSettings.ReadHeaderTimeout) assert.True(t, httpServerSettings.KeepAlivesEnabled) // Default should be true (keep-alives enabled by default) } func TestHTTPServerKeepAlives(t *testing.T) { tests := []struct { name string keepAlivesEnabled bool expectedKeepAlives bool }{ { name: "KeepAlives enabled", keepAlivesEnabled: true, expectedKeepAlives: true, }, { name: "KeepAlives disabled", keepAlivesEnabled: false, expectedKeepAlives: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sc := &ServerConfig{ Endpoint: "localhost:0", KeepAlivesEnabled: tt.keepAlivesEnabled, } server, err := sc.ToServer( context.Background(), nil, componenttest.NewNopTelemetrySettings(), http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) })) require.NoError(t, err) require.NotNil(t, server) // Since http.Server.disableKeepAlives is a private field and difficult to test directly, // we'll verify the configuration was set by testing the server behavior. // The main verification is that ToServer() succeeds without error when DisableKeepAlives is set. ln, err := sc.ToListener(context.Background()) require.NoError(t, err) go func() { _ = server.Serve(ln) }() defer func() { _ = server.Close() }() resp, err := http.Get("http://" + ln.Addr().String()) require.NoError(t, err) require.NotNil(t, resp) _ = resp.Body.Close() assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, tt.keepAlivesEnabled, sc.KeepAlivesEnabled) }) } } func TestHTTPServerTelemetry_Tracing(t *testing.T) { // Create a pattern route. The server name the span after the // pattern rather than the client-specified path. mux := http.NewServeMux() mux.HandleFunc("/b/{bucket}/o/{objectname...}", func(http.ResponseWriter, *http.Request) {}) type testcase struct { handler http.Handler expectedSpanName string } for name, testcase := range map[string]testcase{ "pattern": { handler: mux, expectedSpanName: "GET /b/{bucket}/o/{objectname...}", }, "no_pattern": { handler: http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}), expectedSpanName: "GET", }, } { t.Run(name, func(t *testing.T) { telemetry := componenttest.NewTelemetry() config := NewDefaultServerConfig() config.Endpoint = "localhost:0" srv, err := config.ToServer( context.Background(), nil, telemetry.NewTelemetrySettings(), testcase.handler, ) require.NoError(t, err) done := make(chan struct{}) lis, err := config.ToListener(context.Background()) require.NoError(t, err) go func() { defer close(done) _ = srv.Serve(lis) }() defer func() { assert.NoError(t, srv.Close()) <-done }() resp, err := http.Get(fmt.Sprintf("http://%s/b/bucket123/o/object456/segment", lis.Addr())) require.NoError(t, err) require.Equal(t, http.StatusOK, resp.StatusCode) resp.Body.Close() spans := telemetry.SpanRecorder.Ended() require.Len(t, spans, 1) assert.Equal(t, testcase.expectedSpanName, spans[0].Name()) }) } } // TestUnmarshalYAMLWithMiddlewares tests that the "middlewares" field is correctly // parsed from YAML configurations (fixing the bug where "middleware" was used instead) func TestServerUnmarshalYAMLWithMiddlewares(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "middlewares.yaml")) require.NoError(t, err) // Test server configuration var serverConfig ServerConfig serverSub, err := cm.Sub("server") require.NoError(t, err) require.NoError(t, serverSub.Unmarshal(&serverConfig)) // Validate the server configuration using reflection-based validation require.NoError(t, xconfmap.Validate(&serverConfig), "Server configuration should be valid") assert.Equal(t, "0.0.0.0:4318", serverConfig.Endpoint) require.Len(t, serverConfig.Middlewares, 2) assert.Equal(t, component.MustNewID("careful_middleware"), serverConfig.Middlewares[0].ID) assert.Equal(t, component.MustNewID("support_middleware"), serverConfig.Middlewares[1].ID) } // TestUnmarshalYAMLComprehensiveConfig tests the complete configuration example // to ensure all fields including middlewares are parsed correctly func TestServerUnmarshalYAMLComprehensiveConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) // Test server configuration var serverConfig ServerConfig serverSub, err := cm.Sub("server") require.NoError(t, err) require.NoError(t, serverSub.Unmarshal(&serverConfig)) // Validate the server configuration using reflection-based validation require.NoError(t, xconfmap.Validate(&serverConfig), "Server configuration should be valid") // Verify basic fields assert.Equal(t, "0.0.0.0:4318", serverConfig.Endpoint) assert.Equal(t, 30*time.Second, serverConfig.ReadTimeout) assert.Equal(t, 10*time.Second, serverConfig.ReadHeaderTimeout) assert.Equal(t, 30*time.Second, serverConfig.WriteTimeout) assert.Equal(t, 120*time.Second, serverConfig.IdleTimeout) assert.True(t, serverConfig.KeepAlivesEnabled) // Should be true as configured in config.yaml assert.Equal(t, int64(33554432), serverConfig.MaxRequestBodySize) assert.True(t, serverConfig.IncludeMetadata) // Verify TLS configuration assert.Equal(t, "/path/to/server.crt", serverConfig.TLS.Get().CertFile) assert.Equal(t, "/path/to/server.key", serverConfig.TLS.Get().KeyFile) assert.Equal(t, "/path/to/ca.crt", serverConfig.TLS.Get().CAFile) assert.Equal(t, "/path/to/client-ca.crt", serverConfig.TLS.Get().ClientCAFile) // Verify CORS configuration expectedOrigins := []string{"https://example.com", "https://*.test.com"} assert.Equal(t, expectedOrigins, serverConfig.CORS.Get().AllowedOrigins) corsHeaders := []string{"Content-Type", "Accept"} assert.Equal(t, corsHeaders, serverConfig.CORS.Get().AllowedHeaders) assert.Equal(t, 7200, serverConfig.CORS.Get().MaxAge) // Verify response headers expectedResponseHeaders := configopaque.MapList{ {Name: "Server", Value: "OpenTelemetry-Collector"}, {Name: "X-Flavor", Value: "apple"}, } assert.Equal(t, expectedResponseHeaders, serverConfig.ResponseHeaders) // Verify compression algorithms expectedAlgorithms := []string{"", "gzip", "zstd", "zlib", "snappy", "deflate"} assert.Equal(t, expectedAlgorithms, serverConfig.CompressionAlgorithms) // Verify middlewares require.Len(t, serverConfig.Middlewares, 3) assert.Equal(t, component.MustNewID("server_middleware1"), serverConfig.Middlewares[0].ID) assert.Equal(t, component.MustNewID("server_middleware2"), serverConfig.Middlewares[1].ID) assert.Equal(t, component.MustNewID("server_middleware3"), serverConfig.Middlewares[2].ID) } // TestMiddlewaresFieldCompatibility tests that the new "middlewares" field name // is used instead of the old "middleware" name, ensuring the bug is fixed func TestServerMiddlewaresFieldCompatibility(t *testing.T) { // Test that we can create a config with middlewares using the new field name serverConfig := ServerConfig{ Endpoint: "0.0.0.0:4318", Middlewares: []configmiddleware.Config{ {ID: component.MustNewID("server_middleware")}, }, } assert.Equal(t, "0.0.0.0:4318", serverConfig.Endpoint) assert.Len(t, serverConfig.Middlewares, 1) assert.Equal(t, component.MustNewID("server_middleware"), serverConfig.Middlewares[0].ID) } opentelemetry-collector-0.141.0/config/confighttp/testdata/000077500000000000000000000000001511331344600237615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/confighttp/testdata/ca.crt000066400000000000000000000022301511331344600250530ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDNjCCAh4CCQCBqDI24JacNTANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJB VTESMBAGA1UECAwJQXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoM CU15T3JnTmFtZTEVMBMGA1UEAwwMTXlDb21tb25OYW1lMB4XDTIyMDgwMzA0MTAx N1oXDTMyMDczMTA0MTAxN1owXTELMAkGA1UEBhMCQVUxEjAQBgNVBAgMCUF1c3Ry YWxpYTEPMA0GA1UEBwwGU3lkbmV5MRIwEAYDVQQKDAlNeU9yZ05hbWUxFTATBgNV BAMMDE15Q29tbW9uTmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ANFDGZCSxNdaJQ1q7P5qVAZDKCj+3ClpFWAVT5HYDlOqgIjYRZ45/YGfKsDbK6rj /+v5xTnTZt8e8kRfPgrZTBtPtefu6tKwxYYr3sSCR3TU4bX4dIM9ZwrFaTrPP1hk UXR8zlk7F6gcWS+WX7LdupMs5SdZIePhkzpkxYIBatdRMf7w2f5v6M3UnOrCoyz0 YPvvyZKq5zo9uBlVkrUL/QDrOB5yYjith7l8FkLHAirGTaszfF+8pZwzZn4ykVbn eQQs1g6ujR0DgQh/k6A6XDQfg4JWQqNt3kkiO7NPIHTrl+W/nKdqve864ECAHSM2 NIgGtQqVavPKD6pr15V328cCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEALZuCeu8U yjJlR+BbDqiZw7/EBpGgTX4mv9CofJc9ErxFGJTYiaLZ1Jf3bwE+0G9ym8UfxKG8 9xCYmoVbEQhgLzYDpYPxkKi5X7RUMw9fKlbRqwy2Ek1mDnSIYPRalhfOXBT5E652 OUeILLRJlAPL3SrALjJM5Jjn4pkwankE53mfU4LpC7xWOjuwkSPRor1XCwoAZMTz EZsZGUQf5M69ZAy0wWHu4C94rlgD37hybUEzhsr9UiK2v1Gn3a7BSAgtkbD0OIe5 BzCu+UHQO4u841SbXn4q8aO1idaR8UhPAqfVno+L7ZmHRGsgvMk1vlMbroIIYaAz 2LQP6IwYUWRM9Q== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/confighttp/testdata/client.crt000066400000000000000000000023001511331344600257440ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIJANt5fkUlfxyOMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxMDE3WhcNMzIwNzMxMDQxMDE3WjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEApmnIUees+b/V5gEgEOwyjPo9xeejzd/DSo02x/syauoU4mhINwa8cuB+ nvGhCUY5w+bZfOnWhY03wjnqM1Ay+sg7yHZgqeHclzQh5d39ojeaMa3x8c3IQsKZ j/UTyYmkX6Gap8Z8fk1ucM43clM3nUUf3THzeo0X3MTm7FIs2OCxcbCYo8GUo6GV rn7nhutOrYgyPrgo7bi8xF2sJRRKC/C7MBCeNaJlgj53jB93gF15/ZxPbAQCtI5R J+3YrKp987RSuXtDeqm1zSCmV6LnT2vVsSNmnDdvWHQF7SqgauqT0Z7gm4/M/xXw ge6GJaENOV1wIUsfbYj6UCMt6tZpjQIDAQABoxgwFjAUBgNVHREEDTALgglsb2Nh bGhvc3QwDQYJKoZIhvcNAQELBQADggEBAHwMOQIz++7JPWRb3xHTkt6jIlAw/zVl 3UmdXMqEEscLGcjmDqu0u1qPGlS48Ukb4efAQsp+/2KLQex7jdl3r4p0+3O530AY MEtlK2oH1uE3KDMyswA0INrGeZpHRP2BI6QJGbxcJN22MuHFmKwPBJlltgVtK0Gt IhG/cRJnVMcX+iBdsxygW5u7P8MpC8Eoved/F8yKB66uJ4LyZC5KL9RG58Y0JJin KDvpzSGLMnHgnuJlGOGz/uUYXZ4IX5g95yKiDZ9+GkVo+DRHAUNEUjfQSRujmO10 INTHs4/hd0MI6NaHXwObvmOsa8VRRVWa995O5Y9rZMYg/4mjm1Axcm4= -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/confighttp/testdata/client.key000066400000000000000000000032171511331344600257540ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpAIBAAKCAQEApmnIUees+b/V5gEgEOwyjPo9xeejzd/DSo02x/syauoU4mhI Nwa8cuB+nvGhCUY5w+bZfOnWhY03wjnqM1Ay+sg7yHZgqeHclzQh5d39ojeaMa3x 8c3IQsKZj/UTyYmkX6Gap8Z8fk1ucM43clM3nUUf3THzeo0X3MTm7FIs2OCxcbCY o8GUo6GVrn7nhutOrYgyPrgo7bi8xF2sJRRKC/C7MBCeNaJlgj53jB93gF15/ZxP bAQCtI5RJ+3YrKp987RSuXtDeqm1zSCmV6LnT2vVsSNmnDdvWHQF7SqgauqT0Z7g m4/M/xXwge6GJaENOV1wIUsfbYj6UCMt6tZpjQIDAQABAoIBAEAIGfUyAMPEhchP jIgWakkGjLhWrhesTtejyH1gcYDj+w828vqBVAeby/zamo0YAWgYrny6+TlAIkFQ yYXfCQ6n9yDmM8GKT7e6boSlS0+ct28AMEVLWhAeErpqoad9l8rYQsrlu8dZgfJT 1s/dp1uTWnRhIP95xMHE3dn2sJzuEV9HunkgS6re6YyTqNZFLAPVn33wDRVSaxH6 3VJG6T3Y2xs77AKTKz5Mji/gqK3XFAed0rehowgS4A8mEUrZt9gzioRlmV2tshvx st5KDw7lGEZKbgGB/+cwLJhHgEK7KyJRsR/shtDyXKRlEC19qV6zSupz9BSQNqRN +vWQ070CgYEA0NTYgdxz8msVMXtLCectwMLfLU99H/frGCvjBv0wLni2XF+eS9gX D6W4nFbDA+wZfSBMpEqriHvrDpMk7RN3Q9rAKtqeyzDboWiJRRT4DZeRz9o+WEt3 +wDP8W0dS7IRw8Jnrsj9JgmY35fGXZDUWZRnPuvrpolojUnMTKNK/ccCgYEAzAA1 roKRNOn08P3SZ0jCUA0O+Ke5sycV6QPoLk5qQnL5eEjOlvd+6U128DAf1DW5O6/8 C0YsTMOY/sQxXliSt/iygaJVoo7Tt1L60ctNY4KX5EiWs2AgvvTu89ESwbhvvfvw Xt7PNfa0eBSgC+Lrg5y2Lahs8DijWkTbxo3ebgsCgYEAmyLjzGUnRZnDXsUHE85H sQGTpid8/rjAT26a82A34O4QG0N1Z0aaqycjpBDYQxusO8Y46XwHPhdAoc0yC2UA nsntJGjQuoYLQzdTcpyHQiGtUsoAsrst4KvTzriOoOMiS1kqiTAKz60lgkVQOcYT 2pBiut2sbEV8BCokuXI9jZUCgYBbg9yRJNGvQyU21ycEXoeNEc6djeColegmWDJY U6Unmhx/8Wl8IBs23iF1LqGYuWEXfaM8C4bkCPshjzH2eRWYomCx9vkjq58epoMO in11Hqi1KDsyzPTjtU1c43Xeoba/K75xUNL0CnB7TgVeT7YHnM29PclhGodtf2Z4 dDxMcQKBgQC46rtyosn/2uR+88DCWSVTnc4cA6tOEB8WP7Z7mk8yOv1CGgyP4187 iDPL+91O4C5sT02MFuwElCmxuO1RQQhVTGzIxPd9RQ7t+l1PorTeodYF/ezrRl47 xuxp4nF50ThlTf1AuhQxpPC1JsXqkH3d582ZLErzrgijMYxk5sYJRA== -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/confighttp/testdata/config.yaml000066400000000000000000000051221511331344600261120ustar00rootroot00000000000000# Comprehensive HTTP configuration example showing all available options # with middleware configurations (using the new "middlewares" field) # HTTP Client Configuration client: # The target URL to send data to endpoint: "http://example.com:4318/v1/traces" # Proxy URL setting for the collector proxy_url: "http://proxy.example.com:8080" # TLS configuration tls: insecure: false cert_file: "/path/to/client.crt" key_file: "/path/to/client.key" ca_file: "/path/to/ca.crt" server_name_override: "example.com" insecure_skip_verify: false # HTTP client buffer sizes read_buffer_size: 4096 write_buffer_size: 4096 # Request timeout timeout: 30s # Custom headers headers: "User-Agent": "OpenTelemetry-Collector/1.0" "X-Custom-Header": "custom-value" # Compression setting compression: "gzip" # Disable HTTP/2 disable_keep_alives: false http2_read_idle_timeout: 10s http2_ping_timeout: 15s # Maximum idle connections max_idle_conns: 100 max_idle_conns_per_host: 10 max_conns_per_host: 50 idle_conn_timeout: 90s # Authentication configuration auth: authenticator: "oauth2client" # Cookies configuration cookies: enabled: true # Middlewares configuration (note: plural "middlewares") middlewares: - id: "middleware1" - id: "middleware2" # HTTP Server Configuration server: # Network endpoint configuration endpoint: "0.0.0.0:4318" # TLS configuration tls: cert_file: "/path/to/server.crt" key_file: "/path/to/server.key" ca_file: "/path/to/ca.crt" client_ca_file: "/path/to/client-ca.crt" reload_interval: 24h # CORS configuration cors: allowed_origins: - "https://example.com" - "https://*.test.com" allowed_headers: - "Content-Type" - "Accept" max_age: 7200 # Authentication configuration auth: authenticator: "basic" # Server timeouts read_timeout: 30s read_header_timeout: 10s write_timeout: 30s idle_timeout: 120s # HTTP keep-alives configuration keep_alives_enabled: true # Maximum request size max_request_body_size: 33554432 # 32MB # Include metadata in the context include_metadata: true # Response headers to add to every response response_headers: "Server": "OpenTelemetry-Collector" "X-Flavor": "apple" # Compression algorithms supported by the server compression_algorithms: ["", "gzip", "zstd", "zlib", "snappy", "deflate"] # Middlewares configuration (note: plural "middlewares") middlewares: - id: "server_middleware1" - id: "server_middleware2" - id: "server_middleware3" opentelemetry-collector-0.141.0/config/confighttp/testdata/middlewares.yaml000066400000000000000000000004421511331344600271450ustar00rootroot00000000000000# Simple middleware-focused test configuration client: endpoint: "http://localhost:4318/v1/traces" middlewares: - id: "fancy_middleware" - id: "careful_middleware" server: endpoint: "0.0.0.0:4318" middlewares: - id: "careful_middleware" - id: "support_middleware" opentelemetry-collector-0.141.0/config/confighttp/testdata/server.crt000066400000000000000000000023001511331344600257740ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVTCCAj2gAwIBAgIJANt5fkUlfxyNMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxMDE3WhcNMzIwNzMxMDQxMDE3WjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAupEXxNIX+2k0PC/yLfuWSbFr22eLwYSYkPDydFENKYID905hcWqaqr4o u1Fu8nofbeKrpTgmx7lwXB5VIkdNcnwLyt40nPETGN2m0vBa7Bm6z/KJTW0iHmTz 5fVzt9rggnRTRSovNy43weKoZXHcl/lmGbGy+lqQ69jJTT9yXipkMTIkscYgSHK3 GVxUhrsBc/mZyBLSj3Tpt3Az71N4npTp6XYbgx4MhllbH9xFlw2hLs1DU+vwJhSE w99UrLhRz8L3ePmShdkySD9QZxCKD5euiumVfPLfzWV2JmLejC3MD3sd5ql+5itv WrnYPcky3OclXcnZgDo+ZloWLYPWhQIDAQABoxgwFjAUBgNVHREEDTALgglsb2Nh bGhvc3QwDQYJKoZIhvcNAQELBQADggEBAJGfixdI6T6dxb37fJPNa0Uerq5aZPb9 GLJg3CqkZ4yjfsveZ91lH7fRPRjXld3aMb6978kpoczGYJeAdY8j0BPvA+UfsuYO bzm6HUgiTjyCnLPQIuAlzuYDsBQhzz6gdRclgnuQ8JO/xTDIxVLJDuueannqEn9x s/RQ5PeWf0D+zvSu4p8UENKfaPqoI5q7nb93IHL38PMDfB7n4oEDIkG0zfxX/zYI h5ZhzlWSscfCRE4Hdcb8RcSuzwI2JzidMY/ZXUr20iNuCSbv4zhsoDASk7Ud+yj4 d4JkdOA4NbaT8/aR+Ectc2ItBc2lb0xzEqQnjg3zRQjEzeryHN0hxWU= -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/confighttp/testdata/server.key000066400000000000000000000032171511331344600260040ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEAupEXxNIX+2k0PC/yLfuWSbFr22eLwYSYkPDydFENKYID905h cWqaqr4ou1Fu8nofbeKrpTgmx7lwXB5VIkdNcnwLyt40nPETGN2m0vBa7Bm6z/KJ TW0iHmTz5fVzt9rggnRTRSovNy43weKoZXHcl/lmGbGy+lqQ69jJTT9yXipkMTIk scYgSHK3GVxUhrsBc/mZyBLSj3Tpt3Az71N4npTp6XYbgx4MhllbH9xFlw2hLs1D U+vwJhSEw99UrLhRz8L3ePmShdkySD9QZxCKD5euiumVfPLfzWV2JmLejC3MD3sd 5ql+5itvWrnYPcky3OclXcnZgDo+ZloWLYPWhQIDAQABAoIBAF8u/01vUsT126yJ WamUHgzi9AAwR+EnYR8xjsFBSNHQf22BE73lgZtzARzwYwZawAY0CxZ0G3TyaxzU bOLcNese1nVeAMHBTNj23NHpxrmGNwU43EwgTbPsFXNRUwSOKtTjvEghSY2Bivjk Rr3a5YyztR+OxZ1s71skcy9yG0tmveGRQS2Gn3SrLgrX7PjgUULpd7TNkWlAyTB7 sFvVeHVEv8AcFDvHCBvlNJvMG2WT7kD4vjbRc0V1y89D4wO3kNVumajNjiSUopsU zFe1vegcSLIgf1i2QEtXLob6mrQJplDA3G8oQX4FF0Oovk/bLwzC6IHNeFOo5eFM TfGzd9ECgYEA6Ixx+2Bai2zdSz19NVaQEksDVdT/ivorgYGpIllLOwjU3ZCIEs2J iNNPlIX9uFcwIGcfoHsU66iUWrwprfnbloezq5aPdHuhW2PE+JUEBqzmQDy+ax/i HI2IaD42+OJY5RdRfS7cvczIFrW9XECCTkhr08CxZTO7W7VCP0OnpPMCgYEAzWGQ hHgpyj5kfco/KlRrK6bQBkhbqWkbkoZohVL6hJ2UxC/NBFS3fWYQ2LFyFPBdu+lI RXkDxroCQJfWGNAe4PlbKcWh5Q9Ps/s8wl0DIR/KM2yhzE2GqfDC6pQ3xFpizbcm jl+AL2U6Y9Et1nvPjZKo6STf5yrEdIuHgaq61KcCgYEA4g/tmf2/53vr4AGlXx2I LpBHbMADrzmk41+FaMO/M2NRcxXWgdjW03EAEpTy4am4Ojelch9UZgZaOZ5jMiIL Slke2zYgvI6WfD4Ps8tAv7CCoH2sanzzFOitaxDX5bg7zHCPog7VPZj+Bb2kmDKJ ucoDMDVI/eV9RBh/jvqY1OsCgYEAx5iYxVSucGFgcis6Zd3y5VJRermZczO12xmK vH9e/cDTUjKOUTYvuMuXdbBFiXnr7nIRjYrFE72z8KhfJnAkgklzwk3SP3U45VY1 v0J7hxaJAJ8DQzTYuZFFLIptBAM/YGMtMlI3llgPffBNVtOuawzr4OC4RMV4dTcg svCEb6MCgYEAnRx87p5bAgDVug3pdFI7qRi5Tgxa25c5GsFwhmmr3EgtxKQKLFIH G6KOWJBpFePVrz3PH71d+J1mB/g8GqzpHBuYTBDD3hyz8iKHN+pmoM4m2/tTqKRY 26XUGOUIxnksgsw2O2R9AASrEm4hhAg5AxmANgqOIZijIcHWF8q9QpE= -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/confighttp/xconfighttp/000077500000000000000000000000001511331344600245055ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/confighttp/xconfighttp/Makefile000066400000000000000000000000411511331344600261400ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/config/confighttp/xconfighttp/go.mod000066400000000000000000000120471511331344600256170ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/confighttp/xconfighttp go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/confighttp v0.141.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.1 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/cors v1.11.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/component v1.47.0 // indirect go.opentelemetry.io/collector/config/configauth v1.47.0 // indirect go.opentelemetry.io/collector/config/configcompression v1.47.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/config/configopaque v1.47.0 // indirect go.opentelemetry.io/collector/config/configoptional v1.47.0 // indirect go.opentelemetry.io/collector/config/configtls v1.47.0 // indirect go.opentelemetry.io/collector/confmap v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.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.45.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/config/confighttp => ../../confighttp replace go.opentelemetry.io/collector/client => ../../../client replace go.opentelemetry.io/collector/consumer => ../../../consumer replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/component/componenttest => ../../../component/componenttest replace go.opentelemetry.io/collector/config/configauth => ../../configauth replace go.opentelemetry.io/collector/config/configoptional => ../../configoptional replace go.opentelemetry.io/collector/pdata => ../../../pdata replace go.opentelemetry.io/collector/extension/extensionauth => ../../../extension/extensionauth replace go.opentelemetry.io/collector/config/configopaque => ../../configopaque replace go.opentelemetry.io/collector/component => ../../../component replace go.opentelemetry.io/collector/extension => ../../../extension replace go.opentelemetry.io/collector/config/configtls => ../../configtls replace go.opentelemetry.io/collector/config/configcompression => ../../configcompression replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../../extension/extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../../configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/confmap => ../../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/config/confighttp/xconfighttp/go.sum000066400000000000000000000252351511331344600256470ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/confighttp/xconfighttp/options.go000066400000000000000000000017261511331344600265350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconfighttp // import "go.opentelemetry.io/collector/config/confighttp/xconfighttp" import ( "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/confighttp/internal" ) // WithOtelHTTPOptions allows providing (or overriding) options passed // to the otelhttp.NewHandler() function. // // This is located in the experimental sub-package because the otelhttp library // has not reached v1.x yet and exposing its types in confighttp public API // could lead to breaking changes in the future. // See https://github.com/open-telemetry/opentelemetry-collector/pull/11769 func WithOtelHTTPOptions(httpopts ...otelhttp.Option) confighttp.ToServerOption { return internal.ToServerOptionFunc(func(opts *internal.ToServerOptions) { opts.OtelhttpOpts = append(opts.OtelhttpOpts, httpopts...) }) } opentelemetry-collector-0.141.0/config/confighttp/xconfighttp/options_test.go000066400000000000000000000037311511331344600275720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconfighttp import ( "context" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/confighttp" ) func TestServerWithOtelHTTPOptions(t *testing.T) { // prepare sc := confighttp.ServerConfig{ Endpoint: "localhost:0", } telemetry := componenttest.NewNopTelemetrySettings() tp, te := tracerProvider(t) telemetry.TracerProvider = tp srv, err := sc.ToServer( context.Background(), nil, telemetry, http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}), WithOtelHTTPOptions( otelhttp.WithSpanNameFormatter(func(_ string, r *http.Request) string { return "example" + r.URL.Path }), otelhttp.WithFilter(func(r *http.Request) bool { return r.URL.Path != "/foobar" }), ), ) require.NoError(t, err) for _, path := range []string{"/path", "/foobar"} { response := &httptest.ResponseRecorder{} req, err := http.NewRequest(http.MethodGet, srv.Addr+path, http.NoBody) require.NoError(t, err) srv.Handler.ServeHTTP(response, req) assert.Equal(t, http.StatusOK, response.Result().StatusCode) } spans := te.GetSpans().Snapshots() assert.Len(t, spans, 1, "the request to /foobar should not be traced") assert.Equal(t, "example/path", spans[0].Name()) } func tracerProvider(t *testing.T) (trace.TracerProvider, *tracetest.InMemoryExporter) { exporter := tracetest.NewInMemoryExporter() tp := sdktrace.NewTracerProvider( sdktrace.WithSampler(sdktrace.AlwaysSample()), sdktrace.WithSyncer(exporter), ) t.Cleanup(func() { assert.NoError(t, tp.Shutdown(context.Background())) }) return tp, exporter } opentelemetry-collector-0.141.0/config/configmiddleware/000077500000000000000000000000001511331344600233065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configmiddleware/Makefile000066400000000000000000000000361511331344600247450ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configmiddleware/README.md000066400000000000000000000024721511331344600245720ustar00rootroot00000000000000# OpenTelemetry Collector Middleware Configuration This package implements a configuration struct for referring to [middleware extensions](../../extension/extensionmiddleware/README.md). ## Overview The `configmiddleware` package defines a `Config` type that allows components to configure middleware extensions, typically as an ordered list. This support is built in for push-based receivers configured through `confighttp` and `configgrpc`, as for example in the OTLP receiver: ```yaml receivers: otlp: protocols: http: middlewares: - id: limitermiddleware ``` ## Methods The package provides four key methods to retrieve appropriate middleware handlers: 1. **GetHTTPClientRoundTripper**: Obtains a function to wrap an HTTP client with a middleware extension via a `http.RoundTripper`. 2. **GetHTTPServerHandler**: Obtains a function to wrap an HTTP server with a middleware extension via a `http.Handler`. 3. **GetGRPCClientOptions**: Obtains a `[]grpc.DialOption` that configure a middleware extension for gRPC clients. 4. **GetGRPCServerOptions**: Obtains a `[]grpc.ServerOption` that configure a middleware extension for gRPC servers. These functions are typically called during Start() by a component, passing the `component.Host` extensions. An error is returned if the named extension cannot be found. opentelemetry-collector-0.141.0/config/configmiddleware/configmiddleware.go000066400000000000000000000075071511331344600271510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package configmiddleware implements a configuration struct to // name middleware extensions. package configmiddleware // import "go.opentelemetry.io/collector/config/configmiddleware" import ( "context" "errors" "fmt" "net/http" "google.golang.org/grpc" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension/extensionmiddleware" ) var ( errMiddlewareNotFound = errors.New("middleware not found") errNotHTTPServer = errors.New("requested extension is not an HTTP server middleware") errNotGRPCServer = errors.New("requested extension is not a gRPC server middleware") errNotHTTPClient = errors.New("requested extension is not an HTTP client middleware") errNotGRPCClient = errors.New("requested extension is not a gRPC client middleware") ) // Middleware defines the extension ID for a middleware component. type Config struct { // ID specifies the name of the extension to use. ID component.ID `mapstructure:"id,omitempty"` // prevent unkeyed literal initialization _ struct{} } // GetHTTPClientRoundTripper attempts to select the appropriate // extensionmiddleware.HTTPClient from the map of extensions, and // returns the HTTP client wrapper function. If a middleware is not // found, an error is returned. This should only be used by HTTP // clients. func (m Config) GetHTTPClientRoundTripper(_ context.Context, extensions map[component.ID]component.Component) (func(http.RoundTripper) (http.RoundTripper, error), error) { if ext, found := extensions[m.ID]; found { if client, ok := ext.(extensionmiddleware.HTTPClient); ok { return client.GetHTTPRoundTripper, nil } return nil, errNotHTTPClient } return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) } // GetHTTPServerHandler attempts to select the appropriate // extensionmiddleware.HTTPServer from the map of extensions, and // returns the http.Handler wrapper function. If a middleware is not // found, an error is returned. This should only be used by HTTP // servers. func (m Config) GetHTTPServerHandler(_ context.Context, extensions map[component.ID]component.Component) (func(http.Handler) (http.Handler, error), error) { if ext, found := extensions[m.ID]; found { if server, ok := ext.(extensionmiddleware.HTTPServer); ok { return server.GetHTTPHandler, nil } return nil, errNotHTTPServer } return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) } // GetGRPCClientOptions attempts to select the appropriate // extensionmiddleware.GRPCClient from the map of extensions, and // returns the gRPC dial options. If a middleware is not found, an // error is returned. This should only be used by gRPC clients. func (m Config) GetGRPCClientOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.DialOption, error) { if ext, found := extensions[m.ID]; found { if client, ok := ext.(extensionmiddleware.GRPCClient); ok { return client.GetGRPCClientOptions() } return nil, errNotGRPCClient } return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) } // GetGRPCServerOptions attempts to select the appropriate // extensionmiddleware.GRPCServer from the map of extensions, and // returns the gRPC server options. If a middleware is not found, an // error is returned. This should only be used by gRPC servers. func (m Config) GetGRPCServerOptions(_ context.Context, extensions map[component.ID]component.Component) ([]grpc.ServerOption, error) { if ext, found := extensions[m.ID]; found { if server, ok := ext.(extensionmiddleware.GRPCServer); ok { return server.GetGRPCServerOptions() } return nil, errNotGRPCServer } return nil, fmt.Errorf("failed to resolve middleware %q: %w", m.ID, errMiddlewareNotFound) } opentelemetry-collector-0.141.0/config/configmiddleware/configmiddleware_test.go000066400000000000000000000126051511331344600302030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configmiddleware import ( "context" "testing" "github.com/stretchr/testify/require" "google.golang.org/grpc" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionmiddleware" "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" ) var testID = component.MustNewID("test") type mockWrongType struct { component.StartFunc component.ShutdownFunc } func TestConfig_GetHTTPServerHandler(t *testing.T) { ctx := context.Background() tests := []struct { name string middleware Config extensions map[component.ID]component.Component wantErr error }{ { name: "found_and_valid", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: extensionmiddlewaretest.NewNop(), }, wantErr: nil, }, { name: "middleware_not_found", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{}, wantErr: errMiddlewareNotFound, }, { name: "middleware_wrong_type", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: mockWrongType{}, }, wantErr: errNotHTTPServer, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { value, err := tt.middleware.GetHTTPServerHandler(ctx, tt.extensions) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.NotNil(t, value) } }) } } func TestConfig_GetHTTPClientRoundTripper(t *testing.T) { ctx := context.Background() tests := []struct { name string middleware Config extensions map[component.ID]component.Component wantErr error }{ { name: "found_and_valid", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: extensionmiddlewaretest.NewNop(), }, wantErr: nil, }, { name: "middleware_not_found", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{}, wantErr: errMiddlewareNotFound, }, { name: "middleware_wrong_type", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: mockWrongType{}, }, wantErr: errNotHTTPClient, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { value, err := tt.middleware.GetHTTPClientRoundTripper(ctx, tt.extensions) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.NotNil(t, value) } }) } } func TestConfig_GetGRPCServerOptions(t *testing.T) { ctx := context.Background() tests := []struct { name string middleware Config extensions map[component.ID]component.Component wantErr error }{ { name: "found_and_valid", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: struct { extension.Extension extensionmiddleware.GetGRPCServerOptionsFunc }{ Extension: extensionmiddlewaretest.NewNop(), GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { return []grpc.ServerOption{ grpc.EmptyServerOption{}, }, nil }, }, }, wantErr: nil, }, { name: "middleware_not_found", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{}, wantErr: errMiddlewareNotFound, }, { name: "middleware_wrong_type", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: mockWrongType{}, }, wantErr: errNotGRPCServer, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { value, err := tt.middleware.GetGRPCServerOptions(ctx, tt.extensions) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.NotNil(t, value) } }) } } func TestConfig_GetGRPCClientOptions(t *testing.T) { ctx := context.Background() tests := []struct { name string middleware Config extensions map[component.ID]component.Component wantErr error }{ { name: "found_and_valid", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: struct { extension.Extension extensionmiddleware.GetGRPCClientOptionsFunc }{ Extension: extensionmiddlewaretest.NewNop(), GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { return []grpc.DialOption{ grpc.EmptyDialOption{}, }, nil }, }, }, wantErr: nil, }, { name: "middleware_not_found", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{}, wantErr: errMiddlewareNotFound, }, { name: "middleware_wrong_type", middleware: Config{ ID: testID, }, extensions: map[component.ID]component.Component{ testID: mockWrongType{}, }, wantErr: errNotGRPCClient, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { value, err := tt.middleware.GetGRPCClientOptions(ctx, tt.extensions) if tt.wantErr != nil { require.ErrorIs(t, err, tt.wantErr) } else { require.NoError(t, err) require.NotNil(t, value) } }) } } opentelemetry-collector-0.141.0/config/configmiddleware/go.mod000066400000000000000000000040321511331344600244130ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configmiddleware go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest v0.141.0 google.golang.org/grpc v1.77.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/config/configmiddleware/go.sum000066400000000000000000000160551511331344600244500ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configmiddleware/metadata.yaml000066400000000000000000000002111511331344600257440ustar00rootroot00000000000000type: config/configmiddleware github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/confignet/000077500000000000000000000000001511331344600217575ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/confignet/Makefile000066400000000000000000000000361511331344600234160ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/confignet/README.md000066400000000000000000000022251511331344600232370ustar00rootroot00000000000000# Network Configuration Settings [Receivers](https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/README.md) leverage network configuration to set connection and transport information. - `endpoint`: Configures the address for this network connection. For TCP and UDP networks, the address has the form "host:port". The host must be a literal IP address, or a host name that can be resolved to IP addresses. The port must be a literal port number or a service name. If the host is a literal IPv6 address it must be enclosed in square brackets, as in "[2001:db8::1]:80" or "[fe80::1%zone]:80". The zone specifies the scope of the literal IPv6 address as defined in RFC 4007. - `transport`: Known protocols are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket". - `dialer`: Dialer configuration - `timeout`: Dialer timeout is the maximum amount of time a dial will wait for a connect to complete. The default is no timeout. Note that for TCP receivers only the `endpoint` configuration setting is required. opentelemetry-collector-0.141.0/config/confignet/confignet.go000066400000000000000000000131541511331344600242660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confignet // import "go.opentelemetry.io/collector/config/confignet" import ( "context" "fmt" "net" "time" ) // TransportType represents a type of network transport protocol type TransportType string const ( TransportTypeTCP TransportType = "tcp" TransportTypeTCP4 TransportType = "tcp4" TransportTypeTCP6 TransportType = "tcp6" TransportTypeUDP TransportType = "udp" TransportTypeUDP4 TransportType = "udp4" TransportTypeUDP6 TransportType = "udp6" TransportTypeIP TransportType = "ip" TransportTypeIP4 TransportType = "ip4" TransportTypeIP6 TransportType = "ip6" TransportTypeUnix TransportType = "unix" TransportTypeUnixgram TransportType = "unixgram" TransportTypeUnixPacket TransportType = "unixpacket" transportTypeEmpty TransportType = "" ) // UnmarshalText unmarshalls text to a TransportType. // Valid values are "tcp", "tcp4", "tcp6", "udp", "udp4", // "udp6", "ip", "ip4", "ip6", "unix", "unixgram" and "unixpacket" func (tt *TransportType) UnmarshalText(in []byte) error { typ := TransportType(in) switch typ { case TransportTypeTCP, TransportTypeTCP4, TransportTypeTCP6, TransportTypeUDP, TransportTypeUDP4, TransportTypeUDP6, TransportTypeIP, TransportTypeIP4, TransportTypeIP6, TransportTypeUnix, TransportTypeUnixgram, TransportTypeUnixPacket, transportTypeEmpty: *tt = typ return nil default: return fmt.Errorf("unsupported transport type %q", typ) } } // DialerConfig contains options for connecting to an address. type DialerConfig struct { // Timeout is the maximum amount of time a dial will wait for // a connect to complete. The default is no timeout. Timeout time.Duration `mapstructure:"timeout,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultDialerConfig creates a new DialerConfig with any default values set func NewDefaultDialerConfig() DialerConfig { return DialerConfig{} } // AddrConfig represents a network endpoint address. type AddrConfig struct { // Endpoint configures the address for this network connection. // For TCP and UDP networks, the address has the form "host:port". The host must be a literal IP address, // or a host name that can be resolved to IP addresses. The port must be a literal port number or a service name. // If the host is a literal IPv6 address it must be enclosed in square brackets, as in "[2001:db8::1]:80" or // "[fe80::1%zone]:80". The zone specifies the scope of the literal IPv6 address as defined in RFC 4007. Endpoint string `mapstructure:"endpoint,omitempty"` // Transport to use. Allowed protocols are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only), // "udp6" (IPv6-only), "ip", "ip4" (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket". Transport TransportType `mapstructure:"transport,omitempty"` // DialerConfig contains options for connecting to an address. DialerConfig DialerConfig `mapstructure:"dialer,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultAddrConfig creates a new AddrConfig with any default values set func NewDefaultAddrConfig() AddrConfig { return AddrConfig{ DialerConfig: NewDefaultDialerConfig(), } } // Dial equivalent with net.Dialer's DialContext for this address. func (na *AddrConfig) Dial(ctx context.Context) (net.Conn, error) { d := net.Dialer{Timeout: na.DialerConfig.Timeout} return d.DialContext(ctx, string(na.Transport), na.Endpoint) } // Listen equivalent with net.ListenConfig's Listen for this address. func (na *AddrConfig) Listen(ctx context.Context) (net.Listener, error) { lc := net.ListenConfig{} return lc.Listen(ctx, string(na.Transport), na.Endpoint) } func (na *AddrConfig) Validate() error { switch na.Transport { case TransportTypeTCP, TransportTypeTCP4, TransportTypeTCP6, TransportTypeUDP, TransportTypeUDP4, TransportTypeUDP6, TransportTypeIP, TransportTypeIP4, TransportTypeIP6, TransportTypeUnix, TransportTypeUnixgram, TransportTypeUnixPacket: return nil default: return fmt.Errorf("invalid transport type %q", na.Transport) } } // TCPAddrConfig represents a TCP endpoint address. type TCPAddrConfig struct { // Endpoint configures the address for this network connection. // The address has the form "host:port". The host must be a literal IP address, or a host name that can be // resolved to IP addresses. The port must be a literal port number or a service name. // If the host is a literal IPv6 address it must be enclosed in square brackets, as in "[2001:db8::1]:80" or // "[fe80::1%zone]:80". The zone specifies the scope of the literal IPv6 address as defined in RFC 4007. Endpoint string `mapstructure:"endpoint,omitempty"` // DialerConfig contains options for connecting to an address. DialerConfig DialerConfig `mapstructure:"dialer,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultTCPAddrConfig creates a new TCPAddrConfig with any default values set func NewDefaultTCPAddrConfig() TCPAddrConfig { return TCPAddrConfig{ DialerConfig: NewDefaultDialerConfig(), } } // Dial equivalent with net.Dialer's DialContext for this address. func (na *TCPAddrConfig) Dial(ctx context.Context) (net.Conn, error) { d := net.Dialer{Timeout: na.DialerConfig.Timeout} return d.DialContext(ctx, string(TransportTypeTCP), na.Endpoint) } // Listen equivalent with net.ListenConfig's Listen for this address. func (na *TCPAddrConfig) Listen(ctx context.Context) (net.Listener, error) { lc := net.ListenConfig{} return lc.Listen(ctx, string(TransportTypeTCP), na.Endpoint) } opentelemetry-collector-0.141.0/config/confignet/confignet_test.go000066400000000000000000000071021511331344600253210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confignet import ( "context" "errors" "net" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewDefaultDialerConfig(t *testing.T) { expectedDialerConfig := DialerConfig{} dialerConfig := NewDefaultDialerConfig() require.Equal(t, expectedDialerConfig, dialerConfig) } func TestNewDefaultAddrConfig(t *testing.T) { expectedAddrConfig := AddrConfig{} addrConfig := NewDefaultAddrConfig() require.Equal(t, expectedAddrConfig, addrConfig) } func TestNewDefaultTCPAddrConfig(t *testing.T) { expectedTCPAddrConfig := TCPAddrConfig{} tcpAddrconfig := NewDefaultTCPAddrConfig() require.Equal(t, expectedTCPAddrConfig, tcpAddrconfig) } func TestAddrConfigTimeout(t *testing.T) { nac := &AddrConfig{ Endpoint: "localhost:0", Transport: TransportTypeTCP, DialerConfig: DialerConfig{ Timeout: -1 * time.Second, }, } _, err := nac.Dial(context.Background()) require.Error(t, err) var netErr net.Error if errors.As(err, &netErr) { assert.True(t, netErr.Timeout()) } else { assert.Fail(t, "error should be a net.Error") } } func TestTCPAddrConfigTimeout(t *testing.T) { nac := &TCPAddrConfig{ Endpoint: "localhost:0", DialerConfig: DialerConfig{ Timeout: -1 * time.Second, }, } _, err := nac.Dial(context.Background()) require.Error(t, err) var netErr net.Error if errors.As(err, &netErr) { assert.True(t, netErr.Timeout()) } else { assert.Fail(t, "error should be a net.Error") } } func TestAddrConfig(t *testing.T) { nas := &AddrConfig{ Endpoint: "localhost:0", Transport: TransportTypeTCP, } ln, err := nas.Listen(context.Background()) require.NoError(t, err) done := make(chan bool, 1) go func() { conn, errGo := ln.Accept() assert.NoError(t, errGo) buf := make([]byte, 10) var numChr int numChr, errGo = conn.Read(buf) assert.NoError(t, errGo) assert.Equal(t, "test", string(buf[:numChr])) assert.NoError(t, conn.Close()) done <- true }() nac := &AddrConfig{ Endpoint: ln.Addr().String(), Transport: TransportTypeTCP, } var conn net.Conn conn, err = nac.Dial(context.Background()) require.NoError(t, err) _, err = conn.Write([]byte("test")) assert.NoError(t, err) assert.NoError(t, conn.Close()) <-done assert.NoError(t, ln.Close()) } func Test_NetAddr_Validate(t *testing.T) { na := &AddrConfig{ Transport: TransportTypeTCP, } require.NoError(t, na.Validate()) na = &AddrConfig{ Transport: transportTypeEmpty, } require.Error(t, na.Validate()) na = &AddrConfig{ Transport: "random string", } assert.Error(t, na.Validate()) } func TestTCPAddrConfig(t *testing.T) { nas := &TCPAddrConfig{ Endpoint: "localhost:0", } ln, err := nas.Listen(context.Background()) require.NoError(t, err) done := make(chan bool, 1) go func() { conn, errGo := ln.Accept() assert.NoError(t, errGo) buf := make([]byte, 10) var numChr int numChr, errGo = conn.Read(buf) assert.NoError(t, errGo) assert.Equal(t, "test", string(buf[:numChr])) assert.NoError(t, conn.Close()) done <- true }() nac := &TCPAddrConfig{ Endpoint: ln.Addr().String(), } var conn net.Conn conn, err = nac.Dial(context.Background()) require.NoError(t, err) _, err = conn.Write([]byte("test")) assert.NoError(t, err) assert.NoError(t, conn.Close()) <-done assert.NoError(t, ln.Close()) } func Test_TransportType_UnmarshalText(t *testing.T) { var tt TransportType err := tt.UnmarshalText([]byte("tcp")) require.NoError(t, err) err = tt.UnmarshalText([]byte("invalid")) require.Error(t, err) } opentelemetry-collector-0.141.0/config/confignet/doc.go000066400000000000000000000004231511331344600230520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package confignet implements the configuration settings for protocols to // connect and transport data information. package confignet // import "go.opentelemetry.io/collector/config/confignet" opentelemetry-collector-0.141.0/config/confignet/go.mod000066400000000000000000000007011511331344600230630ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/confignet go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/config/confignet/go.sum000066400000000000000000000041771511331344600231230ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/confignet/metadata.yaml000066400000000000000000000002021511331344600244150ustar00rootroot00000000000000type: config/confignet github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/confignet/package_test.go000066400000000000000000000003121511331344600247340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confignet import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configopaque/000077500000000000000000000000001511331344600224635ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configopaque/Makefile000066400000000000000000000000361511331344600241220ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configopaque/doc.go000066400000000000000000000021051511331344600235550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package configopaque implements a String type alias to mask sensitive information. // Use configopaque.String on the type of sensitive fields, to mask the // opaque string as `[REDACTED]`. // // This ensures that no sensitive information is leaked in logs or when printing the // full Collector configurations. // // The only way to view the value stored in a configopaque.String is to first convert // it to a string by casting with the builtin `string` function. // // To achieve this, configopaque.String implements standard library interfaces // like fmt.Stringer, encoding.TextMarshaler and others to ensure that the // underlying value is masked when printed or serialized. // // If new interfaces that would leak opaque values are added to the standard library // or become widely used in the Go ecosystem, these will eventually be implemented // by configopaque.String as well. This is not considered a breaking change. package configopaque // import "go.opentelemetry.io/collector/config/configopaque" opentelemetry-collector-0.141.0/config/configopaque/doc_test.go000066400000000000000000000040531511331344600246200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configopaque_test import ( "encoding/json" "fmt" yaml "go.yaml.in/yaml/v3" "go.opentelemetry.io/collector/config/configopaque" ) func Example_opaqueString() { rawBytes := []byte(`{ "Censored": "sensitive", "Uncensored": "not sensitive" }`) // JSON unmarshaling var cfg ExampleConfigString err := json.Unmarshal(rawBytes, &cfg) if err != nil { panic(err) } // YAML marshaling bytes, err := yaml.Marshal(cfg) if err != nil { panic(err) } fmt.Printf("encoded cfg (YAML) is:\n%s\n\n", string(bytes)) // Output: encoded cfg (YAML) is: // censored: '[REDACTED]' // uncensored: not sensitive } type ExampleConfigString struct { Censored configopaque.String Uncensored string } func Example_opaqueSlice() { cfg := &ExampleConfigSlice{ Censored: []configopaque.String{"data", "is", "sensitive"}, Uncensored: []string{"data", "is", "not", "sensitive"}, } // JSON marshaling bytes, err := json.MarshalIndent(cfg, "", " ") if err != nil { panic(err) } fmt.Printf("encoded cfg (JSON) is\n%s\n\n", string(bytes)) // Output: encoded cfg (JSON) is // { // "Censored": [ // "[REDACTED]", // "[REDACTED]", // "[REDACTED]" // ], // "Uncensored": [ // "data", // "is", // "not", // "sensitive" // ] // } } type ExampleConfigSlice struct { Censored []configopaque.String Uncensored []string } func Example_opaqueMap() { cfg := &ExampleConfigMap{ Censored: map[string]configopaque.String{ "token": "sensitivetoken", }, Uncensored: map[string]string{ "key": "cloud.zone", "value": "zone-1", }, } // yaml marshaling bytes, err := yaml.Marshal(cfg) if err != nil { panic(err) } fmt.Printf("encoded cfg (YAML) is:\n%s\n\n", string(bytes)) // Output: encoded cfg (YAML) is: // censored: // token: '[REDACTED]' // uncensored: // key: cloud.zone // value: zone-1 } type ExampleConfigMap struct { Censored map[string]configopaque.String Uncensored map[string]string } opentelemetry-collector-0.141.0/config/configopaque/go.mod000066400000000000000000000024011511331344600235660ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configopaque go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.uber.org/goleak v1.3.0 go.yaml.in/yaml/v3 v3.0.4 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/config/configopaque/go.sum000066400000000000000000000067421511331344600236270ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configopaque/maplist.go000066400000000000000000000061001511331344600244600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configopaque // import "go.opentelemetry.io/collector/config/configopaque" import ( "cmp" "fmt" "iter" "slices" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/xconfmap" ) // Pair is an element of a MapList, and consists of a name and an opaque value. type Pair struct { Name string `mapstructure:"name"` Value String `mapstructure:"value"` // prevent unkeyed literal initialization _ struct{} } // MapList is a replacement for map[string]configopaque.String with a similar API, // which can also be unmarshalled from (and is stored as) a list of name/value pairs. // // Pairs are assumed to have distinct names. This is checked during config validation. type MapList []Pair var _ confmap.Unmarshaler = (*MapList)(nil) // Unmarshal is called by the Collector when unmarshalling from a map. // When the input config is a slice, this will be skipped, // and mapstructure's default unmarshalling logic will be used. func (ml *MapList) Unmarshal(conf *confmap.Conf) error { var m2 map[string]String if err := conf.Unmarshal(&m2); err != nil { return err } *ml = make(MapList, 0, len(m2)) for name, value := range m2 { *ml = append(*ml, Pair{ Name: name, Value: value, }) } slices.SortFunc(*ml, func(p1, p2 Pair) int { return cmp.Compare(p1.Name, p2.Name) }) return nil } var _ xconfmap.Validator = MapList(nil) func (ml MapList) Validate() error { // Check for duplicate keys counts := make(map[string]int, len(ml)) for _, OpaquePair := range ml { counts[OpaquePair.Name]++ } if len(counts) == len(ml) { return nil } var duplicates []string for name, cnt := range counts { if cnt > 1 { duplicates = append(duplicates, name) } } slices.Sort(duplicates) return fmt.Errorf("duplicate keys in map-style list: %v", duplicates) } var _ iter.Seq2[string, String] = MapList(nil).Iter // Iter is an iterator over key/value pairs for use in for-range loops. // It is the MapList equivalent of directly ranging over a map. func (ml MapList) Iter(yield func(name string, value String) bool) { for _, OpaquePair := range ml { if !yield(OpaquePair.Name, OpaquePair.Value) { break } } } // Get looks up a pair's value based on its name. // It is the MapList equivalent of `val, ok := m[key]`. // However, it has linear time complexity. func (ml MapList) Get(name string) (val String, ok bool) { for _, OpaquePair := range ml { if OpaquePair.Name == name { return OpaquePair.Value, true } } return val, false } // Set sets the value corresponding to a given name. // It is the MapList equivalent of `m[key] = val`. // However, it has linear time complexity, // and does not affect shallow copies. func (ml *MapList) Set(name string, val String) { if ml == nil { panic("assignment to entry in nil *MapList") } for i, OpaquePair := range *ml { if OpaquePair.Name == name { *ml = slices.Clone(*ml) (*ml)[i].Value = val return } } *ml = append(make(MapList, 0, len(*ml)+1), *ml...) *ml = append(*ml, Pair{Name: name, Value: val}) } opentelemetry-collector-0.141.0/config/configopaque/maplist_test.go000066400000000000000000000071611511331344600255270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configopaque_test import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/xconfmap" ) const headersList = ` headers: - name: "a" value: "b" - name: "c" value: "d" ` const headersMap = ` headers: "a": "b" "c": "d" ` const headersBad1 = ` headers: "bad": 1 ` const headersBad2 = ` headers: "foo" ` const headersDupe = ` headers: - name: "foo" value: "bar" - name: "foo" value: "baz" ` type testConfig struct { Headers configopaque.MapList `mapstructure:"headers"` } func TestMapListDuality(t *testing.T) { retrieved1, err := confmap.NewRetrievedFromYAML([]byte(headersList)) require.NoError(t, err) conf1, err := retrieved1.AsConf() require.NoError(t, err) var tc1 testConfig require.NoError(t, conf1.Unmarshal(&tc1)) assert.NoError(t, xconfmap.Validate(&tc1)) retrieved2, err := confmap.NewRetrievedFromYAML([]byte(headersMap)) require.NoError(t, err) conf2, err := retrieved2.AsConf() require.NoError(t, err) var tc2 testConfig require.NoError(t, conf2.Unmarshal(&tc2)) assert.NoError(t, xconfmap.Validate(&tc2)) assert.Equal(t, tc1, tc2) } func TestMapListUnmarshalError(t *testing.T) { var tc testConfig retrieved, err := confmap.NewRetrievedFromYAML([]byte(headersBad1)) require.NoError(t, err) conf, err := retrieved.AsConf() require.NoError(t, err) require.EqualError(t, conf.Unmarshal(&tc), "decoding failed due to the following error(s):\n\n"+ "'headers' decoding failed due to the following error(s):\n\n"+ "'[bad]' expected type 'configopaque.String', got unconvertible type 'int'") retrieved, err = confmap.NewRetrievedFromYAML([]byte(headersBad2)) require.NoError(t, err) conf, err = retrieved.AsConf() require.NoError(t, err) // Not sure if there is a way to change the error message to include the map case? require.EqualError(t, conf.Unmarshal(&tc), "decoding failed due to the following error(s):\n\n"+ "'headers' source data must be an array or slice, got string") } func TestMapListValidate(t *testing.T) { retrieved, err := confmap.NewRetrievedFromYAML([]byte(headersDupe)) require.NoError(t, err) conf, err := retrieved.AsConf() require.NoError(t, err) var tc testConfig require.NoError(t, conf.Unmarshal(&tc)) require.EqualError(t, xconfmap.Validate(&tc), `headers: duplicate keys in map-style list: [foo]`) } func TestMapListMethods(t *testing.T) { ml := configopaque.MapList{ {Name: "a", Value: "1"}, {Name: "b", Value: "2"}, {Name: "c", Value: "3"}, } type pair = struct { k string v configopaque.String } var kvs []pair for k, v := range ml.Iter { kvs = append(kvs, pair{k, v}) if k == "b" { break } } assert.Equal(t, []pair{{"a", "1"}, {"b", "2"}}, kvs) v, ok := ml.Get("a") assert.True(t, ok) if ok { assert.Equal(t, configopaque.String("1"), v) } v, ok = ml.Get("d") assert.False(t, ok) assert.Zero(t, v) ml2 := ml assert.Len(t, ml2, 3) // Set existing key ml2.Set("c", "4") assert.Len(t, ml, 3) assert.Len(t, ml2, 3) v, _ = ml.Get("c") assert.Equal(t, configopaque.String("3"), v) v, _ = ml2.Get("c") assert.Equal(t, configopaque.String("4"), v) // Set new key ml2.Set("d", "5") assert.Len(t, ml, 3) assert.Len(t, ml2, 4) _, ok = ml.Get("d") assert.False(t, ok) v, ok = ml2.Get("d") assert.True(t, ok) assert.Equal(t, configopaque.String("5"), v) } func TestMapListNil(t *testing.T) { var ml *configopaque.MapList assert.Panics(t, func() { ml.Set("a", "0") }) } opentelemetry-collector-0.141.0/config/configopaque/metadata.yaml000066400000000000000000000002051511331344600251240ustar00rootroot00000000000000type: config/configopaque github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configopaque/opaque.go000066400000000000000000000016741511331344600243140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configopaque // import "go.opentelemetry.io/collector/config/configopaque" import ( "fmt" ) // String alias that is marshaled and printed in an opaque way. // To recover the original value, cast it to a string. type String string const maskedString = "[REDACTED]" // MarshalText marshals the string as `[REDACTED]`. func (s String) MarshalText() ([]byte, error) { return []byte(maskedString), nil } // String formats the string as `[REDACTED]`. // This is used for the %s and %q verbs. func (s String) String() string { return maskedString } // GoString formats the string as `[REDACTED]`. // This is used for the %#v verb. func (s String) GoString() string { return fmt.Sprintf("%#v", maskedString) } // MarshalBinary marshals the string `[REDACTED]` as []byte. func (s String) MarshalBinary() (text []byte, err error) { return []byte(maskedString), nil } opentelemetry-collector-0.141.0/config/configopaque/opaque_test.go000066400000000000000000000045601511331344600253500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configopaque // import "go.opentelemetry.io/collector/config/configopaque" import ( "encoding" "encoding/hex" "encoding/json" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var _ encoding.TextMarshaler = String("") var _ fmt.Stringer = String("") var _ fmt.GoStringer = String("") var _ encoding.BinaryMarshaler = String("") func TestStringMarshalText(t *testing.T) { examples := []String{"opaque", "s", "veryveryveryveryveryveryveryveryveryverylong"} for _, example := range examples { opaque, err := example.MarshalText() require.NoError(t, err) assert.Equal(t, maskedString, string(opaque)) } } type TestStruct struct { Opaque String `json:"opaque" yaml:"opaque"` Plain string `json:"plain" yaml:"plain"` } var example = TestStruct{ Opaque: "opaque", Plain: "plain", } func TestStringJSON(t *testing.T) { bytes, err := json.Marshal(example) require.NoError(t, err) assert.JSONEq(t, `{"opaque":"[REDACTED]","plain":"plain"}`, string(bytes)) } func TestStringFmt(t *testing.T) { examples := []String{"opaque", "s", "veryveryveryveryveryveryveryveryveryverylong"} verbs := []string{"%s", "%q", "%v", "%#v", "%+v", "%x"} for _, example := range examples { for _, verb := range verbs { t.Run(fmt.Sprintf("%s/%s", string(example), verb), func(t *testing.T) { assert.Equal(t, fmt.Sprintf(verb, maskedString), fmt.Sprintf(verb, example), ) }) } for _, verb := range verbs { t.Run(fmt.Sprintf("string(%s)/%s", string(example), verb), func(t *testing.T) { // converting to a string allows to output as an unredacted string still: var expected string switch verb { case "%s", "%v", "%+v": expected = string(example) case "%q", "%#v": expected = "\"" + string(example) + "\"" case "%x": expected = hex.EncodeToString([]byte(example)) default: t.Errorf("unexpected verb %q", verb) } assert.Equal(t, expected, fmt.Sprintf(verb, string(example)), ) }) } } } func TestStringMarshalBinary(t *testing.T) { examples := []String{"opaque", "s", "veryveryveryveryveryveryveryveryveryverylong"} for _, example := range examples { opaque, err := example.MarshalBinary() require.NoError(t, err) assert.Equal(t, []byte("[REDACTED]"), opaque) } } opentelemetry-collector-0.141.0/config/configopaque/package_test.go000066400000000000000000000003151511331344600254430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configopaque import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configoptional/000077500000000000000000000000001511331344600230165ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configoptional/Makefile000066400000000000000000000000361511331344600244550ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configoptional/go.mod000066400000000000000000000024031511331344600241230ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configoptional go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/config/configoptional/go.sum000066400000000000000000000067421511331344600241620ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configoptional/metadata.yaml000066400000000000000000000002071511331344600254610ustar00rootroot00000000000000type: config/configoptional github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configoptional/optional.go000066400000000000000000000215411511331344600251750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configoptional // import "go.opentelemetry.io/collector/config/configoptional" import ( "errors" "fmt" "reflect" "strings" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/featuregate" ) type flavor int const ( noneFlavor flavor = 0 defaultFlavor flavor = 1 someFlavor flavor = 2 ) // Optional represents a value that may or may not be present. // It supports two flavors for all types: Some(value) and None. // It supports a third flavor for struct types: Default(defaultVal). // // For struct types, it supports unmarshaling from a configuration source. // For struct types, it supports an 'enabled' field to explicitly disable a section. // The zero value of Optional is None. type Optional[T any] struct { // value is the value of the Optional. value T // flavor indicates the flavor of the Optional. // The zero value of flavor is noneFlavor. flavor flavor } // deref a reflect.Type to its underlying type. func deref(t reflect.Type) reflect.Type { for t.Kind() == reflect.Ptr { t = t.Elem() } return t } // assertStructKind checks if T can be dereferenced into a type with struct kind. // // We assert this because our unmarshaling logic currently only supports structs. // This can be removed if we ever support scalar values. func assertStructKind[T any]() error { var instance T t := deref(reflect.TypeOf(instance)) if t.Kind() != reflect.Struct { return fmt.Errorf("configoptional: %q does not have a struct kind", t) } return nil } // assertNoEnabledField checks that a struct type // does not have a field with a mapstructure tag "enabled". // // We assert this because we discussed an alternative design where we have an explicit // "enabled" field in the struct to indicate if the struct is enabled or not. // See https://github.com/open-telemetry/opentelemetry-collector/pull/13060. // This can be removed if we ever support such a design (or if we just want to allow // the "enabled" field in the struct). func assertNoEnabledField[T any]() error { var i T t := deref(reflect.TypeOf(i)) if t.Kind() != reflect.Struct { // Not a struct, no need to check for "enabled" field. return nil } // Check if the struct has a field with the name "enabled". for i := 0; i < t.NumField(); i++ { field := t.Field(i) mapstructureTags := strings.SplitN(field.Tag.Get("mapstructure"), ",", 2) if len(mapstructureTags) > 0 && mapstructureTags[0] == "enabled" { return errors.New("configoptional: underlying type cannot have a field with mapstructure tag 'enabled'") } } return nil } // Some creates an Optional with a value and no factory. // // It panics if T has a field with the mapstructure tag "enabled". func Some[T any](value T) Optional[T] { if err := assertNoEnabledField[T](); err != nil { panic(err) } return Optional[T]{value: value, flavor: someFlavor} } // Default creates an Optional with a default value for unmarshaling. // // It panics if // - T is not a struct OR // - T has a field with the mapstructure tag "enabled". func Default[T any](value T) Optional[T] { err := errors.Join(assertStructKind[T](), assertNoEnabledField[T]()) if err != nil { panic(err) } return Optional[T]{value: value, flavor: defaultFlavor} } // None has no value. It has the same behavior as a nil pointer when unmarshaling. // // The zero value of Optional[T] is None[T]. Prefer using this constructor // for validation. // // It panics if T has a field with the mapstructure tag "enabled". func None[T any]() Optional[T] { if err := assertNoEnabledField[T](); err != nil { panic(err) } return Optional[T]{} } // HasValue checks if the Optional has a value. func (o Optional[T]) HasValue() bool { return o.flavor == someFlavor } // Get returns the value of the Optional. // If the value is not present, it returns nil. func (o *Optional[T]) Get() *T { if !o.HasValue() { return nil } return &o.value } // GetOrInsertDefault makes the Optional into a Some(val) and returns val. // // In particular, if it is Default(val) it turns it into Some(val) // and if it is None[T]() it turns it into Some(zeroVal) where zeroVal is T's zero value. // This method is useful for programmatic usage of an optional. // // It panics if // - T is not a struct OR // - T has a field with the mapstructure tag "enabled". func (o *Optional[T]) GetOrInsertDefault() *T { err := errors.Join(assertStructKind[T](), assertNoEnabledField[T]()) if err != nil { panic(err) } if o.HasValue() { return o.Get() } empty := confmap.NewFromStringMap(map[string]any{}) if err := empty.Unmarshal(o); err != nil { // This should never happen, if it happens it is a bug, so this panic is not documented. panic(fmt.Errorf("failed to unmarshal empty map into %T type: %w. Please report this bug", o.value, err)) } return o.Get() } var _ confmap.Unmarshaler = (*Optional[any])(nil) var ( addEnabledFieldFeatureGateID = "configoptional.AddEnabledField" addEnabledFieldFeatureGate = featuregate.GlobalRegistry().MustRegister( addEnabledFieldFeatureGateID, featuregate.StageBeta, featuregate.WithRegisterFromVersion("v0.138.0"), featuregate.WithRegisterDescription("Allows optional fields to be toggled via an 'enabled' field."), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/issues/14021"), ) ) // Unmarshal the configuration into the Optional value. // // The behavior of this method depends on the state of the Optional: // - None[T]: does nothing if the configuration is nil, otherwise it unmarshals into the zero value of T. // - Some[T](val): equivalent to unmarshaling into a field of type T with value val. // - Default[T](val), equivalent to unmarshaling into a field of type T with base value val, // using val without overrides from the configuration if the configuration is nil. // // (Under the `configoptional.AddEnabledField` feature gate) // If the configuration contains an 'enabled' field: // - if enabled is true: the Optional becomes Some after unmarshaling. // - if enabled is false: the Optional becomes None regardless of other configuration values. // // T must be derefenceable to a type with struct kind and not have an 'enabled' field. // Scalar values are not supported. func (o *Optional[T]) Unmarshal(conf *confmap.Conf) error { if err := assertNoEnabledField[T](); err != nil { return err } if o.flavor == noneFlavor && conf.ToStringMap() == nil { // If the Optional is None and the configuration is nil, we do nothing. // This replicates the behavior of unmarshaling into a field with a nil pointer. return nil } isEnabled := true if addEnabledFieldFeatureGate.IsEnabled() && conf.IsSet("enabled") { enabled := conf.Get("enabled") conf.Delete("enabled") var ok bool if isEnabled, ok = enabled.(bool); !ok { return fmt.Errorf("unexpected type %T for 'enabled': got '%v' value expected 'true' or 'false'", enabled, enabled) } } if err := conf.Unmarshal(&o.value); err != nil { return err } if isEnabled { o.flavor = someFlavor } else { o.flavor = noneFlavor // override o.value with zero value. var zero T o.value = zero } return nil } var _ confmap.Marshaler = (*Optional[any])(nil) // Marshal the Optional value into the configuration. // If the Optional is None or Default, it does not marshal anything. // If the Optional is Some, it marshals the value into the configuration. // // T must be derefenceable to a type with struct kind. // Scalar values are not supported. func (o Optional[T]) Marshal(conf *confmap.Conf) error { if err := assertStructKind[T](); err != nil { return err } if o.flavor == noneFlavor || o.flavor == defaultFlavor { // Optional is None or Default, do not marshal anything. return conf.Marshal(map[string]any(nil)) } if err := conf.Marshal(o.value); err != nil { return fmt.Errorf("configoptional: failed to marshal Optional value: %w", err) } return nil } var _ xconfmap.Validator = (*Optional[any])(nil) // Validate implements [xconfmap.Validator]. This is required because the // private fields in [xconfmap.Validator] can't be seen by the reflection used // by [xconfmap.Validate], and therefore we have to continue the validation // chain manually. This method isn't meant to be called directly, and should // generally only be called by [xconfmap.Validate]. func (o *Optional[T]) Validate() error { // When the flavor is None, the user has not passed this value, // and therefore we should not validate it. The parent struct holding // the Optional type can determine whether a None value is valid for // a given config. // // If the flavor is still Default, then the user has not passed this // value and we should also not validate it. if o.flavor == noneFlavor || o.flavor == defaultFlavor { return nil } // For the some flavor, validate the actual value. return xconfmap.Validate(o.value) } opentelemetry-collector-0.141.0/config/configoptional/optional_test.go000066400000000000000000000453441511331344600262430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configoptional import ( "errors" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/featuregate" ) type Config[T any] struct { Sub1 Optional[T] `mapstructure:"sub"` } type Sub struct { Foo string `mapstructure:"foo"` } type WithEnabled struct { Enabled bool `mapstructure:"enabled"` } type WithEnabledOmitEmpty struct { Enabled bool `mapstructure:"enabled,omitempty"` } type OmitEmpty struct { Foo int `mapstructure:",omitempty"` } type NoMapstructure struct { Foo string } var subDefault = Sub{ Foo: "foobar", } func ptr[T any](v T) *T { return &v } func TestDefaultPanics(t *testing.T) { assert.Panics(t, func() { _ = Default(1) }) assert.Panics(t, func() { _ = Default(ptr(1)) }) assert.Panics(t, func() { _ = Default(WithEnabled{}) }) assert.Panics(t, func() { _ = Default(WithEnabledOmitEmpty{}) }) assert.Panics(t, func() { _ = Some(WithEnabled{}) }) assert.Panics(t, func() { _ = None[WithEnabled]() }) assert.Panics(t, func() { opt := None[int]() _ = opt.GetOrInsertDefault() }) assert.Panics(t, func() { var opt Optional[WithEnabled] _ = opt.GetOrInsertDefault() }) assert.NotPanics(t, func() { _ = Default(NoMapstructure{}) }) assert.NotPanics(t, func() { _ = Default(OmitEmpty{}) }) assert.NotPanics(t, func() { _ = Default(subDefault) }) assert.NotPanics(t, func() { _ = Default(ptr(subDefault)) }) } func TestEqualityDefault(t *testing.T) { defaultOne := Default(subDefault) defaultTwo := Default(subDefault) assert.Equal(t, defaultOne, defaultTwo) } func TestNoneZeroVal(t *testing.T) { var none Optional[Sub] require.False(t, none.HasValue()) require.Nil(t, none.Get()) var zeroVal Sub ret := none.GetOrInsertDefault() require.True(t, none.HasValue()) assert.Equal(t, &zeroVal, ret) } func TestNone(t *testing.T) { none := None[Sub]() require.False(t, none.HasValue()) require.Nil(t, none.Get()) var zeroVal Sub ret := none.GetOrInsertDefault() require.True(t, none.HasValue()) assert.Equal(t, &zeroVal, ret) } func ExampleNone() { type Person struct { Name string Age int } opt := None[Person]() // A None has no value. fmt.Println(opt.HasValue()) fmt.Println(opt.Get()) // GetOrInsertDefault places the zero value // and returns it, allowing you to modify it. opt.GetOrInsertDefault().Name = "John Doe" fmt.Println(opt.HasValue()) fmt.Println(opt.Get()) // Output: // false // // true // &{John Doe 0} } func TestSome(t *testing.T) { some := Some(Sub{ Foo: "foobar", }) require.True(t, some.HasValue()) retGet := some.Get() assert.Equal(t, "foobar", retGet.Foo) retGetOrInsertDefault := some.GetOrInsertDefault() require.True(t, some.HasValue()) assert.Equal(t, retGet, retGetOrInsertDefault) } func ExampleSome() { type Person struct { Name string Age int } opt := Some(Person{ Name: "John Doe", Age: 42, }) // A Some has a value. fmt.Println(opt.HasValue()) fmt.Println(opt.Get()) // GetOrInsertDefault only returns a reference // to the inner value without modifying it. opt.GetOrInsertDefault().Name = "Jane Doe" fmt.Println(opt.HasValue()) fmt.Println(opt.Get()) // Output: // true // &{John Doe 42} // true // &{Jane Doe 42} } func TestDefault(t *testing.T) { defaultSub := Default(subDefault) require.False(t, defaultSub.HasValue()) require.Nil(t, defaultSub.Get()) ret := defaultSub.GetOrInsertDefault() require.True(t, defaultSub.HasValue()) assert.Equal(t, &subDefault, ret) } func ExampleDefault() { type Person struct { Name string Age int } opt := Default(Person{ Name: "John Doe", Age: 42, }) // A Default has no value. fmt.Println(opt.HasValue()) fmt.Println(opt.Get()) // GetOrInsertDefault places the default value // and returns it, allowing you to modify it. opt.GetOrInsertDefault().Age = 38 fmt.Println(opt.HasValue()) fmt.Println(opt.Get()) // Output: // false // // true // &{John Doe 38} } func TestUnmarshalOptional(t *testing.T) { tests := []struct { name string config map[string]any defaultCfg Config[Sub] expectedSub bool expectedFoo string }{ { name: "none_no_config", defaultCfg: Config[Sub]{ Sub1: None[Sub](), }, expectedSub: false, }, { name: "none_with_config", config: map[string]any{ "sub": map[string]any{ "foo": "bar", }, }, defaultCfg: Config[Sub]{ Sub1: None[Sub](), }, expectedSub: true, expectedFoo: "bar", // input overrides default }, { // nil is treated as an empty map because of the hooks we use. name: "none_with_config_no_foo", config: map[string]any{ "sub": nil, }, defaultCfg: Config[Sub]{ Sub1: None[Sub](), }, expectedSub: false, }, { name: "none_with_config_no_foo_empty_map", config: map[string]any{ "sub": map[string]any{}, }, defaultCfg: Config[Sub]{ Sub1: None[Sub](), }, expectedSub: true, expectedFoo: "", }, { name: "default_no_config", defaultCfg: Config[Sub]{ Sub1: Default(subDefault), }, expectedSub: false, }, { name: "default_with_config", config: map[string]any{ "sub": map[string]any{ "foo": "bar", }, }, defaultCfg: Config[Sub]{ Sub1: Default(subDefault), }, expectedSub: true, expectedFoo: "bar", // input overrides default }, { name: "default_with_config_no_foo", config: map[string]any{ "sub": nil, }, defaultCfg: Config[Sub]{ Sub1: Default(subDefault), }, expectedSub: true, expectedFoo: "foobar", // default applies }, { name: "default_with_config_no_foo_empty_map", config: map[string]any{ "sub": map[string]any{}, }, defaultCfg: Config[Sub]{ Sub1: Default(subDefault), }, expectedSub: true, expectedFoo: "foobar", // default applies }, { name: "some_no_config", defaultCfg: Config[Sub]{ Sub1: Some(Sub{ Foo: "foobar", }), }, expectedSub: true, expectedFoo: "foobar", // value is not modified }, { name: "some_with_config", config: map[string]any{ "sub": map[string]any{ "foo": "bar", }, }, defaultCfg: Config[Sub]{ Sub1: Some(Sub{ Foo: "foobar", }), }, expectedSub: true, expectedFoo: "bar", // input overrides previous value }, { name: "some_with_config_no_foo", config: map[string]any{ "sub": nil, }, defaultCfg: Config[Sub]{ Sub1: Some(Sub{ Foo: "foobar", }), }, expectedSub: true, expectedFoo: "foobar", // default applies }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { cfg := test.defaultCfg conf := confmap.NewFromStringMap(test.config) require.NoError(t, conf.Unmarshal(&cfg)) require.Equal(t, test.expectedSub, cfg.Sub1.HasValue()) if test.expectedSub { require.Equal(t, test.expectedFoo, cfg.Sub1.Get().Foo) } }) } } func TestAddFieldEnabledFeatureGate(t *testing.T) { tests := []struct { name string config map[string]any defaultCfg Config[Sub] expectedSub bool expectedFoo string }{ { name: "none_with_enabled_true", config: map[string]any{ "sub": map[string]any{ "enabled": true, "foo": "bar", }, }, defaultCfg: Config[Sub]{ Sub1: None[Sub](), }, expectedSub: true, expectedFoo: "bar", }, { name: "none_with_enabled_false", config: map[string]any{ "sub": map[string]any{ "enabled": false, "foo": "bar", }, }, defaultCfg: Config[Sub]{ Sub1: None[Sub](), }, expectedSub: false, }, { name: "none_with_enabled_false_no_other_config", config: map[string]any{ "sub": map[string]any{ "enabled": false, }, }, defaultCfg: Config[Sub]{ Sub1: None[Sub](), }, expectedSub: false, }, { name: "default_with_enabled_true", config: map[string]any{ "sub": map[string]any{ "enabled": true, "foo": "bar", }, }, defaultCfg: Config[Sub]{ Sub1: Default(subDefault), }, expectedSub: true, expectedFoo: "bar", }, { name: "default_with_enabled_false", config: map[string]any{ "sub": map[string]any{ "enabled": false, "foo": "bar", }, }, defaultCfg: Config[Sub]{ Sub1: Default(subDefault), }, expectedSub: false, }, { name: "default_with_enabled_false_no_other_config", config: map[string]any{ "sub": map[string]any{ "enabled": false, }, }, defaultCfg: Config[Sub]{ Sub1: Default(subDefault), }, expectedSub: false, }, { name: "some_with_enabled_true", config: map[string]any{ "sub": map[string]any{ "enabled": true, "foo": "baz", }, }, defaultCfg: Config[Sub]{ Sub1: Some(Sub{ Foo: "foobar", }), }, expectedSub: true, expectedFoo: "baz", }, { name: "some_with_enabled_false", config: map[string]any{ "sub": map[string]any{ "enabled": false, "foo": "baz", }, }, defaultCfg: Config[Sub]{ Sub1: Some(Sub{ Foo: "foobar", }), }, expectedSub: false, }, { name: "some_with_enabled_false_no_other_config", config: map[string]any{ "sub": map[string]any{ "enabled": false, }, }, defaultCfg: Config[Sub]{ Sub1: Some(Sub{ Foo: "foobar", }), }, expectedSub: false, }, } oldVal := addEnabledFieldFeatureGate.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(addEnabledFieldFeatureGateID, true)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(addEnabledFieldFeatureGateID, oldVal)) }() for _, test := range tests { t.Run(test.name, func(t *testing.T) { cfg := test.defaultCfg conf := confmap.NewFromStringMap(test.config) require.NoError(t, conf.Unmarshal(&cfg)) require.Equal(t, test.expectedSub, cfg.Sub1.HasValue()) if test.expectedSub { require.Equal(t, test.expectedFoo, cfg.Sub1.Get().Foo) } }) } } func TestEnabledFalseResetsValue(t *testing.T) { oldVal := addEnabledFieldFeatureGate.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(addEnabledFieldFeatureGateID, true)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(addEnabledFieldFeatureGateID, oldVal)) }() cfg := Config[Sub]{Sub1: Some(Sub{Foo: "initial"})} require.True(t, cfg.Sub1.HasValue()) cm := confmap.NewFromStringMap(map[string]any{ "sub": map[string]any{"enabled": false, "foo": "ignored"}, }) require.NoError(t, cm.Unmarshal(&cfg)) require.Equal(t, None[Sub](), cfg.Sub1) } func TestUnmarshalErrorEnabledInvalidType(t *testing.T) { oldVal := addEnabledFieldFeatureGate.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(addEnabledFieldFeatureGateID, true)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(addEnabledFieldFeatureGateID, oldVal)) }() cm := confmap.NewFromStringMap(map[string]any{ "sub": map[string]any{ "enabled": "something", "foo": "bar", }, }) cfg := Config[Sub]{ Sub1: None[Sub](), } err := cm.Unmarshal(&cfg) require.ErrorContains(t, err, "unexpected type string for 'enabled': got 'something' value expected 'true' or 'false'") } func TestUnmarshalErrorEnabledField(t *testing.T) { cm := confmap.NewFromStringMap(map[string]any{ "enabled": true, }) // Use zero value to avoid panic on constructor. var none Optional[WithEnabled] require.Error(t, cm.Unmarshal(&none)) } func TestUnmarshalConfigPointer(t *testing.T) { cm := confmap.NewFromStringMap(map[string]any{ "sub": map[string]any{ "foo": "bar", }, }) var cfg Config[*Sub] err := cm.Unmarshal(&cfg) require.NoError(t, err) assert.True(t, cfg.Sub1.HasValue()) assert.Equal(t, "bar", (*cfg.Sub1.Get()).Foo) } func TestUnmarshalErr(t *testing.T) { cm := confmap.NewFromStringMap(map[string]any{ "field": "value", }) cfg := Config[Sub]{ Sub1: Default(subDefault), } assert.False(t, cfg.Sub1.HasValue()) err := cm.Unmarshal(&cfg) require.Error(t, err) require.ErrorContains(t, err, "has invalid keys: field") assert.False(t, cfg.Sub1.HasValue()) } type MyIntConfig struct { Val int `mapstructure:"my_int"` } type MyConfig struct { Optional[MyIntConfig] `mapstructure:",squash"` } var myIntDefault = MyIntConfig{ Val: 1, } func TestSquashedOptional(t *testing.T) { cm := confmap.NewFromStringMap(map[string]any{ "my_int": 42, }) cfg := MyConfig{ Default(myIntDefault), } err := cm.Unmarshal(&cfg) require.NoError(t, err) assert.True(t, cfg.HasValue()) assert.Equal(t, 42, cfg.Get().Val) } func confFromYAML(t *testing.T, yaml string) *confmap.Conf { t.Helper() cm, err := confmap.NewRetrievedFromYAML([]byte(yaml)) require.NoError(t, err) conf, err := cm.AsConf() require.NoError(t, err) return conf } func TestComparePointerUnmarshal(t *testing.T) { tests := []struct { yaml string }{ {yaml: ""}, {yaml: "sub: "}, {yaml: "sub: null"}, {yaml: "sub: {}"}, {yaml: "sub: {foo: bar}"}, } for _, test := range tests { t.Run(test.yaml, func(t *testing.T) { var optCfg Config[Sub] conf := confFromYAML(t, test.yaml) optErr := conf.Unmarshal(&optCfg) require.NoError(t, optErr) var ptrCfg struct { Sub1 *Sub `mapstructure:"sub"` } ptrErr := conf.Unmarshal(&ptrCfg) require.NoError(t, ptrErr) assert.Equal(t, optCfg.Sub1.Get(), ptrCfg.Sub1) }) } } func TestOptionalMarshal(t *testing.T) { tests := []struct { name string value Config[Sub] expected map[string]any }{ { name: "none (zero value)", value: Config[Sub]{}, expected: map[string]any{"sub": nil}, }, { name: "none", value: Config[Sub]{Sub1: None[Sub]()}, expected: map[string]any{"sub": nil}, }, { name: "default", value: Config[Sub]{Sub1: Default(subDefault)}, expected: map[string]any{"sub": nil}, }, { name: "some", value: Config[Sub]{Sub1: Some(Sub{ Foo: "bar", })}, expected: map[string]any{ "sub": map[string]any{ "foo": "bar", }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { conf := confmap.New() require.NoError(t, conf.Marshal(test.value)) assert.Equal(t, test.expected, conf.ToStringMap()) }) } } func TestComparePointerMarshal(t *testing.T) { type Wrap[T any] struct { // Note: passes without requiring "squash". Sub1 T `mapstructure:"sub"` } type WrapOmitEmpty[T any] struct { // Note: passes without requiring "squash", except with Default-flavored Optional values. Sub1 T `mapstructure:"sub,omitempty"` } tests := []struct { pointer *Sub optional Optional[Sub] skipOmitEmpty bool }{ {pointer: nil, optional: None[Sub]()}, {pointer: nil, optional: Default(subDefault), skipOmitEmpty: true}, // does not work with omitempty {pointer: &Sub{Foo: "bar"}, optional: Some(Sub{Foo: "bar"})}, } for _, test := range tests { t.Run(fmt.Sprintf("%v vs %v", test.pointer, test.optional), func(t *testing.T) { wrapPointer := Wrap[*Sub]{Sub1: test.pointer} confPointer := confmap.NewFromStringMap(nil) require.NoError(t, confPointer.Marshal(wrapPointer)) wrapOptional := Wrap[Optional[Sub]]{Sub1: test.optional} confOptional := confmap.NewFromStringMap(nil) require.NoError(t, confOptional.Marshal(wrapOptional)) assert.Equal(t, confPointer.ToStringMap(), confOptional.ToStringMap()) }) if test.skipOmitEmpty { continue } t.Run(fmt.Sprintf("%v vs %v (omitempty)", test.pointer, test.optional), func(t *testing.T) { wrapPointer := WrapOmitEmpty[*Sub]{Sub1: test.pointer} confPointer := confmap.NewFromStringMap(nil) require.NoError(t, confPointer.Marshal(wrapPointer)) wrapOptional := WrapOmitEmpty[Optional[Sub]]{Sub1: test.optional} confOptional := confmap.NewFromStringMap(nil) require.NoError(t, confOptional.Marshal(wrapOptional)) assert.Equal(t, confPointer.ToStringMap(), confOptional.ToStringMap()) }) } } type invalid struct{} func (invalid) Validate() error { return errors.New("invalid") } var _ xconfmap.Validator = invalid{} type hasNested struct { CouldBe Optional[invalid] } func TestOptionalValidate(t *testing.T) { require.NoError(t, xconfmap.Validate(hasNested{ CouldBe: None[invalid](), })) require.NoError(t, xconfmap.Validate(hasNested{ CouldBe: Default(invalid{}), })) require.Error(t, xconfmap.Validate(hasNested{ CouldBe: Some(invalid{}), })) } type validatedConfig struct { Default Optional[optionalConfig] `mapstructure:"default"` Some Optional[someConfig] `mapstructure:"some"` } var _ xconfmap.Validator = (*optionalConfig)(nil) type optionalConfig struct { StringVal string `mapstructure:"string_val"` } func (n optionalConfig) Validate() error { if n.StringVal == "invalid" { return errors.New("field `string_val` cannot be set to `invalid`") } return nil } type someConfig struct { Nested Optional[optionalConfig] `mapstructure:"nested"` } func newDefaultValidatedConfig() validatedConfig { return validatedConfig{ Default: Default(optionalConfig{StringVal: "valid"}), } } func newInvalidDefaultConfig() validatedConfig { return validatedConfig{ Default: Default(optionalConfig{StringVal: "invalid"}), } } func TestOptionalFileValidate(t *testing.T) { cases := []struct { name string variant string cfg func() validatedConfig err error }{ { name: "valid default with just key set and no subfields", variant: "implicit", cfg: newDefaultValidatedConfig, }, { name: "valid default with keys set in default", variant: "explicit", cfg: newDefaultValidatedConfig, }, { name: "invalid config", variant: "invalid", cfg: newDefaultValidatedConfig, err: errors.New("default: field `string_val` cannot be set to `invalid`\nsome: nested: field `string_val` cannot be set to `invalid`"), }, { name: "invalid default throws an error", variant: "implicit", cfg: newInvalidDefaultConfig, err: errors.New("default: field `string_val` cannot be set to `invalid`"), }, { name: "invalid default does not throw an error when key is not set", variant: "no_default", cfg: newInvalidDefaultConfig, }, { name: "invalid default invalid default does not throw an error when the value is overridden", variant: "explicit", cfg: newInvalidDefaultConfig, }, } for _, tt := range cases { t.Run(tt.name, func(t *testing.T) { conf, err := confmaptest.LoadConf(fmt.Sprintf("testdata/validate_%s.yaml", tt.variant)) require.NoError(t, err) cfg := tt.cfg() err = conf.Unmarshal(&cfg) require.NoError(t, err) err = xconfmap.Validate(cfg) if tt.err == nil { require.NoError(t, err) } else { require.EqualError(t, err, tt.err.Error()) } }) } } opentelemetry-collector-0.141.0/config/configoptional/package_test.go000066400000000000000000000003171511331344600260000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configoptional import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configoptional/testdata/000077500000000000000000000000001511331344600246275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configoptional/testdata/validate_explicit.yaml000066400000000000000000000001031511331344600311770ustar00rootroot00000000000000default: string_val: valid some: nested: string_val: valid opentelemetry-collector-0.141.0/config/configoptional/testdata/validate_implicit.yaml000066400000000000000000000000601511331344600311720ustar00rootroot00000000000000default: some: nested: string_val: value1 opentelemetry-collector-0.141.0/config/configoptional/testdata/validate_invalid.yaml000066400000000000000000000001071511331344600310100ustar00rootroot00000000000000default: string_val: invalid some: nested: string_val: invalid opentelemetry-collector-0.141.0/config/configoptional/testdata/validate_no_default.yaml000066400000000000000000000000471511331344600315050ustar00rootroot00000000000000some: nested: string_val: value1 opentelemetry-collector-0.141.0/config/configretry/000077500000000000000000000000001511331344600223365ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configretry/Makefile000066400000000000000000000000361511331344600237750ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configretry/backoff.go000066400000000000000000000054051511331344600242640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configretry // import "go.opentelemetry.io/collector/config/configretry" import ( "errors" "time" "github.com/cenkalti/backoff/v5" ) // NewDefaultBackOffConfig returns the default settings for RetryConfig. func NewDefaultBackOffConfig() BackOffConfig { return BackOffConfig{ Enabled: true, InitialInterval: 5 * time.Second, RandomizationFactor: backoff.DefaultRandomizationFactor, Multiplier: backoff.DefaultMultiplier, MaxInterval: 30 * time.Second, MaxElapsedTime: 5 * time.Minute, } } // BackOffConfig defines configuration for retrying batches in case of export failure. // The current supported strategy is exponential backoff. type BackOffConfig struct { // Enabled indicates whether to not retry sending batches in case of export failure. Enabled bool `mapstructure:"enabled"` // InitialInterval the time to wait after the first failure before retrying. InitialInterval time.Duration `mapstructure:"initial_interval"` // RandomizationFactor is a random factor used to calculate next backoffs // Randomized interval = RetryInterval * (1 ยฑ RandomizationFactor) RandomizationFactor float64 `mapstructure:"randomization_factor"` // Multiplier is the value multiplied by the backoff interval bounds Multiplier float64 `mapstructure:"multiplier"` // MaxInterval is the upper bound on backoff interval. Once this value is reached the delay between // consecutive retries will always be `MaxInterval`. MaxInterval time.Duration `mapstructure:"max_interval"` // MaxElapsedTime is the maximum amount of time (including retries) spent trying to send a request/batch. // Once this value is reached, the data is discarded. If set to 0, the retries are never stopped. MaxElapsedTime time.Duration `mapstructure:"max_elapsed_time"` // prevent unkeyed literal initialization _ struct{} } func (bs *BackOffConfig) Validate() error { if !bs.Enabled { return nil } if bs.InitialInterval < 0 { return errors.New("'initial_interval' must be non-negative") } if bs.RandomizationFactor < 0 || bs.RandomizationFactor > 1 { return errors.New("'randomization_factor' must be within [0, 1]") } if bs.Multiplier < 0 { return errors.New("'multiplier' must be non-negative") } if bs.MaxInterval < 0 { return errors.New("'max_interval' must be non-negative") } if bs.MaxElapsedTime < 0 { return errors.New("'max_elapsed_time' must be non-negative") } if bs.MaxElapsedTime > 0 { if bs.MaxElapsedTime < bs.InitialInterval { return errors.New("'max_elapsed_time' must not be less than 'initial_interval'") } if bs.MaxElapsedTime < bs.MaxInterval { return errors.New("'max_elapsed_time' must not be less than 'max_interval'") } } return nil } opentelemetry-collector-0.141.0/config/configretry/backoff_test.go000066400000000000000000000046121511331344600253220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configretry import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewDefaultBackOffSettings(t *testing.T) { cfg := NewDefaultBackOffConfig() require.NoError(t, cfg.Validate()) assert.Equal(t, BackOffConfig{ Enabled: true, InitialInterval: 5 * time.Second, RandomizationFactor: 0.5, Multiplier: 1.5, MaxInterval: 30 * time.Second, MaxElapsedTime: 5 * time.Minute, }, cfg) } func TestInvalidInitialInterval(t *testing.T) { cfg := NewDefaultBackOffConfig() require.NoError(t, cfg.Validate()) cfg.InitialInterval = -1 assert.Error(t, cfg.Validate()) } func TestInvalidRandomizationFactor(t *testing.T) { cfg := NewDefaultBackOffConfig() require.NoError(t, cfg.Validate()) cfg.RandomizationFactor = -1 require.Error(t, cfg.Validate()) cfg.RandomizationFactor = 2 assert.Error(t, cfg.Validate()) } func TestInvalidMultiplier(t *testing.T) { cfg := NewDefaultBackOffConfig() require.NoError(t, cfg.Validate()) cfg.Multiplier = -1 assert.Error(t, cfg.Validate()) } func TestZeroMultiplierIsValid(t *testing.T) { cfg := NewDefaultBackOffConfig() assert.NoError(t, cfg.Validate()) cfg.Multiplier = 0 assert.NoError(t, cfg.Validate()) } func TestInvalidMaxInterval(t *testing.T) { cfg := NewDefaultBackOffConfig() require.NoError(t, cfg.Validate()) cfg.MaxInterval = -1 assert.Error(t, cfg.Validate()) } func TestInvalidMaxElapsedTime(t *testing.T) { cfg := NewDefaultBackOffConfig() require.NoError(t, cfg.Validate()) cfg.MaxElapsedTime = -1 require.Error(t, cfg.Validate()) cfg.MaxElapsedTime = 60 // MaxElapsedTime is 60, InitialInterval is 5s, so it should be invalid require.Error(t, cfg.Validate()) cfg.InitialInterval = 0 // MaxElapsedTime is 60, MaxInterval is 30s, so it should be invalid require.Error(t, cfg.Validate()) cfg.MaxInterval = 0 assert.NoError(t, cfg.Validate()) cfg.InitialInterval = 50 // MaxElapsedTime is 0, so it should be valid cfg.MaxElapsedTime = 0 assert.NoError(t, cfg.Validate()) } func TestDisabledWithInvalidValues(t *testing.T) { cfg := BackOffConfig{ Enabled: false, InitialInterval: -1, RandomizationFactor: -1, Multiplier: 0, MaxInterval: -1, MaxElapsedTime: -1, } assert.NoError(t, cfg.Validate()) } opentelemetry-collector-0.141.0/config/configretry/go.mod000066400000000000000000000007521511331344600234500ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configretry go 1.24.0 require ( github.com/cenkalti/backoff/v5 v5.0.3 github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/config/configretry/go.sum000066400000000000000000000044621511331344600234770ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configretry/metadata.yaml000066400000000000000000000002041511331344600247760ustar00rootroot00000000000000type: config/configretry github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configretry/package_test.go000066400000000000000000000003141511331344600253150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configretry import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configtelemetry/000077500000000000000000000000001511331344600232035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configtelemetry/Makefile000066400000000000000000000000361511331344600246420ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configtelemetry/configtelemetry.go000066400000000000000000000033701511331344600267350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtelemetry // import "go.opentelemetry.io/collector/config/configtelemetry" import ( "errors" "fmt" "strings" ) const ( // LevelNone indicates that no telemetry should be collected. LevelNone Level = iota - 1 // LevelBasic indicates that only core Collector telemetry should be collected. LevelBasic // LevelNormal indicates that all low-overhead telemetry should be collected. LevelNormal // LevelDetailed indicates that all available telemetry should be collected. LevelDetailed levelNoneStr = "None" levelBasicStr = "Basic" levelNormalStr = "Normal" levelDetailedStr = "Detailed" ) // Level is the level of internal telemetry (metrics, logs, traces about the component itself) // that every component should generate. type Level int32 func (l Level) String() string { switch l { case LevelNone: return levelNoneStr case LevelBasic: return levelBasicStr case LevelNormal: return levelNormalStr case LevelDetailed: return levelDetailedStr } return "" } // MarshalText marshals Level to text. func (l Level) MarshalText() (text []byte, err error) { return []byte(l.String()), nil } // UnmarshalText unmarshalls text to a Level. func (l *Level) UnmarshalText(text []byte) error { if l == nil { return errors.New("cannot unmarshal to a nil *Level") } str := strings.ToLower(string(text)) switch str { case strings.ToLower(levelNoneStr): *l = LevelNone return nil case strings.ToLower(levelBasicStr): *l = LevelBasic return nil case strings.ToLower(levelNormalStr): *l = LevelNormal return nil case strings.ToLower(levelDetailedStr): *l = LevelDetailed return nil } return fmt.Errorf("unknown metrics level %q", str) } opentelemetry-collector-0.141.0/config/configtelemetry/configtelemetry_test.go000066400000000000000000000035371511331344600300010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtelemetry import ( "encoding" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( _ encoding.TextMarshaler = (*Level)(nil) _ encoding.TextUnmarshaler = (*Level)(nil) ) func TestUnmarshalText(t *testing.T) { tests := []struct { str []string level Level err bool }{ { str: []string{"", "other_string"}, level: LevelNone, err: true, }, { str: []string{"none", "None", "NONE"}, level: LevelNone, }, { str: []string{"basic", "Basic", "BASIC"}, level: LevelBasic, }, { str: []string{"normal", "Normal", "NORMAL"}, level: LevelNormal, }, { str: []string{"detailed", "Detailed", "DETAILED"}, level: LevelDetailed, }, } for _, test := range tests { for _, str := range test.str { t.Run(str, func(t *testing.T) { var lvl Level err := lvl.UnmarshalText([]byte(str)) if test.err { assert.Error(t, err) } else { require.NoError(t, err) assert.Equal(t, test.level, lvl) } }) } } } func TestUnmarshalTextNilLevel(t *testing.T) { lvl := (*Level)(nil) assert.Error(t, lvl.UnmarshalText([]byte(levelNormalStr))) } func TestLevelStringMarshal(t *testing.T) { tests := []struct { str string level Level err bool }{ { str: "", level: Level(-10), }, { str: levelNoneStr, level: LevelNone, }, { str: levelBasicStr, level: LevelBasic, }, { str: levelNormalStr, level: LevelNormal, }, { str: levelDetailedStr, level: LevelDetailed, }, } for _, tt := range tests { t.Run(tt.str, func(t *testing.T) { assert.Equal(t, tt.str, tt.level.String()) got, err := tt.level.MarshalText() require.NoError(t, err) assert.Equal(t, tt.str, string(got)) }) } } opentelemetry-collector-0.141.0/config/configtelemetry/doc.go000066400000000000000000000035511511331344600243030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package configtelemetry defines various telemetry level for configuration. // It enables every component to have access to telemetry level // to enable metrics only when necessary. // // This document provides guidance on which telemetry level to adopt for Collector metrics. // When adopting a telemetry level, component authors are expected to rely on this guidance to // justify their choice of telemetry level. // // 1. configtelemetry.None // // No telemetry data is recorded. // // 2. configtelemetry.Basic // // Telemetry associated with this level provides essential coverage of the Collector telemetry. // It should only be used for telemetry generated by the core Collector API. // Components outside of the core API MUST NOT record telemetry at this level. // // 3. configtelemetry.Normal // // Telemetry associated with this level provides intermediate coverage of the Collector telemetry. // It should be the default for component authors. // // Normal-level telemetry should have limited cardinality and data volume, though it is acceptable // for them to scale linearly with the monitored resources. // For example, there may be a limit of 5 attribute sets or 5 spans generated per request. // // Normal-level telemetry should also have a low computational cost: it should not contain values // requiring significant additional computation compared to the normal flow of processing. // // This is the default level recommended when running the Collector. // // 4. configtelemetry.Detailed // // Telemetry associated with this level provides complete coverage of the collector telemetry. // // The signals associated with this level may exhibit high cardinality, high data volume, or high // computational cost. package configtelemetry // import "go.opentelemetry.io/collector/config/configtelemetry" opentelemetry-collector-0.141.0/config/configtelemetry/go.mod000066400000000000000000000007071511331344600243150ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configtelemetry go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/config/configtelemetry/go.sum000066400000000000000000000041771511331344600243470ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configtelemetry/metadata.yaml000066400000000000000000000002101511331344600256400ustar00rootroot00000000000000type: config/configtelemetry github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configtelemetry/package_test.go000066400000000000000000000003201511331344600261570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtelemetry import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/config/configtls/000077500000000000000000000000001511331344600217735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configtls/Makefile000066400000000000000000000000361511331344600234320ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/config/configtls/README.md000066400000000000000000000152051511331344600232550ustar00rootroot00000000000000# TLS Configuration Settings Crypto TLS exposes a [variety of settings](https://godoc.org/crypto/tls). Several of these settings are available for configuration within individual receivers or exporters. Note that mutual TLS (mTLS) is also supported. ## TLS / mTLS Configuration By default, TLS is enabled: - `insecure` (default = false): whether to enable client transport security for the exporter's HTTPs or gRPC connection. See [grpc.WithInsecure()](https://godoc.org/google.golang.org/grpc#WithInsecure) for gRPC. - `curve_preferences` (default = []): specify your curve preferences that will be used in an ECDHE handshake, in preference order. Accepted values are: - X25519 - P521 - P256 - P384 As a result, the following parameters are also required: - `cert_file`: Path to the TLS cert to use for TLS required connections. Should only be used if `insecure` is set to false. - `cert_pem`: Alternative to `cert_file`. Provide the certificate contents as a string instead of a filepath. - `key_file`: Path to the TLS key to use for TLS required connections. Should only be used if `insecure` is set to false. - `key_pem`: Alternative to `key_file`. Provide the key contents as a string instead of a filepath. A certificate authority may also need to be defined: - `ca_file`: Path to the CA cert. For a client this verifies the server certificate. For a server this verifies client certificates. If empty uses system root CA. Should only be used if `insecure` is set to false. - `ca_pem`: Alternative to `ca_file`. Provide the CA cert contents as a string instead of a filepath. You can also combine defining a certificate authority with the system certificate authorities. - `include_system_ca_certs_pool` (default = false): whether to load the system certificate authorities pool alongside the certificate authority. Additionally you can configure TLS to be enabled but skip verifying the server's certificate chain. This cannot be combined with `insecure` since `insecure` won't use TLS at all. - `insecure_skip_verify` (default = false): whether to skip verifying the certificate or not. Minimum and maximum TLS version can be set: __IMPORTANT__: TLS 1.0 and 1.1 are deprecated due to known vulnerabilities and should be avoided. - `min_version` (default = "1.2"): Minimum acceptable TLS version. - options: ["1.0", "1.1", "1.2", "1.3"] - `max_version` (default = "" handled by [crypto/tls](https://github.com/golang/go/blob/ed9db1d36ad6ef61095d5941ad9ee6da7ab6d05a/src/crypto/tls/common.go#L700) - currently TLS 1.3): Maximum acceptable TLS version. - options: ["1.0", "1.1", "1.2", "1.3"] Explicit cipher suites can be set. If left blank, a safe default list is used. See https://go.dev/src/crypto/tls/cipher_suites.go for a list of supported cipher suites. - `cipher_suites`: (default = []): List of cipher suites to use. Example: ``` cipher_suites: - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 ``` Additionally certificates may be reloaded by setting the below configuration. - `reload_interval` (optional) : ReloadInterval specifies the duration after which the certificate will be reloaded. If not set, it will never be reloaded. Accepts a [duration string](https://pkg.go.dev/time#ParseDuration), valid time units are "ns", "us" (or "ยตs"), "ms", "s", "m", "h". How TLS/mTLS is configured depends on whether configuring the client or server. See below for examples. - `tpm` (optional): Use the trusted platform module to retrieve the TLS key. ## Client Configuration [Exporters](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/README.md) leverage client configuration. The TLS configuration parameters are defined under `tls`, like server configuration. Beyond TLS configuration, the following setting can optionally be configured: - `server_name_override`: If set to a non-empty string, it will override the virtual host name of authority (e.g. :authority header field) in requests (typically used for testing). Example: ```yaml exporters: otlp: endpoint: myserver.local:55690 tls: insecure: false ca_file: server.crt cert_file: client.crt key_file: client.key min_version: "1.1" max_version: "1.2" otlp/insecure: endpoint: myserver.local:55690 tls: insecure: true otlp/secure_no_verify: endpoint: myserver.local:55690 tls: insecure: false insecure_skip_verify: true ``` ## Server Configuration [Receivers](https://github.com/open-telemetry/opentelemetry-collector/blob/main/receiver/README.md) leverage server configuration. Beyond TLS configuration, the following setting can optionally be configured (required for mTLS): - `client_ca_file`: Path to the TLS cert to use by the server to verify a client certificate. (optional) This sets the ClientCAs and ClientAuth to RequireAndVerifyClientCert in the TLSConfig. Please refer to https://godoc.org/crypto/tls#Config for more information. - `client_ca_file_reload` (default = false): Reload the ClientCAs file when it is modified. Example: ```yaml receivers: otlp: protocols: grpc: endpoint: mysite.local:55690 tls: cert_file: server.crt key_file: server.key otlp/mtls: protocols: grpc: endpoint: mysite.local:55690 tls: client_ca_file: client.pem cert_file: server.crt key_file: server.key otlp/notls: protocols: grpc: endpoint: mysite.local:55690 ``` ## Trusted platform module (TPM) configuration The [trusted platform module](https://trustedcomputinggroup.org/resource/trusted-platform-module-tpm-summary/) (TPM) configuration can be used for loading TLS key from TPM. Currently only TSS2 format is supported. - `enabled` (default = false): Enables loading `tls.key_file` from TPM. - `path` (default = ""): The path to the TPM device or Unix domain socket. For instance `/dev/tpm0` or `/dev/tpmrm0`. This option is not supported on Windows. - `owner_auth` (default = ""): The owner authorization value. This is used to authenticate the TPM device. If not set, the default owner authorization will be used. - `auth` (default = ""): The authorization value. This is used to authenticate the TPM device. If not set, the default authorization will be used. Example: ```yaml exporters: otlp: endpoint: myserver.local:55690 tls: ca_file: ca.crt cert_file: client.crt key_file: client-tss2.key tpm: enabled: true path: /dev/tpmrm0 ``` The `client-tss2.key` private key with TSS2 format will be loaded from the TPM device `/dev/tpmrm0`.opentelemetry-collector-0.141.0/config/configtls/clientcasfilereloader.go000066400000000000000000000066641511331344600266610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtls // import "go.opentelemetry.io/collector/config/configtls" import ( "crypto/tls" "crypto/x509" "errors" "fmt" "sync" "github.com/fsnotify/fsnotify" ) type clientCAsFileReloader struct { clientCAsFile string certPool *x509.CertPool lastReloadError error lock sync.RWMutex loader clientCAsFileLoader watcher *fsnotify.Watcher shutdownCH chan bool } type clientCAsFileLoader interface { loadClientCAFile() (*x509.CertPool, error) } func newClientCAsReloader(clientCAsFile string, loader clientCAsFileLoader) (*clientCAsFileReloader, error) { certPool, err := loader.loadClientCAFile() if err != nil { return nil, fmt.Errorf("failed to load client CA CertPool: %w", err) } reloader := &clientCAsFileReloader{ clientCAsFile: clientCAsFile, certPool: certPool, loader: loader, shutdownCH: nil, watcher: nil, } return reloader, nil } func (r *clientCAsFileReloader) getClientConfig(original *tls.Config) (*tls.Config, error) { r.lock.RLock() defer r.lock.RUnlock() return &tls.Config{ RootCAs: original.RootCAs, GetCertificate: original.GetCertificate, GetClientCertificate: original.GetClientCertificate, MinVersion: original.MinVersion, MaxVersion: original.MaxVersion, NextProtos: original.NextProtos, ClientCAs: r.certPool, ClientAuth: tls.RequireAndVerifyClientCert, }, nil } func (r *clientCAsFileReloader) reload() { r.lock.Lock() defer r.lock.Unlock() certPool, err := r.loader.loadClientCAFile() if err != nil { r.lastReloadError = err } else { r.certPool = certPool r.lastReloadError = nil } } func (r *clientCAsFileReloader) getLastError() error { r.lock.Lock() defer r.lock.Unlock() return r.lastReloadError } func (r *clientCAsFileReloader) startWatching() error { if r.shutdownCH != nil { return errors.New("client CA file watcher already started") } watcher, err := fsnotify.NewWatcher() if err != nil { return fmt.Errorf("failed to create watcher to reload client CA CertPool: %w", err) } r.watcher = watcher err = watcher.Add(r.clientCAsFile) if err != nil { return fmt.Errorf("failed to add client CA file to watcher: %w", err) } r.shutdownCH = make(chan bool) go r.handleWatcherEvents() return nil } func (r *clientCAsFileReloader) handleWatcherEvents() { defer r.watcher.Close() for { select { case _, ok := <-r.shutdownCH: _ = ok return case event, ok := <-r.watcher.Events: if !ok { continue } // NOTE: k8s configmaps uses symlinks, we need this workaround. // original configmap file is removed. // SEE: https://martensson.io/go-fsnotify-and-kubernetes-configmaps/ if event.Has(fsnotify.Remove) || event.Has(fsnotify.Chmod) { // remove the watcher since the file is removed if err := r.watcher.Remove(event.Name); err != nil { r.lastReloadError = err } // add a new watcher pointing to the new symlink/file if err := r.watcher.Add(r.clientCAsFile); err != nil { r.lastReloadError = err } r.reload() } if event.Has(fsnotify.Write) { r.reload() } } } } func (r *clientCAsFileReloader) shutdown() error { if r.shutdownCH == nil { return errors.New("client CAs file watcher is not running") } r.shutdownCH <- true close(r.shutdownCH) r.shutdownCH = nil return nil } opentelemetry-collector-0.141.0/config/configtls/clientcasfilereloader_test.go000066400000000000000000000050101511331344600277000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtls import ( "crypto/x509" "fmt" "os" "path/filepath" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestCannotShutdownIfNotWatching(t *testing.T) { reloader, _, _ := createReloader(t) err := reloader.shutdown() assert.Error(t, err) } func TestCannotStartIfAlreadyWatching(t *testing.T) { reloader, _, _ := createReloader(t) err := reloader.startWatching() require.NoError(t, err) err = reloader.startWatching() require.Error(t, err) err = reloader.shutdown() assert.NoError(t, err) } func TestClosingWatcherDoesntBreakReloader(t *testing.T) { reloader, loader, _ := createReloader(t) err := reloader.startWatching() require.NoError(t, err) assert.Equal(t, 1, loader.reloadNumber()) err = reloader.watcher.Close() require.NoError(t, err) err = reloader.shutdown() assert.NoError(t, err) } func TestErrorRecordedIfFileDeleted(t *testing.T) { reloader, loader, filePath := createReloader(t) err := reloader.startWatching() require.NoError(t, err) assert.Equal(t, 1, loader.reloadNumber()) loader.returnErrorOnSubsequentCalls("test error on reload") err = os.WriteFile(filePath, []byte("some_data"), 0o600) require.NoError(t, err) assert.Eventually(t, func() bool { return loader.reloadNumber() > 1 && reloader.getLastError() != nil }, 5*time.Second, 10*time.Millisecond) lastErr := reloader.getLastError() require.EqualError(t, lastErr, "test error on reload") err = reloader.shutdown() assert.NoError(t, err) } func createReloader(t *testing.T) (*clientCAsFileReloader, *testLoader, string) { tmpClientCAsFilePath := createTempFile(t) loader := &testLoader{} reloader, _ := newClientCAsReloader(tmpClientCAsFilePath, loader) return reloader, loader, tmpClientCAsFilePath } func createTempFile(t *testing.T) string { tmpCa, err := os.CreateTemp(t.TempDir(), "clientCAs.crt") require.NoError(t, err) tmpCaPath, err := filepath.Abs(tmpCa.Name()) assert.NoError(t, err) assert.NoError(t, tmpCa.Close()) return tmpCaPath } type testLoader struct { err atomic.Value counter atomic.Uint32 } func (r *testLoader) loadClientCAFile() (*x509.CertPool, error) { r.counter.Add(1) v := r.err.Load() if v == nil { return nil, nil } return nil, v.(error) } func (r *testLoader) returnErrorOnSubsequentCalls(msg string) { r.err.Store(fmt.Errorf("%s", msg)) } func (r *testLoader) reloadNumber() int { return int(r.counter.Load()) } opentelemetry-collector-0.141.0/config/configtls/configtls.go000066400000000000000000000411301511331344600243110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtls // import "go.opentelemetry.io/collector/config/configtls" import ( "context" "crypto/tls" "crypto/x509" "errors" "fmt" "maps" "os" "path/filepath" "slices" "sync" "time" "go.opentelemetry.io/collector/config/configopaque" ) // We should avoid that users unknowingly use a vulnerable TLS version. // The defaults should be a safe configuration const defaultMinTLSVersion = tls.VersionTLS12 // Uses the default MaxVersion from "crypto/tls" which is the maximum supported version const defaultMaxTLSVersion = 0 var systemCertPool = x509.SystemCertPool // Config exposes the common client and server TLS configurations. // Note: Since there isn't anything specific to a server connection. Components // with server connections should use Config. type Config struct { // Path to the CA cert. For a client this verifies the server certificate. // For a server this verifies client certificates. If empty uses system root CA. // (optional) CAFile string `mapstructure:"ca_file,omitempty"` // In memory PEM encoded cert. (optional) CAPem configopaque.String `mapstructure:"ca_pem,omitempty"` // If true, load system CA certificates pool in addition to the certificates // configured in this struct. IncludeSystemCACertsPool bool `mapstructure:"include_system_ca_certs_pool,omitempty"` // Path to the TLS cert to use for TLS required connections. (optional) CertFile string `mapstructure:"cert_file,omitempty"` // In memory PEM encoded TLS cert to use for TLS required connections. (optional) CertPem configopaque.String `mapstructure:"cert_pem,omitempty"` // Path to the TLS key to use for TLS required connections. (optional) KeyFile string `mapstructure:"key_file,omitempty"` // In memory PEM encoded TLS key to use for TLS required connections. (optional) KeyPem configopaque.String `mapstructure:"key_pem,omitempty"` // MinVersion sets the minimum TLS version that is acceptable. // If not set, TLS 1.2 will be used. (optional) MinVersion string `mapstructure:"min_version,omitempty"` // MaxVersion sets the maximum TLS version that is acceptable. // If not set, refer to crypto/tls for defaults. (optional) MaxVersion string `mapstructure:"max_version,omitempty"` // CipherSuites is a list of TLS cipher suites that the TLS transport can use. // If left blank, a safe default list is used. // See https://go.dev/src/crypto/tls/cipher_suites.go for a list of supported cipher suites. CipherSuites []string `mapstructure:"cipher_suites,omitempty"` // ReloadInterval specifies the duration after which the certificate will be reloaded // If not set, it will never be reloaded (optional) ReloadInterval time.Duration `mapstructure:"reload_interval,omitempty"` // contains the elliptic curves that will be used in // an ECDHE handshake, in preference order // Defaults to empty list and "crypto/tls" defaults are used, internally. CurvePreferences []string `mapstructure:"curve_preferences,omitempty"` // Trusted platform module configuration TPMConfig TPMConfig `mapstructure:"tpm,omitempty"` } // NewDefaultConfig creates a new Config with any default values set. func NewDefaultConfig() Config { return Config{} } // ClientConfig contains TLS configurations that are specific to client // connections in addition to the common configurations. This should be used by // components configuring TLS client connections. type ClientConfig struct { // squash ensures fields are correctly decoded in embedded struct. Config `mapstructure:",squash"` // These are config options specific to client connections. // In gRPC and HTTP when set to true, this is used to disable the client transport security. // See https://godoc.org/google.golang.org/grpc#WithInsecure for gRPC. // Please refer to https://godoc.org/crypto/tls#Config for more information. // (optional, default false) Insecure bool `mapstructure:"insecure,omitempty"` // InsecureSkipVerify will enable TLS but not verify the certificate. InsecureSkipVerify bool `mapstructure:"insecure_skip_verify,omitempty"` // ServerName requested by client for virtual hosting. // This sets the ServerName in the TLSConfig. Please refer to // https://godoc.org/crypto/tls#Config for more information. (optional) ServerName string `mapstructure:"server_name_override,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultClientConfig creates a new ClientConfig with any default values set. func NewDefaultClientConfig() ClientConfig { return ClientConfig{ Config: NewDefaultConfig(), } } // ServerConfig contains TLS configurations that are specific to server // connections in addition to the common configurations. This should be used by // components configuring TLS server connections. type ServerConfig struct { // squash ensures fields are correctly decoded in embedded struct. Config `mapstructure:",squash"` // These are config options specific to server connections. // Path to the TLS cert to use by the server to verify a client certificate. (optional) // This sets the ClientCAs and ClientAuth to RequireAndVerifyClientCert in the TLSConfig. Please refer to // https://godoc.org/crypto/tls#Config for more information. (optional) ClientCAFile string `mapstructure:"client_ca_file,omitempty"` // Reload the ClientCAs file when it is modified // (optional, default false) ReloadClientCAFile bool `mapstructure:"client_ca_file_reload,omitempty"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultServerConfig creates a new ServerConfig with any default values set. func NewDefaultServerConfig() ServerConfig { return ServerConfig{ Config: NewDefaultConfig(), } } // certReloader is a wrapper object for certificate reloading // Its GetCertificate method will either return the current certificate or reload from disk // if the last reload happened more than ReloadInterval ago type certReloader struct { nextReload time.Time cert *tls.Certificate lock sync.RWMutex tls Config } func (c Config) newCertReloader() (*certReloader, error) { cert, err := c.loadCertificate() if err != nil { return nil, err } return &certReloader{ tls: c, nextReload: time.Now().Add(c.ReloadInterval), cert: &cert, }, nil } func (r *certReloader) GetCertificate() (*tls.Certificate, error) { now := time.Now() // Read locking here before we do the time comparison // If a reload is in progress this will block and we will skip reloading in the current // call once we can continue r.lock.RLock() if r.tls.ReloadInterval != 0 && r.nextReload.Before(now) && (r.tls.hasCertFile() || r.tls.hasKeyFile()) { // Need to release the read lock, otherwise we deadlock r.lock.RUnlock() r.lock.Lock() defer r.lock.Unlock() cert, err := r.tls.loadCertificate() if err != nil { return nil, fmt.Errorf("failed to load TLS cert and key: %w", err) } r.cert = &cert r.nextReload = now.Add(r.tls.ReloadInterval) return r.cert, nil } defer r.lock.RUnlock() return r.cert, nil } func (c Config) Validate() error { if c.hasCAFile() && c.hasCAPem() { return errors.New("provide either a CA file or the PEM-encoded string, but not both") } // Ensure certificate is not set using both file and PEM if c.hasCertFile() && c.hasCertPem() { return errors.New("provide either certificate file or PEM, but not both") } // Ensure key is not set using both file and PEM if c.hasKeyFile() && c.hasKeyPem() { return errors.New("provide either key file or PEM, but not both") } // Fail if only one of cert/key is provided (mismatch case) if c.hasCert() != c.hasKey() { return errors.New("TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)") } minTLS, err := convertVersion(c.MinVersion, defaultMinTLSVersion) if err != nil { return fmt.Errorf("invalid TLS min_version: %w", err) } maxTLS, err := convertVersion(c.MaxVersion, defaultMaxTLSVersion) if err != nil { return fmt.Errorf("invalid TLS max_version: %w", err) } if maxTLS < minTLS && maxTLS != defaultMaxTLSVersion { return errors.New("invalid TLS configuration: min_version cannot be greater than max_version") } return nil } func (c ServerConfig) Validate() error { // For servers, both certificate and key are required: // - If both are missing, error. // - If only one is provided (mismatch), error. if !c.hasCert() && !c.hasKey() { return errors.New("TLS configuration must include both certificate and key for server connections") } return nil } // loadTLSConfig loads TLS certificates and returns a tls.Config. // This will set the RootCAs and Certificates of a tls.Config. func (c Config) loadTLSConfig() (*tls.Config, error) { certPool, err := c.loadCACertPool() if err != nil { return nil, err } var getCertificate func(*tls.ClientHelloInfo) (*tls.Certificate, error) var getClientCertificate func(*tls.CertificateRequestInfo) (*tls.Certificate, error) if c.hasCert() || c.hasKey() { var certReloader *certReloader certReloader, err = c.newCertReloader() if err != nil { return nil, fmt.Errorf("failed to load TLS cert and key: %w", err) } getCertificate = func(*tls.ClientHelloInfo) (*tls.Certificate, error) { return certReloader.GetCertificate() } getClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) { return certReloader.GetCertificate() } } minTLS, err := convertVersion(c.MinVersion, defaultMinTLSVersion) if err != nil { return nil, fmt.Errorf("invalid TLS min_version: %w", err) } maxTLS, err := convertVersion(c.MaxVersion, defaultMaxTLSVersion) if err != nil { return nil, fmt.Errorf("invalid TLS max_version: %w", err) } cipherSuites, err := convertCipherSuites(c.CipherSuites) if err != nil { return nil, err } allowedCurves := slices.Collect(maps.Values(tlsCurveTypes)) curvePreferences := make([]tls.CurveID, 0, len(c.CurvePreferences)) for _, curve := range c.CurvePreferences { curveID, ok := tlsCurveTypes[curve] if !ok { return nil, fmt.Errorf("invalid curve type: %s. Expected values are %s", curveID, allowedCurves) } curvePreferences = append(curvePreferences, curveID) } // If no curve preferences were explicitly specified in the configuration, use // the ones we allow. This helps in particular with FIPS builds where not all curves // are allowed. if len(curvePreferences) == 0 { curvePreferences = allowedCurves } return &tls.Config{ RootCAs: certPool, GetCertificate: getCertificate, GetClientCertificate: getClientCertificate, MinVersion: minTLS, MaxVersion: maxTLS, CipherSuites: cipherSuites, CurvePreferences: curvePreferences, }, nil } func convertCipherSuites(cipherSuites []string) ([]uint16, error) { var result []uint16 var errs []error for _, suite := range cipherSuites { found := false for _, supported := range tls.CipherSuites() { if suite == supported.Name { result = append(result, supported.ID) found = true break } } if !found { errs = append(errs, fmt.Errorf("invalid TLS cipher suite: %q", suite)) } } return result, errors.Join(errs...) } func (c Config) loadCACertPool() (*x509.CertPool, error) { // There is no need to load the System Certs for RootCAs because // if the value is nil, it will default to checking against th System Certs. var err error var certPool *x509.CertPool switch { case c.hasCAFile() && c.hasCAPem(): return nil, errors.New("failed to load CA CertPool: provide either a CA file or the PEM-encoded string, but not both") case c.hasCAFile(): // Set up user specified truststore from file certPool, err = c.loadCertFile(c.CAFile) if err != nil { return nil, fmt.Errorf("failed to load CA CertPool File: %w", err) } case c.hasCAPem(): // Set up user specified truststore from PEM certPool, err = c.loadCertPem([]byte(c.CAPem)) if err != nil { return nil, fmt.Errorf("failed to load CA CertPool PEM: %w", err) } } return certPool, nil } func (c Config) loadCertFile(certPath string) (*x509.CertPool, error) { certPem, err := os.ReadFile(filepath.Clean(certPath)) if err != nil { return nil, fmt.Errorf("failed to load cert %s: %w", certPath, err) } return c.loadCertPem(certPem) } func (c Config) loadCertPem(certPem []byte) (*x509.CertPool, error) { certPool := x509.NewCertPool() if c.IncludeSystemCACertsPool { scp, err := systemCertPool() if err != nil { return nil, err } if scp != nil { certPool = scp } } if !certPool.AppendCertsFromPEM(certPem) { return nil, errors.New("failed to parse cert") } return certPool, nil } func (c Config) loadCertificate() (tls.Certificate, error) { switch { case c.hasCert() != c.hasKey(): return tls.Certificate{}, errors.New("for auth via TLS, provide both certificate and key, or neither") case !c.hasCert() && !c.hasKey(): return tls.Certificate{}, nil case c.hasCertFile() && c.hasCertPem(): return tls.Certificate{}, errors.New("for auth via TLS, provide either a certificate or the PEM-encoded string, but not both") case c.hasKeyFile() && c.hasKeyPem(): return tls.Certificate{}, errors.New("for auth via TLS, provide either a key or the PEM-encoded string, but not both") } var certPem, keyPem []byte var err error if c.hasCertFile() { certPem, err = os.ReadFile(c.CertFile) if err != nil { return tls.Certificate{}, err } } else { certPem = []byte(c.CertPem) } if c.hasKeyFile() { keyPem, err = os.ReadFile(c.KeyFile) if err != nil { return tls.Certificate{}, err } } else { keyPem = []byte(c.KeyPem) } if c.TPMConfig.Enabled { certificate, errTPM := c.TPMConfig.tpmCertificate(keyPem, certPem, openTPM(c.TPMConfig.Path)) if errTPM != nil { return tls.Certificate{}, fmt.Errorf("failed to load private key from TPM: %w", errTPM) } return certificate, nil } certificate, errKeyPair := tls.X509KeyPair(certPem, keyPem) if errKeyPair != nil { return tls.Certificate{}, fmt.Errorf("failed to load TLS cert and key PEMs: %w", errKeyPair) } return certificate, err } func (c Config) loadCert(caPath string) (*x509.CertPool, error) { caPEM, err := os.ReadFile(filepath.Clean(caPath)) if err != nil { return nil, fmt.Errorf("failed to load CA %s: %w", caPath, err) } var certPool *x509.CertPool if c.IncludeSystemCACertsPool { if certPool, err = systemCertPool(); err != nil { return nil, err } } if certPool == nil { certPool = x509.NewCertPool() } if !certPool.AppendCertsFromPEM(caPEM) { return nil, fmt.Errorf("failed to parse CA %s", caPath) } return certPool, nil } // LoadTLSConfig loads the TLS configuration. func (c ClientConfig) LoadTLSConfig(_ context.Context) (*tls.Config, error) { if c.Insecure && !c.hasCA() { return nil, nil } tlsCfg, err := c.loadTLSConfig() if err != nil { return nil, fmt.Errorf("failed to load TLS config: %w", err) } tlsCfg.ServerName = c.ServerName tlsCfg.InsecureSkipVerify = c.InsecureSkipVerify return tlsCfg, nil } // LoadTLSConfig loads the TLS configuration. func (c ServerConfig) LoadTLSConfig(_ context.Context) (*tls.Config, error) { tlsCfg, err := c.loadTLSConfig() if err != nil { return nil, fmt.Errorf("failed to load TLS config: %w", err) } if c.ClientCAFile != "" { reloader, err := newClientCAsReloader(c.ClientCAFile, &c) if err != nil { return nil, err } if c.ReloadClientCAFile { err = reloader.startWatching() if err != nil { return nil, err } tlsCfg.GetConfigForClient = func(*tls.ClientHelloInfo) (*tls.Config, error) { return reloader.getClientConfig(tlsCfg) } } tlsCfg.ClientCAs = reloader.certPool tlsCfg.ClientAuth = tls.RequireAndVerifyClientCert } return tlsCfg, nil } func (c ServerConfig) loadClientCAFile() (*x509.CertPool, error) { return c.loadCert(c.ClientCAFile) } func (c Config) hasCA() bool { return c.hasCAFile() || c.hasCAPem() } func (c Config) hasCert() bool { return c.hasCertFile() || c.hasCertPem() } func (c Config) hasKey() bool { return c.hasKeyFile() || c.hasKeyPem() } func (c Config) hasCAFile() bool { return c.CAFile != "" } func (c Config) hasCAPem() bool { return len(c.CAPem) != 0 } func (c Config) hasCertFile() bool { return c.CertFile != "" } func (c Config) hasCertPem() bool { return len(c.CertPem) != 0 } func (c Config) hasKeyFile() bool { return c.KeyFile != "" } func (c Config) hasKeyPem() bool { return len(c.KeyPem) != 0 } func convertVersion(v string, defaultVersion uint16) (uint16, error) { // Use a default that is explicitly defined if v == "" { return defaultVersion, nil } val, ok := tlsVersions[v] if !ok { return 0, fmt.Errorf("unsupported TLS version: %q", v) } return val, nil } var tlsVersions = map[string]uint16{ "1.0": tls.VersionTLS10, "1.1": tls.VersionTLS11, "1.2": tls.VersionTLS12, "1.3": tls.VersionTLS13, } opentelemetry-collector-0.141.0/config/configtls/configtls_test.go000066400000000000000000001015721511331344600253570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtls import ( "context" "crypto/tls" "crypto/x509" "errors" "fmt" "io" "os" "path/filepath" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/confmap/xconfmap" ) func TestNewDefaultConfig(t *testing.T) { expectedConfig := Config{} config := NewDefaultConfig() require.Equal(t, expectedConfig, config) } func TestNewDefaultClientConfig(t *testing.T) { expectedConfig := ClientConfig{ Config: NewDefaultConfig(), } config := NewDefaultClientConfig() require.Equal(t, expectedConfig, config) } func TestNewDefaultServerConfig(t *testing.T) { expectedConfig := ServerConfig{ Config: NewDefaultConfig(), } config := NewDefaultServerConfig() require.Equal(t, expectedConfig, config) } func TestOptionsToConfig(t *testing.T) { tests := []struct { name string options Config expectError string }{ { name: "should load system CA", options: Config{CAFile: ""}, }, { name: "should load custom CA", options: Config{CAFile: filepath.Join("testdata", "ca-1.crt")}, }, { name: "should load system CA and custom CA", options: Config{IncludeSystemCACertsPool: true, CAFile: filepath.Join("testdata", "ca-1.crt")}, }, { name: "should fail with invalid CA file path", options: Config{CAFile: filepath.Join("testdata", "not/valid")}, expectError: "failed to load CA", }, { name: "should fail with invalid CA file content", options: Config{CAFile: filepath.Join("testdata", "testCA-bad.txt")}, expectError: "failed to parse cert", }, { name: "should load valid TLS settings", options: Config{ CAFile: filepath.Join("testdata", "ca-1.crt"), CertFile: filepath.Join("testdata", "server-1.crt"), KeyFile: filepath.Join("testdata", "server-1.key"), }, }, { name: "should fail with missing TLS KeyFile", options: Config{ CAFile: filepath.Join("testdata", "ca-1.crt"), CertFile: filepath.Join("testdata", "server-1.crt"), }, expectError: "provide both certificate and key, or neither", }, { name: "should fail with invalid TLS KeyFile", options: Config{ CAFile: filepath.Join("testdata", "ca-1.crt"), CertFile: filepath.Join("testdata", "server-1.crt"), KeyFile: filepath.Join("testdata", "not/valid"), }, expectError: "failed to load TLS cert and key", }, { name: "should fail with missing TLS Cert", options: Config{ CAFile: filepath.Join("testdata", "ca-1.crt"), KeyFile: filepath.Join("testdata", "server-1.key"), }, expectError: "provide both certificate and key, or neither", }, { name: "should fail with invalid TLS Cert", options: Config{ CAFile: filepath.Join("testdata", "ca-1.crt"), CertFile: filepath.Join("testdata", "not/valid"), KeyFile: filepath.Join("testdata", "server-1.key"), }, expectError: "failed to load TLS cert and key", }, { name: "should fail with invalid TLS CA", options: Config{ CAFile: filepath.Join("testdata", "not/valid"), }, expectError: "failed to load CA", }, { name: "should fail with invalid CA pool", options: Config{ CAFile: filepath.Join("testdata", "testCA-bad.txt"), }, expectError: "failed to parse cert", }, { name: "should pass with valid CA pool", options: Config{ CAFile: filepath.Join("testdata", "ca-1.crt"), }, }, { name: "should pass with valid min and max version", options: Config{ MinVersion: "1.1", MaxVersion: "1.2", }, }, { name: "should pass with invalid min", options: Config{ MinVersion: "1.7", }, expectError: "invalid TLS min_", }, { name: "should pass with invalid max", options: Config{ MaxVersion: "1.7", }, expectError: "invalid TLS max_", }, { name: "should load custom CA PEM", options: Config{CAPem: readFilePanics("testdata/ca-1.crt")}, }, { name: "should load valid TLS settings with PEMs", options: Config{ CAPem: readFilePanics("testdata/ca-1.crt"), CertPem: readFilePanics("testdata/server-1.crt"), KeyPem: readFilePanics("testdata/server-1.key"), }, }, { name: "mix Cert file and Key PEM provided", options: Config{ CertFile: "testdata/server-1.crt", KeyPem: readFilePanics("testdata/server-1.key"), }, }, { name: "mix Cert PEM and Key File provided", options: Config{ CertPem: readFilePanics("testdata/server-1.crt"), KeyFile: "testdata/server-1.key", }, }, { name: "should fail with invalid CA PEM", options: Config{CAPem: readFilePanics("testdata/testCA-bad.txt")}, expectError: "failed to parse cert", }, { name: "should fail CA file and PEM both provided", options: Config{ CAFile: "testdata/ca-1.crt", CAPem: readFilePanics("testdata/ca-1.crt"), }, expectError: "provide either a CA file or the PEM-encoded string, but not both", }, { name: "should fail Cert file and PEM both provided", options: Config{ CertFile: "testdata/server-1.crt", CertPem: readFilePanics("testdata/server-1.crt"), KeyFile: "testdata/server-1.key", }, expectError: "provide either a certificate or the PEM-encoded string, but not both", }, { name: "should fail Key file and PEM both provided", options: Config{ CertFile: "testdata/server-1.crt", KeyFile: "testdata/ca-1.crt", KeyPem: readFilePanics("testdata/server-1.key"), }, expectError: "provide either a key or the PEM-encoded string, but not both", }, { name: "should fail to load valid TLS settings with bad Cert PEM", options: Config{ CAPem: readFilePanics("testdata/ca-1.crt"), CertPem: readFilePanics("testdata/testCA-bad.txt"), KeyPem: readFilePanics("testdata/server-1.key"), }, expectError: "failed to load TLS cert and key PEMs", }, { name: "should fail to load valid TLS settings with bad Key PEM", options: Config{ CAPem: readFilePanics("testdata/ca-1.crt"), CertPem: readFilePanics("testdata/server-1.crt"), KeyPem: readFilePanics("testdata/testCA-bad.txt"), }, expectError: "failed to load TLS cert and key PEMs", }, { name: "should fail with missing TLS KeyPem", options: Config{ CAPem: readFilePanics("testdata/ca-1.crt"), CertPem: readFilePanics("testdata/server-1.crt"), }, expectError: "provide both certificate and key, or neither", }, { name: "should fail with missing TLS Cert PEM", options: Config{ CAPem: readFilePanics("testdata/ca-1.crt"), KeyPem: readFilePanics("testdata/server-1.key"), }, expectError: "provide both certificate and key, or neither", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { cfg, err := test.options.loadTLSConfig() if test.expectError != "" { assert.ErrorContains(t, err, test.expectError) } else { require.NoError(t, err) assert.NotNil(t, cfg) } }) } } func readFilePanics(filePath string) configopaque.String { fileContents, err := os.ReadFile(filepath.Clean(filePath)) if err != nil { panic(fmt.Sprintf("failed to read file %s: %v", filePath, err)) } return configopaque.String(fileContents) } func TestLoadTLSClientConfigError(t *testing.T) { tlsSetting := ClientConfig{ Config: Config{ CertFile: "doesnt/exist", KeyFile: "doesnt/exist", }, } _, err := tlsSetting.LoadTLSConfig(context.Background()) assert.Error(t, err) } func TestLoadTLSClientConfig(t *testing.T) { tlsSetting := ClientConfig{ Insecure: true, } tlsCfg, err := tlsSetting.LoadTLSConfig(context.Background()) require.NoError(t, err) assert.Nil(t, tlsCfg) tlsSetting = ClientConfig{} tlsCfg, err = tlsSetting.LoadTLSConfig(context.Background()) require.NoError(t, err) assert.NotNil(t, tlsCfg) tlsSetting = ClientConfig{ InsecureSkipVerify: true, } tlsCfg, err = tlsSetting.LoadTLSConfig(context.Background()) require.NoError(t, err) assert.NotNil(t, tlsCfg) assert.True(t, tlsCfg.InsecureSkipVerify) } func TestLoadTLSServerConfigError(t *testing.T) { tlsSetting := ServerConfig{ Config: Config{ CertFile: "doesnt/exist", KeyFile: "doesnt/exist", }, } _, err := tlsSetting.LoadTLSConfig(context.Background()) require.Error(t, err) tlsSetting = ServerConfig{ ClientCAFile: "doesnt/exist", } _, err = tlsSetting.LoadTLSConfig(context.Background()) assert.Error(t, err) } func TestLoadTLSServerConfig(t *testing.T) { tlsSetting := ServerConfig{} tlsCfg, err := tlsSetting.LoadTLSConfig(context.Background()) require.NoError(t, err) assert.NotNil(t, tlsCfg) } func TestLoadTLSServerConfigReload(t *testing.T) { tmpCaPath := createTempClientCaFile(t) overwriteClientCA(t, tmpCaPath, "ca-1.crt") tlsSetting := ServerConfig{ ClientCAFile: tmpCaPath, ReloadClientCAFile: true, } tlsCfg, err := tlsSetting.LoadTLSConfig(context.Background()) require.NoError(t, err) assert.NotNil(t, tlsCfg) firstClient, err := tlsCfg.GetConfigForClient(nil) require.NoError(t, err) overwriteClientCA(t, tmpCaPath, "ca-2.crt") assert.EventuallyWithT(t, func(t *assert.CollectT) { secondClient, err := tlsCfg.GetConfigForClient(nil) require.NoError(t, err) assert.NotEqual(t, firstClient.ClientCAs, secondClient.ClientCAs) }, 5*time.Second, 10*time.Millisecond) } func TestLoadTLSServerConfigFailingReload(t *testing.T) { tmpCaPath := createTempClientCaFile(t) overwriteClientCA(t, tmpCaPath, "ca-1.crt") tlsSetting := ServerConfig{ ClientCAFile: tmpCaPath, ReloadClientCAFile: true, } tlsCfg, err := tlsSetting.LoadTLSConfig(context.Background()) require.NoError(t, err) assert.NotNil(t, tlsCfg) firstClient, err := tlsCfg.GetConfigForClient(nil) require.NoError(t, err) overwriteClientCA(t, tmpCaPath, "testCA-bad.txt") assert.Eventually(t, func() bool { _, loadError := tlsCfg.GetConfigForClient(nil) return loadError == nil }, 5*time.Second, 10*time.Millisecond) secondClient, err := tlsCfg.GetConfigForClient(nil) require.NoError(t, err) assert.Equal(t, firstClient.ClientCAs, secondClient.ClientCAs) } func TestLoadTLSServerConfigFailingInitialLoad(t *testing.T) { tmpCaPath := createTempClientCaFile(t) overwriteClientCA(t, tmpCaPath, "testCA-bad.txt") tlsSetting := ServerConfig{ ClientCAFile: tmpCaPath, ReloadClientCAFile: true, } tlsCfg, err := tlsSetting.LoadTLSConfig(context.Background()) require.Error(t, err) assert.Nil(t, tlsCfg) } func TestLoadTLSServerConfigWrongPath(t *testing.T) { tmpCaPath := createTempClientCaFile(t) tlsSetting := ServerConfig{ ClientCAFile: tmpCaPath + "wrong-path", ReloadClientCAFile: true, } tlsCfg, err := tlsSetting.LoadTLSConfig(context.Background()) require.Error(t, err) assert.Nil(t, tlsCfg) } func TestLoadTLSServerConfigFailing(t *testing.T) { tmpCaPath := createTempClientCaFile(t) overwriteClientCA(t, tmpCaPath, "ca-1.crt") tlsSetting := ServerConfig{ ClientCAFile: tmpCaPath, ReloadClientCAFile: true, } tlsCfg, err := tlsSetting.LoadTLSConfig(context.Background()) require.NoError(t, err) assert.NotNil(t, tlsCfg) firstClient, err := tlsCfg.GetConfigForClient(nil) require.NoError(t, err) assert.NotNil(t, firstClient) err = os.Remove(tmpCaPath) require.NoError(t, err) firstClient, err = tlsCfg.GetConfigForClient(nil) require.NoError(t, err) assert.NotNil(t, firstClient) } func overwriteClientCA(t *testing.T, targetFilePath, testdataFileName string) { targetFile, err := os.OpenFile(filepath.Clean(targetFilePath), os.O_RDWR, 0o600) require.NoError(t, err) testdataFilePath := filepath.Join("testdata", testdataFileName) testdataFile, err := os.OpenFile(filepath.Clean(testdataFilePath), os.O_RDONLY, 0o200) require.NoError(t, err) _, err = io.Copy(targetFile, testdataFile) assert.NoError(t, err) assert.NoError(t, targetFile.Close()) assert.NoError(t, testdataFile.Close()) } func createTempClientCaFile(t *testing.T) string { tmpCa, err := os.CreateTemp(t.TempDir(), "ca-tmp.crt") require.NoError(t, err) tmpCaPath, err := filepath.Abs(tmpCa.Name()) assert.NoError(t, err) assert.NoError(t, tmpCa.Close()) return tmpCaPath } func TestEagerlyLoadCertificate(t *testing.T) { options := Config{ CertFile: filepath.Join("testdata", "client-1.crt"), KeyFile: filepath.Join("testdata", "client-1.key"), } cfg, err := options.loadTLSConfig() require.NoError(t, err) assert.NotNil(t, cfg) cert, err := cfg.GetCertificate(&tls.ClientHelloInfo{}) require.NoError(t, err) assert.NotNil(t, cert) pCert, err := x509.ParseCertificate(cert.Certificate[0]) require.NoError(t, err) assert.NotNil(t, pCert) assert.ElementsMatch(t, []string{"example1"}, pCert.DNSNames) } func TestCertificateReload(t *testing.T) { tests := []struct { name string reloadInterval time.Duration wait time.Duration cert2 string key2 string dns1 string dns2 string errText string }{ { name: "Should reload the certificate after reload-interval", reloadInterval: 100 * time.Microsecond, wait: 100 * time.Microsecond, cert2: "client-2.crt", key2: "client-2.key", dns1: "example1", dns2: "example2", }, { name: "Should return same cert if called before reload-interval", reloadInterval: 100 * time.Millisecond, wait: 100 * time.Microsecond, cert2: "client-2.crt", key2: "client-2.key", dns1: "example1", dns2: "example1", }, { name: "Should always return same cert if reload-interval is 0", reloadInterval: 0, wait: 100 * time.Microsecond, cert2: "client-2.crt", key2: "client-2.key", dns1: "example1", dns2: "example1", }, { name: "Should return an error if reloading fails", reloadInterval: 100 * time.Microsecond, wait: 100 * time.Microsecond, cert2: "testCA-bad.txt", key2: "client-2.key", dns1: "example1", errText: "failed to load TLS cert and key: failed to load TLS cert and key PEMs: tls: failed to find any PEM data in certificate input", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { // Copy certs into a temp dir so we can safely modify them tempDir := t.TempDir() certFile, err := os.CreateTemp(tempDir, "cert") require.NoError(t, err) defer certFile.Close() keyFile, err := os.CreateTemp(tempDir, "key") require.NoError(t, err) defer keyFile.Close() fdc, err := os.Open(filepath.Join("testdata", "client-1.crt")) require.NoError(t, err) _, err = io.Copy(certFile, fdc) require.NoError(t, err) require.NoError(t, fdc.Close()) fdk, err := os.Open(filepath.Join("testdata", "client-1.key")) require.NoError(t, err) _, err = io.Copy(keyFile, fdk) assert.NoError(t, err) assert.NoError(t, fdk.Close()) options := Config{ CertFile: certFile.Name(), KeyFile: keyFile.Name(), ReloadInterval: test.reloadInterval, } cfg, err := options.loadTLSConfig() require.NoError(t, err) assert.NotNil(t, cfg) // Assert that we loaded the original certificate cert, err := cfg.GetCertificate(&tls.ClientHelloInfo{}) require.NoError(t, err) assert.NotNil(t, cert) pCert, err := x509.ParseCertificate(cert.Certificate[0]) require.NoError(t, err) assert.NotNil(t, pCert) assert.Equal(t, test.dns1, pCert.DNSNames[0]) // Change the certificate assert.NoError(t, certFile.Truncate(0)) assert.NoError(t, keyFile.Truncate(0)) _, err = certFile.Seek(0, 0) require.NoError(t, err) _, err = keyFile.Seek(0, 0) require.NoError(t, err) fdc2, err := os.Open(filepath.Join("testdata", test.cert2)) require.NoError(t, err) _, err = io.Copy(certFile, fdc2) assert.NoError(t, err) assert.NoError(t, fdc2.Close()) fdk2, err := os.Open(filepath.Join("testdata", test.key2)) require.NoError(t, err) _, err = io.Copy(keyFile, fdk2) assert.NoError(t, err) assert.NoError(t, fdk2.Close()) // Wait ReloadInterval to ensure a reload will happen time.Sleep(test.wait) // Assert that we loaded the new certificate cert, err = cfg.GetCertificate(&tls.ClientHelloInfo{}) if test.errText == "" { require.NoError(t, err) assert.NotNil(t, cert) pCert, err = x509.ParseCertificate(cert.Certificate[0]) require.NoError(t, err) assert.NotNil(t, pCert) assert.Equal(t, test.dns2, pCert.DNSNames[0]) } else { assert.EqualError(t, err, test.errText) } }) } } func TestMinMaxTLSVersions(t *testing.T) { tests := []struct { name string minVersion string maxVersion string outMinVersion uint16 outMaxVersion uint16 errorTxt string }{ {name: `TLS Config ["", ""] to give [TLS1.2, 0]`, minVersion: "", maxVersion: "", outMinVersion: tls.VersionTLS12, outMaxVersion: 0}, {name: `TLS Config ["", "1.3"] to give [TLS1.2, TLS1.3]`, minVersion: "", maxVersion: "1.3", outMinVersion: tls.VersionTLS12, outMaxVersion: tls.VersionTLS13}, {name: `TLS Config ["1.2", ""] to give [TLS1.2, 0]`, minVersion: "1.2", maxVersion: "", outMinVersion: tls.VersionTLS12, outMaxVersion: 0}, {name: `TLS Config ["1.3", "1.3"] to give [TLS1.3, TLS1.3]`, minVersion: "1.3", maxVersion: "1.3", outMinVersion: tls.VersionTLS13, outMaxVersion: tls.VersionTLS13}, {name: `TLS Config ["1.0", "1.1"] to give [TLS1.0, TLS1.1]`, minVersion: "1.0", maxVersion: "1.1", outMinVersion: tls.VersionTLS10, outMaxVersion: tls.VersionTLS11}, {name: `TLS Config ["asd", ""] to give [Error]`, minVersion: "asd", maxVersion: "", errorTxt: `invalid TLS min_version: unsupported TLS version: "asd"`}, {name: `TLS Config ["", "asd"] to give [Error]`, minVersion: "", maxVersion: "asd", errorTxt: `invalid TLS max_version: unsupported TLS version: "asd"`}, {name: `TLS Config ["0.4", ""] to give [Error]`, minVersion: "0.4", maxVersion: "", errorTxt: `invalid TLS min_version: unsupported TLS version: "0.4"`}, // Allowing this, however, expecting downstream TLS handshake will throw an error {name: `TLS Config ["1.2", "1.1"] to give [TLS1.2, TLS1.1]`, minVersion: "1.2", maxVersion: "1.1", outMinVersion: tls.VersionTLS12, outMaxVersion: tls.VersionTLS11}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { setting := Config{ MinVersion: test.minVersion, MaxVersion: test.maxVersion, } config, err := setting.loadTLSConfig() if test.errorTxt == "" { assert.Equal(t, config.MinVersion, test.outMinVersion) assert.Equal(t, config.MaxVersion, test.outMaxVersion) } else { assert.EqualError(t, err, test.errorTxt) } }) } } func TestConfigValidate(t *testing.T) { tests := []struct { name string tlsConfig Config errorTxt string }{ {name: `TLS Config ["", ""] to be valid`, tlsConfig: Config{MinVersion: "", MaxVersion: ""}}, {name: `TLS Config ["", "1.3"] to be valid`, tlsConfig: Config{MinVersion: "", MaxVersion: "1.3"}}, {name: `TLS Config ["1.2", ""] to be valid`, tlsConfig: Config{MinVersion: "1.2", MaxVersion: ""}}, {name: `TLS Config ["1.3", "1.3"] to be valid`, tlsConfig: Config{MinVersion: "1.3", MaxVersion: "1.3"}}, {name: `TLS Config ["1.0", "1.1"] to be valid`, tlsConfig: Config{MinVersion: "1.0", MaxVersion: "1.1"}}, {name: `TLS Config ["asd", ""] to give [Error]`, tlsConfig: Config{MinVersion: "asd", MaxVersion: ""}, errorTxt: `invalid TLS min_version: unsupported TLS version: "asd"`}, {name: `TLS Config ["", "asd"] to give [Error]`, tlsConfig: Config{MinVersion: "", MaxVersion: "asd"}, errorTxt: `invalid TLS max_version: unsupported TLS version: "asd"`}, {name: `TLS Config ["0.4", ""] to give [Error]`, tlsConfig: Config{MinVersion: "0.4", MaxVersion: ""}, errorTxt: `invalid TLS min_version: unsupported TLS version: "0.4"`}, {name: `TLS Config ["1.2", "1.1"] to give [Error]`, tlsConfig: Config{MinVersion: "1.2", MaxVersion: "1.1"}, errorTxt: `invalid TLS configuration: min_version cannot be greater than max_version`}, {name: `TLS Config with both CA File and PEM`, tlsConfig: Config{CAFile: "test", CAPem: "test"}, errorTxt: `provide either a CA file or the PEM-encoded string, but not both`}, {name: `TLS Config with cert file but no key`, tlsConfig: Config{CertFile: "cert.pem"}, errorTxt: `TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)`}, {name: `TLS Config with key file but no cert`, tlsConfig: Config{KeyFile: "key.pem"}, errorTxt: `TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)`}, {name: `TLS Config with cert PEM but no key`, tlsConfig: Config{CertPem: "cert-pem"}, errorTxt: `TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)`}, {name: `TLS Config with key PEM but no cert`, tlsConfig: Config{KeyPem: "key-pem"}, errorTxt: `TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)`}, {name: `TLS Config with both cert file and cert PEM`, tlsConfig: Config{CertFile: "cert.pem", CertPem: "cert-pem", KeyFile: "key.pem"}, errorTxt: `provide either certificate file or PEM, but not both`}, {name: `TLS Config with both key file and key PEM`, tlsConfig: Config{CertFile: "cert.pem", KeyFile: "key.pem", KeyPem: "key-pem"}, errorTxt: `provide either key file or PEM, but not both`}, {name: `TLS Config with cert file and key PEM`, tlsConfig: Config{CertFile: "cert.pem", KeyPem: "key-pem"}}, {name: `TLS Config with cert PEM and key file`, tlsConfig: Config{CertPem: "cert-pem", KeyFile: "key.pem"}}, {name: `TLS Config with valid cert and key files`, tlsConfig: Config{CertFile: "cert.pem", KeyFile: "key.pem"}}, {name: `TLS Config with valid cert and key PEM`, tlsConfig: Config{CertPem: "cert-pem", KeyPem: "key-pem"}}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := test.tlsConfig.Validate() if test.errorTxt == "" { assert.NoError(t, err) } else { assert.EqualError(t, err, test.errorTxt) } }) } } func TestCipherSuites(t *testing.T) { tests := []struct { name string tlsSetting Config wantErr string result []uint16 }{ { name: "no suites set", tlsSetting: Config{}, result: nil, }, { name: "one cipher suite set", tlsSetting: Config{ CipherSuites: []string{"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"}, }, result: []uint16{tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, }, { name: "invalid cipher suite set", tlsSetting: Config{ CipherSuites: []string{"FOO"}, }, wantErr: `invalid TLS cipher suite: "FOO"`, }, { name: "multiple invalid cipher suites set", tlsSetting: Config{ CipherSuites: []string{"FOO", "BAR"}, }, wantErr: `invalid TLS cipher suite: "FOO" invalid TLS cipher suite: "BAR"`, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { config, err := test.tlsSetting.loadTLSConfig() if test.wantErr != "" { assert.EqualError(t, err, test.wantErr) } else { require.NoError(t, err) assert.Equal(t, test.result, config.CipherSuites) } }) } } func TestSystemCertPool(t *testing.T) { anError := errors.New("my error") tests := []struct { name string tlsConfig Config wantErr error systemCertFn func() (*x509.CertPool, error) }{ { name: "not using system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: false, CAFile: filepath.Join("testdata", "ca-1.crt"), }, wantErr: nil, systemCertFn: x509.SystemCertPool, }, { name: "using system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: true, CAFile: filepath.Join("testdata", "ca-1.crt"), }, wantErr: nil, systemCertFn: x509.SystemCertPool, }, { name: "error loading system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: true, CAFile: filepath.Join("testdata", "ca-1.crt"), }, wantErr: anError, systemCertFn: func() (*x509.CertPool, error) { return nil, anError }, }, { name: "nil system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: true, CAFile: filepath.Join("testdata", "ca-1.crt"), }, wantErr: nil, systemCertFn: func() (*x509.CertPool, error) { return nil, nil }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { oldSystemCertPool := systemCertPool systemCertPool = test.systemCertFn defer func() { systemCertPool = oldSystemCertPool }() serverConfig := ServerConfig{ Config: test.tlsConfig, } c, err := serverConfig.LoadTLSConfig(context.Background()) if test.wantErr != nil { require.ErrorContains(t, err, test.wantErr.Error()) } else { assert.NotNil(t, c.RootCAs) } clientConfig := ClientConfig{ Config: test.tlsConfig, } c, err = clientConfig.LoadTLSConfig(context.Background()) if test.wantErr != nil { assert.ErrorContains(t, err, test.wantErr.Error()) } else { assert.NotNil(t, c.RootCAs) } }) } } func TestSystemCertPool_loadCert(t *testing.T) { anError := errors.New("my error") tests := []struct { name string tlsConfig Config wantErr error systemCertFn func() (*x509.CertPool, error) }{ { name: "not using system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: false, }, wantErr: nil, systemCertFn: x509.SystemCertPool, }, { name: "using system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: true, }, wantErr: nil, systemCertFn: x509.SystemCertPool, }, { name: "error loading system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: true, }, wantErr: anError, systemCertFn: func() (*x509.CertPool, error) { return nil, anError }, }, { name: "nil system cert pool", tlsConfig: Config{ IncludeSystemCACertsPool: true, }, wantErr: nil, systemCertFn: func() (*x509.CertPool, error) { return nil, nil }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { oldSystemCertPool := systemCertPool systemCertPool = test.systemCertFn defer func() { systemCertPool = oldSystemCertPool }() certPool, err := test.tlsConfig.loadCert(filepath.Join("testdata", "ca-1.crt")) if test.wantErr != nil { assert.Equal(t, test.wantErr, err) } else { assert.NotNil(t, certPool) } }) } } func TestCurvePreferences(t *testing.T) { type testCase struct { name string preferences []string expectedCurveIDs []tls.CurveID expectedErr string } tests := []testCase{ { name: "P521", preferences: []string{"P521"}, expectedCurveIDs: []tls.CurveID{tls.CurveP521}, }, { name: "P-256", preferences: []string{"P256"}, expectedCurveIDs: []tls.CurveID{tls.CurveP256}, }, { name: "multiple", preferences: []string{"P256", "P521"}, expectedCurveIDs: []tls.CurveID{tls.CurveP256, tls.CurveP521}, }, { name: "invalid-curve", preferences: []string{"P25223236"}, expectedCurveIDs: []tls.CurveID{}, expectedErr: "invalid curve type", }, } // X25519 curves are not supported when GODEBUG=fips140=only is set, so we // detect if it is and conditionally add test cases for those curves. if !strings.Contains(os.Getenv("GODEBUG"), "fips140=only") { tests = append(tests, testCase{ name: "X25519MLKEM768", preferences: []string{"X25519MLKEM768"}, expectedCurveIDs: []tls.CurveID{tls.X25519MLKEM768}, }, testCase{ name: "X25519", preferences: []string{"X25519"}, expectedCurveIDs: []tls.CurveID{tls.X25519}, }, ) } for _, test := range tests { t.Run(test.name, func(t *testing.T) { tlsSetting := ClientConfig{ Config: Config{ CurvePreferences: test.preferences, }, } config, err := tlsSetting.LoadTLSConfig(context.Background()) if test.expectedErr == "" { require.NoError(t, err) require.ElementsMatchf(t, test.expectedCurveIDs, config.CurvePreferences, "expected %v, got %v", test.expectedCurveIDs, config.CurvePreferences) } else { require.ErrorContains(t, err, test.expectedErr) } }) } } func TestServerConfigValidate(t *testing.T) { tests := []struct { name string serverConfig ServerConfig errorTxt string }{ { name: "server config without certificates", serverConfig: ServerConfig{}, errorTxt: "TLS configuration must include both certificate and key for server connections", }, { name: "server config with cert file but no key", serverConfig: ServerConfig{ Config: Config{ CertFile: "cert.pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, { name: "server config with key file but no cert", serverConfig: ServerConfig{ Config: Config{ KeyFile: "key.pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, { name: "server config with cert PEM but no key", serverConfig: ServerConfig{ Config: Config{ CertPem: "cert-pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, { name: "server config with key PEM but no cert", serverConfig: ServerConfig{ Config: Config{ KeyPem: "key-pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, { name: "server config with both cert file and cert PEM", serverConfig: ServerConfig{ Config: Config{ CertFile: "cert.pem", CertPem: "cert-pem", KeyFile: "key.pem", }, }, errorTxt: "config: provide either certificate file or PEM, but not both", }, { name: "server config with both key file and key PEM", serverConfig: ServerConfig{ Config: Config{ CertFile: "cert.pem", KeyFile: "key.pem", KeyPem: "key-pem", }, }, errorTxt: "config: provide either key file or PEM, but not both", }, { name: "valid server config with cert and key files", serverConfig: ServerConfig{ Config: Config{ CertFile: "cert.pem", KeyFile: "key.pem", }, }, }, { name: "valid server config with cert and key PEM", serverConfig: ServerConfig{ Config: Config{ CertPem: "cert-pem", KeyPem: "key-pem", }, }, }, { name: "valid server config with mixed cert file and key PEM", serverConfig: ServerConfig{ Config: Config{ CertFile: "cert.pem", KeyPem: "key-pem", }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := xconfmap.Validate(test.serverConfig) if test.errorTxt == "" { assert.NoError(t, err) } else { assert.ErrorContains(t, err, test.errorTxt) } }) } } func TestClientConfigValidate(t *testing.T) { tests := []struct { name string clientConfig ClientConfig errorTxt string }{ { name: "valid empty client config", clientConfig: ClientConfig{}, }, { name: "valid client config with insecure connection", clientConfig: ClientConfig{ Insecure: true, }, }, { name: "valid client config with cert and key files", clientConfig: ClientConfig{ Config: Config{ CertFile: "cert.pem", KeyFile: "key.pem", }, }, }, { name: "valid client config with mixed cert file and key PEM", clientConfig: ClientConfig{ Config: Config{ CertFile: "cert.pem", KeyPem: "key-pem", }, }, }, { name: "client config with only cert file", clientConfig: ClientConfig{ Config: Config{ CertFile: "cert.pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, { name: "client config with only key file", clientConfig: ClientConfig{ Config: Config{ KeyFile: "key.pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, { name: "client config with only cert PEM", clientConfig: ClientConfig{ Config: Config{ CertPem: "cert-pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, { name: "client config with only key PEM", clientConfig: ClientConfig{ Config: Config{ KeyPem: "key-pem", }, }, errorTxt: "config: TLS configuration must include both certificate and key (CertFile/CertPem and KeyFile/KeyPem)", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { err := xconfmap.Validate(test.clientConfig) if test.errorTxt == "" { assert.NoError(t, err) } else { assert.ErrorContains(t, err, test.errorTxt) } }) } } opentelemetry-collector-0.141.0/config/configtls/curves_fips.go000066400000000000000000000011021511331344600246440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build requirefips package configtls // import "go.opentelemetry.io/collector/config/configtls" import "crypto/tls" var tlsCurveTypes = map[string]tls.CurveID{ "P256": tls.CurveP256, "P384": tls.CurveP384, "P521": tls.CurveP521, // The following X25519 curves are not available in FIPS mode, so we remove them from the map. // See also https://cs.opensource.google/go/go/+/refs/tags/go1.24.6:src/crypto/ecdh/x25519.go //"X25519": tls.X25519, //"X25519MLKEM768": tls.X25519MLKEM768, } opentelemetry-collector-0.141.0/config/configtls/curves_nofips.go000066400000000000000000000006451511331344600252140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build !requirefips package configtls // import "go.opentelemetry.io/collector/config/configtls" import "crypto/tls" var tlsCurveTypes = map[string]tls.CurveID{ "P256": tls.CurveP256, "P384": tls.CurveP384, "P521": tls.CurveP521, "X25519": tls.X25519, "X25519MLKEM768": tls.X25519MLKEM768, } opentelemetry-collector-0.141.0/config/configtls/doc.go000066400000000000000000000003771511331344600230760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package configtls implements the TLS settings to load and // configure TLS clients and servers. package configtls // import "go.opentelemetry.io/collector/config/configtls" opentelemetry-collector-0.141.0/config/configtls/go.mod000066400000000000000000000033161511331344600231040ustar00rootroot00000000000000module go.opentelemetry.io/collector/config/configtls go 1.24.0 require ( github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d github.com/fsnotify/fsnotify v1.9.0 github.com/google/go-tpm v0.9.7 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/go-tpm-tools v0.4.4 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/confmap v1.47.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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.45.0 // indirect golang.org/x/sys v0.38.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/config/configopaque => ../configopaque replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/config/configtls/go.sum000066400000000000000000000144121511331344600231300ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/go-configfs-tsm v0.2.2 h1:YnJ9rXIOj5BYD7/0DNnzs8AOp7UcvjfTvt215EWcs98= github.com/google/go-configfs-tsm v0.2.2/go.mod h1:EL1GTDFMb5PZQWDviGfZV9n87WeGTR/JUg13RfwkgRo= github.com/google/go-sev-guest v0.9.3 h1:GOJ+EipURdeWFl/YYdgcCxyPeMgQUWlI056iFkBD8UU= github.com/google/go-sev-guest v0.9.3/go.mod h1:hc1R4R6f8+NcJwITs0L90fYWTsBpd1Ix+Gur15sqHDs= github.com/google/go-tdx-guest v0.3.1 h1:gl0KvjdsD4RrJzyLefDOvFOUH3NAJri/3qvaL5m83Iw= github.com/google/go-tdx-guest v0.3.1/go.mod h1:/rc3d7rnPykOPuY8U9saMyEps0PZDThLk/RygXm04nE= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= github.com/google/logger v1.1.1/go.mod h1:BkeJZ+1FhQ+/d087r4dzojEg1u2ZX+ZqG1jTUrLM+zQ= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/config/configtls/metadata.yaml000066400000000000000000000002021511331344600244310ustar00rootroot00000000000000type: config/configtls github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg opentelemetry-collector-0.141.0/config/configtls/testdata/000077500000000000000000000000001511331344600236045ustar00rootroot00000000000000opentelemetry-collector-0.141.0/config/configtls/testdata/ca-1.crt000066400000000000000000000022301511331344600250340ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDNjCCAh4CCQDkU3rM23H5hzANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJB VTESMBAGA1UECAwJQXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoM CU15T3JnTmFtZTEVMBMGA1UEAwwMTXlDb21tb25OYW1lMB4XDTIyMDgwMzA0MTgx OFoXDTMyMDczMTA0MTgxOFowXTELMAkGA1UEBhMCQVUxEjAQBgNVBAgMCUF1c3Ry YWxpYTEPMA0GA1UEBwwGU3lkbmV5MRIwEAYDVQQKDAlNeU9yZ05hbWUxFTATBgNV BAMMDE15Q29tbW9uTmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB AK836YUxmCDcznt11ReI5fY/DSJzz+Fs7czoE72RMvW+SMH2YhX9XC55xAMPZ+IV szoG5Fatd/GWBfoACmaM3ZEmYskuRnu4pxqOEpRIsBukOiILBMxa/cwqiDyLiacC w0B1NhysG28XnxUWrYxd9jFlJ+wAIx7XT+1QM0xGCGr9agSQ/ow6+QMWZ5Qc1n2e EmaoU861qlF+0LeyZeBNeo+C7jTikIC+CRKVNX5t9MLqSmlxfrXe0qCS99zmPKfg OhtteZVAKbdPKSoi2ls6EQ1dNB2Mq3GHkd8kGi30FuRCTQLKaXacUdjtQfbKxuGl RjXlN6mDoUs8mIO861mVFXECAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAUrgRTBBO pwYjZsLNw10FYK19P6FpVm/nbbzTJmqKlxReLRkkTyNm/tB5W1LdRN9RG15h62Ii JBGxpeCMDElwCwXN2OOwqdXczafLa9AhPnPw/DYuQAd9dS7/XHG/ArQFTL+GLd8T bdlnED9Z9qMygF13btLQUHzKaOk6dndLsquoTjgjj4SNBe2Isj7z4upZOix2cgJB 9ddZGlv8/zKSgRp9UotGOOxG7HJ1KWhYLU7E0aERqambNv8UFvhmf+biHq3nCeAF HBeua27MNj4kGCzqHS7sVqZKVU81aFyhV2WmfIUA0Qp+nh9QEW0yrgI+pTnOx6np JUHGleZ3rKHQZw== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configtls/testdata/ca-2.crt000066400000000000000000000022301511331344600250350ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDNjCCAh4CCQDOIY+kxxC6dzANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJB VTESMBAGA1UECAwJQXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoM CU15T3JnTmFtZTEVMBMGA1UEAwwMTXlDb21tb25OYW1lMB4XDTIyMDgwMzA0MTgy N1oXDTMyMDczMTA0MTgyN1owXTELMAkGA1UEBhMCQVUxEjAQBgNVBAgMCUF1c3Ry YWxpYTEPMA0GA1UEBwwGU3lkbmV5MRIwEAYDVQQKDAlNeU9yZ05hbWUxFTATBgNV BAMMDE15Q29tbW9uTmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB ALm3FA/0uN36RPpMnRbV7HF2dY0quEevuHFPjDwBa6bRrn+p1kDezkZ+YGatT7yg Or+HLU+9WoJKQe738d/gp+BRwTpuTkFh6YeM1t+EclZZfSX/jQwia/7p0CGZ24wD CR33YifauT+AMS1VLbkTTFQFQ+XwkIqUL8aP3T1XvYSnOvbeNcIYEH6ABXyDwBdL ytuJ0YnFwYj0lJcAHf1EYQEXNXz6s1E1Y3r4pZfo209PK8aHR/oT1Gc310B35cfA trYaGsynla/aUjrvm147hj32Wln3EG10qkIOAwkR0iTYNfYdCG4vJKUFOSj1AFei A0PWnOYP+zDFR1bEz22VfV8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAluPjsPhg OZ31iLqnRoxDJ8EuYtY2ft1RV4WUY+o9zY24JRZ/1b1cC6VzTECQQTiOuM+G+U0k FlTfU3VaY+m+oP8F/2n9X+9M87flX1AgE3EOqae3CNN7IYCu6ipCLaOZQwL4CjFe hsurX7eyu8LDrX8/T+B60V13gCsXi6E1Dt+9lRNzjIU9YcqwuDqlPU0I0WCjuP2H flisUQ3Z70gg9bPd7h3EVfdrlceGYQpuiO5aHXhzr8oIoOo3K6L6RXaHAjLd56SM ZKa+VUCCJcfq6HwnSRUveu2txD1lUHFag2amfJu22V0JgB4Dvm1ZkzU4PM00ZJSK lSu6E+lI09aLHg== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configtls/testdata/client-1.crt000066400000000000000000000023001511331344600257250ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIJANt5fkUlfxyeMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxODE5WhcNMzIwNzMxMDQxODE5WjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAwDgNEcPTkTASpfFa0AwPlUFPWhlm2Av1mh3oNsf3kHOBXQymJ3HkXDq/ 7durWduubkP1jsOGqO9rcXD1Q3mmNYqsqRRydi5DbMHcFcSSA6g2QncTJwhRE/q/ /00t6e5BhBLXscK+uJEDzEGu9CJVFkkdbeMccfb26C3os1VHGzcp5c/pCNjj93TM 3iwlQYMoEgCo7iUDxyIQ5tjQBn/QmEPcytut11tAIlGPy+SxQjMCykREPOVuwvNh hZFscpCkvQPTEvv7KBZFBvYafa820CY3z++IIqQ7YBZdxYpYwBuVamUyPKB+lpsn aD5G2LQjENdjYcRXys04bWgafalZJQIDAQABoxcwFTATBgNVHREEDDAKgghleGFt cGxlMTANBgkqhkiG9w0BAQsFAAOCAQEAoN6fyv+0ri3wnYMZaP2+m4NA/gk+I4Lp eP4OpQHkHbm3wjbWZUYLJZ6IvhPHfCNAXdqCs+mpG35HI6Bg+x1CVFrNeueInKTg 0v+0q1FlvSQhsQJoumX2bk/uSLHMIU3hhYIts0vFC0k04Vf7n9hEq7pOZD/akTaw haLsQe/SRXSTjkar+Csi4DXyi/qshlkV6FOUz9vogAR0W3l8x7dqzwBHL4gRMddM ZdSfhVFOMwKqUrucYebYZhdAvYqMtlTph46lk+hd5TarFDFJ2zEjbx9NU5gY1b8V /Kfm2ZHR0yWKGfg9I4TRGZgufm1HBEMnMq1b15DUZxNTagFtPAP18Q== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configtls/testdata/client-1.key000066400000000000000000000032131511331344600257310ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAwDgNEcPTkTASpfFa0AwPlUFPWhlm2Av1mh3oNsf3kHOBXQym J3HkXDq/7durWduubkP1jsOGqO9rcXD1Q3mmNYqsqRRydi5DbMHcFcSSA6g2QncT JwhRE/q//00t6e5BhBLXscK+uJEDzEGu9CJVFkkdbeMccfb26C3os1VHGzcp5c/p CNjj93TM3iwlQYMoEgCo7iUDxyIQ5tjQBn/QmEPcytut11tAIlGPy+SxQjMCykRE POVuwvNhhZFscpCkvQPTEvv7KBZFBvYafa820CY3z++IIqQ7YBZdxYpYwBuVamUy PKB+lpsnaD5G2LQjENdjYcRXys04bWgafalZJQIDAQABAoIBAFemN29uWD7QKPC6 SaqslT599W0kQB0r9uY71POF44Fe6hI//lPmPzc/It2XWV80KSnmm0ZqKjFGWzvz QiNuiTfI8Ep5JGh3WA9zpqPWaq54OaW9HmKiDDaMFJiZ3OHa3s0Wunw4TTdkCNNO 8DQqo5nx5RWChioBbz0YEhAURsRFbGqFavDPvlEPOSanCB+mDOliKqX0XizffRZ3 UBQuWa6VjDxHH93b+oJ2/zR5UOlXKHgcqNWeBofxBiiX8ZF5ylwNGOCEE2Gm+KfZ KUYxGlDKohSYxVjmcyLPoWGrUX83lDKD2u9VrVdgCJwA+IHEsIg9KARb6jFLzACp RYSDM9ECgYEA7gm8+h44D27I1yRF/3rbhxggsgRo0j5ag9NVLehp11G0ZsdoklJx uVhDJbjHG9HVqEMfduljr4GpyeMt2ayEmo/ejcWyl0JBMFXPXRvrubM5qoCVOqUu WYo/JtvIyEAQQicwo5okiPddhFvcQebSH7NXRpKWROMftnlisgtv/xsCgYEAzrk1 vB2O/DTydcLxkY2m8E5qo1ZvTMPW6211ZCKNyQ475ZE/QxZ5iuodwErCQOHjAlV7 n6FeWWZveOsVQeTkSvUOnPCocct+/Dx+sMcRO8k9HuC33bNcw9eHwBoztginIxEb s7ee+S06AT6r7SQScgBrhD6uevW+dUVbdw/6TL8CgYEAzOyNSDZjxMV3GeAccsjt 3Oukmhy5sOYFPp/dINyI4dlxGVpqaC2Zwhp+FCdzIjwPWAARQmnCbAGQjkGJ429l 6ToaOqsMCLP9MwNstZen5AKrjmGMFyTFNkiR/X4Q6HReitT6Rp4Y/eEXHS+H+yQf mTLn29WukDeHwavWj7jQ/ikCgYBDPYEZ+C9bH8nBvjAfHQkw3wDWsjWvrX/JwifN 82NVA3k+GbmPE89i/PXCZ066Ff9l8fItISr0P1qA5U5byZzsOLuRFsJjiUJ7vx2i WI3leXaVBZko1r+UwBVayesKCdR7loQBN/fQqwJUB1Oa5gHN7Q8Ly+uq+SYDNRUk LCFJNwKBgGWcVuIarQ2mCLqqZ0zxeAp3lFTNeWG2ZMQtzeuo0iGx0xTTUEaZSiNW MSAvYjGrRzM6XpGEYasfwy0Zoc3loi9nzP5uE4tv8vE72nyMf+OhaPG+Rn+mdBv4 7emViVNVfzLW7L//IkxtEamV0yc6gYwcCfzUckxxXVRD4z2aM78q -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/configtls/testdata/client-2.crt000066400000000000000000000023001511331344600257260ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIJANt5fkUlfxygMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxODI3WhcNMzIwNzMxMDQxODI3WjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA3lTMPmGwYAC86UQWOiXxz5zOPWayTJabxZFyiBkO2kSB2oPD8UuY9Lmn SFd3lj1d5d87sODImwBfpAl8OtWkAlQ7Gz94Qx94tkK1h5t44u2GEM/AZZbAoeaw gLxoGXnWPIt043ZocMlwZHhuwOLTg0sPA8Nqiw6wwrTw6iPvbZZ9h5MtQTETJ2qa BN1sKB/NsHWGfGsIcsiTvDMYfjjOv8w9xKjsVvipsA4MTN6caoJ7Ei1XT61ssp08 zUT+SCQQERlgO+rnVCsz2XbFEJBYqvV1m+QoU/4Ow9D7toT6tgMrGTIKgefiyUSW toMosHXVxK1O7cEjO5ml1o2yhVn6DQIDAQABoxcwFTATBgNVHREEDDAKgghleGFt cGxlMjANBgkqhkiG9w0BAQsFAAOCAQEAO17rOH/w0fZtJ6XL/uVBtcRBX6++7gx0 0hwQ6Gle/XBC/Rt9kK8bGNlULC7f/RIwe2tAvSR9ecu6e29r9tHl+YD7nrHSUsfX iio+pTX7NwD3cERqftq8Gigb9Kgsi6zMlJucwZZFoJfZqC7I0QYUCWasuQLfAQPy X8YFqVsuylICeKbW3WjN3c+Myfr8FGVnA7iXl28nlCMhqQHBQamG1SXlUjYi3jCv +9yPO3fpKeY/KZTfiNVxwYo/JbXorKHjzzObP3gqvHY5ofeOfVsG9dyaTj3oTT1W uLvKkUJqCtgFDsx/F3cUp+aBMCFRkbUHDHEl7HJizqutomTZategNg== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configtls/testdata/client-2.key000066400000000000000000000032171511331344600257360ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpQIBAAKCAQEA3lTMPmGwYAC86UQWOiXxz5zOPWayTJabxZFyiBkO2kSB2oPD 8UuY9LmnSFd3lj1d5d87sODImwBfpAl8OtWkAlQ7Gz94Qx94tkK1h5t44u2GEM/A ZZbAoeawgLxoGXnWPIt043ZocMlwZHhuwOLTg0sPA8Nqiw6wwrTw6iPvbZZ9h5Mt QTETJ2qaBN1sKB/NsHWGfGsIcsiTvDMYfjjOv8w9xKjsVvipsA4MTN6caoJ7Ei1X T61ssp08zUT+SCQQERlgO+rnVCsz2XbFEJBYqvV1m+QoU/4Ow9D7toT6tgMrGTIK gefiyUSWtoMosHXVxK1O7cEjO5ml1o2yhVn6DQIDAQABAoIBAQDTSe8YUapWch0V 6fjdpfXaAgEV5SUJGBBNf95CbN3qnDRzv8lU5S0lVdIeM9GYXBWCQdXuUJEUjRRX RhRjrWjCNd4+FOFrmNsVCuyNRTlrH6PLEkSbxtqmgh+3GFYt79WjkDyzdnHmzekb 8j/+2xF7srdAMlRsdreRMnfJbAE8OISfk3aYoLc1Kn4YGKXLegcEAPTrEKOMNaXZ jGRwHlj1A/HFCh8tHnzdLJOay1aKxyuo82zPV4uVCXcz5Tof21QPjDjW3SaPOq+m UHRYGKqFzK7WWBN7xnbMIkup/HpRtx7ZJ3jaTHBAP72foQyfbBJ+1KLawPK/BBET wcgBkvHBAoGBAPg/tgA3mjNWkwMeAao+YCOND2nhsXejnSHfA44PPOyDWqxefzDx hyf29Rq2dDcJyJV6uyMkyu9XQb0pf+Hh+a4NRXlS6dPzIW0Z1XPoSu9VeXVLPSh0 CZg82t8UtGMTtGinfDEULM3v0sQWhND1xsX/vFCZvBEXlwAI1zuqFm/1AoGBAOVF 7GywlCdm4xn4RErA/+HqWPaNAaJAAo4OVgvj/mcu91swGrQoLy6yFEu61mkAr2nn H+hYV/WU8nhkR6nStq1eydBKZxzyRIi8ZAmT4CemGX2C/fNF7KSNYqzFsHK/Pymh AsMNiykvPFCeG7S2GiDEFO+AKExqy5O16Q4nBYq5AoGAUZ9BDBk8Dh0tAR1glsUj fwzmQH4Ah8G37GcTGCZSdcFKktoPH9yJ/83nEP1kgKQq21sbJJb4UnFyH+wBLBfM rDmY2ic00odiOikAUbfSy5Zi9PnkBeUBMpjvreF03g6ghrhq0Qg9IwjzV52/1aS5 0mgfVrD1cPk8oLpHakqmTfECgYEAvvra8MK59oRWwigyws43l7j8+AsHBF8rgadh d7AoF01hEF1msREUFGKUU2zD8111wNKcmo8UXeX/f9eQdl6meo4Nr+p6L/uCqR+8 eNnsCzrp2soFveJON9fqDR7zVvIFrCiJw26BsAG/zSuWypYx938+LS5k4xrGjzkl c/t/O0kCgYEA0Iwb+qWOCQ4U+wlQjYjhTn3scDZ/EpVEzuh53FEOWY1OtXm8f1qK m5I8yj1mOJ5N11cuk7zi0THFJ/wDYSJBshG+05jx2ngk5rWsnnV0jmX6ivOUMrFf BbZZjSvzRQlRQbrtwKWluC7yDO0X+YuG4Wbte4i6XNMn5fseWTnwGdY= -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/configtls/testdata/server-1.crt000066400000000000000000000023001511331344600257550ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIJANt5fkUlfxydMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxODE4WhcNMzIwNzMxMDQxODE4WjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAzEc0zUZZhPx+70Et3YVvNv9Ss/EriG3x/Eo7gUr+JH1bi2dJe8bBhaqJ j1XXr0qFAahOlj9+/NDS7RON8p1AeXLMzL8mJ162WUU+a4Uus78Md6l0oVKNsVm+ tUiNT2RVeJWkJtJPRnScdXqf10I498xNNYDfYcl0u/JHX33oekwKPhxn6zHJ6V/b Z6BbOsV/MXaB6WRYHRfzxO25hoxELBS6rdlrLdeqy0hlQ3i2UE/Yet3pl1Wi18bh Bk6kyhoqIfF5tMLNdwwYfHNVNutpv9jUcPFkxLWXVU/FxwjJrBsGVAp4fohUbSN8 lHj+BtYthyF6vL0gdXxnD01jkYXDVwIDAQABoxcwFTATBgNVHREEDDAKgghleGFt cGxlMTANBgkqhkiG9w0BAQsFAAOCAQEAKFflP5DnHjloj3PvSQ1iVKBRTvxwEtKV 9ObCPK59uUaLZbwZ0QljgfkqxNtL/8FB/LgBdvqHioYx9F4kocpJrwci8a6oU42/ iOpw+D4d6emjPWZDf3WVgmynjyPd5VxK/TO8ly//FjPXNTDpWCs/CqIphHR64/5B l1VunN9STqj24WP+Ud+3OxNd1GPu0r45lqO/PDdn7cWWYbNZ67zJdnZPoHQRyL1U dZ/jYmS99y66AfG16TFFKNa3bfCS4uRFOlddNs1uXnq40yqsaE/Gv6Ts7X3uND/0 qExVGHaK2iR7qgBIV8axE3nwZ5RbIxF5LR64I43RI5HaDrRt2e1YAw== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configtls/testdata/server-1.key000066400000000000000000000032131511331344600257610ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAzEc0zUZZhPx+70Et3YVvNv9Ss/EriG3x/Eo7gUr+JH1bi2dJ e8bBhaqJj1XXr0qFAahOlj9+/NDS7RON8p1AeXLMzL8mJ162WUU+a4Uus78Md6l0 oVKNsVm+tUiNT2RVeJWkJtJPRnScdXqf10I498xNNYDfYcl0u/JHX33oekwKPhxn 6zHJ6V/bZ6BbOsV/MXaB6WRYHRfzxO25hoxELBS6rdlrLdeqy0hlQ3i2UE/Yet3p l1Wi18bhBk6kyhoqIfF5tMLNdwwYfHNVNutpv9jUcPFkxLWXVU/FxwjJrBsGVAp4 fohUbSN8lHj+BtYthyF6vL0gdXxnD01jkYXDVwIDAQABAoIBAQCxGeLLPPyLcSTT ZJzQ+sgq1DztSF9HjppG8kyYkV24YP4m48svhmds7ScJn5C4plCd2T8Yv7/mi1zy sQtVlcO6By9LK0V2yIQq7P9q1DJjH3U9oSo+WoYBhh7yqA3rEL+RJZsFFTwphxvG NiOxyfX9z5/4jNwduTx9XVVHkq8kpo9saJ0FAPCgAlwKTrUwVANm9D0UlJEotat2 qDLV2WKzJHL3v0MLku2hN1B4pOpOCIzQUNMtxvW9kWSETBBYuEDj0qmUoRQgCJS2 4dbF5nvbiK3dEdZgp1dGDX2RJY/+Oe3jDlCtvJCLShLnb2g/j8ByKRY7zICrYtIO EBxvmvyhAoGBAOqRQl95l8zw8uaBZu8QQ9RnbSt9nk7aYJGMdUABE88Hc8sOtC2U ayBKd1v/d46Op2otDEYWNQI0DzLdW0LBIjP1qbTiGL2FCknGq4fqbvySy21DcX+b +sGd90fNRVG3XJGn63nhoGKGnYvzQGrmm0cVlbQ3KyMzwhsqcUrDv5/ZAoGBAN7x dDoIximyp/98CFmCFMtxCMBvNVywmHTTyieeO36A3Mdy300IItUwBtENxMjotXB0 Kc6MX3JrJh8d+z8xsAkmeFnfL9uMjjL0EpZy11eDTi/+fUZ/Bcph/zOYFfPFccK7 cHLCJyFhnSJNR63QE0Avz6oPcFI7rvjMJnSOsq6vAoGAIznhT9lA1MQyli9EuA4n QZSurmNVDN56tiDz0sLWqLajyxDQOjAZzmWgey5oU/5UYfuV5kibeVM8HRVlCSdb 7ZWtAL8bnAqIuv+c7vJj7IZXCnegaduQ0tbYNe47xMPWoQEoucsKfQFeU5AaUnOD Si+RpdjLH6Q8ODwte17ePjECgYA5G/j99MluXQmT9J3e7+eLxcTMJrCwsbwcETSz uWDcIv5rSQ3SmcbyfX8BhllmbdYsnFUpR+QbVz9IsVFu+rdxYJ1ryDRmNTcn7kXk rD5leIlK2hIVQOymzzukZ80XyPg/PeysOPf1ISAzbUBzUd3cj2LO2W2YYxmLOiCP sw4qmQKBgCR0EpTfcm+wzQ3LWAPbsA6DsqvDtYfQumfg1uFglHrJXHtPZj9Mp0om ZdRWL4vOmI/o6lfmHYdqHMnwyMHJU1JkcBnnhbQo5cGJZ17d580FZ9oVPVqqVQvR OhjWcqU7n+0ZvSWakHAvbgPSCeQpA19x0WLDR1WUbKszHIoQwzwe -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/configtls/testdata/server-2.crt000066400000000000000000000023001511331344600257560ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDVDCCAjygAwIBAgIJANt5fkUlfxyfMA0GCSqGSIb3DQEBCwUAMF0xCzAJBgNV BAYTAkFVMRIwEAYDVQQIDAlBdXN0cmFsaWExDzANBgNVBAcMBlN5ZG5leTESMBAG A1UECgwJTXlPcmdOYW1lMRUwEwYDVQQDDAxNeUNvbW1vbk5hbWUwHhcNMjIwODAz MDQxODI3WhcNMzIwNzMxMDQxODI3WjBdMQswCQYDVQQGEwJBVTESMBAGA1UECAwJ QXVzdHJhbGlhMQ8wDQYDVQQHDAZTeWRuZXkxEjAQBgNVBAoMCU15T3JnTmFtZTEV MBMGA1UEAwwMTXlDb21tb25OYW1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEA2bdn2gv8i6J0gNHilYDFVTwYUgNWJNe23sdxyuAbSoocir61LT1HBtWP m/Slfw8xcGYomiu5iIPNWF6KGDpUsafawkxZFySNCWTXlU68Vk7iyJLGQ3e1uhFM lOsRvrRB65OUsdyXF1e4+T1KMGiz2yEWIDxpe1o4uchenVM1WOddlZMIPB1E3UzR DjLJUXfihWeoQwWisfBJw6bHPne1sj7OmS0feUJUza9i8bXe8TgYLkLyo5IUNQpf EkpAu+7DoOdRfURApz4TpeY5RkQ5ztSC8LnXQ0ZR4C0D8i8DdOxW1Sj2HTkjY9KO exPnP12UgVeo9KsdtEqIF15n3TDxzQIDAQABoxcwFTATBgNVHREEDDAKgghleGFt cGxlMjANBgkqhkiG9w0BAQsFAAOCAQEAq05+tW+c6jg/Kes9RPpnGKgm73COu+qR T/n9D+jeqizBszQbjvwwQWzyQEIeN5hVf0DqMa/GJPvtVu+Im4FeW9cCc/2UccvK KsRagdLJUBih9KkY4Z+uzVcPUt6xYFQHgKlR7aR7uSoUicgw8Xtg84px4BDrKlJJ RoPAI6+RdauRUs9XqYG4bU1rr1pbhxNMMlNYAvLekgT/5h39uxuaqgkmWZXRRQBP rbddw+wPPhYJ0X6lzs5LbtAa1oiaLgQxWnrmKWAgEQqfr8apWBuC3CWg9GyXH5OK 5AgjxKCQJHc5WdUUxbcNYCMBubEBxGp9FTwfvYOF6sFhrC8+1kTrHg== -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configtls/testdata/server-2.key000066400000000000000000000032171511331344600257660ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEpgIBAAKCAQEA2bdn2gv8i6J0gNHilYDFVTwYUgNWJNe23sdxyuAbSoocir61 LT1HBtWPm/Slfw8xcGYomiu5iIPNWF6KGDpUsafawkxZFySNCWTXlU68Vk7iyJLG Q3e1uhFMlOsRvrRB65OUsdyXF1e4+T1KMGiz2yEWIDxpe1o4uchenVM1WOddlZMI PB1E3UzRDjLJUXfihWeoQwWisfBJw6bHPne1sj7OmS0feUJUza9i8bXe8TgYLkLy o5IUNQpfEkpAu+7DoOdRfURApz4TpeY5RkQ5ztSC8LnXQ0ZR4C0D8i8DdOxW1Sj2 HTkjY9KOexPnP12UgVeo9KsdtEqIF15n3TDxzQIDAQABAoIBAQCoCDKiCoBG8QJD 7jmXs4QZ7cDDg4m387lTJdGAiAjoNcIjn17L5LBt6OPmtSIJ95rrqh0KKFcQstEI tCaW3mZBm1Buh2h3QSGNL4Rn2xXm8wl7TjSxG7JpQjK9+NOAQTVjcUrhH2SJgo3j 51bcF+NAa7/c72Nl7dM8KBZGDFNvIe3uhFk67aBZ/A3Qto7ZYTz9hrowc08iehhm i9fZ0T09UPw3Mplpx5bUx8kSZQLe15No7B5VJ31J4+64ufG9iypEW62bueROitgz shBTifEg/9rhZbt2wDIC31oZ2jXORSFLZPKjji5ygSm7ExVvaTfgsn+XMXP4JXVt v5F0gDthAoGBAPPk3y9ZAmTTecAiFL01FQdpEpd4qOQQenGBhhuOxaP7ZQRjxGDK yWV7taJyAVhdXAhKLMpqsE6wLMskRp8FZwkFZc+1Wt5QE4XfNmme2s/tSltQ2uG+ 7bMeGys5yhUjsWWuZ/57/1xlyUmMpYTPG66CQuqg4qGn3SFg2aiqZ5GZAoGBAOSF 5gzo4Wn/jFeRTXUqkn1smBPBZC5/zqyfX6zlzJrPFm93NJ8jZqp53qzixcCs+yls EWIUkFCFy7GN+tU+Wkz4JWs2BTXcThraoa4hciAmYIHCB+ZTbncnaHbBP/C/0pZp Z0HvhKR01FAXEDfxN+A0807LoHcFDlv7cRvBzqpVAoGBAJlkPsJGluzW3GHsjWKa eglZGipN5trZSkkND01RtBf4SoZCQQYnRBchgRET5qiuvu0vyY/dHdm/j8yLmib1 fOH9lRTXmLjtX/n4cv5mvHO9Z+Car67/J/xZWPkMtX4qHq42zI0Pa4GvOrOZU5h9 sYlFv9RVL3RAYSFXCk28LrsxAoGBAMrBLoq3uQAWF0u+hM329sBHsGqexKcpCJNK WFYMEcws/wfo6QxlGXsZ5ALatYAtOi7XTlkKS7zV6RNhGHNI/k+aP4DvDhJqo/XZ k2fvDtYNlsSqBd5KmhEoKtxqu7N8Tnjbjh0HSVWsvo9M1zv7ToskD9gSfQ38s2/T GNj6zMV9AoGBAJAdinxXTWMWLCWyZREPolRiRMoahYhPYuHWHU0LiWJ3VidGo8Uv haTOyhyx3zHqRtQKBTHdQLcGa2NGwdeKWmctCn7v593ykKIwde66xu0RFNbwrxbl D2m1zpim+nKj4YQqmSBg+Y7FixLgywKgE2djmUTHFl8Fa3d1xw9mXUS5 -----END RSA PRIVATE KEY----- opentelemetry-collector-0.141.0/config/configtls/testdata/testCA-bad.txt000066400000000000000000000001061511331344600262510ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- bad certificate -----END CERTIFICATE----- opentelemetry-collector-0.141.0/config/configtls/tpm.go000066400000000000000000000030501511331344600231200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configtls // import "go.opentelemetry.io/collector/config/configtls" import ( "crypto/tls" "crypto/x509" "encoding/pem" "fmt" tpmkeyfile "github.com/foxboron/go-tpm-keyfiles" "github.com/google/go-tpm/tpm2/transport" ) // TPMConfig defines trusted platform module configuration for storing TLS keys. type TPMConfig struct { Enabled bool `mapstructure:"enabled"` // The path to the TPM device or Unix domain socket. // For instance /dev/tpm0 or /dev/tpmrm0. Path string `mapstructure:"path"` OwnerAuth string `mapstructure:"owner_auth"` Auth string `mapstructure:"auth"` // prevent unkeyed literal initialization _ struct{} } func (c TPMConfig) tpmCertificate(keyPem, certPem []byte, openTPM func() (transport.TPMCloser, error)) (tls.Certificate, error) { tpm, err := openTPM() if err != nil { return tls.Certificate{}, err } tpmKey, err := tpmkeyfile.Decode(keyPem) if err != nil { return tls.Certificate{}, fmt.Errorf("failed to load TPM key: %w", err) } tpmSigner, err := tpmKey.Signer(tpm, []byte(c.OwnerAuth), []byte(c.Auth)) if err != nil { return tls.Certificate{}, fmt.Errorf("failed to load TPM signer: %w", err) } certDER, _ := pem.Decode(certPem) x509Cert, err := x509.ParseCertificate(certDER.Bytes) if err != nil { return tls.Certificate{}, fmt.Errorf("failed to parse certificate: %w", err) } return tls.Certificate{ Certificate: [][]byte{ x509Cert.Raw, }, Leaf: x509Cert, PrivateKey: tpmSigner, }, nil } opentelemetry-collector-0.141.0/config/configtls/tpm_open_linux.go000066400000000000000000000013661511331344600253700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build linux package configtls // import "go.opentelemetry.io/collector/config/configtls" import ( "errors" "fmt" "github.com/google/go-tpm/tpm2/transport" "github.com/google/go-tpm/tpmutil" ) // for testing var tpmSimulator transport.TPMCloser func openTPM(path string) func() (transport.TPMCloser, error) { return func() (transport.TPMCloser, error) { if path == "" { return nil, errors.New("TPM path is not set") } if path == "simulator" { return tpmSimulator, nil } tpm, err := tpmutil.OpenTPM(path) if err != nil { return nil, fmt.Errorf("failed to open TPM (%s): %w", path, err) } return transport.FromReadWriteCloser(tpm), nil } } opentelemetry-collector-0.141.0/config/configtls/tpm_open_others.go000066400000000000000000000010431511331344600255250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build !linux && !windows package configtls // import "go.opentelemetry.io/collector/config/configtls" import ( "errors" "github.com/google/go-tpm/tpm2/transport" ) // for testing var tpmSimulator transport.TPMCloser func openTPM(path string) func() (transport.TPMCloser, error) { return func() (transport.TPMCloser, error) { if path == "simulator" { return tpmSimulator, nil } return nil, errors.New("TPM is not supported on this platform") } } opentelemetry-collector-0.141.0/config/configtls/tpm_open_windows.go000066400000000000000000000010441511331344600257140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build windows package configtls // import "go.opentelemetry.io/collector/config/configtls" import ( "fmt" "github.com/google/go-tpm/tpm2/transport" "github.com/google/go-tpm/tpmutil" ) func openTPM(_ string) func() (transport.TPMCloser, error) { return func() (transport.TPMCloser, error) { tpm, err := tpmutil.OpenTPM() if err != nil { return nil, fmt.Errorf("failed to open TPM: %w", err) } return transport.FromReadWriteCloser(tpm), nil } } opentelemetry-collector-0.141.0/config/configtls/tpm_test.go000066400000000000000000000136601511331344600241670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Don't run this test on Windows, as it requires a TPM simulator which depends on openssl headers. //go:build !windows && !darwin package configtls // import "go.opentelemetry.io/collector/config/configtls" import ( "bytes" "crypto" "crypto/rand" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "errors" "io" "math/big" "net" "os" "path/filepath" "testing" "time" keyfile "github.com/foxboron/go-tpm-keyfiles" "github.com/google/go-tpm/tpm2" "github.com/google/go-tpm/tpm2/transport" "github.com/google/go-tpm/tpm2/transport/simulator" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestTPM_loadCertificate(t *testing.T) { testutil.SkipIfFIPSOnly(t, "use of CFB is not allowed in FIPS 140-only mode") tpm, err := simulator.OpenSimulator() require.NoError(t, err) defer tpm.Close() tpmSimulator = tpm // create a TPM key and certificate // the TPM key will be stored in the simulator tpmKey, cert := createTPMKeyCert(t, tpm) tempFileKey, err := os.CreateTemp(t.TempDir(), "tpmkey.key") require.NoError(t, err) _, err = tempFileKey.Write(tpmKey) require.NoError(t, err) tempFileCrt, err := os.CreateTemp(t.TempDir(), "tpmcert.crt") require.NoError(t, err) _, err = tempFileCrt.Write(cert) require.NoError(t, err) defer func() { tempFileKey.Close() os.Remove(tempFileKey.Name()) tempFileCrt.Close() os.Remove(tempFileCrt.Name()) }() tlsCfg := Config{ CertFile: tempFileCrt.Name(), KeyFile: tempFileKey.Name(), TPMConfig: TPMConfig{ Enabled: true, Path: "simulator", }, } tlsCertificate, err := tlsCfg.loadCertificate() require.NoError(t, err) require.NotNil(t, tlsCertificate) h := crypto.SHA256.New() h.Write([]byte("message")) b := h.Sum(nil) // this is delegated to the TPM signer := tlsCertificate.PrivateKey.(crypto.Signer) signature, _ := signer.Sign(io.Reader(nil), b, crypto.SHA256) // load the key again to get access to verify function loadedTPMKey, err := keyfile.Decode(tpmKey) require.NoError(t, err) ok, err := loadedTPMKey.Verify(crypto.SHA256, b, signature) require.NoError(t, err) assert.True(t, ok) } func TestTPM_loadCertificate_error(t *testing.T) { tlsCfg := Config{ CertPem: "invalid", KeyPem: "invalid", TPMConfig: TPMConfig{ Enabled: true, Path: "simulator", }, } tlsCertificate, err := tlsCfg.loadCertificate() assert.Equal(t, "failed to load private key from TPM: failed to load TPM key: not an armored key", err.Error()) require.NotNil(t, tlsCertificate) } func TestTPM_tpmCertificate_errors(t *testing.T) { tpm, err := simulator.OpenSimulator() require.NoError(t, err) defer tpm.Close() openTPMFunc := func() (transport.TPMCloser, error) { return tpm, nil } key, _ := createTPMKeyCert(t, tpm) invalidCert := []byte(`-----BEGIN CERTIFICATE----- VGhpcyBpcyBub3QgYSBjZXJ0aWZpY2F0ZS4= -----END CERTIFICATE-----`) tests := []struct { name string key string openTPM func() (transport.TPMCloser, error) cert string err string }{ { name: "invalid key", key: "invalid", openTPM: openTPMFunc, err: "failed to load TPM key: not an armored key", }, { name: "invalid cert", key: string(key), cert: string(invalidCert), openTPM: openTPMFunc, err: "failed to parse certificate: x509: malformed certificate", }, { name: "failed to open TPM", openTPM: func() (transport.TPMCloser, error) { return nil, errors.New("failed to open TPM") }, err: "failed to open TPM", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { tpmCfg := &TPMConfig{} _, err = tpmCfg.tpmCertificate([]byte(test.key), []byte(test.cert), test.openTPM) assert.EqualError(t, err, test.err) }) } } func TestTPM_open(t *testing.T) { socketPath := filepath.Join(t.TempDir(), "app.sock") listener, err := net.Listen("unix", socketPath) require.NoError(t, err) defer listener.Close() tests := []struct { path string err string }{ { path: "", err: "TPM path is not set", }, { path: "/foo", err: "failed to open TPM (/foo): stat /foo: no such file or directory", }, { path: socketPath, }, } for _, test := range tests { t.Run(test.path, func(t *testing.T) { tpm, openErr := openTPM(test.path)() if test.err != "" { require.Nil(t, tpm) assert.Equal(t, test.err, openErr.Error()) } else { require.NoError(t, openErr) require.NotNil(t, tpm) tpm.Close() } }) } } func createTPMKeyCert(t *testing.T, tpm transport.TPMCloser) ([]byte, []byte) { tpmKey, err := keyfile.NewLoadableKey(tpm, tpm2.TPMAlgECC, 256, []byte("")) require.NoError(t, err) tpmKeySigner, err := tpmKey.Signer(tpm, []byte(""), []byte("")) require.NoError(t, err) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) // 128-bit random number serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) require.NoError(t, err) template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"OpenTelemetry"}, CommonName: "localhost", }, NotBefore: time.Now(), NotAfter: time.Now().Add(366 * 24 * time.Hour), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, BasicConstraintsValid: true, DNSNames: []string{"localhost"}, IPAddresses: []net.IP{ net.ParseIP("127.0.0.1"), net.ParseIP("::1"), }, } tpmPublicKey, err := tpmKey.PublicKey() require.NoError(t, err) derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, tpmPublicKey, tpmKeySigner) require.NoError(t, err) certBuffer := &bytes.Buffer{} err = pem.Encode(certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) require.NoError(t, err) return tpmKey.Bytes(), certBuffer.Bytes() } opentelemetry-collector-0.141.0/confmap/000077500000000000000000000000001511331344600201615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/Makefile000066400000000000000000000000331511331344600216150ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/confmap/README.md000066400000000000000000000261701511331344600214460ustar00rootroot00000000000000# Confmap | Status | | | ------------- |-----------| | Stability | [stable]: logs, metrics, traces | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Apkg%2Fconfmap%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Apkg%2Fconfmap) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Apkg%2Fconfmap%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Apkg%2Fconfmap) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@mx-psi](https://www.github.com/mx-psi), [@evan-bradley](https://www.github.com/evan-bradley) | [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable # High Level Design ## Conf The [Conf](confmap.go) represents the raw configuration for a service (e.g. OpenTelemetry Collector). ## Provider The [Provider](provider.go) provides configuration, and allows to watch/monitor for changes. Any `Provider` has a `` associated with it, and will provide configs for `configURI` that follow the ":" format. This format is compatible with the URI definition (see [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986)). The `` MUST be always included in the `configURI`. The scheme for any `Provider` MUST be at least 2 characters long to avoid conflicting with a driver-letter identifier as specified in [file URI syntax](https://datatracker.ietf.org/doc/html/rfc8089#section-2). ## Converter The [Converter](converter.go) allows implementing conversion logic for the provided configuration. One of the most common use-case is to migrate/transform the configuration after a backwards incompatible change. ## Resolver The `Resolver` handles the use of multiple [Providers](#provider) and [Converters](#converter) simplifying configuration parsing, monitoring for updates, and the overall life-cycle of the used config providers. The `Resolver` provides two main functionalities: [Configuration Resolving](#configuration-resolving) and [Watching for Updates](#watching-for-updates). ### Configuration Resolving The `Resolver` receives as input a set of `Providers`, a list of `Converters`, and a list of configuration identifier `configURI` that will be used to generate the resulting, or effective, configuration in the form of a `Conf`, that can be used by code that is oblivious to the usage of `Providers` and `Converters`. `Providers` are used to provide an entire configuration when the `configURI` is given directly to the `Resolver`, or an individual value (partial configuration) when the `configURI` is embedded into the `Conf` as a values using the syntax `${configURI}`. **Limitation:** - When embedding a `${configURI}` the uri cannot contain dollar sign ("$") character unless it embeds another uri. - The number of URIs is limited to 100. ```terminal Resolver Provider Resolve โ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€ โ”‚ Retrieve โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ โ”‚ Conf โ”‚ โ”‚ โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค foreach โ”‚ โ”‚ โ”‚ configURI โ”‚ โ”œโ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚Merge โ”‚ โ”‚ โ”‚โ—„โ”€โ”€โ”˜ โ”‚ โ””โ”€ โ”‚ โ”‚ โ”Œโ”€ โ”‚ Retrieve โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ โ”‚ Partial Conf Value โ”‚ โ”‚ โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค foreach โ”‚ โ”‚ โ”‚ embedded โ”‚ โ”‚ โ”‚ configURI โ”‚ โ”œโ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚Replace โ”‚ โ”‚ โ”‚โ—„โ”€โ”€โ”˜ โ”‚ โ””โ”€ โ”‚ โ”‚ โ”‚ Converter โ”‚ โ”Œโ”€ โ”‚ Convert โ”‚ โ”‚ โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ foreach โ”‚ โ”‚ โ”‚ โ”‚ Converter โ”‚ โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ””โ”€ โ”‚ โ”‚ โ”‚ โ”‚ โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ``` The `Resolve` method proceeds in the following steps: 1. Start with an empty "result" of `Conf` type. 2. For each config URI retrieves individual configurations, and merges it into the "result". 3. For each embedded config URI retrieves individual value, and replaces it into the "result". 4. For each "Converter", call "Convert" for the "result". 5. Return the "result", aka effective, configuration. #### (Experimental) Append merging strategy for lists You can opt-in to experimentally combine slices instead of discarding the existing ones by enabling the `confmap.enableMergeAppendOption` feature flag. Lists are appended in the order in which they appear in their configuration sources. This will **not** become the default in the future, we are still deciding how this should be configured and want your feedback on [this issue](https://github.com/open-telemetry/opentelemetry-collector/issues/8754). ##### Example Consider the following configs, ```yaml # main.yaml receivers: otlp/in: processors: attributes/example: actions: - key: key value: "value" action: upsert exporters: otlp/out: extensions: file_storage: service: pipelines: traces: receivers: [ otlp/in ] processors: [ attributes/example ] exporters: [ otlp/out ] extensions: [ file_storage ] ``` ```yaml # extra_extension.yaml extensions: healthcheckv2: service: extensions: [ healthcheckv2 ] pipelines: traces: ``` If you run the Collector with following command, ``` otelcol --config=main.yaml --config=extra_extension.yaml --feature-gates=confmap.enableMergeAppendOption ``` then the final configuration after config resolution will look like following: ```yaml # main.yaml receivers: otlp/in: processors: attributes/example: actions: - key: key value: "value" action: upsert exporters: otlp/out: extensions: file_storage: healthcheckv2: service: pipelines: traces: receivers: [ otlp/in ] processors: [ attributes/example ] exporters: [ otlp/out ] extensions: [ file_storage, healthcheckv2 ] ``` Notice that the `service::extensions` list is a combination of both configurations. By default, the value of the last configuration source passed, `extra_extension`, would be used, so the extensions list would be: `service::extensions: [healthcheckv2]`. > [!NOTE] > By enabling this feature gate, all the lists in the given configuration will be merged. ### Watching for Updates After the configuration was processed, the `Resolver` can be used as a single point to watch for updates in the configuration retrieved via the `Provider` used to retrieve the โ€œinitialโ€ configuration and to generate the โ€œeffectiveโ€ one. ```terminal Resolver Provider โ”‚ โ”‚ Watch โ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ โ”‚ โ”‚ . . . . . . โ”‚ onChange โ”‚ โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ``` The `Resolver` does that by passing an `onChange` func to each `Provider.Retrieve` call and capturing all watch events. Calling the `onChange` func from a provider triggers the collector to re-resolve new configuration: ```terminal Resolver Provider โ”‚ โ”‚ Watch โ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ โ”‚ โ”‚ . . . . . . โ”‚ onChange โ”‚ โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ | | Resolve โ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Retrieve โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ โ”‚ Conf โ”‚ โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ ``` An example of a `Provider` with an `onChange` func that periodically gets notified can be found in provider_test.go as UpdatingProvider ## Troubleshooting ### Null Maps Due to how our underlying merge library, [koanf](https://github.com/knadh/koanf), behaves, configuration resolution will treat configuration such as ```yaml processors: ``` as null, which is a valid value. As a result if you have configuration `A`: ```yaml receivers: nop: processors: nop: exporters: nop: extensions: nop: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] ``` and configuration `B`: ```yaml processors: ``` and do `./otelcorecol --config A.yaml --config B.yaml` The result will be an error: ``` Error: invalid configuration: service::pipelines::traces: references processor "nop" which is not configured 2024/06/10 14:37:14 collector server run finished with error: invalid configuration: service::pipelines::traces: references processor "nop" which is not configured ``` This happens because configuration `B` sets `processors` to null, removing the `nop` processor defined in configuration `A`, so the `nop` processor referenced in configuration `A`'s pipeline no longer exists. This situation can be remedied 2 ways: 1. Use `{}` when you want to represent an empty map, such as `processors: {}` instead of `processors:`. 2. Omit configuration like `processors:` from your configuration. opentelemetry-collector-0.141.0/confmap/confmap.go000066400000000000000000000034211511331344600221330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package confmap // import "go.opentelemetry.io/collector/confmap" import ( "go.opentelemetry.io/collector/confmap/internal" ) // KeyDelimiter is used as the default key delimiter in the default koanf instance. var KeyDelimiter = internal.KeyDelimiter // MapstructureTag is the struct field tag used to record marshaling/unmarshaling settings. // See https://pkg.go.dev/github.com/go-viper/mapstructure/v2 for supported values. var MapstructureTag = internal.MapstructureTag // New creates a new empty confmap.Conf instance. func New() *Conf { return internal.New() } // NewFromStringMap creates a confmap.Conf from a map[string]any. func NewFromStringMap(data map[string]any) *Conf { return internal.NewFromStringMap(data) } // Conf represents the raw configuration map for the OpenTelemetry Collector. // The confmap.Conf can be unmarshalled into the Collector's config using the "service" package. type Conf = internal.Conf type UnmarshalOption = internal.UnmarshalOption // WithIgnoreUnused sets an option to ignore errors if existing // keys in the original Conf were unused in the decoding process // (extra keys). func WithIgnoreUnused() UnmarshalOption { return internal.WithIgnoreUnused() } type MarshalOption = internal.MarshalOption // Unmarshaler interface may be implemented by types to customize their behavior when being unmarshaled from a Conf. // Only types with struct or pointer to struct kind are supported. type Unmarshaler = internal.Unmarshaler // Marshaler defines an optional interface for custom configuration marshaling. // A configuration struct can implement this interface to override the default // marshaling. type Marshaler = internal.Marshaler opentelemetry-collector-0.141.0/confmap/confmaptest/000077500000000000000000000000001511331344600225045ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/confmaptest/configtest.go000066400000000000000000000031371511331344600252040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmaptest // import "go.opentelemetry.io/collector/confmap/confmaptest" import ( "fmt" "os" "path/filepath" "regexp" yaml "go.yaml.in/yaml/v3" "go.opentelemetry.io/collector/confmap" ) // LoadConf loads a confmap.Conf from file, and does NOT validate the configuration. func LoadConf(fileName string) (*confmap.Conf, error) { // Clean the path before using it. content, err := os.ReadFile(filepath.Clean(fileName)) if err != nil { return nil, fmt.Errorf("unable to read the file %v: %w", fileName, err) } var rawConf map[string]any if err := yaml.Unmarshal(content, &rawConf); err != nil { return nil, err } return confmap.NewFromStringMap(rawConf), nil } var schemeValidator = regexp.MustCompile("^[A-Za-z][A-Za-z0-9+.-]+$") // ValidateProviderScheme enforces that given confmap.Provider.Scheme() object is following the restriction defined by the collector: // - Checks that the scheme name follows the restrictions defined https://datatracker.ietf.org/doc/html/rfc3986#section-3.1 // - Checks that the scheme name has at leas two characters per the confmap.Provider.Scheme() comment. func ValidateProviderScheme(p confmap.Provider) error { scheme := p.Scheme() if len(scheme) < 2 { return fmt.Errorf("scheme must be at least 2 characters long: %q", scheme) } if !schemeValidator.MatchString(scheme) { return fmt.Errorf("scheme names consist of a sequence of characters beginning with a letter and followed by any combination of letters, digits, \"+\", \".\", or \"-\": %q", scheme) } return nil } opentelemetry-collector-0.141.0/confmap/confmaptest/configtest_test.go000066400000000000000000000034321511331344600262410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmaptest import ( "context" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" ) func TestLoadConfFileNotFound(t *testing.T) { _, err := LoadConf("file/not/found") assert.Error(t, err) } func TestLoadConfInvalidYAML(t *testing.T) { _, err := LoadConf(filepath.Join("testdata", "invalid.yaml")) require.Error(t, err) } func TestLoadConf(t *testing.T) { cfg, err := LoadConf(filepath.Join("testdata", "simple.yaml")) require.NoError(t, err) assert.Equal(t, map[string]any{"floating": 3.14}, cfg.ToStringMap()) } func TestToStringMapSanitizeEmptySlice(t *testing.T) { cfg, err := LoadConf(filepath.Join("testdata", "empty-slice.yaml")) require.NoError(t, err) assert.Equal(t, map[string]any{"slice": []any{}}, cfg.ToStringMap()) } func TestValidateProviderScheme(t *testing.T) { assert.NoError(t, ValidateProviderScheme(&schemeProvider{scheme: "file"})) assert.NoError(t, ValidateProviderScheme(&schemeProvider{scheme: "s3"})) assert.NoError(t, ValidateProviderScheme(&schemeProvider{scheme: "a.l-l+"})) // Too short. require.Error(t, ValidateProviderScheme(&schemeProvider{scheme: "a"})) // Invalid first character. require.Error(t, ValidateProviderScheme(&schemeProvider{scheme: "3s"})) // Invalid underscore character. assert.Error(t, ValidateProviderScheme(&schemeProvider{scheme: "all_"})) } type schemeProvider struct { scheme string } func (s schemeProvider) Retrieve(context.Context, string, confmap.WatcherFunc) (*confmap.Retrieved, error) { return nil, nil } func (s schemeProvider) Scheme() string { return s.scheme } func (s schemeProvider) Shutdown(context.Context) error { return nil } opentelemetry-collector-0.141.0/confmap/confmaptest/doc.go000066400000000000000000000004121511331344600235750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package confmaptest helps loading confmap.Conf to test packages implementing using the configuration. package confmaptest // import "go.opentelemetry.io/collector/confmap/confmaptest" opentelemetry-collector-0.141.0/confmap/confmaptest/package_test.go000066400000000000000000000003141511331344600254630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmaptest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/confmaptest/provider_settings.go000066400000000000000000000005351511331344600266100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmaptest // import "go.opentelemetry.io/collector/confmap/confmaptest" import ( "go.uber.org/zap" "go.opentelemetry.io/collector/confmap" ) func NewNopProviderSettings() confmap.ProviderSettings { return confmap.ProviderSettings{Logger: zap.NewNop()} } opentelemetry-collector-0.141.0/confmap/confmaptest/testdata/000077500000000000000000000000001511331344600243155ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/confmaptest/testdata/empty-slice.yaml000066400000000000000000000000751511331344600274360ustar00rootroot00000000000000slice: [] # empty slices are sanitized to nil in ToStringMap opentelemetry-collector-0.141.0/confmap/confmaptest/testdata/invalid.yaml000066400000000000000000000000111511331344600266170ustar00rootroot00000000000000[invalid,opentelemetry-collector-0.141.0/confmap/confmaptest/testdata/simple.yaml000066400000000000000000000000201511331344600264620ustar00rootroot00000000000000floating: 3.14 opentelemetry-collector-0.141.0/confmap/converter.go000066400000000000000000000026151511331344600225230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap // import "go.opentelemetry.io/collector/confmap" import ( "context" "go.uber.org/zap" ) // ConverterSettings are the settings to initialize a Converter. type ConverterSettings struct { // Logger is a zap.Logger that will be passed to Converters. // Converters should be able to rely on the Logger being non-nil; // when instantiating a Converter with a ConverterFactory, // nil Logger references should be replaced with a no-op Logger. Logger *zap.Logger // prevent unkeyed literal initialization _ struct{} } // ConverterFactory defines a factory that can be used to instantiate // new instances of a Converter. type ConverterFactory = moduleFactory[Converter, ConverterSettings] // CreateConverterFunc is a function that creates a Converter instance. type CreateConverterFunc = createConfmapFunc[Converter, ConverterSettings] // NewConverterFactory can be used to create a ConverterFactory. func NewConverterFactory(f CreateConverterFunc) ConverterFactory { return newConfmapModuleFactory(f) } // Converter is a converter interface for the confmap.Conf that allows distributions // (in the future components as well) to build backwards compatible config converters. type Converter interface { // Convert applies the conversion logic to the given "conf". Convert(ctx context.Context, conf *Conf) error } opentelemetry-collector-0.141.0/confmap/doc_test.go000066400000000000000000000064001511331344600223140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap_test import ( "fmt" "slices" "time" "go.opentelemetry.io/collector/confmap" ) type DiskScrape struct { Disk string `mapstructure:"disk"` Scrape time.Duration `mapstructure:"scrape"` } // We can annotate a struct with mapstructure field annotations. func Example_simpleUnmarshaling() { conf := confmap.NewFromStringMap(map[string]any{ "disk": "c", "scrape": "5s", }) scrapeInfo := &DiskScrape{} if err := conf.Unmarshal(scrapeInfo); err != nil { panic(err) } fmt.Printf("Configuration contains the following:\nDisk: %q\nScrape: %s\n", scrapeInfo.Disk, scrapeInfo.Scrape) // Output: Configuration contains the following: // Disk: "c" // Scrape: 5s } type CPUScrape struct { Enabled bool `mapstructure:"enabled"` } type ComputerScrape struct { DiskScrape `mapstructure:",squash"` CPUScrape `mapstructure:",squash"` } // We can unmarshal embedded structs with mapstructure field annotations. func Example_embeddedUnmarshaling() { conf := confmap.NewFromStringMap(map[string]any{ "disk": "c", "scrape": "5s", "enabled": true, }) scrapeInfo := &ComputerScrape{} if err := conf.Unmarshal(scrapeInfo); err != nil { panic(err) } fmt.Printf("Configuration contains the following:\nDisk: %q\nScrape: %s\nEnabled: %v\n", scrapeInfo.Disk, scrapeInfo.Scrape, scrapeInfo.Enabled) // Output: Configuration contains the following: // Disk: "c" // Scrape: 5s // Enabled: true } type NetworkScrape struct { Enabled bool `mapstructure:"enabled"` Networks []string `mapstructure:"networks"` Wifi bool `mapstructure:"wifi"` } func (n *NetworkScrape) Unmarshal(c *confmap.Conf) error { if err := c.Unmarshal(n, confmap.WithIgnoreUnused()); err != nil { return err } if slices.Contains(n.Networks, "wlan0") { n.Wifi = true } return nil } type ManualScrapeInfo struct { Disk string Scrape time.Duration } func (m *ManualScrapeInfo) Unmarshal(c *confmap.Conf) error { m.Disk = c.Get("disk").(string) if c.Get("vinyl") == "33" { m.Scrape = 10 * time.Second } else { m.Scrape = 2 * time.Second } return nil } type RouterScrape struct { NetworkScrape `mapstructure:",squash"` } // We can unmarshal an embedded struct with a custom `Unmarshal` method. func Example_embeddedManualUnmarshaling() { conf := confmap.NewFromStringMap(map[string]any{ "networks": []string{"eth0", "eth1", "wlan0"}, "enabled": true, }) scrapeInfo := &RouterScrape{} if err := conf.Unmarshal(scrapeInfo); err != nil { panic(err) } fmt.Printf("Configuration contains the following:\nNetworks: %q\nWifi: %v\nEnabled: %v\n", scrapeInfo.Networks, scrapeInfo.Wifi, scrapeInfo.Enabled) // Output: Configuration contains the following: // Networks: ["eth0" "eth1" "wlan0"] // Wifi: true // Enabled: true } func Example_manualUnmarshaling() { conf := confmap.NewFromStringMap(map[string]any{ "disk": "Beatles", "vinyl": "33", }) scrapeInfo := &ManualScrapeInfo{} if err := conf.Unmarshal(scrapeInfo, confmap.WithIgnoreUnused()); err != nil { panic(err) } fmt.Printf("Configuration contains the following:\nDisk: %q\nScrape: %s\n", scrapeInfo.Disk, scrapeInfo.Scrape) // Output: Configuration contains the following: // Disk: "Beatles" // Scrape: 10s } opentelemetry-collector-0.141.0/confmap/example_provider_and_converter_test.go000066400000000000000000000063221511331344600300300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap_test import ( "context" "fmt" "strings" "go.opentelemetry.io/collector/confmap" ) // mockFileProvider simulates the standard file provider behavior. // In typical usage, it reads a single file as the root configuration. // This mock implementation always returns a fixed configuration: // { "my-config": "${expand:to-expand}" } type mockFileProvider struct{} func (d mockFileProvider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { expectedURI := "file:mock-file" if uri != expectedURI { panic("should not happen, the uri is expected to be " + expectedURI + " for mockFileProvider") } return confmap.NewRetrieved(map[string]any{ "my-config": "${expand:to-expand}", }) } func (d mockFileProvider) Scheme() string { return "file" } func (d mockFileProvider) Shutdown(_ context.Context) error { return nil } // mockExpandProvider simulates a typical inline expansion provider. // In configurations, you can use expressions like ${SCHEMA:VALUE}, // where the provider associated with SCHEMA is responsible for resolving the value. type mockExpandProvider struct{} func (m mockExpandProvider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { expectedURI := "expand:to-expand" if uri != expectedURI { panic("should not happen, the uri is expected to be " + expectedURI + " for mockExpandProvider") } return confmap.NewRetrieved("expanded") } func (m mockExpandProvider) Scheme() string { return "expand" } func (m mockExpandProvider) Shutdown(_ context.Context) error { return nil } // mockUpperCaseConverter transforms the value of the `my-config` field in the configuration to uppercase. type mockUpperCaseConverter struct{} func (m mockUpperCaseConverter) Convert(_ context.Context, conf *confmap.Conf) error { currentValue := conf.Get("my-config") expectedValue := "expanded" if currentValue != expectedValue { panic("should not happen, the value for converter should always be " + expectedValue + " for mockUpperCaseConverter") } upperCaseConf := confmap.NewFromStringMap(map[string]any{ "my-config": strings.ToUpper(currentValue.(string)), }) if conf.Merge(upperCaseConf) != nil { panic("merge failed, this should not happen in this example.") } return nil } func Example() { resolver, err := confmap.NewResolver(confmap.ResolverSettings{ URIs: []string{"file:mock-file"}, ProviderFactories: []confmap.ProviderFactory{ confmap.NewProviderFactory(func(_ confmap.ProviderSettings) confmap.Provider { return &mockFileProvider{} }), confmap.NewProviderFactory(func(_ confmap.ProviderSettings) confmap.Provider { return &mockExpandProvider{} }), }, ConverterFactories: []confmap.ConverterFactory{ confmap.NewConverterFactory(func(_ confmap.ConverterSettings) confmap.Converter { return &mockUpperCaseConverter{} }), }, }) if err != nil { panic(err) } conf, err := resolver.Resolve(context.Background()) if err != nil { panic(err) } fmt.Printf("Configuration contains the following:\nmy-config: %s", conf.Get("my-config")) // Output: Configuration contains the following: // my-config: EXPANDED } opentelemetry-collector-0.141.0/confmap/expand.go000066400000000000000000000147351511331344600220010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap // import "go.opentelemetry.io/collector/confmap" import ( "context" "errors" "fmt" "regexp" "strings" "go.opentelemetry.io/collector/confmap/internal" ) // schemePattern defines the regexp pattern for scheme names. // Scheme name consist of a sequence of characters beginning with a letter and followed by any // combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). const schemePattern = `[A-Za-z][A-Za-z0-9+.-]+` var ( // Need to match new line as well in the OpaqueValue, so setting the "s" flag. See https://pkg.go.dev/regexp/syntax. uriRegexp = regexp.MustCompile(`(?s:^(?P` + schemePattern + `):(?P.*)$)`) errTooManyRecursiveExpansions = errors.New("too many recursive expansions") ) func (mr *Resolver) expandValueRecursively(ctx context.Context, value any) (any, error) { for range 1000 { val, changed, err := mr.expandValue(ctx, value) if err != nil { return nil, err } if !changed { return val, nil } value = val } return nil, errTooManyRecursiveExpansions } func (mr *Resolver) expandValue(ctx context.Context, value any) (any, bool, error) { switch v := value.(type) { case internal.ExpandedValue: expanded, changed, err := mr.expandValue(ctx, v.Value) if err != nil { return nil, false, err } switch exp := expanded.(type) { case internal.ExpandedValue, string: // Return expanded values or strings verbatim. return exp, changed, nil } // At this point we don't know the target field type, so we need to expand the original representation as well. originalExpanded, originalChanged, err := mr.expandValue(ctx, v.Original) if err != nil { // The original representation is not valid, return the expanded value. return expanded, changed, nil } if originalExpanded, ok := originalExpanded.(string); ok { // If the original representation is a string, return the expanded value with the original representation. return internal.ExpandedValue{ Value: expanded, Original: originalExpanded, }, changed || originalChanged, nil } return expanded, changed, nil case string: if !strings.Contains(v, "${") || !strings.Contains(v, "}") { // No URIs to expand. return value, false, nil } // Embedded or nested URIs. return mr.findAndExpandURI(ctx, v) case []any: nslice := make([]any, 0, len(v)) nchanged := false for _, vint := range v { val, changed, err := mr.expandValue(ctx, vint) if err != nil { return nil, false, err } nslice = append(nslice, val) nchanged = nchanged || changed } return nslice, nchanged, nil case map[string]any: nmap := map[string]any{} nchanged := false for mk, mv := range v { val, changed, err := mr.expandValue(ctx, mv) if err != nil { return nil, false, err } nmap[mk] = val nchanged = nchanged || changed } return nmap, nchanged, nil } return value, false, nil } // findURI attempts to find the first potentially expandable URI in input. It returns a potentially expandable // URI, or an empty string if none are found. // Note: findURI is only called when input contains a closing bracket. // We do not support escaping nested URIs (such as ${env:$${FOO}}, since that would result in an invalid outer URI (${env:${FOO}}). func (mr *Resolver) findURI(input string) string { closeIndex := strings.Index(input, "}") remaining := input[closeIndex+1:] openIndex := strings.LastIndex(input[:closeIndex+1], "${") // if there is any of: // - a missing "${" // - there is no default scheme AND no scheme is detected because no `:` is found. // then check the next URI. if openIndex < 0 || (mr.defaultScheme == "" && !strings.Contains(input[openIndex:closeIndex+1], ":")) { // if remaining does not contain "}", there are no URIs left: stop recursion. if !strings.Contains(remaining, "}") { return "" } return mr.findURI(remaining) } index := openIndex - 1 currentRune := '$' count := 0 for index >= 0 && currentRune == '$' { currentRune = rune(input[index]) if currentRune == '$' { count++ } index-- } // if we found an odd number of immediately $ preceding ${, then the expansion is escaped if count%2 == 1 { return "" } return input[openIndex : closeIndex+1] } // findAndExpandURI attempts to find and expand the first occurrence of an expandable URI in input. If an expandable URI is found it // returns the input with the URI expanded, true and nil. Otherwise, it returns the unchanged input, false and the expanding error. // This method expects input to start with ${ and end with } func (mr *Resolver) findAndExpandURI(ctx context.Context, input string) (any, bool, error) { uri := mr.findURI(input) if uri == "" { // No URI found, return. return input, false, nil } if uri == input { // If the value is a single URI, then the return value can be anything. // This is the case `foo: ${file:some_extra_config.yml}`. ret, err := mr.expandURI(ctx, input) if err != nil { return input, false, err } val, err := ret.AsRaw() if err != nil { return input, false, err } if asStr, err2 := ret.AsString(); err2 == nil { return internal.ExpandedValue{ Value: val, Original: asStr, }, true, nil } return val, true, nil } expanded, err := mr.expandURI(ctx, uri) if err != nil { return input, false, err } repl, err := expanded.AsString() if err != nil { return input, false, fmt.Errorf("expanding %v: %w", uri, err) } return strings.ReplaceAll(input, uri, repl), true, err } func (mr *Resolver) expandURI(ctx context.Context, input string) (*Retrieved, error) { // strip ${ and } uri := input[2 : len(input)-1] if !strings.Contains(uri, ":") { uri = fmt.Sprintf("%s:%s", mr.defaultScheme, uri) } lURI, err := newLocation(uri) if err != nil { return nil, err } if strings.Contains(lURI.opaqueValue, "$") { return nil, fmt.Errorf("the uri %q contains unsupported characters ('$')", lURI.asString()) } ret, err := mr.retrieveValue(ctx, lURI) if err != nil { return nil, err } mr.closers = append(mr.closers, ret.Close) return ret, nil } type location struct { scheme string opaqueValue string } func (c location) asString() string { return c.scheme + ":" + c.opaqueValue } func newLocation(uri string) (location, error) { submatches := uriRegexp.FindStringSubmatch(uri) if len(submatches) != 3 { return location{}, fmt.Errorf("invalid uri: %q", uri) } return location{scheme: submatches[1], opaqueValue: submatches[2]}, nil } opentelemetry-collector-0.141.0/confmap/expand_test.go000066400000000000000000000423021511331344600230270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap // import "go.opentelemetry.io/collector/confmap" import ( "context" "errors" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestResolverExpandEnvVars(t *testing.T) { testCases := []struct { name string // test case name (also file name containing config yaml) }{ {name: "expand-with-no-env.yaml"}, {name: "expand-with-partial-env.yaml"}, {name: "expand-with-all-env.yaml"}, } envs := map[string]string{ "EXTRA": "some string", "EXTRA_MAP_VALUE_1": "some map value_1", "EXTRA_MAP_VALUE_2": "some map value_2", "EXTRA_LIST_MAP_VALUE_1": "some list map value_1", "EXTRA_LIST_MAP_VALUE_2": "some list map value_2", "EXTRA_LIST_VALUE_1": "some list value_1", "EXTRA_LIST_VALUE_2": "some list value_2", } expectedCfgMap := newConfFromFile(t, filepath.Join("testdata", "expand-with-no-env.yaml")) fileProvider := newFakeProvider("file", func(_ context.Context, uri string, _ WatcherFunc) (*Retrieved, error) { return NewRetrieved(newConfFromFile(t, uri[5:])) }) envProvider := newFakeProvider("env", func(_ context.Context, uri string, _ WatcherFunc) (*Retrieved, error) { return NewRetrieved(envs[uri[4:]]) }) for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { resolver, err := NewResolver(ResolverSettings{URIs: []string{filepath.Join("testdata", tt.name)}, ProviderFactories: []ProviderFactory{fileProvider, envProvider}, ConverterFactories: nil}) require.NoError(t, err) // Test that expanded configs are the same with the simple config with no env vars. cfgMap, err := resolver.Resolve(context.Background()) require.NoError(t, err) assert.Equal(t, expectedCfgMap, cfgMap.ToStringMap()) }) } } func TestResolverDoneNotExpandOldEnvVars(t *testing.T) { expectedCfgMap := map[string]any{"test.1": "${EXTRA}", "test.2": "$EXTRA", "test.3": "${EXTRA}:${EXTRA}"} fileProvider := newFakeProvider("test", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(expectedCfgMap) }) envProvider := newFakeProvider("env", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved("some string") }) resolver, err := NewResolver(ResolverSettings{URIs: []string{"test:"}, ProviderFactories: []ProviderFactory{fileProvider, envProvider}, ConverterFactories: nil}) require.NoError(t, err) // Test that expanded configs are the same with the simple config with no env vars. cfgMap, err := resolver.Resolve(context.Background()) require.NoError(t, err) assert.Equal(t, expectedCfgMap, cfgMap.ToStringMap()) } func TestResolverExpandMapAndSliceValues(t *testing.T) { provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{ "test_map": map[string]any{"recv": "${test:MAP_VALUE}"}, "test_slice": []any{"${test:MAP_VALUE}"}, }) }) const receiverExtraMapValue = "some map value" testProvider := newFakeProvider("test", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(receiverExtraMapValue) }) resolver, err := NewResolver(ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, testProvider}, ConverterFactories: nil}) require.NoError(t, err) cfgMap, err := resolver.Resolve(context.Background()) require.NoError(t, err) expectedMap := map[string]any{ "test_map": map[string]any{"recv": receiverExtraMapValue}, "test_slice": []any{receiverExtraMapValue}, } assert.Equal(t, expectedMap, cfgMap.ToStringMap()) } func TestResolverExpandStringValues(t *testing.T) { tests := []struct { name string input string output any defaultProvider bool }{ // Embedded. { name: "NoMatchOldStyle", input: "${HOST}:${PORT}", output: "${HOST}:${PORT}", }, { name: "NoMatchOldStyleDefaultProvider", input: "${HOST}:${PORT}", output: "localhost:3044", defaultProvider: true, }, { name: "NoMatchOldStyleNoBrackets", input: "${HOST}:$PORT", output: "${HOST}:$PORT", }, { name: "NoMatchOldStyleNoBracketsDefaultProvider", input: "${HOST}:$PORT", output: "localhost:$PORT", defaultProvider: true, }, { name: "ComplexValue", input: "${env:COMPLEX_VALUE}", output: []any{"localhost:3042"}, }, { name: "Embedded", input: "${env:HOST}:3043", output: "localhost:3043", }, { name: "EmbeddedMulti", input: "${env:HOST}:${env:PORT}", output: "localhost:3044", }, { name: "EmbeddedConcat", input: "https://${env:HOST}:3045", output: "https://localhost:3045", }, { name: "EmbeddedNewAndOldStyle", input: "${env:HOST}:${PORT}", output: "localhost:${PORT}", }, { name: "EmbeddedNewAndOldStyleDefaultProvider", input: "${env:HOST}:${PORT}", output: "localhost:3044", defaultProvider: true, }, { name: "Int", input: "test_${env:INT}", output: "test_1", }, { name: "Int32", input: "test_${env:INT32}", output: "test_32", }, { name: "Int64", input: "test_${env:INT64}", output: "test_64", }, { name: "Float32", input: "test_${env:FLOAT32}", output: "test_3.25", }, { name: "Float64", input: "test_${env:FLOAT64}", output: "test_6.4", }, { name: "Bool", input: "test_${env:BOOL}", output: "test_true", }, { name: "Timestamp", input: "test_${env:TIMESTAMP}", output: "test_2023-03-20T03:17:55.432328Z", }, { name: "MultipleSameMatches", input: "test_${env:BOOL}_test_${env:BOOL}", output: "test_true_test_true", }, // Nested. { name: "Nested", input: "${test:localhost:${env:PORT}}", output: "localhost:3044", }, { name: "NestedDefaultProvider", input: "${test:localhost:${PORT}}", output: "localhost:3044", defaultProvider: true, }, { name: "EmbeddedInNested", input: "${test:${env:HOST}:${env:PORT}}", output: "localhost:3044", }, { name: "EmbeddedInNestedDefaultProvider", input: "${test:${HOST}:${PORT}}", output: "localhost:3044", defaultProvider: true, }, { name: "EmbeddedAndNested", input: "${test:localhost:${env:PORT}}?os=${env:OS}", output: "localhost:3044?os=ubuntu", }, { name: "NestedMultiple", input: "${test:1${test:2${test:3${test:4${test:5${test:6}}}}}}", output: "123456", }, // No expand. { name: "NoMatchMissingOpeningBracket", input: "env:HOST}", output: "env:HOST}", }, { name: "NoMatchMissingOpeningBracketDefaultProvider", input: "env:HOST}", output: "env:HOST}", defaultProvider: true, }, { name: "NoMatchMissingClosingBracket", input: "${HOST", output: "${HOST", }, { name: "NoMatchMissingClosingBracketDefaultProvider", input: "${HOST", output: "${HOST", defaultProvider: true, }, { name: "NoMatchBracketsWithout$", input: "HO{ST}", output: "HO{ST}", }, { name: "NoMatchBracketsWithout$DefaultProvider", input: "HO{ST}", output: "HO{ST}", defaultProvider: true, }, { name: "NoMatchOnlyMissingClosingBracket", input: "${env:HOST${env:PORT?os=${env:OS", output: "${env:HOST${env:PORT?os=${env:OS", }, { name: "NoMatchOnlyMissingClosingBracketDefaultProvider", input: "${env:HOST${env:PORT?os=${env:OS", output: "${env:HOST${env:PORT?os=${env:OS", defaultProvider: true, }, { name: "NoMatchOnlyMissingOpeningBracket", input: "env:HOST}env:PORT}?os=env:OS}", output: "env:HOST}env:PORT}?os=env:OS}", }, { name: "NoMatchOnlyMissingOpeningBracketDefaultProvider", input: "env:HOST}env:PORT}?os=env:OS}", output: "env:HOST}env:PORT}?os=env:OS}", defaultProvider: true, }, { name: "NoMatchCloseBeforeOpen", input: "env:HOST}${env:PORT", output: "env:HOST}${env:PORT", }, { name: "NoMatchCloseBeforeOpenDefaultProvider", input: "env:HOST}${env:PORT", output: "env:HOST}${env:PORT", defaultProvider: true, }, { name: "NoMatchOldStyleNested", input: "${test:localhost:${PORT}}", output: "${test:localhost:${PORT}}", }, // Partial expand. { name: "PartialMatchMissingOpeningBracketFirst", input: "env:HOST}${env:PORT}", output: "env:HOST}3044", }, { name: "PartialMatchMissingOpeningBracketFirstDefaultProvider", input: "env:HOST}${PORT}", output: "env:HOST}3044", defaultProvider: true, }, { name: "PartialMatchMissingOpeningBracketLast", input: "${env:HOST}env:PORT}", output: "localhostenv:PORT}", }, { name: "PartialMatchMissingClosingBracketFirst", input: "${env:HOST${env:PORT}", output: "${env:HOST3044", }, { name: "PartialMatchMissingClosingBracketLast", input: "${env:HOST}${env:PORT", output: "localhost${env:PORT", }, { name: "PartialMatchMultipleMissingOpen", input: "env:HOST}env:PORT}?os=${env:OS}", output: "env:HOST}env:PORT}?os=ubuntu", }, { name: "PartialMatchMultipleMissingClosing", input: "${env:HOST${env:PORT?os=${env:OS}", output: "${env:HOST${env:PORT?os=ubuntu", }, { name: "PartialMatchMoreClosingBrackets", input: "${env:HOST}}}}}}${env:PORT?os=${env:OS}", output: "localhost}}}}}${env:PORT?os=ubuntu", }, { name: "PartialMatchMoreOpeningBrackets", input: "${env:HOST}${${${${${env:PORT}?os=${env:OS}", output: "localhost${${${${3044?os=ubuntu", }, { name: "PartialMatchAlternatingMissingOpening", input: "env:HOST}${env:PORT}?os=env:OS}&pr=${env:PR}", output: "env:HOST}3044?os=env:OS}&pr=amd", }, { name: "PartialMatchAlternatingMissingClosing", input: "${env:HOST${env:PORT}?os=${env:OS&pr=${env:PR}", output: "${env:HOST3044?os=${env:OS&pr=amd", }, { name: "SchemeAfterNoSchemeIsExpanded", input: "${HOST}${env:PORT}", output: "${HOST}3044", }, { name: "SchemeAfterNoSchemeIsExpandedDefaultProvider", input: "${HOST}${env:PORT}", output: "localhost3044", defaultProvider: true, }, { name: "SchemeBeforeNoSchemeIsExpanded", input: "${env:HOST}${PORT}", output: "localhost${PORT}", }, { name: "SchemeBeforeNoSchemeIsExpandedDefaultProvider", input: "${env:HOST}${PORT}", output: "localhost3044", defaultProvider: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{tt.name: tt.input}) }) testProvider := newFakeProvider("test", func(_ context.Context, uri string, _ WatcherFunc) (*Retrieved, error) { return NewRetrieved(uri[5:]) }) envProvider := newEnvProvider() set := ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, envProvider, testProvider}, ConverterFactories: nil} if tt.defaultProvider { set.DefaultScheme = "env" } resolver, err := NewResolver(set) require.NoError(t, err) cfgMap, err := resolver.Resolve(context.Background()) require.NoError(t, err) assert.Equal(t, map[string]any{tt.name: tt.output}, cfgMap.ToStringMap()) }) } } func newEnvProvider() ProviderFactory { return newFakeProvider("env", func(_ context.Context, uri string, _ WatcherFunc) (*Retrieved, error) { // When using `env` as the default scheme for tests, the uri will not include `env:`. // Instead of duplicating the switch cases, the scheme is added instead. if uri[0:4] != "env:" { uri = "env:" + uri } switch uri { case "env:COMPLEX_VALUE": return NewRetrievedFromYAML([]byte("[localhost:3042]")) case "env:HOST": return NewRetrievedFromYAML([]byte("localhost")) case "env:TIMESTAMP": return NewRetrievedFromYAML([]byte("2023-03-20T03:17:55.432328Z")) case "env:OS": return NewRetrievedFromYAML([]byte("ubuntu")) case "env:PR": return NewRetrievedFromYAML([]byte("amd")) case "env:PORT": return NewRetrievedFromYAML([]byte("3044")) case "env:INT": return NewRetrievedFromYAML([]byte("1")) case "env:INT32": return NewRetrieved(int32(32), withStringRepresentation("32")) case "env:INT64": return NewRetrieved(int64(64), withStringRepresentation("64")) case "env:FLOAT32": return NewRetrieved(float32(3.25), withStringRepresentation("3.25")) case "env:FLOAT64": return NewRetrieved(float64(6.4), withStringRepresentation("6.4")) case "env:BOOL": return NewRetrievedFromYAML([]byte("true")) } return nil, errors.New("impossible") }) } func TestResolverExpandReturnError(t *testing.T) { tests := []struct { name string input any }{ { name: "string_value", input: "${test:VALUE}", }, { name: "slice_value", input: []any{"${test:VALUE}"}, }, { name: "map_value", input: map[string]any{"test": "${test:VALUE}"}, }, { name: "string_embedded_value", input: "https://${test:HOST}:3045", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{tt.name: tt.input}) }) myErr := errors.New(tt.name) testProvider := newFakeProvider("test", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return nil, myErr }) resolver, err := NewResolver(ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, testProvider}, ConverterFactories: nil}) require.NoError(t, err) _, err = resolver.Resolve(context.Background()) assert.ErrorIs(t, err, myErr) }) } } func TestResolverInfiniteExpand(t *testing.T) { const receiverValue = "${test:VALUE}" provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{"test": receiverValue}) }) testProvider := newFakeProvider("test", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(receiverValue) }) resolver, err := NewResolver(ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, testProvider}, ConverterFactories: nil}) require.NoError(t, err) _, err = resolver.Resolve(context.Background()) assert.ErrorIs(t, err, errTooManyRecursiveExpansions) } func TestResolverExpandInvalidScheme(t *testing.T) { provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{"test": "${g_c_s:VALUE}"}) }) testProvider := newFakeProvider("g_c_s", func(context.Context, string, WatcherFunc) (*Retrieved, error) { panic("must not be called") }) _, err := NewResolver(ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, testProvider}, ConverterFactories: nil}) assert.ErrorContains(t, err, "invalid 'confmap.Provider' scheme") } func TestResolverExpandInvalidOpaqueValue(t *testing.T) { provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{"test": []any{map[string]any{"test": "${test:$VALUE}"}}}) }) testProvider := newFakeProvider("test", func(context.Context, string, WatcherFunc) (*Retrieved, error) { panic("must not be called") }) resolver, err := NewResolver(ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, testProvider}, ConverterFactories: nil}) require.NoError(t, err) _, err = resolver.Resolve(context.Background()) assert.EqualError(t, err, `the uri "test:$VALUE" contains unsupported characters ('$')`) } func TestResolverExpandUnsupportedScheme(t *testing.T) { provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{"test": "${unsupported:VALUE}"}) }) testProvider := newFakeProvider("test", func(context.Context, string, WatcherFunc) (*Retrieved, error) { panic("must not be called") }) resolver, err := NewResolver(ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, testProvider}, ConverterFactories: nil}) require.NoError(t, err) _, err = resolver.Resolve(context.Background()) assert.EqualError(t, err, `scheme "unsupported" is not supported for uri "unsupported:VALUE"`) } func TestResolverDefaultProviderExpand(t *testing.T) { provider := newFakeProvider("input", func(context.Context, string, WatcherFunc) (*Retrieved, error) { return NewRetrieved(map[string]any{"foo": "${HOST}"}) }) resolver, err := NewResolver(ResolverSettings{URIs: []string{"input:"}, ProviderFactories: []ProviderFactory{provider, newEnvProvider()}, DefaultScheme: "env", ConverterFactories: nil}) require.NoError(t, err) cfgMap, err := resolver.Resolve(context.Background()) require.NoError(t, err) assert.Equal(t, map[string]any{"foo": "localhost"}, cfgMap.ToStringMap()) } opentelemetry-collector-0.141.0/confmap/factory.go000066400000000000000000000010411511331344600221530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap // import "go.opentelemetry.io/collector/confmap" type moduleFactory[T any, S any] interface { Create(s S) T } type createConfmapFunc[T any, S any] func(s S) T type confmapModuleFactory[T any, S any] struct { f createConfmapFunc[T, S] } func (c confmapModuleFactory[T, S]) Create(s S) T { return c.f(s) } func newConfmapModuleFactory[T, S any](f createConfmapFunc[T, S]) moduleFactory[T, S] { return confmapModuleFactory[T, S]{ f: f, } } opentelemetry-collector-0.141.0/confmap/generated_package_test.go000066400000000000000000000002461511331344600251620ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package confmap import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/go.mod000066400000000000000000000021101511331344600212610ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap go 1.24.0 require ( github.com/go-viper/mapstructure/v2 v2.4.0 github.com/gobwas/glob v0.2.3 github.com/knadh/koanf/maps v0.1.2 github.com/knadh/koanf/providers/confmap v1.0.0 github.com/knadh/koanf/v2 v2.3.0 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.1 go.yaml.in/yaml/v3 v3.0.4 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace ( go.opentelemetry.io/collector/featuregate => ../featuregate go.opentelemetry.io/collector/internal/testutil => ../internal/testutil ) opentelemetry-collector-0.141.0/confmap/go.sum000066400000000000000000000067421511331344600213250ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/confmap/internal/000077500000000000000000000000001511331344600217755ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/conf.go000066400000000000000000000156171511331344600232630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" import ( "errors" "fmt" "reflect" "github.com/knadh/koanf/maps" "github.com/knadh/koanf/providers/confmap" "github.com/knadh/koanf/v2" encoder "go.opentelemetry.io/collector/confmap/internal/mapstructure" ) const ( // KeyDelimiter is used as the default key delimiter in the default koanf instance. KeyDelimiter = "::" ) // Conf represents the raw configuration map for the OpenTelemetry Collector. // The confmap.Conf can be unmarshalled into the Collector's config using the "service" package. type Conf struct { k *koanf.Koanf // If true, upon unmarshaling do not call the Unmarshal function on the struct // if it implements Unmarshaler and is the top-level struct. // This avoids running into an infinite recursion where Unmarshaler.Unmarshal and // Conf.Unmarshal would call each other. skipTopLevelUnmarshaler bool // isNil is true if this Conf was created from a nil field, as opposed to an empty map. // AllKeys must return an empty slice if this is true. isNil bool } // New creates a new empty confmap.Conf instance. func New() *Conf { return &Conf{k: koanf.New(KeyDelimiter), isNil: false} } // NewFromStringMap creates a confmap.Conf from a map[string]any. func NewFromStringMap(data map[string]any) *Conf { p := New() if data == nil { p.isNil = true } else { // Cannot return error because the koanf instance is empty. _ = p.k.Load(confmap.Provider(data, KeyDelimiter), nil) } return p } // Unmarshal unmarshalls the config into a struct using the given options. // Tags on the fields of the structure must be properly set. func (l *Conf) Unmarshal(result any, opts ...UnmarshalOption) error { set := UnmarshalOptions{} for _, opt := range opts { opt.apply(&set) } return Decode(l.toStringMapWithExpand(), result, set, l.skipTopLevelUnmarshaler) } // Marshal encodes the config and merges it into the Conf. func (l *Conf) Marshal(rawVal any, opts ...MarshalOption) error { set := MarshalOptions{} for _, opt := range opts { opt.apply(&set) } enc := encoder.New(EncoderConfig(rawVal, set)) data, err := enc.Encode(rawVal) if err != nil { return err } out, ok := data.(map[string]any) if !ok { return errors.New("invalid config encoding") } return l.Merge(NewFromStringMap(out)) } // AllKeys returns all keys holding a value, regardless of where they are set. // Nested keys are returned with a KeyDelimiter separator. func (l *Conf) AllKeys() []string { return l.k.Keys() } // Get can retrieve any value given the key to use. func (l *Conf) Get(key string) any { val := l.unsanitizedGet(key) return sanitizeExpanded(val, false) } // IsSet checks to see if the key has been set in any of the data locations. func (l *Conf) IsSet(key string) bool { return l.k.Exists(key) } // Merge merges the input given configuration into the existing config. // Note that the given map may be modified. func (l *Conf) Merge(in *Conf) error { if EnableMergeAppendOption.IsEnabled() { // only use MergeAppend when EnableMergeAppendOption featuregate is enabled. return l.mergeAppend(in) } l.isNil = l.isNil && in.isNil return l.k.Merge(in.k) } // Delete a path from the Conf. // If the path exists, deletes it and returns true. // If the path does not exist, does nothing and returns false. func (l *Conf) Delete(key string) bool { wasSet := l.IsSet(key) l.k.Delete(key) return wasSet } // mergeAppend merges the input given configuration into the existing config. // Note that the given map may be modified. // Additionally, mergeAppend performs deduplication when merging lists. // For example, if listA = [extension1, extension2] and listB = [extension1, extension3], // the resulting list will be [extension1, extension2, extension3]. func (l *Conf) mergeAppend(in *Conf) error { err := l.k.Load(confmap.Provider(in.ToStringMap(), ""), nil, koanf.WithMergeFunc(mergeAppend)) if err != nil { return err } l.isNil = l.isNil && in.isNil return nil } // Sub returns new Conf instance representing a sub-config of this instance. // It returns an error is the sub-config is not a map[string]any (use Get()), and an empty Map if none exists. func (l *Conf) Sub(key string) (*Conf, error) { // Code inspired by the koanf "Cut" func, but returns an error instead of empty map for unsupported sub-config type. data := l.unsanitizedGet(key) if data == nil { c := New() c.isNil = true return c, nil } switch v := data.(type) { case map[string]any: return NewFromStringMap(v), nil case ExpandedValue: if m, ok := v.Value.(map[string]any); ok { return NewFromStringMap(m), nil } else if v.Value == nil { // If the value is nil, return a new empty Conf. c := New() c.isNil = true return c, nil } // override data with the original value to make the error message more informative. data = v.Value } return nil, fmt.Errorf("unexpected sub-config value kind for key:%s value:%v kind:%v", key, data, reflect.TypeOf(data).Kind()) } func (l *Conf) toStringMapWithExpand() map[string]any { if l.isNil { return nil } m := maps.Unflatten(l.k.All(), KeyDelimiter) return m } // ToStringMap creates a map[string]any from a Conf. // Values with multiple representations // are normalized with the YAML parsed representation. // // For example, for a Conf created from `foo: ${env:FOO}` and `FOO=123` // ToStringMap will return `map[string]any{"foo": 123}`. // // For any map `m`, `NewFromStringMap(m).ToStringMap() == m`. // In particular, if the Conf was created from a nil value, // ToStringMap will return map[string]any(nil). func (l *Conf) ToStringMap() map[string]any { return sanitize(l.toStringMapWithExpand()).(map[string]any) } func (l *Conf) unsanitizedGet(key string) any { return l.k.Get(key) } // sanitize recursively removes expandedValue references from the given data. // It uses the expandedValue.Value field to replace the expandedValue references. func sanitize(a any) any { return sanitizeExpanded(a, false) } // sanitizeToStringMap recursively removes expandedValue references from the given data. // It uses the expandedValue.Original field to replace the expandedValue references. func sanitizeToStr(a any) any { return sanitizeExpanded(a, true) } func sanitizeExpanded(a any, useOriginal bool) any { switch m := a.(type) { case map[string]any: c := maps.Copy(m) for k, v := range m { c[k] = sanitizeExpanded(v, useOriginal) } return c case []any: // If the value is nil, return nil. var newSlice []any if m == nil { return newSlice } newSlice = make([]any, 0, len(m)) for _, e := range m { newSlice = append(newSlice, sanitizeExpanded(e, useOriginal)) } return newSlice case ExpandedValue: if useOriginal { return m.Original } return m.Value } return a } type UnsanitizedGetter struct { Conf *Conf } func (ug *UnsanitizedGetter) UnsanitizedGet(key string) any { return ug.Conf.unsanitizedGet(key) } opentelemetry-collector-0.141.0/confmap/internal/confmap.go000066400000000000000000000017101511331344600237460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" // Unmarshaler interface may be implemented by types to customize their behavior when being unmarshaled from a Conf. // Only types with struct or pointer to struct kind are supported. type Unmarshaler interface { // Unmarshal a Conf into the struct in a custom way. // The Conf for this specific component may be nil or empty if no config available. // This method should only be called by decoding hooks when calling Conf.Unmarshal. Unmarshal(component *Conf) error } // Marshaler defines an optional interface for custom configuration marshaling. // A configuration struct can implement this interface to override the default // marshaling. type Marshaler interface { // Marshal the config into a Conf in a custom way. // The Conf will be empty and can be merged into. Marshal(component *Conf) error } opentelemetry-collector-0.141.0/confmap/internal/confmap_test.go000066400000000000000000000765511511331344600250240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "errors" "math" "os" "path/filepath" "reflect" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" yaml "go.yaml.in/yaml/v3" ) func TestToStringMapFlatten(t *testing.T) { conf := NewFromStringMap(map[string]any{"key::embedded": int64(123)}) assert.Equal(t, map[string]any{"key": map[string]any{"embedded": int64(123)}}, conf.ToStringMap()) } func TestToStringMap(t *testing.T) { tests := []struct { name string fileName string stringMap map[string]any }{ { name: "Sample Collector configuration", fileName: filepath.Join("testdata", "config.yaml"), stringMap: map[string]any{ "receivers": map[string]any{ "nop": nil, "nop/myreceiver": nil, }, "processors": map[string]any{ "nop": nil, "nop/myprocessor": nil, }, "exporters": map[string]any{ "nop": nil, "nop/myexporter": nil, }, "extensions": map[string]any{ "nop": nil, "nop/myextension": nil, }, "service": map[string]any{ "extensions": []any{"nop"}, "pipelines": map[string]any{ "traces": map[string]any{ "receivers": []any{"nop"}, "processors": []any{"nop"}, "exporters": []any{"nop"}, }, }, }, }, }, { name: "Sample types", fileName: filepath.Join("testdata", "basic_types.yaml"), stringMap: map[string]any{ "typed.options": map[string]any{ "floating.point.example": 3.14, "integer.example": 1234, "bool.example": false, "string.example": "this is a string", "nil.example": nil, }, }, }, { name: "Embedded keys", fileName: filepath.Join("testdata", "embedded_keys.yaml"), stringMap: map[string]any{ "typed": map[string]any{"options": map[string]any{ "floating": map[string]any{"point": map[string]any{"example": 3.14}}, "integer": map[string]any{"example": 1234}, "bool": map[string]any{"example": false}, "string": map[string]any{"example": "this is a string"}, "nil": map[string]any{"example": nil}, }}, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { assert.Equal(t, test.stringMap, newConfFromFile(t, test.fileName)) }) } } type testConfigAny struct { AnyField any `mapstructure:"any_field"` } func TestNilToAnyField(t *testing.T) { stringMap := map[string]any{ "any_field": nil, } conf := NewFromStringMap(stringMap) cfg := &testConfigAny{} require.NoError(t, conf.Unmarshal(cfg)) assert.Nil(t, cfg.AnyField) } func TestExpandNilStructPointersHookFunc(t *testing.T) { stringMap := map[string]any{ "boolean": nil, "struct": nil, "map_struct": map[string]any{ "struct": nil, }, } conf := NewFromStringMap(stringMap) cfg := &testConfig{} assert.Nil(t, cfg.Struct) require.NoError(t, conf.Unmarshal(cfg)) assert.Nil(t, cfg.Boolean) // assert.False(t, *cfg.Boolean) assert.Nil(t, cfg.Struct) assert.NotNil(t, cfg.MapStruct) assert.Equal(t, &myStruct{}, cfg.MapStruct["struct"]) } func TestExpandNilStructPointersHookFuncDefaultNotNilConfigNil(t *testing.T) { stringMap := map[string]any{ "boolean": nil, "struct": nil, "map_struct": map[string]any{ "struct": nil, }, } conf := NewFromStringMap(stringMap) varBool := true s1 := &myStruct{Name: "s1"} s2 := &myStruct{Name: "s2"} cfg := &testConfig{ Boolean: &varBool, Struct: s1, MapStruct: map[string]*myStruct{"struct": s2}, } require.NoError(t, conf.Unmarshal(cfg)) assert.NotNil(t, cfg.Boolean) assert.True(t, *cfg.Boolean) assert.NotNil(t, cfg.Struct) assert.Equal(t, s1, cfg.Struct) assert.NotNil(t, cfg.MapStruct) assert.Equal(t, &myStruct{}, cfg.MapStruct["struct"]) } func TestUnmarshalWithIgnoreUnused(t *testing.T) { stringMap := map[string]any{ "boolean": true, "string": "this is a string", } conf := NewFromStringMap(stringMap) require.Error(t, conf.Unmarshal(&testIDConfig{})) assert.NoError(t, conf.Unmarshal(&testIDConfig{}, WithIgnoreUnused())) } type testConfig struct { Boolean *bool `mapstructure:"boolean"` Struct *myStruct `mapstructure:"struct"` MapStruct map[string]*myStruct `mapstructure:"map_struct"` } func (t testConfig) Marshal(conf *Conf) error { if t.Boolean != nil && !*t.Boolean { return errors.New("unable to marshal") } if err := conf.Marshal(t); err != nil { return err } return conf.Merge(NewFromStringMap(map[string]any{ "additional": "field", })) } type myStruct struct { Name string } type TestID string func (tID *TestID) UnmarshalText(text []byte) error { *tID = TestID(strings.TrimSuffix(string(text), "_")) if *tID == "error" { return errors.New("parsing error") } return nil } func (tID TestID) MarshalText() (text []byte, err error) { out := string(tID) if !strings.HasSuffix(out, "_") { out += "_" } return []byte(out), nil } type testIDConfig struct { Boolean bool `mapstructure:"bool"` Map map[TestID]string `mapstructure:"map"` } func TestMapKeyStringToMapKeyTextUnmarshalerHookFunc(t *testing.T) { stringMap := map[string]any{ "bool": true, "map": map[string]any{ "string": "this is a string", }, } conf := NewFromStringMap(stringMap) cfg := &testIDConfig{} require.NoError(t, conf.Unmarshal(cfg)) assert.True(t, cfg.Boolean) assert.Equal(t, map[TestID]string{"string": "this is a string"}, cfg.Map) } type uint32Config struct { Value uint32 `mapstructure:"value"` } func TestUint32UnmarshalerSuccess(t *testing.T) { tests := []struct { name string testValue uint32 }{ { name: "Test convert 0 to uint", testValue: 0, }, { name: "Test positive uint conversion", testValue: 1000, }, { name: "Test largest uint64 conversion", testValue: math.MaxUint32, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { stringMap := map[string]any{ "value": int(tt.testValue), } conf := NewFromStringMap(stringMap) cfg := &uint32Config{} err := conf.Unmarshal(cfg) require.NoError(t, err) assert.Equal(t, cfg.Value, tt.testValue) }) } } func TestUint32UnmarshalerFailure(t *testing.T) { stringMap := map[string]any{ "value": -1000, } conf := NewFromStringMap(stringMap) cfg := &uint32Config{} err := conf.Unmarshal(cfg) assert.ErrorContains(t, err, "decoding failed due to the following error(s):\n\n'value' cannot parse value as 'uint32': -1000 overflows uint") } type uint64Config struct { Value uint64 `mapstructure:"value"` } func TestUint64Unmarshaler(t *testing.T) { // Equivalent to -1000, but converted to uint64 value := uint64(1000) testValue := ^(value - 1) stringMap := map[string]any{ "value": testValue, } conf := NewFromStringMap(stringMap) cfg := &uint64Config{} err := conf.Unmarshal(cfg) require.NoError(t, err) assert.Equal(t, cfg.Value, testValue) } func TestUint64UnmarshalerFailure(t *testing.T) { stringMap := map[string]any{ "value": -1000, } conf := NewFromStringMap(stringMap) cfg := &uint64Config{} err := conf.Unmarshal(cfg) assert.ErrorContains(t, err, "decoding failed due to the following error(s):\n\n'value' cannot parse value as 'uint64': -1000 overflows uint") } func TestMapKeyStringToMapKeyTextUnmarshalerHookFuncDuplicateID(t *testing.T) { stringMap := map[string]any{ "bool": true, "map": map[string]any{ "string": "this is a string", "string_": "this is another string", }, } conf := NewFromStringMap(stringMap) cfg := &testIDConfig{} assert.Error(t, conf.Unmarshal(cfg)) } func TestMapKeyStringToMapKeyTextUnmarshalerHookFuncErrorUnmarshal(t *testing.T) { stringMap := map[string]any{ "bool": true, "map": map[string]any{ "error": "this is a string", }, } conf := NewFromStringMap(stringMap) cfg := &testIDConfig{} assert.Error(t, conf.Unmarshal(cfg)) } func TestMarshal(t *testing.T) { conf := New() cfg := &testIDConfig{ Boolean: true, Map: map[TestID]string{ "string": "this is a string", }, } require.NoError(t, conf.Marshal(cfg)) assert.Equal(t, true, conf.Get("bool")) assert.Equal(t, map[string]any{"string_": "this is a string"}, conf.Get("map")) } func TestMarshalDuplicateID(t *testing.T) { conf := New() cfg := &testIDConfig{ Boolean: true, Map: map[TestID]string{ "string": "this is a string", "string_": "this is another string", }, } assert.Error(t, conf.Marshal(cfg)) } func TestMarshalError(t *testing.T) { conf := New() assert.Error(t, conf.Marshal(nil)) } func TestMarshaler(t *testing.T) { conf := New() cfg := &testConfig{ Struct: &myStruct{ Name: "StructName", }, } require.NoError(t, conf.Marshal(cfg)) assert.Equal(t, "field", conf.Get("additional")) conf = New() type NestedMarshaler struct { TestConfig *testConfig } nmCfg := &NestedMarshaler{ TestConfig: cfg, } require.NoError(t, conf.Marshal(nmCfg)) sub, err := conf.Sub("testconfig") require.NoError(t, err) assert.True(t, sub.IsSet("additional")) assert.Equal(t, "field", sub.Get("additional")) varBool := false nmCfg.TestConfig.Boolean = &varBool assert.Error(t, conf.Marshal(nmCfg)) } // newConfFromFile creates a new Conf by reading the given file. func newConfFromFile(tb testing.TB, fileName string) map[string]any { content, err := os.ReadFile(filepath.Clean(fileName)) require.NoErrorf(tb, err, "unable to read the file %v", fileName) var data map[string]any require.NoError(tb, yaml.Unmarshal(content, &data), "unable to parse yaml") return NewFromStringMap(data).ToStringMap() } type testConfig2 struct { Next *nextConfig `mapstructure:"next"` Another string `mapstructure:"another"` EmbeddedConfig `mapstructure:",squash"` EmbeddedConfig2 `mapstructure:",squash"` } type testConfigWithoutUnmarshaler struct { Next *nextConfig `mapstructure:"next"` Another string `mapstructure:"another"` EmbeddedConfig `mapstructure:",squash"` EmbeddedConfig2 `mapstructure:",squash"` } type testConfigWithEmbeddedError struct { Next *nextConfig `mapstructure:"next"` Another string `mapstructure:"another"` EmbeddedConfigWithError `mapstructure:",squash"` } type testConfigWithMarshalError struct { Next *nextConfig `mapstructure:"next"` Another string `mapstructure:"another"` EmbeddedConfigWithMarshalError `mapstructure:",squash"` } func (tc *testConfigWithEmbeddedError) Unmarshal(component *Conf) error { if err := component.Unmarshal(tc, WithIgnoreUnused()); err != nil { return err } return nil } type EmbeddedConfig struct { Some string `mapstructure:"some"` } func (ec *EmbeddedConfig) Unmarshal(component *Conf) error { if err := component.Unmarshal(ec, WithIgnoreUnused()); err != nil { return err } ec.Some += " is also called" return nil } type EmbeddedConfig2 struct { Some2 string `mapstructure:"some_2"` } func (ec *EmbeddedConfig2) Unmarshal(component *Conf) error { if err := component.Unmarshal(ec, WithIgnoreUnused()); err != nil { return err } ec.Some2 += " also called2" return nil } type EmbeddedConfigWithError struct{} func (ecwe *EmbeddedConfigWithError) Unmarshal(_ *Conf) error { return errors.New("embedded error") } type EmbeddedConfigWithMarshalError struct{} func (ecwe EmbeddedConfigWithMarshalError) Marshal(_ *Conf) error { return errors.New("marshaling error") } func (ecwe EmbeddedConfigWithMarshalError) Unmarshal(_ *Conf) error { return nil } func (tc *testConfig2) Unmarshal(component *Conf) error { if err := component.Unmarshal(tc); err != nil { return err } tc.Another += " is only called directly" return nil } type nextConfig struct { String string `mapstructure:"string"` private string } func (nc *nextConfig) Unmarshal(component *Conf) error { if err := component.Unmarshal(nc); err != nil { return err } nc.String += " is called" return nil } func TestUnmarshaler(t *testing.T) { cfgMap := NewFromStringMap(map[string]any{ "next": map[string]any{ "string": "make sure this", }, "another": "make sure this", "some": "make sure this", "some_2": "this better be", }) tc := &testConfig2{} require.NoError(t, cfgMap.Unmarshal(tc)) assert.Equal(t, "make sure this is only called directly", tc.Another) assert.Equal(t, "make sure this is called", tc.Next.String) assert.Equal(t, "make sure this is also called", tc.Some) assert.Equal(t, "this better be also called2", tc.Some2) } func TestEmbeddedUnmarshaler(t *testing.T) { cfgMap := NewFromStringMap(map[string]any{ "next": map[string]any{ "string": "make sure this", }, "another": "make sure this", "some": "make sure this", "some_2": "this better be", }) tc := &testConfigWithoutUnmarshaler{} require.NoError(t, cfgMap.Unmarshal(tc)) assert.Equal(t, "make sure this", tc.Another) assert.Equal(t, "make sure this is called", tc.Next.String) assert.Equal(t, "make sure this is also called", tc.Some) assert.Equal(t, "this better be also called2", tc.Some2) } func TestEmbeddedUnmarshalerError(t *testing.T) { cfgMap := NewFromStringMap(map[string]any{ "next": map[string]any{ "string": "make sure this", }, "another": "make sure this", "some": "make sure this", }) tc := &testConfigWithEmbeddedError{} assert.ErrorContains(t, cfgMap.Unmarshal(tc), "embedded error") } func TestEmbeddedMarshalerError(t *testing.T) { t.Skip("This test fails because the main struct calls the embedded struct Unmarshal method, and doesn't execute the embedded struct hook.") cfgMap := NewFromStringMap(map[string]any{ "next": map[string]any{ "string": "make sure this", }, "another": "make sure this", }) tc := &testConfigWithMarshalError{} assert.EqualError(t, cfgMap.Unmarshal(tc), "error running encode hook: marshaling error") } type B struct { String string `mapstructure:"string"` } func (b *B) Unmarshal(conf *Conf) error { return conf.Unmarshal(b) } type A struct { B `mapstructure:",squash"` } func (a *A) Unmarshal(conf *Conf) error { return conf.Unmarshal(a) } func TestUnmarshalerEmbeddedNilMap(t *testing.T) { cfg := A{} nilConf := NewFromStringMap(nil) require.NoError(t, nilConf.Unmarshal(&cfg)) } func TestUnmarshalerKeepAlreadyInitialized(t *testing.T) { cfgMap := NewFromStringMap(map[string]any{ "next": map[string]any{ "string": "make sure this", }, "another": "make sure this", }) tc := &testConfig2{Next: &nextConfig{ private: "keep already configured members", }} require.NoError(t, cfgMap.Unmarshal(tc)) assert.Equal(t, "make sure this is only called directly", tc.Another) assert.Equal(t, "make sure this is called", tc.Next.String) assert.Equal(t, "keep already configured members", tc.Next.private) } func TestDirectUnmarshaler(t *testing.T) { cfgMap := NewFromStringMap(map[string]any{ "next": map[string]any{ "string": "make sure this", }, "another": "make sure this", }) tc := &testConfig2{Next: &nextConfig{ private: "keep already configured members", }} require.NoError(t, tc.Unmarshal(cfgMap)) assert.Equal(t, "make sure this is only called directly is only called directly", tc.Another) assert.Equal(t, "make sure this is called", tc.Next.String) assert.Equal(t, "keep already configured members", tc.Next.private) } type testErrConfig struct { Err errConfig `mapstructure:"err"` } type errConfig struct { Foo string `mapstructure:"foo"` } func (tc *errConfig) Unmarshal(*Conf) error { return errors.New("never works") } func TestUnmarshalerErr(t *testing.T) { cfgMap := NewFromStringMap(map[string]any{ "err": map[string]any{ "foo": "will not unmarshal due to error", }, }) tc := &testErrConfig{} require.EqualError(t, cfgMap.Unmarshal(tc), "decoding failed due to the following error(s):\n\n'err' never works") assert.Empty(t, tc.Err.Foo) } func TestZeroSliceHookFunc(t *testing.T) { type structWithSlices struct { Strings []string `mapstructure:"strings"` } tests := []struct { name string cfg map[string]any provided any expected any }{ { name: "overridden by slice", cfg: map[string]any{ "strings": []string{"111"}, }, provided: &structWithSlices{ Strings: []string{"xxx", "yyyy", "zzzz"}, }, expected: &structWithSlices{ Strings: []string{"111"}, }, }, { name: "overridden by a bigger slice", cfg: map[string]any{ "strings": []string{"111", "222", "333"}, }, provided: &structWithSlices{ Strings: []string{"xxx", "yyyy"}, }, expected: &structWithSlices{ Strings: []string{"111", "222", "333"}, }, }, { name: "overridden by an empty slice", cfg: map[string]any{ "strings": []string{}, }, provided: &structWithSlices{ Strings: []string{"xxx", "yyyy"}, }, expected: &structWithSlices{ Strings: []string{}, }, }, { name: "not overridden by nil", cfg: map[string]any{ "strings": nil, }, provided: &structWithSlices{ Strings: []string{"xxx", "yyyy"}, }, expected: &structWithSlices{ Strings: []string{"xxx", "yyyy"}, }, }, { name: "not overridden by missing value", cfg: map[string]any{}, provided: &structWithSlices{ Strings: []string{"xxx", "yyyy"}, }, expected: &structWithSlices{ Strings: []string{"xxx", "yyyy"}, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := NewFromStringMap(tt.cfg) err := cfg.Unmarshal(tt.provided) if assert.NoError(t, err) { assert.Equal(t, tt.expected, tt.provided) } }) } } // Tests for issue that happened in https://github.com/open-telemetry/opentelemetry-collector/issues/12661. func TestStructValuesReplaced(t *testing.T) { type S struct { A string `mapstructure:"A,omitempty"` B string `mapstructure:"B,omitempty"` } type structWithSlices struct { Structs []S `mapstructure:"structs"` } slicesStruct := structWithSlices{ Structs: []S{ {A: "A"}, }, } bCfg := map[string]any{ "structs": []any{ map[string]any{ "B": "B", }, }, } bConf := NewFromStringMap(bCfg) err := bConf.Unmarshal(&slicesStruct) require.NoError(t, err) assert.Equal(t, []S{{B: "B"}}, slicesStruct.Structs) } func TestNilValuesUnchanged(t *testing.T) { type structWithSlices struct { Strings []string `mapstructure:"strings"` } slicesStruct := &structWithSlices{} nilCfg := map[string]any{ "strings": []any(nil), } nilConf := NewFromStringMap(nilCfg) err := nilConf.Unmarshal(slicesStruct) require.NoError(t, err) confFromStruct := New() err = confFromStruct.Marshal(slicesStruct) require.NoError(t, err) require.Equal(t, nilCfg, nilConf.ToStringMap()) require.Equal(t, confFromStruct.ToStringMap(), nilConf.ToStringMap()) } func TestEmptySliceUnchanged(t *testing.T) { type structWithSlices struct { Strings []string `mapstructure:"strings"` } slicesStruct := &structWithSlices{} nilCfg := map[string]any{ "strings": []any{}, } nilConf := NewFromStringMap(nilCfg) err := nilConf.Unmarshal(slicesStruct) require.NoError(t, err) confFromStruct := New() err = confFromStruct.Marshal(slicesStruct) require.NoError(t, err) require.Equal(t, nilCfg, nilConf.ToStringMap()) require.Equal(t, nilConf.ToStringMap(), confFromStruct.ToStringMap()) } type c struct { Modifiers []string `mapstructure:"modifiers"` } func (c *c) Unmarshal(conf *Conf) error { if err := conf.Unmarshal(c); err != nil { return err } c.Modifiers = append(c.Modifiers, "c.Unmarshal") return nil } type b struct { Modifiers []string `mapstructure:"modifiers"` C c `mapstructure:"c"` } func (b *b) Unmarshal(conf *Conf) error { if err := conf.Unmarshal(b); err != nil { return err } b.Modifiers = append(b.Modifiers, "B.Unmarshal") b.C.Modifiers = append(b.C.Modifiers, "B.Unmarshal") return nil } type a struct { Modifiers []string `mapstructure:"modifiers"` B b `mapstructure:"b"` } func (a *a) Unmarshal(conf *Conf) error { if err := conf.Unmarshal(a); err != nil { return err } a.Modifiers = append(a.Modifiers, "A.Unmarshal") a.B.Modifiers = append(a.B.Modifiers, "A.Unmarshal") a.B.C.Modifiers = append(a.B.C.Modifiers, "A.Unmarshal") return nil } type wrapper struct { A a `mapstructure:"a"` } // Test that calling the Unmarshal method on configuration structs is done from the inside out. func TestNestedUnmarshalerImplementations(t *testing.T) { conf := NewFromStringMap(map[string]any{"a": map[string]any{ "modifiers": []string{"conf.Unmarshal"}, "b": map[string]any{ "modifiers": []string{"conf.Unmarshal"}, "c": map[string]any{ "modifiers": []string{"conf.Unmarshal"}, }, }, }}) // Use a wrapper struct until we deprecate component.UnmarshalConfig w := &wrapper{} require.NoError(t, conf.Unmarshal(w)) a := w.A assert.Equal(t, []string{"conf.Unmarshal", "A.Unmarshal"}, a.Modifiers) assert.Equal(t, []string{"conf.Unmarshal", "B.Unmarshal", "A.Unmarshal"}, a.B.Modifiers) assert.Equal(t, []string{"conf.Unmarshal", "c.Unmarshal", "B.Unmarshal", "A.Unmarshal"}, a.B.C.Modifiers) } // Test that unmarshaling the same conf twice works. func TestUnmarshalDouble(t *testing.T) { conf := NewFromStringMap(map[string]any{ "str": "test", }) type Struct struct { Str string `mapstructure:"str"` } s := &Struct{} require.NoError(t, conf.Unmarshal(s)) assert.Equal(t, "test", s.Str) type Struct2 struct { Str string `mapstructure:"str"` } s2 := &Struct2{} require.NoError(t, conf.Unmarshal(s2)) assert.Equal(t, "test", s2.Str) } type embeddedStructWithUnmarshal struct { Foo string `mapstructure:"foo"` success string } func (e *embeddedStructWithUnmarshal) Unmarshal(c *Conf) error { if err := c.Unmarshal(e, WithIgnoreUnused()); err != nil { return err } e.success = "success" return nil } type configWithUnmarshalFromEmbeddedStruct struct { embeddedStructWithUnmarshal } type topLevel struct { Cfg *configWithUnmarshalFromEmbeddedStruct `mapstructure:"toplevel"` } // Test that Unmarshal is called on the embedded struct on the struct. func TestUnmarshalThroughEmbeddedStruct(t *testing.T) { c := NewFromStringMap(map[string]any{ "toplevel": map[string]any{ "foo": "bar", }, }) cfg := &topLevel{} err := c.Unmarshal(cfg) require.NoError(t, err) require.Equal(t, "success", cfg.Cfg.success) require.Equal(t, "bar", cfg.Cfg.Foo) } type configWithOwnUnmarshalAndEmbeddedSquashedStruct struct { embeddedStructWithUnmarshal `mapstructure:",squash"` } type topLevelSquashedEmbedded struct { Cfg *configWithOwnUnmarshalAndEmbeddedSquashedStruct `mapstructure:"toplevel"` } // Test that the Unmarshal method is called on the squashed, embedded struct. func TestUnmarshalOwnThroughEmbeddedSquashedStruct(t *testing.T) { c := NewFromStringMap(map[string]any{ "toplevel": map[string]any{ "foo": "bar", }, }) cfg := &topLevelSquashedEmbedded{} err := c.Unmarshal(cfg) require.NoError(t, err) require.Equal(t, "success", cfg.Cfg.success) require.Equal(t, "bar", cfg.Cfg.Foo) } type recursive struct { Foo string `mapstructure:"foo"` } func (r *recursive) Unmarshal(conf *Conf) error { newR := &recursive{} if err := conf.Unmarshal(newR); err != nil { return err } *r = *newR return nil } // Tests that a struct can unmarshal itself by creating a new copy of itself, unmarshaling itself, and setting its value. func TestRecursiveUnmarshaling(t *testing.T) { conf := NewFromStringMap(map[string]any{ "foo": "something", }) r := &recursive{} require.NoError(t, conf.Unmarshal(r)) require.Equal(t, "something", r.Foo) } func TestExpandedValue(t *testing.T) { cm := NewFromStringMap(map[string]any{ "key": ExpandedValue{ Value: 0xdeadbeef, Original: "original", }, }) assert.Equal(t, 0xdeadbeef, cm.Get("key")) assert.Equal(t, map[string]any{"key": 0xdeadbeef}, cm.ToStringMap()) type ConfigStr struct { Key string `mapstructure:"key"` } cfgStr := ConfigStr{} require.NoError(t, cm.Unmarshal(&cfgStr)) assert.Equal(t, "original", cfgStr.Key) type ConfigInt struct { Key int `mapstructure:"key"` } cfgInt := ConfigInt{} require.NoError(t, cm.Unmarshal(&cfgInt)) assert.Equal(t, 0xdeadbeef, cfgInt.Key) type ConfigBool struct { Key bool `mapstructure:"key"` } cfgBool := ConfigBool{} assert.Error(t, cm.Unmarshal(&cfgBool)) } func TestSubExpandedValue(t *testing.T) { cm := NewFromStringMap(map[string]any{ "key": map[string]any{ "subkey": ExpandedValue{ Value: map[string]any{"subsubkey": "value"}, Original: "subsubkey: value", }, }, }) assert.Equal(t, map[string]any{"subkey": map[string]any{"subsubkey": "value"}}, cm.Get("key")) assert.Equal(t, map[string]any{"key": map[string]any{"subkey": map[string]any{"subsubkey": "value"}}}, cm.ToStringMap()) assert.Equal(t, map[string]any{"subsubkey": "value"}, cm.Get("key::subkey")) sub, err := cm.Sub("key::subkey") require.NoError(t, err) assert.Equal(t, map[string]any{"subsubkey": "value"}, sub.ToStringMap()) // This should return value, but currently `Get` does not support keys within expanded values. assert.Nil(t, cm.Get("key::subkey::subsubkey")) } func TestStringyTypes(t *testing.T) { tests := []struct { valueOfType any isStringy bool }{ { valueOfType: "string", isStringy: true, }, { valueOfType: 1, isStringy: false, }, { valueOfType: map[string]any{}, isStringy: false, }, { valueOfType: []any{}, isStringy: false, }, { valueOfType: map[string]string{}, isStringy: true, }, { valueOfType: []string{}, isStringy: true, }, { valueOfType: map[string][]string{}, isStringy: true, }, { valueOfType: map[string]map[string]string{}, isStringy: true, }, { valueOfType: []map[string]any{}, isStringy: false, }, { valueOfType: []map[string]string{}, isStringy: true, }, } for _, tt := range tests { // Create a reflect.Type from the value to := reflect.TypeOf(tt.valueOfType) assert.Equal(t, tt.isStringy, isStringyStructure(to)) } } func TestConfDelete(t *testing.T) { tests := []struct { path string stringMap map[string]any }{ { path: "key", stringMap: map[string]any{"key": "value"}, }, { path: "map::expanded", stringMap: map[string]any{"map": map[string]any{ "expanded": ExpandedValue{ Value: 0o1234, Original: "01234", }, }}, }, } for _, test := range tests { t.Run(test.path, func(t *testing.T) { cm := NewFromStringMap(test.stringMap) assert.True(t, cm.IsSet(test.path)) assert.True(t, cm.Delete(test.path)) assert.Nil(t, cm.Get(test.path)) assert.False(t, cm.IsSet(test.path)) assert.False(t, cm.Delete(test.path)) assert.Nil(t, cm.Get(test.path)) assert.False(t, cm.IsSet(test.path)) }) } } type structWithConfigOpaqueMap struct { Headers map[string]string `mapstructure:"headers"` } func TestMapMerge(t *testing.T) { tests := []struct { name string initial map[string]string added map[string]string expected map[string]string }{ { name: "both nil", initial: nil, added: nil, expected: nil, }, { name: "nil map", initial: map[string]string{}, added: nil, expected: map[string]string{}, }, { name: "initialized", initial: map[string]string{ "foo": "bar", }, added: nil, expected: map[string]string{ "foo": "bar", }, }, { name: "both", initial: map[string]string{ "foo": "bar", }, added: map[string]string{ "foobar": "bar", }, expected: map[string]string{ "foo": "bar", "foobar": "bar", }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { s := structWithConfigOpaqueMap{ Headers: test.initial, } c := NewFromStringMap(map[string]any{ "headers": test.added, }) require.NoError(t, c.Unmarshal(&s)) assert.Equal(t, test.expected, s.Headers) }) } } func TestConfIsNil(t *testing.T) { const subKey = "foo" testCases := []struct { name string input map[string]any expectIsNil bool subExpectNil bool subExpectErr string }{ { name: "nil input", input: nil, expectIsNil: true, subExpectNil: true, }, { name: "empty map", input: map[string]any{}, expectIsNil: false, subExpectNil: true, }, { name: "nil subkey", input: map[string]any{subKey: nil}, expectIsNil: false, subExpectNil: true, }, { name: "empty subkey", input: map[string]any{subKey: map[string]any{}}, expectIsNil: false, subExpectNil: false, }, { name: "non-empty map", input: map[string]any{subKey: map[string]any{"bar": 42}}, expectIsNil: false, subExpectNil: false, }, { name: "non-map subkey", input: map[string]any{subKey: 123}, expectIsNil: false, subExpectErr: "unexpected sub-config value kind", }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { conf := NewFromStringMap(tc.input) if tc.expectIsNil { assert.Empty(t, conf.AllKeys()) assert.Equal(t, map[string]any(nil), conf.ToStringMap()) } else { assert.NotEqual(t, map[string]any(nil), conf.ToStringMap()) } sub, err := conf.Sub(subKey) if tc.subExpectErr != "" { assert.ErrorContains(t, err, tc.subExpectErr) } else { assert.NoError(t, err) if tc.subExpectNil { assert.Empty(t, sub.AllKeys()) assert.Equal(t, map[string]any(nil), sub.ToStringMap()) } else { assert.NotEqual(t, map[string]any(nil), sub.ToStringMap()) } } }) } } func TestConfmapNilMerge(t *testing.T) { tests := []struct { name string left map[string]any right map[string]any expected map[string]any }{ { name: "both nil", left: nil, right: nil, expected: nil, }, { name: "left nil", left: nil, right: map[string]any{"key": "value"}, expected: map[string]any{"key": "value"}, }, { name: "right nil", left: map[string]any{"key": "value"}, right: nil, expected: map[string]any{"key": "value"}, }, { name: "both non-nil", left: map[string]any{"key1": "value1"}, right: map[string]any{"key2": "value2"}, expected: map[string]any{"key1": "value1", "key2": "value2"}, }, { name: "left empty, right non-empty", left: map[string]any{}, right: map[string]any{"key": "value"}, expected: map[string]any{"key": "value"}, }, { name: "left non-empty, right empty", left: map[string]any{"key": "value"}, right: map[string]any{}, expected: map[string]any{"key": "value"}, }, { name: "left nil, right empty", left: nil, right: map[string]any{}, expected: map[string]any{}, }, { name: "left empty, right nil", left: map[string]any{}, right: nil, expected: map[string]any{}, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { leftConf := NewFromStringMap(test.left) assert.Equal(t, test.left, leftConf.ToStringMap()) rightConf := NewFromStringMap(test.right) assert.Equal(t, test.right, rightConf.ToStringMap()) err := leftConf.Merge(rightConf) require.NoError(t, err) assert.Equal(t, test.expected, leftConf.ToStringMap()) }) t.Run(test.name+"merge append", func(t *testing.T) { leftConf := NewFromStringMap(test.left) assert.Equal(t, test.left, leftConf.ToStringMap()) rightConf := NewFromStringMap(test.right) assert.Equal(t, test.right, rightConf.ToStringMap()) err := leftConf.mergeAppend(rightConf) require.NoError(t, err) assert.Equal(t, test.expected, leftConf.ToStringMap()) }) } } opentelemetry-collector-0.141.0/confmap/internal/decoder.go000066400000000000000000000326521511331344600237410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" import ( "encoding" "errors" "fmt" "maps" "reflect" "slices" "strings" "github.com/go-viper/mapstructure/v2" "go.opentelemetry.io/collector/confmap/internal/third_party/composehook" ) const ( // MapstructureTag is the struct field tag used to record marshaling/unmarshaling settings. // See https://pkg.go.dev/github.com/go-viper/mapstructure/v2 for supported values. MapstructureTag = "mapstructure" ) // WithIgnoreUnused sets an option to ignore errors if existing // keys in the original Conf were unused in the decoding process // (extra keys). func WithIgnoreUnused() UnmarshalOption { return UnmarshalOptionFunc(func(uo *UnmarshalOptions) { uo.IgnoreUnused = true }) } // Decode decodes the contents of the Conf into the result argument, using a // mapstructure decoder with the following notable behaviors. Ensures that maps whose // values are nil pointer structs resolved to the zero value of the target struct (see // expandNilStructPointers). Converts string to []string by splitting on ','. Ensures // uniqueness of component IDs (see mapKeyStringToMapKeyTextUnmarshalerHookFunc). // Decodes time.Duration from strings. Allows custom unmarshaling for structs implementing // encoding.TextUnmarshaler. Allows custom unmarshaling for structs implementing confmap.Unmarshaler. func Decode(input, result any, settings UnmarshalOptions, skipTopLevelUnmarshaler bool) error { dc := &mapstructure.DecoderConfig{ ErrorUnused: !settings.IgnoreUnused, Result: result, TagName: MapstructureTag, WeaklyTypedInput: false, MatchName: caseSensitiveMatchName, DecodeNil: true, DecodeHook: composehook.ComposeDecodeHookFunc( useExpandValue(), expandNilStructPointersHookFunc(), mapstructure.StringToSliceHookFunc(","), mapKeyStringToMapKeyTextUnmarshalerHookFunc(), mapstructure.StringToTimeDurationHookFunc(), mapstructure.TextUnmarshallerHookFunc(), unmarshalerHookFunc(result, skipTopLevelUnmarshaler), // after the main unmarshaler hook is called, // we unmarshal the embedded structs if present to merge with the result: unmarshalerEmbeddedStructsHookFunc(), zeroSliceAndMapHookFunc(), ), } decoder, err := mapstructure.NewDecoder(dc) if err != nil { return err } if err = decoder.Decode(input); err != nil { if strings.HasPrefix(err.Error(), "error decoding ''") { return errors.Unwrap(err) } return err } return nil } // When a value has been loaded from an external source via a provider, we keep both the // parsed value and the original string value. This allows us to expand the value to its // original string representation when decoding into a string field, and use the original otherwise. func useExpandValue() mapstructure.DecodeHookFuncType { return func( _ reflect.Type, to reflect.Type, data any, ) (any, error) { if exp, ok := data.(ExpandedValue); ok { v := castTo(exp, to.Kind() == reflect.String) // See https://github.com/open-telemetry/opentelemetry-collector/issues/10949 // If the `to.Kind` is not a string, then expandValue's original value is useless and // the casted-to value will be nil. In that scenario, we need to use the default value of `to`'s kind. if v == nil { return reflect.Zero(to).Interface(), nil } return v, nil } switch to.Kind() { case reflect.Array, reflect.Slice, reflect.Map: if isStringyStructure(to) { // If the target field is a stringy structure, sanitize to use the original string value everywhere. return sanitizeToStr(data), nil } // Otherwise, sanitize to use the parsed value everywhere. return sanitize(data), nil } return data, nil } } // In cases where a config has a mapping of something to a struct pointers // we want nil values to resolve to a pointer to the zero value of the // underlying struct just as we want nil values of a mapping of something // to a struct to resolve to the zero value of that struct. // // e.g. given a config type: // type Config struct { Thing *SomeStruct `mapstructure:"thing"` } // // and yaml of: // config: // // thing: // // we want an unmarshaled Config to be equivalent to // Config{Thing: &SomeStruct{}} instead of Config{Thing: nil} func expandNilStructPointersHookFunc() mapstructure.DecodeHookFuncValue { return safeWrapDecodeHookFunc(func(from, to reflect.Value) (any, error) { // ensure we are dealing with map to map comparison if from.Kind() == reflect.Map && to.Kind() == reflect.Map { toElem := to.Type().Elem() // ensure that map values are pointers to a struct // (that may be nil and require manual setting w/ zero value) if toElem.Kind() == reflect.Ptr && toElem.Elem().Kind() == reflect.Struct { fromRange := from.MapRange() for fromRange.Next() { fromKey := fromRange.Key() fromValue := fromRange.Value() // ensure that we've run into a nil pointer instance if fromValue.IsNil() { newFromValue := reflect.New(toElem.Elem()) from.SetMapIndex(fromKey, newFromValue) } } } } return from.Interface(), nil }) } // mapKeyStringToMapKeyTextUnmarshalerHookFunc returns a DecodeHookFuncType that checks that a conversion from // map[string]any to map[encoding.TextUnmarshaler]any does not overwrite keys, // when UnmarshalText produces equal elements from different strings (e.g. trims whitespaces). // // This is needed in combination with ComponentID, which may produce equal IDs for different strings, // and an error needs to be returned in that case, otherwise the last equivalent ID overwrites the previous one. func mapKeyStringToMapKeyTextUnmarshalerHookFunc() mapstructure.DecodeHookFuncType { return func(from, to reflect.Type, data any) (any, error) { if from.Kind() != reflect.Map || from.Key().Kind() != reflect.String { return data, nil } if to.Kind() != reflect.Map { return data, nil } // Checks that the key type of to implements the TextUnmarshaler interface. if _, ok := reflect.New(to.Key()).Interface().(encoding.TextUnmarshaler); !ok { return data, nil } // Create a map with key value of to's key to bool. fieldNameSet := reflect.MakeMap(reflect.MapOf(to.Key(), reflect.TypeFor[bool]())) for k := range data.(map[string]any) { // Create a new value of the to's key type. tKey := reflect.New(to.Key()) // Use tKey to unmarshal the key of the map. if err := tKey.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(k)); err != nil { return nil, err } // Checks if the key has already been decoded in a previous iteration. if fieldNameSet.MapIndex(reflect.Indirect(tKey)).IsValid() { return nil, fmt.Errorf("duplicate name %q after unmarshaling %v", k, tKey) } fieldNameSet.SetMapIndex(reflect.Indirect(tKey), reflect.ValueOf(true)) } return data, nil } } // unmarshalerEmbeddedStructsHookFunc provides a mechanism for embedded structs to define their own unmarshal logic, // by implementing the Unmarshaler interface. func unmarshalerEmbeddedStructsHookFunc() mapstructure.DecodeHookFuncValue { return safeWrapDecodeHookFunc(func(from, to reflect.Value) (any, error) { if to.Type().Kind() != reflect.Struct { return from.Interface(), nil } fromAsMap, ok := from.Interface().(map[string]any) if !ok { return from.Interface(), nil } for i := 0; i < to.Type().NumField(); i++ { // embedded structs passed in via `squash` cannot be pointers. We just check if they are structs: f := to.Type().Field(i) if f.IsExported() && slices.Contains(strings.Split(f.Tag.Get(MapstructureTag), ","), "squash") { if unmarshaler, ok := to.Field(i).Addr().Interface().(Unmarshaler); ok { c := NewFromStringMap(fromAsMap) c.skipTopLevelUnmarshaler = true if err := unmarshaler.Unmarshal(c); err != nil { return nil, err } // the struct we receive from this unmarshaling only contains fields related to the embedded struct. // we merge this partially unmarshaled struct with the rest of the result. // note we already unmarshaled the main struct earlier, and therefore merge with it. conf := New() if err := conf.Marshal(unmarshaler); err != nil { return nil, err } resultMap := conf.ToStringMap() if fromAsMap == nil && len(resultMap) > 0 { fromAsMap = make(map[string]any, len(resultMap)) } maps.Copy(fromAsMap, resultMap) } } } return fromAsMap, nil }) } // Provides a mechanism for individual structs to define their own unmarshal logic, // by implementing the Unmarshaler interface, unless skipTopLevelUnmarshaler is // true and the struct matches the top level object being unmarshaled. func unmarshalerHookFunc(result any, skipTopLevelUnmarshaler bool) mapstructure.DecodeHookFuncValue { return safeWrapDecodeHookFunc(func(from, to reflect.Value) (any, error) { if !to.CanAddr() { return from.Interface(), nil } toPtr := to.Addr().Interface() // Need to ignore the top structure to avoid running into an infinite recursion // where Unmarshaler.Unmarshal and Conf.Unmarshal would call each other. if toPtr == result && skipTopLevelUnmarshaler { return from.Interface(), nil } unmarshaler, ok := toPtr.(Unmarshaler) if !ok { return from.Interface(), nil } if _, ok = from.Interface().(map[string]any); !ok { return from.Interface(), nil } // Use the current object if not nil (to preserve other configs in the object), otherwise zero initialize. if to.Addr().IsNil() { unmarshaler = reflect.New(to.Type()).Interface().(Unmarshaler) } c := NewFromStringMap(from.Interface().(map[string]any)) c.skipTopLevelUnmarshaler = true if err := unmarshaler.Unmarshal(c); err != nil { return nil, err } return unmarshaler, nil }) } // safeWrapDecodeHookFunc wraps a DecodeHookFuncValue to ensure fromVal is a valid `reflect.Value` // object and therefore it is safe to call `reflect.Value` methods on fromVal. // // Use this only if the hook does not need to be called on untyped nil values. // Typed nil values are safe to call and will be passed to the hook. // See https://github.com/golang/go/issues/51649 func safeWrapDecodeHookFunc( f mapstructure.DecodeHookFuncValue, ) mapstructure.DecodeHookFuncValue { return func(fromVal, toVal reflect.Value) (any, error) { if !fromVal.IsValid() { return nil, nil } return f(fromVal, toVal) } } // This hook is used to solve the issue: https://github.com/open-telemetry/opentelemetry-collector/issues/4001 // We adopt the suggestion provided in this issue: https://github.com/mitchellh/mapstructure/issues/74#issuecomment-279886492 // We should empty every slice before unmarshalling unless user provided slice is nil. // Assume that we had a struct with a field of type slice called `keys`, which has default values of ["a", "b"] // // type Config struct { // Keys []string `mapstructure:"keys"` // } // // The configuration provided by users may have following cases // 1. configuration have `keys` field and have a non-nil values for this key, the output should be overridden // - for example, input is {"keys", ["c"]}, then output is Config{ Keys: ["c"]} // // 2. configuration have `keys` field and have an empty slice for this key, the output should be overridden by empty slices // - for example, input is {"keys", []}, then output is Config{ Keys: []} // // 3. configuration have `keys` field and have nil value for this key, the output should be default config // - for example, input is {"keys": nil}, then output is Config{ Keys: ["a", "b"]} // // 4. configuration have no `keys` field specified, the output should be default config // - for example, input is {}, then output is Config{ Keys: ["a", "b"]} // // This hook is also used to solve https://github.com/open-telemetry/opentelemetry-collector/issues/13117. // Since v0.127.0, we decode nil values to avoid creating empty map objects. // The nil value is not well understood when layered on top of a default map non-nil value. // The fix is to avoid the assignment and return the previous value. func zeroSliceAndMapHookFunc() mapstructure.DecodeHookFuncValue { return safeWrapDecodeHookFunc(func(from, to reflect.Value) (any, error) { if to.CanSet() && to.Kind() == reflect.Slice && from.Kind() == reflect.Slice { if !from.IsNil() { // input slice is not nil, set the output slice to a new slice of the same type. to.Set(reflect.MakeSlice(to.Type(), from.Len(), from.Cap())) } } if to.CanSet() && to.Kind() == reflect.Map && from.Kind() == reflect.Map { if from.IsNil() { return to.Interface(), nil } } return from.Interface(), nil }) } // case-sensitive version of the callback to be used in the MatchName property // of the DecoderConfig. The default for MatchEqual is to use strings.EqualFold, // which is case-insensitive. func caseSensitiveMatchName(a, b string) bool { return a == b } func castTo(exp ExpandedValue, useOriginal bool) any { // If the target field is a string, use `exp.Original` or fail if not available. if useOriginal { return exp.Original } // Otherwise, use the parsed value (previous behavior). return exp.Value } // Check if a reflect.Type is of the form T, where: // X is any type or interface // T = string | map[X]T | []T | [n]T func isStringyStructure(t reflect.Type) bool { if t.Kind() == reflect.String { return true } if t.Kind() == reflect.Map { return isStringyStructure(t.Elem()) } if t.Kind() == reflect.Slice || t.Kind() == reflect.Array { return isStringyStructure(t.Elem()) } return false } opentelemetry-collector-0.141.0/confmap/internal/e2e/000077500000000000000000000000001511331344600224505ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/e2e/Makefile000066400000000000000000000000411511331344600241030ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/confmap/internal/e2e/expand_test.go000066400000000000000000000100461511331344600253160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2etest import ( "context" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/envprovider" "go.opentelemetry.io/collector/confmap/provider/fileprovider" ) func Test_EscapedEnvVars_NoDefaultScheme(t *testing.T) { const expandedValue = "some expanded value" t.Setenv("ENV_VALUE", expandedValue) t.Setenv("ENV_LIST", "['$$ESCAPE_ME','$${ESCAPE_ME}','$${env:ESCAPE_ME}']") t.Setenv("ENV_MAP", "{'key1':'$$ESCAPE_ME','key2':'$${ESCAPE_ME}','key3':'$${env:ESCAPE_ME}'}") t.Setenv("ENV_NESTED_DOLLARSIGN", "here is 1 $$") t.Setenv("ENV_NESTED_DOLLARSIGN_ESCAPED", "here are 2 $$$") t.Setenv("ENV_EXPAND_NESTED", "${env:ENV_VALUE} came from nested expansion") expectedMap := map[string]any{ "test_map": map[string]any{ "key1": "$ENV_VALUE", "key2": "$$ENV_VALUE", "key3": "$${ENV_VALUE}", "key4": "some${ENV_VALUE}text", "key5": "some${ENV_VALUE}text", "key6": "${ONE}${TWO}", "key7": "text$", "key8": "$", "key9": "${1}${env:2}", "key10": "some${env:ENV_VALUE}text", "key11": "${env:${ENV_VALUE}}", "key12": "${env:${ENV_VALUE}}", "key13": "env:MAP_VALUE_2}${ENV_VALUE}{", "key14": "$" + expandedValue, "key15": "$ENV_VALUE", "key16": []any{"$ESCAPE_ME", "${ESCAPE_ME}", "${env:ESCAPE_ME}"}, "key17": map[string]any{"key1": "$ESCAPE_ME", "key2": "${ESCAPE_ME}", "key3": "${env:ESCAPE_ME}"}, "key18": "here is 1 $", "key19": "here are 2 $$", "key20": "some expanded value came from nested expansion", }, } resolver, err := confmap.NewResolver(confmap.ResolverSettings{ URIs: []string{filepath.Join("testdata", "expand-escaped-env.yaml")}, ProviderFactories: []confmap.ProviderFactory{fileprovider.NewFactory(), envprovider.NewFactory()}, DefaultScheme: "", }) require.NoError(t, err) // Test that expanded configs are the same with the simple config with no env vars. cfgMap, err := resolver.Resolve(context.Background()) require.NoError(t, err) m := cfgMap.ToStringMap() assert.Equal(t, expectedMap, m) } func Test_EscapedEnvVars_DefaultScheme(t *testing.T) { const expandedValue = "some expanded value" t.Setenv("ENV_VALUE", expandedValue) t.Setenv("ENV_LIST", "['$$ESCAPE_ME','$${ESCAPE_ME}','$${env:ESCAPE_ME}']") t.Setenv("ENV_MAP", "{'key1':'$$ESCAPE_ME','key2':'$${ESCAPE_ME}','key3':'$${env:ESCAPE_ME}'}") t.Setenv("ENV_NESTED_DOLLARSIGN", "here is 1 $$") t.Setenv("ENV_NESTED_DOLLARSIGN_ESCAPED", "here are 2 $$$") t.Setenv("ENV_EXPAND_NESTED", "${env:ENV_VALUE} came from nested expansion") expectedMap := map[string]any{ "test_map": map[string]any{ "key1": "$ENV_VALUE", "key2": "$$ENV_VALUE", "key3": "$" + expandedValue, "key4": "some" + expandedValue + "text", "key5": "some${ENV_VALUE}text", "key6": "${ONE}${TWO}", "key7": "text$", "key8": "$", "key9": "${1}${env:2}", "key10": "some${env:ENV_VALUE}text", "key11": "${env:" + expandedValue + "}", "key12": "${env:${ENV_VALUE}}", "key13": "env:MAP_VALUE_2}${ENV_VALUE}{", "key14": "$" + expandedValue, "key15": "$ENV_VALUE", "key16": []any{"$ESCAPE_ME", "${ESCAPE_ME}", "${env:ESCAPE_ME}"}, "key17": map[string]any{"key1": "$ESCAPE_ME", "key2": "${ESCAPE_ME}", "key3": "${env:ESCAPE_ME}"}, "key18": "here is 1 $", "key19": "here are 2 $$", "key20": "some expanded value came from nested expansion", }, } resolver, err := confmap.NewResolver(confmap.ResolverSettings{ URIs: []string{filepath.Join("testdata", "expand-escaped-env.yaml")}, ProviderFactories: []confmap.ProviderFactory{fileprovider.NewFactory(), envprovider.NewFactory()}, DefaultScheme: "env", }) require.NoError(t, err) // Test that expanded configs are the same with the simple config with no env vars. cfgMap, err := resolver.Resolve(context.Background()) require.NoError(t, err) m := cfgMap.ToStringMap() assert.Equal(t, expectedMap, m) } opentelemetry-collector-0.141.0/confmap/internal/e2e/fuzz_test.go000066400000000000000000000037241511331344600250420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2etest import ( "context" "os" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // targetNested tests the following property: // > Passing a value of type T directly through an environment variable // > should be equivalent to passing it through a nested environment variable. func targetNested[T any](t *testing.T, value string) { resolver := NewResolver(t, "types_expand.yaml") // Use os.Setenv so we can check the error and return instead of failing the fuzzing. os.Setenv("ENV", "${env:ENV2}") //nolint:usetesting defer os.Unsetenv("ENV") err := os.Setenv("ENV2", value) //nolint:usetesting defer os.Unsetenv("ENV2") if err != nil { return } confNested, errResolveNested := resolver.Resolve(context.Background()) err = os.Setenv("ENV", value) //nolint:usetesting if err != nil { return } confSimple, errResolveSimple := resolver.Resolve(context.Background()) require.Equal(t, errResolveNested, errResolveSimple) if errResolveNested != nil { return } var cfgNested targetConfig[T] errNested := confNested.Unmarshal(cfgNested) var cfgSimple targetConfig[T] errSimple := confSimple.Unmarshal(cfgSimple) require.Equal(t, errNested, errSimple) if errNested != nil { return } assert.Equal(t, cfgNested, cfgSimple) } // testStrings for fuzzing targets var testStrings = []string{ "123", "opentelemetry", "!!str 123", "\"0123\"", "\"", "1111:1111:1111:1111:1111::", "{field: value}", "0xdeadbeef", "0b101", "field:", "2006-01-02T15:04:05Z07:00", } func FuzzNestedString(f *testing.F) { for _, value := range testStrings { f.Add(value) } f.Fuzz(targetNested[string]) } func FuzzNestedInt(f *testing.F) { for _, value := range testStrings { f.Add(value) } f.Fuzz(targetNested[int]) } func FuzzNestedMap(f *testing.F) { for _, value := range testStrings { f.Add(value) } f.Fuzz(targetNested[map[string]any]) } opentelemetry-collector-0.141.0/confmap/internal/e2e/go.mod000066400000000000000000000033331511331344600235600ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap/internal/e2e go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/provider/envprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../ replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../provider/fileprovider replace go.opentelemetry.io/collector/confmap/provider/envprovider => ../../provider/envprovider replace go.opentelemetry.io/collector/config/configopaque => ../../../config/configopaque replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/confmap/xconfmap => ../../xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/confmap/internal/e2e/go.sum000066400000000000000000000067421511331344600236140ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/confmap/internal/e2e/nil_test.go000066400000000000000000000046531511331344600246300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2etest import ( "context" "testing" "github.com/stretchr/testify/require" ) func TestNilToStringMap(t *testing.T) { tests := []struct { name string expectedMap map[string]any expectedSub map[string]any }{ { name: "subsection_null.yaml", expectedMap: map[string]any{ "field": map[string]any{ "key": nil, }, }, expectedSub: nil, }, { name: "subsection_empty_map.yaml", expectedMap: map[string]any{ "field": map[string]any{ "key": map[string]any{}, }, }, expectedSub: map[string]any{}, }, { name: "subsection_set_but_empty.yaml", expectedMap: map[string]any{ "field": map[string]any{ "key": nil, }, }, expectedSub: nil, }, { name: "subsection_unset.yaml", expectedMap: map[string]any{ "field": nil, }, expectedSub: nil, }, { name: "subsection_unset_empty_map.yaml", expectedMap: map[string]any{ "field": map[string]any{}, }, expectedSub: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resolver := NewResolver(t, tt.name) conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) require.Equal(t, tt.expectedMap, conf.ToStringMap()) sub, err := conf.Sub("field::key") require.NoError(t, err) require.Equal(t, tt.expectedSub, sub.ToStringMap()) }) } } func TestNilToStringMapEnv(t *testing.T) { tests := []struct { envValue string expectedMap map[string]any expectedSub map[string]any }{ { envValue: "null", expectedMap: map[string]any{ "field": map[string]any{ "key": nil, }, }, expectedSub: nil, }, { envValue: "{}", expectedMap: map[string]any{ "field": map[string]any{ "key": map[string]any{}, }, }, expectedSub: map[string]any{}, }, { envValue: "", expectedMap: map[string]any{ "field": map[string]any{ "key": nil, }, }, expectedSub: nil, }, } for _, tt := range tests { t.Run(tt.envValue, func(t *testing.T) { t.Setenv("VALUE", tt.envValue) resolver := NewResolver(t, "types_map.yaml") conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) require.Equal(t, tt.expectedMap, conf.ToStringMap()) sub, err := conf.Sub("field::key") require.NoError(t, err) require.Equal(t, tt.expectedSub, sub.ToStringMap()) }) } } opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/000077500000000000000000000000001511331344600242615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/expand-escaped-env.yaml000066400000000000000000000021551511331344600306170ustar00rootroot00000000000000test_map: # $$ -> escaped $ key1: "$$ENV_VALUE" # $$$$ -> two escaped $ key2: "$$$$ENV_VALUE" # $$ -> escaped $ + ${ENV_VALUE} expanded key3: "$$${ENV_VALUE}" # expanded in the middle key4: "some${ENV_VALUE}text" # escaped $ in the middle key5: "some$${ENV_VALUE}text" # two escaped $ key6: "$${ONE}$${TWO}" # trailing escaped $ key7: "text$$" # escaped $ alone key8: "$$" # escaped number and uri key9: "$${1}$${env:2}" # escape provider key10: "some$${env:ENV_VALUE}text" # can escape outer when nested key11: "$${env:${ENV_VALUE}}" # can escape inner and outer when nested key12: "$${env:$${ENV_VALUE}}" # can escape partial key13: "env:MAP_VALUE_2}$${ENV_VALUE}{" # $$$ -> escaped $ + expanded env var key14: "$$${env:ENV_VALUE}" # $ -> $ key15: "$ENV_VALUE" # list is escaped key16: "${env:ENV_LIST}" # map is escaped key17: "${env:ENV_MAP}" # nested $$ -> escaped $ key18: "${env:ENV_NESTED_DOLLARSIGN}" # nested $$$ -> escaped $$ key19: "${env:ENV_NESTED_DOLLARSIGN_ESCAPED}" # nested env var syntax is expanded key20: "${env:ENV_EXPAND_NESTED}" opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/indirect-slice-env-var-main.yaml000066400000000000000000000003051511331344600323370ustar00rootroot00000000000000receivers: nop: otlp: protocols: grpc: exporters: nop: otlp: endpoint: localhost:4317 service: pipelines: ${file:${env:BASE_FOLDER}/indirect-slice-env-var-pipelines.yaml} opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/indirect-slice-env-var-pipelines.yaml000066400000000000000000000001241511331344600334020ustar00rootroot00000000000000logs: receivers: ${env:OTEL_LOGS_RECEIVER} exporters: ${env:OTEL_LOGS_EXPORTER} opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/issue-10787-main.yaml000066400000000000000000000005651511331344600277110ustar00rootroot00000000000000receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: memory_limiter: exporters: ${file:testdata/issue-10787-snippet.yaml} service: telemetry: metrics: level: detailed pipelines: traces: receivers: [otlp] processors: [memory_limiter] exporters: [debug] opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/issue-10787-snippet.yaml000066400000000000000000000000561511331344600304420ustar00rootroot00000000000000# ${hello.world} debug: verbosity: detailed opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/subsection_empty_map.yaml000066400000000000000000000000211511331344600313670ustar00rootroot00000000000000field: key: {} opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/subsection_null.yaml000066400000000000000000000000231511331344600303500ustar00rootroot00000000000000field: key: null opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/subsection_set_but_empty.yaml000066400000000000000000000000161511331344600322630ustar00rootroot00000000000000field: key: opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/subsection_unset.yaml000066400000000000000000000000071511331344600305360ustar00rootroot00000000000000field: opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/subsection_unset_empty_map.yaml000066400000000000000000000000121511331344600326050ustar00rootroot00000000000000field: {} opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/types_complex.yaml000066400000000000000000000000371511331344600300400ustar00rootroot00000000000000field: [key: ["${env:VALUE}"]] opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/types_expand.yaml000066400000000000000000000000221511331344600276420ustar00rootroot00000000000000field: ${env:ENV} opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/types_expand_inline.yaml000066400000000000000000000000601511331344600312020ustar00rootroot00000000000000field: "inline field with ${env:ENV} expansion" opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/types_map.yaml000066400000000000000000000000331511331344600271420ustar00rootroot00000000000000field: key: ${env:VALUE} opentelemetry-collector-0.141.0/confmap/internal/e2e/testdata/types_slice.yaml000066400000000000000000000000301511331344600274610ustar00rootroot00000000000000field: ["${env:VALUE}"] opentelemetry-collector-0.141.0/confmap/internal/e2e/types_test.go000066400000000000000000000426541511331344600252150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2etest import ( "context" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/envprovider" "go.opentelemetry.io/collector/confmap/provider/fileprovider" ) type TargetField string const ( TargetFieldInt TargetField = "int_field" TargetFieldString TargetField = "string_field" TargetFieldBool TargetField = "bool_field" TargetFieldInlineString TargetField = "inline_string_field" TargetFieldSlice TargetField = "slice_field" ) type Test struct { value string targetField TargetField expected any resolveErr string unmarshalErr string } type targetConfig[T any] struct { Field T `mapstructure:"field"` } func NewResolver(tb testing.TB, path string) *confmap.Resolver { resolver, err := confmap.NewResolver(confmap.ResolverSettings{ URIs: []string{filepath.Join("testdata", path)}, ProviderFactories: []confmap.ProviderFactory{ fileprovider.NewFactory(), envprovider.NewFactory(), }, DefaultScheme: "env", }) require.NoError(tb, err) return resolver } func AssertExpectedMatch[T any](t *testing.T, tt Test, conf *confmap.Conf, cfg *targetConfig[T]) { err := conf.Unmarshal(cfg) if tt.unmarshalErr != "" { require.ErrorContains(t, err, tt.unmarshalErr) return } require.NoError(t, err) require.Equal(t, tt.expected, cfg.Field) } func AssertResolvesTo(t *testing.T, resolver *confmap.Resolver, tt Test) { conf, err := resolver.Resolve(context.Background()) if tt.resolveErr != "" { require.ErrorContains(t, err, tt.resolveErr) return } require.NoError(t, err) switch tt.targetField { case TargetFieldInt: var cfg targetConfig[int] AssertExpectedMatch(t, tt, conf, &cfg) case TargetFieldString, TargetFieldInlineString: var cfg targetConfig[string] AssertExpectedMatch(t, tt, conf, &cfg) case TargetFieldBool: var cfg targetConfig[bool] AssertExpectedMatch(t, tt, conf, &cfg) case TargetFieldSlice: var cfg targetConfig[[]any] AssertExpectedMatch(t, tt, conf, &cfg) default: t.Fatalf("unexpected target field %q", tt.targetField) } } func TestStrictTypeCasting(t *testing.T) { t.Setenv("ENV_VALUE", "testreceiver") values := []Test{ { value: "123", targetField: TargetFieldInt, expected: 123, }, { value: "123", targetField: TargetFieldString, expected: "123", }, { value: "123", targetField: TargetFieldInlineString, expected: "inline field with 123 expansion", }, { value: "0123", targetField: TargetFieldInt, expected: 83, }, { value: "0123", targetField: TargetFieldString, expected: "0123", }, { value: "0123", targetField: TargetFieldInlineString, expected: "inline field with 0123 expansion", }, { value: "0xdeadbeef", targetField: TargetFieldInt, expected: 3735928559, }, { value: "0xdeadbeef", targetField: TargetFieldString, expected: "0xdeadbeef", }, { value: "0xdeadbeef", targetField: TargetFieldInlineString, expected: "inline field with 0xdeadbeef expansion", }, { value: "\"0123\"", targetField: TargetFieldString, expected: "\"0123\"", }, { value: "\"0123\"", targetField: TargetFieldInt, unmarshalErr: "'field' expected type 'int', got unconvertible type 'string'", }, { value: "\"0123\"", targetField: TargetFieldInlineString, expected: "inline field with \"0123\" expansion", }, { value: "!!str 0123", targetField: TargetFieldString, expected: "!!str 0123", }, { value: "!!str 0123", targetField: TargetFieldInlineString, expected: "inline field with !!str 0123 expansion", }, { value: "t", targetField: TargetFieldBool, unmarshalErr: "'field' expected type 'bool', got unconvertible type 'string'", }, { value: "23", targetField: TargetFieldBool, unmarshalErr: "'field' expected type 'bool', got unconvertible type 'int'", }, { value: "{\"field\": 123}", targetField: TargetFieldInlineString, expected: "inline field with {\"field\": 123} expansion", }, { value: "1111:1111:1111:1111:1111::", targetField: TargetFieldInlineString, expected: "inline field with 1111:1111:1111:1111:1111:: expansion", }, { value: "1111:1111:1111:1111:1111::", targetField: TargetFieldString, expected: "1111:1111:1111:1111:1111::", }, { value: "2006-01-02T15:04:05Z07:00", targetField: TargetFieldString, expected: "2006-01-02T15:04:05Z07:00", }, { value: "2006-01-02T15:04:05Z07:00", targetField: TargetFieldInlineString, expected: "inline field with 2006-01-02T15:04:05Z07:00 expansion", }, { value: "2023-03-20T03:17:55.432328Z", targetField: TargetFieldString, expected: "2023-03-20T03:17:55.432328Z", }, { value: "2023-03-20T03:17:55.432328Z", targetField: TargetFieldInlineString, expected: "inline field with 2023-03-20T03:17:55.432328Z expansion", }, // issue 10787 { value: "true # comment with a ${env:hello.world} reference", targetField: TargetFieldBool, expected: true, }, { value: "true # comment with a ${env:hello.world} reference", targetField: TargetFieldString, unmarshalErr: `expected type 'string', got unconvertible type 'bool'`, }, { value: "true # comment with a ${env:hello.world} reference", targetField: TargetFieldInlineString, resolveErr: `environment variable "hello.world" has invalid name`, }, // issue 10759 { value: `["a",`, targetField: TargetFieldString, expected: `["a",`, }, { value: `["a",`, targetField: TargetFieldInlineString, expected: `inline field with ["a", expansion`, }, // issue 10799 { value: `[filelog,windowseventlog/application]`, targetField: TargetFieldSlice, expected: []any{"filelog", "windowseventlog/application"}, }, { value: `[filelog,windowseventlog/application]`, targetField: TargetFieldString, expected: "[filelog,windowseventlog/application]", }, { value: `[filelog,windowseventlog/application]`, targetField: TargetFieldInlineString, expected: "inline field with [filelog,windowseventlog/application] expansion", }, { value: "$$ENV", targetField: TargetFieldString, expected: "$ENV", }, { value: "$$ENV", targetField: TargetFieldInlineString, expected: "inline field with $ENV expansion", }, { value: "$${ENV}", targetField: TargetFieldString, expected: "${ENV}", }, { value: "$${ENV}", targetField: TargetFieldInlineString, expected: "inline field with ${ENV} expansion", }, { value: "$${env:ENV}", targetField: TargetFieldString, expected: "${env:ENV}", }, { value: "$${env:ENV}", targetField: TargetFieldInlineString, expected: "inline field with ${env:ENV} expansion", }, { value: `[filelog,${env:ENV_VALUE}]`, targetField: TargetFieldString, expected: "[filelog,testreceiver]", }, { value: `[filelog,${ENV_VALUE}]`, targetField: TargetFieldString, expected: "[filelog,testreceiver]", }, { value: `["filelog","$${env:ENV_VALUE}"]`, targetField: TargetFieldString, expected: `["filelog","${env:ENV_VALUE}"]`, }, { value: `["filelog","$${ENV_VALUE}"]`, targetField: TargetFieldString, expected: `["filelog","${ENV_VALUE}"]`, }, { value: `["filelog","$$ENV_VALUE"]`, targetField: TargetFieldString, expected: `["filelog","$ENV_VALUE"]`, }, { value: `["filelog","$ENV_VALUE"]`, targetField: TargetFieldString, expected: `["filelog","$ENV_VALUE"]`, }, } for _, tt := range values { t.Run(tt.value+"/"+string(tt.targetField)+"/"+"direct", func(t *testing.T) { testFile := "types_expand.yaml" if tt.targetField == TargetFieldInlineString { testFile = "types_expand_inline.yaml" } resolver := NewResolver(t, testFile) t.Setenv("ENV", tt.value) AssertResolvesTo(t, resolver, tt) }) t.Run(tt.value+"/"+string(tt.targetField)+"/"+"indirect", func(t *testing.T) { testFile := "types_expand.yaml" if tt.targetField == TargetFieldInlineString { testFile = "types_expand_inline.yaml" } resolver := NewResolver(t, testFile) t.Setenv("ENV", "${env:ENV2}") t.Setenv("ENV2", tt.value) AssertResolvesTo(t, resolver, tt) }) } } func TestRecursiveInlineString(t *testing.T) { values := []Test{ { value: "123", targetField: TargetFieldString, expected: "The value The value 123 is wrapped is wrapped", }, { value: "123", targetField: TargetFieldInlineString, expected: "inline field with The value The value 123 is wrapped is wrapped expansion", }, { value: "opentelemetry", targetField: TargetFieldString, expected: "The value The value opentelemetry is wrapped is wrapped", }, { value: "opentelemetry", targetField: TargetFieldInlineString, expected: "inline field with The value The value opentelemetry is wrapped is wrapped expansion", }, } for _, tt := range values { t.Run(tt.value+"/"+string(tt.targetField), func(t *testing.T) { testFile := "types_expand.yaml" if tt.targetField == TargetFieldInlineString { testFile = "types_expand_inline.yaml" } resolver := NewResolver(t, testFile) t.Setenv("ENV", "The value ${env:ENV2} is wrapped") t.Setenv("ENV2", "The value ${env:ENV3} is wrapped") t.Setenv("ENV3", tt.value) AssertResolvesTo(t, resolver, tt) }) } } func TestRecursiveMaps(t *testing.T) { value := "{value: 123}" resolver := NewResolver(t, "types_expand.yaml") t.Setenv("ENV", `{env: "${env:ENV2}", inline: "inline ${env:ENV2}"}`) t.Setenv("ENV2", `{env2: "${env:ENV3}"}`) t.Setenv("ENV3", value) conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) type Value struct { Value int `mapstructure:"value"` } type ENV2 struct { Env2 Value `mapstructure:"env2"` } type ENV struct { Env ENV2 `mapstructure:"env"` Inline string `mapstructure:"inline"` } type Target struct { Field ENV `mapstructure:"field"` } var cfg Target err = conf.Unmarshal(&cfg) require.NoError(t, err) require.Equal(t, Target{Field: ENV{ Env: ENV2{ Env2: Value{ Value: 123, }, }, Inline: "inline {env2: \"{value: 123}\"}", }}, cfg, ) confStr, err := resolver.Resolve(context.Background()) require.NoError(t, err) var cfgStr targetConfig[string] err = confStr.Unmarshal(&cfgStr) require.NoError(t, err) require.Equal(t, `{env: "{env2: "{value: 123}"}", inline: "inline {env2: "{value: 123}"}"}`, cfgStr.Field, ) } // Test that comments with invalid ${env:...} references do not prevent configuration from loading. func TestIssue10787(t *testing.T) { resolver := NewResolver(t, "issue-10787-main.yaml") conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) assert.Equal(t, map[string]any{ "exporters": map[string]any{ "debug": map[string]any{ "verbosity": "detailed", }, }, "processors": map[string]any{ "memory_limiter": nil, }, "receivers": map[string]any{ "otlp": map[string]any{ "protocols": map[string]any{ "grpc": map[string]any{ "endpoint": "0.0.0.0:4317", }, "http": map[string]any{ "endpoint": "0.0.0.0:4318", }, }, }, }, "service": map[string]any{ "pipelines": map[string]any{ "traces": map[string]any{ "exporters": []any{"debug"}, "processors": []any{"memory_limiter"}, "receivers": []any{"otlp"}, }, }, "telemetry": map[string]any{ "metrics": map[string]any{ "level": "detailed", }, }, }, }, conf.ToStringMap(), ) } func TestStructMappingIssue10787(t *testing.T) { resolver := NewResolver(t, "types_expand.yaml") t.Setenv("ENV", `# this is a comment debug: verbosity: detailed`) conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) type Debug struct { Verbosity string `mapstructure:"verbosity"` } type Exporters struct { Debug Debug `mapstructure:"debug"` } type Target struct { Field Exporters `mapstructure:"field"` } var cfg Target err = conf.Unmarshal(&cfg) require.NoError(t, err) require.Equal(t, Target{Field: Exporters{ Debug: Debug{ Verbosity: "detailed", }, }}, cfg, ) confStr, err := resolver.Resolve(context.Background()) require.NoError(t, err) var cfgStr targetConfig[string] err = confStr.Unmarshal(&cfgStr) require.NoError(t, err) require.Equal(t, `# this is a comment debug: verbosity: detailed`, cfgStr.Field, ) } func TestStructMappingIssue10787_ExpandComment(t *testing.T) { resolver := NewResolver(t, "types_expand.yaml") t.Setenv("EXPAND_ME", "an expanded env var") t.Setenv("ENV", `# this is a comment with ${EXPAND_ME} debug: verbosity: detailed`) conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) type Debug struct { Verbosity string `mapstructure:"verbosity"` } type Exporters struct { Debug Debug `mapstructure:"debug"` } type Target struct { Field Exporters `mapstructure:"field"` } var cfg Target err = conf.Unmarshal(&cfg) require.NoError(t, err) require.Equal(t, Target{Field: Exporters{ Debug: Debug{ Verbosity: "detailed", }, }}, cfg, ) confStr, err := resolver.Resolve(context.Background()) require.NoError(t, err) var cfgStr targetConfig[string] err = confStr.Unmarshal(&cfgStr) require.NoError(t, err) require.Equal(t, `# this is a comment with an expanded env var debug: verbosity: detailed`, cfgStr.Field, ) } func TestIndirectSliceEnvVar(t *testing.T) { // This replicates the situation in https://github.com/open-telemetry/opentelemetry-collector/issues/10799 // where a configuration file is loaded that contains a reference to a slice of strings in an environment variable. t.Setenv("BASE_FOLDER", "testdata") t.Setenv("OTEL_LOGS_RECEIVER", "[nop, otlp]") t.Setenv("OTEL_LOGS_EXPORTER", "[otlp, nop]") resolver := NewResolver(t, "indirect-slice-env-var-main.yaml") conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) type CollectorConf struct { Exporters struct { OTLP struct { Endpoint string `mapstructure:"endpoint"` } `mapstructure:"otlp"` Nop struct{} `mapstructure:"nop"` } `mapstructure:"exporters"` Receivers struct { OTLP struct { Protocols struct { GRPC struct{} `mapstructure:"grpc"` } `mapstructure:"protocols"` } `mapstructure:"otlp"` Nop struct{} `mapstructure:"nop"` } `mapstructure:"receivers"` Service struct { Pipelines struct { Logs struct { Exporters []string `mapstructure:"exporters"` Receivers []string `mapstructure:"receivers"` } `mapstructure:"logs"` } `mapstructure:"pipelines"` } `mapstructure:"service"` } var collectorConf CollectorConf err = conf.Unmarshal(&collectorConf) require.NoError(t, err) assert.Equal(t, "localhost:4317", collectorConf.Exporters.OTLP.Endpoint) assert.Equal(t, []string{"nop", "otlp"}, collectorConf.Service.Pipelines.Logs.Receivers) assert.Equal(t, []string{"otlp", "nop"}, collectorConf.Service.Pipelines.Logs.Exporters) } func TestIssue10937_MapType(t *testing.T) { t.Setenv("VALUE", "1234") resolver := NewResolver(t, "types_map.yaml") conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) var cfg targetConfig[map[string]configopaque.String] err = conf.Unmarshal(&cfg) require.NoError(t, err) require.Equal(t, map[string]configopaque.String{"key": "1234"}, cfg.Field) } func TestIssue10937_ArrayType(t *testing.T) { t.Setenv("VALUE", "1234") resolver := NewResolver(t, "types_slice.yaml") conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) var cfgStrSlice targetConfig[[]string] err = conf.Unmarshal(&cfgStrSlice) require.NoError(t, err) require.Equal(t, []string{"1234"}, cfgStrSlice.Field) var cfgStrArray targetConfig[[1]string] err = conf.Unmarshal(&cfgStrArray) require.NoError(t, err) require.Equal(t, [1]string{"1234"}, cfgStrArray.Field) var cfgAnySlice targetConfig[[]any] err = conf.Unmarshal(&cfgAnySlice) require.NoError(t, err) require.Equal(t, []any{1234}, cfgAnySlice.Field) var cfgAnyArray targetConfig[[1]any] err = conf.Unmarshal(&cfgAnyArray) require.NoError(t, err) require.Equal(t, [1]any{1234}, cfgAnyArray.Field) } func TestIssue10937_ComplexType(t *testing.T) { t.Setenv("VALUE", "1234") resolver := NewResolver(t, "types_complex.yaml") conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) var cfgStringy targetConfig[[]map[string][]string] err = conf.Unmarshal(&cfgStringy) require.NoError(t, err) require.Equal(t, []map[string][]string{{"key": {"1234"}}}, cfgStringy.Field) var cfgNotStringy targetConfig[[]map[string][]any] err = conf.Unmarshal(&cfgNotStringy) require.NoError(t, err) require.Equal(t, []map[string][]any{{"key": {1234}}}, cfgNotStringy.Field) } func TestIssue10949_UnsetVar(t *testing.T) { t.Setenv("ENV", "") resolver := NewResolver(t, "types_expand.yaml") conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) var cfg targetConfig[int] err = conf.Unmarshal(&cfg) require.NoError(t, err) require.Equal(t, 0, cfg.Field) } opentelemetry-collector-0.141.0/confmap/internal/encoder.go000066400000000000000000000037101511331344600237440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" import ( "reflect" "github.com/go-viper/mapstructure/v2" encoder "go.opentelemetry.io/collector/confmap/internal/mapstructure" ) // EncoderConfig returns a default encoder.EncoderConfig that includes // an EncodeHook that handles both TextMarshaler and Marshaler // interfaces. func EncoderConfig(rawVal any, _ MarshalOptions) *encoder.EncoderConfig { return &encoder.EncoderConfig{ EncodeHook: mapstructure.ComposeDecodeHookFunc( encoder.YamlMarshalerHookFunc(), encoder.TextMarshalerHookFunc(), marshalerHookFunc(rawVal), ), } } // marshalerHookFunc returns a DecodeHookFuncValue that checks structs that aren't // the original to see if they implement the Marshaler interface. func marshalerHookFunc(orig any) mapstructure.DecodeHookFuncValue { origType := reflect.TypeOf(orig) return safeWrapDecodeHookFunc(func(from, _ reflect.Value) (any, error) { if from.Kind() != reflect.Struct { return from.Interface(), nil } // ignore original to avoid infinite loop. if from.Type() == origType && reflect.DeepEqual(from.Interface(), orig) { return from.Interface(), nil } marshaler, ok := from.Interface().(Marshaler) if !ok { return from.Interface(), nil } conf := NewFromStringMap(nil) if err := marshaler.Marshal(conf); err != nil { return nil, err } stringMap := conf.ToStringMap() if stringMap == nil { // If conf is still nil after marshaling, we want to encode it as an untyped nil // instead of a map-typed nil. This ensures the value is a proper null value // in the final marshaled output instead of an empty map. We hit this case // when marshaling wrapper structs that have no direct representation // in the marshaled output that aren't tagged with "squash" on the fields // they're used on. return nil, nil } return stringMap, nil }) } opentelemetry-collector-0.141.0/confmap/internal/envvar/000077500000000000000000000000001511331344600232765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/envvar/pattern.go000066400000000000000000000004451511331344600253050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package envvar // import "go.opentelemetry.io/collector/confmap/internal/envvar" import "regexp" const ValidationPattern = `^[a-zA-Z_][a-zA-Z0-9_]*$` var ValidationRegexp = regexp.MustCompile(ValidationPattern) opentelemetry-collector-0.141.0/confmap/internal/expand.go000066400000000000000000000011741511331344600236060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" // ExpandedValue holds the YAML parsed value and original representation of a value. // It keeps track of the original representation to be used by the 'useExpandValue' hook // if the target field is a string. We need to keep both representations because we don't know // what the target field type is until `Unmarshal` is called. type ExpandedValue struct { // Value is the expanded value. Value any // Original is the original representation of the value. Original string } opentelemetry-collector-0.141.0/confmap/internal/featuregates.go000066400000000000000000000013011511331344600247760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" import "go.opentelemetry.io/collector/featuregate" var EnableMergeAppendOption = featuregate.GlobalRegistry().MustRegister( "confmap.enableMergeAppendOption", featuregate.StageAlpha, featuregate.WithRegisterFromVersion("v0.120.0"), featuregate.WithRegisterDescription("Combines lists when resolving configs from different sources. This feature gate will not be stabilized 'as is'; the current behavior will remain the default."), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/issues/8754"), ) opentelemetry-collector-0.141.0/confmap/internal/mapstructure/000077500000000000000000000000001511331344600245335ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/mapstructure/encoder.go000066400000000000000000000166431511331344600265130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package mapstructure // import "go.opentelemetry.io/collector/confmap/internal/mapstructure" import ( "encoding" "errors" "fmt" "maps" "reflect" "strings" "github.com/go-viper/mapstructure/v2" yaml "go.yaml.in/yaml/v3" ) const ( tagNameMapStructure = "mapstructure" optionSeparator = "," optionOmitEmpty = "omitempty" optionSquash = "squash" optionRemain = "remain" optionSkip = "-" ) var errNonStringEncodedKey = errors.New("non string-encoded key") // tagInfo stores the mapstructure tag details. type tagInfo struct { name string omitEmpty bool squash bool } // An Encoder takes structured data and converts it into an // interface following the mapstructure tags. type Encoder struct { config *EncoderConfig } // EncoderConfig is the configuration used to create a new encoder. type EncoderConfig struct { // EncodeHook, if set, is a way to provide custom encoding. It // will be called before structs and primitive types. EncodeHook mapstructure.DecodeHookFunc } // New returns a new encoder for the configuration. func New(cfg *EncoderConfig) *Encoder { return &Encoder{config: cfg} } // Encode takes the input and uses reflection to encode it to // an interface based on the mapstructure spec. func (e *Encoder) Encode(input any) (any, error) { return e.encode(reflect.ValueOf(input)) } // encode processes the value based on the reflect.Kind. func (e *Encoder) encode(value reflect.Value) (any, error) { if value.IsValid() { switch value.Kind() { case reflect.Interface, reflect.Ptr: return e.encode(value.Elem()) case reflect.Map: return e.encodeMap(value) case reflect.Slice: return e.encodeSlice(value) case reflect.Struct: return e.encodeStruct(value) default: return e.encodeHook(value) } } return nil, nil } // encodeHook calls the EncodeHook in the EncoderConfig with the value passed in. // This is called before processing structs and for primitive data types. func (e *Encoder) encodeHook(value reflect.Value) (any, error) { if e.config != nil && e.config.EncodeHook != nil { out, err := mapstructure.DecodeHookExec(e.config.EncodeHook, value, value) if err != nil { return nil, fmt.Errorf("error running encode hook: %w", err) } return out, nil } return value.Interface(), nil } // encodeStruct encodes the struct by iterating over the fields, getting the // mapstructure tagInfo for each exported field, and encoding the value. func (e *Encoder) encodeStruct(value reflect.Value) (any, error) { if value.Kind() != reflect.Struct { return nil, &reflect.ValueError{ Method: "encodeStruct", Kind: value.Kind(), } } out, err := e.encodeHook(value) if err != nil { return nil, err } value = reflect.ValueOf(out) // if the output of encodeHook is no longer a struct, // call encode against it. if value.Kind() != reflect.Struct { return e.encode(value) } result := make(map[string]any) for i := 0; i < value.NumField(); i++ { field := value.Field(i) if field.CanInterface() { info := getTagInfo(value.Type().Field(i)) if (info.omitEmpty && field.IsZero()) || info.name == optionSkip { continue } encoded, err := e.encode(field) if err != nil { return nil, fmt.Errorf("error encoding field %q: %w", info.name, err) } if info.squash { if m, ok := encoded.(map[string]any); ok { maps.Copy(result, m) } } else { result[info.name] = encoded } } } return result, nil } // encodeSlice iterates over the slice and encodes each of the elements. func (e *Encoder) encodeSlice(value reflect.Value) (any, error) { if value.Kind() != reflect.Slice { return nil, &reflect.ValueError{ Method: "encodeSlice", Kind: value.Kind(), } } if value.IsNil() { return []any(nil), nil } result := make([]any, value.Len()) for i := 0; i < value.Len(); i++ { var err error if result[i], err = e.encode(value.Index(i)); err != nil { return nil, fmt.Errorf("error encoding element in slice at index %d: %w", i, err) } } return result, nil } // encodeMap encodes a map by encoding the key and value. Returns errNonStringEncodedKey // if the key is not encoded into a string. func (e *Encoder) encodeMap(value reflect.Value) (any, error) { if value.Kind() != reflect.Map { return nil, &reflect.ValueError{ Method: "encodeMap", Kind: value.Kind(), } } var result map[string]any if value.Len() > 0 || !value.IsNil() { result = make(map[string]any) } iterator := value.MapRange() for iterator.Next() { encoded, err := e.encode(iterator.Key()) if err != nil { return nil, fmt.Errorf("error encoding key: %w", err) } v := reflect.ValueOf(encoded) var key string switch v.Kind() { case reflect.String: key = v.String() default: return nil, fmt.Errorf("%w, key: %q, kind: %v, type: %T", errNonStringEncodedKey, iterator.Key().Interface(), iterator.Key().Kind(), encoded) } if _, ok := result[key]; ok { return nil, fmt.Errorf("duplicate key %q while encoding", key) } if result[key], err = e.encode(iterator.Value()); err != nil { return nil, fmt.Errorf("error encoding map value for key %q: %w", key, err) } } return result, nil } // getTagInfo looks up the mapstructure tag and uses that if available. // Uses the lowercase field if not found. Checks for omitempty and squash. func getTagInfo(field reflect.StructField) *tagInfo { info := tagInfo{} if tag, ok := field.Tag.Lookup(tagNameMapStructure); ok { options := strings.Split(tag, optionSeparator) info.name = options[0] if len(options) > 1 { for _, option := range options[1:] { switch option { case optionOmitEmpty: info.omitEmpty = true case optionSquash, optionRemain: info.squash = true } } } } else { info.name = strings.ToLower(field.Name) } return &info } // TextMarshalerHookFunc returns a DecodeHookFuncValue that checks // for the encoding.TextMarshaler interface and calls the MarshalText // function if found. func TextMarshalerHookFunc() mapstructure.DecodeHookFuncValue { return func(from, _ reflect.Value) (any, error) { marshaler, ok := from.Interface().(encoding.TextMarshaler) if !ok { return from.Interface(), nil } out, err := marshaler.MarshalText() if err != nil { return nil, err } return string(out), nil } } // YamlMarshalerHookFunc returns a DecodeHookFuncValue that checks for structs // that have yaml tags but no mapstructure tags. If found, it will convert the struct // to map[string]any using the yaml package, which respects the yaml tags. Ultimately, // this allows mapstructure to later marshal the map[string]any in a generic way. func YamlMarshalerHookFunc() mapstructure.DecodeHookFuncValue { return func(from, _ reflect.Value) (any, error) { if from.Kind() == reflect.Struct { for i := 0; i < from.NumField(); i++ { if _, ok := from.Type().Field(i).Tag.Lookup("mapstructure"); ok { // The struct has at least one mapstructure tag so don't do anything. return from.Interface(), nil } if _, ok := from.Type().Field(i).Tag.Lookup("yaml"); ok { // The struct has at least one yaml tag, so convert it to map[string]any using yaml. yamlBytes, err := yaml.Marshal(from.Interface()) if err != nil { return nil, err } var m map[string]any err = yaml.Unmarshal(yamlBytes, &m) if err != nil { return nil, err } return m, nil } } } return from.Interface(), nil } } opentelemetry-collector-0.141.0/confmap/internal/mapstructure/encoder_test.go000066400000000000000000000224761511331344600275530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package mapstructure import ( "encoding" "errors" "reflect" "strings" "testing" "github.com/go-viper/mapstructure/v2" "github.com/stretchr/testify/require" ) type TestComplexStruct struct { Skipped TestEmptyStruct `mapstructure:",squash"` Nested TestSimpleStruct `mapstructure:",squash"` Slice []TestSimpleStruct `mapstructure:"slice,omitempty"` Pointer *TestSimpleStruct `mapstructure:"ptr"` Map map[string]TestSimpleStruct `mapstructure:"map,omitempty"` Remain map[string]any `mapstructure:",remain"` TranslatedYaml TestYamlStruct `mapstructure:"translated"` SquashedYaml TestYamlStruct `mapstructure:",squash"` PointerTranslatedYaml *TestPtrToYamlStruct `mapstructure:"translated_ptr"` PointerSquashedYaml *TestPtrToYamlStruct `mapstructure:",squash"` Interface encoding.TextMarshaler } type TestSimpleStruct struct { Value string `mapstructure:"value"` skipped string err error } type TestEmptyStruct struct { Value string `mapstructure:"-"` } type TestYamlStruct struct { YamlValue string `yaml:"yaml_value"` YamlOmitEmpty string `yaml:"yaml_omit,omitempty"` YamlInline TestYamlSimpleStruct `yaml:",inline"` } type TestPtrToYamlStruct struct { YamlValue string `yaml:"yaml_value_ptr"` YamlOmitEmpty string `yaml:"yaml_omit_ptr,omitempty"` YamlInline *TestYamlPtrToSimpleStruct `yaml:",inline"` } type TestYamlSimpleStruct struct { Inline string `yaml:"yaml_inline"` } type TestYamlPtrToSimpleStruct struct { InlinePtr string `yaml:"yaml_inline_ptr"` } type TestID string func (tID TestID) MarshalText() (text []byte, err error) { out := string(tID) if out == "error" { return nil, errors.New("parsing error") } if !strings.HasSuffix(out, "_") { out += "_" } return []byte(out), nil } type TestStringLike string func TestEncode(t *testing.T) { enc := New(&EncoderConfig{ EncodeHook: mapstructure.ComposeDecodeHookFunc( YamlMarshalerHookFunc(), TextMarshalerHookFunc(), ), }) testCases := map[string]struct { input any want any }{ "WithString": { input: "test", want: "test", }, "WithTextMarshaler": { input: TestID("type"), want: "type_", }, "MapWithTextMarshalerKey": { input: map[TestID]TestSimpleStruct{ TestID("type"): {Value: "value"}, }, want: map[string]any{ "type_": map[string]any{"value": "value"}, }, }, "MapWithoutTextMarshalerKey": { input: map[TestStringLike]TestSimpleStruct{ TestStringLike("key"): {Value: "value"}, }, want: map[string]any{ "key": map[string]any{"value": "value"}, }, }, "WithSlice": { input: []TestID{ TestID("nop"), TestID("type_"), }, want: []any{"nop_", "type_"}, }, "WithSimpleStruct": { input: TestSimpleStruct{Value: "test", skipped: "skipped"}, want: map[string]any{ "value": "test", }, }, "WithComplexStruct": { input: &TestComplexStruct{ Skipped: TestEmptyStruct{ Value: "omitted", }, Nested: TestSimpleStruct{ Value: "nested", }, Slice: []TestSimpleStruct{ {Value: "slice"}, }, Map: map[string]TestSimpleStruct{ "Key": {Value: "map"}, }, Pointer: &TestSimpleStruct{ Value: "pointer", }, Remain: map[string]any{ "remain1": 23, "remain2": "value", }, Interface: TestID("value"), TranslatedYaml: TestYamlStruct{ YamlValue: "foo_translated", YamlOmitEmpty: "", YamlInline: TestYamlSimpleStruct{ Inline: "bar_translated", }, }, SquashedYaml: TestYamlStruct{ YamlValue: "foo_squashed", YamlOmitEmpty: "", YamlInline: TestYamlSimpleStruct{ Inline: "bar_squashed", }, }, PointerTranslatedYaml: &TestPtrToYamlStruct{ YamlValue: "foo_translated_ptr", YamlOmitEmpty: "", YamlInline: &TestYamlPtrToSimpleStruct{ InlinePtr: "bar_translated_ptr", }, }, PointerSquashedYaml: &TestPtrToYamlStruct{ YamlValue: "foo_squashed_ptr", YamlOmitEmpty: "", YamlInline: &TestYamlPtrToSimpleStruct{ InlinePtr: "bar_squashed_ptr", }, }, }, want: map[string]any{ "value": "nested", "slice": []any{map[string]any{"value": "slice"}}, "map": map[string]any{ "Key": map[string]any{"value": "map"}, }, "ptr": map[string]any{"value": "pointer"}, "interface": "value_", "yaml_value": "foo_squashed", "yaml_inline": "bar_squashed", "translated": map[string]any{ "yaml_value": "foo_translated", "yaml_inline": "bar_translated", }, "yaml_value_ptr": "foo_squashed_ptr", "yaml_inline_ptr": "bar_squashed_ptr", "translated_ptr": map[string]any{ "yaml_value_ptr": "foo_translated_ptr", "yaml_inline_ptr": "bar_translated_ptr", }, "remain1": 23, "remain2": "value", }, }, } for name, testCase := range testCases { t.Run(name, func(t *testing.T) { got, err := enc.Encode(testCase.input) require.NoError(t, err) require.Equal(t, testCase.want, got) }) } // without the TextMarshalerHookFunc enc.config.EncodeHook = nil testCase := TestID("test") got, err := enc.Encode(testCase) require.NoError(t, err) require.Equal(t, testCase, got) } func TestGetTagInfo(t *testing.T) { testCases := []struct { name string field reflect.StructField wantName string wantOmit bool wantSquash bool }{ { name: "WithoutTags", field: reflect.StructField{ Name: "Test", }, wantName: "test", }, { name: "WithoutMapStructureTag", field: reflect.StructField{ Tag: `yaml:"hello,inline"`, Name: "YAML", }, wantName: "yaml", }, { name: "WithRename", field: reflect.StructField{ Tag: `mapstructure:"hello"`, Name: "Test", }, wantName: "hello", }, { name: "WithOmitEmpty", field: reflect.StructField{ Tag: `mapstructure:"hello,omitempty"`, Name: "Test", }, wantName: "hello", wantOmit: true, }, { name: "WithSquash", field: reflect.StructField{ Tag: `mapstructure:",squash"`, Name: "Test", }, wantSquash: true, }, { name: "WithRemain", field: reflect.StructField{ Tag: `mapstructure:",remain"`, Name: "Test", }, wantSquash: true, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { got := getTagInfo(tt.field) require.Equal(t, tt.wantName, got.name) require.Equal(t, tt.wantOmit, got.omitEmpty) require.Equal(t, tt.wantSquash, got.squash) }) } } func TestEncodeValueError(t *testing.T) { enc := New(nil) testValue := reflect.ValueOf("") testCases := []struct { encodeFn func(value reflect.Value) (any, error) wantErr error }{ {encodeFn: enc.encodeMap, wantErr: &reflect.ValueError{Method: "encodeMap", Kind: reflect.String}}, {encodeFn: enc.encodeStruct, wantErr: &reflect.ValueError{Method: "encodeStruct", Kind: reflect.String}}, {encodeFn: enc.encodeSlice, wantErr: &reflect.ValueError{Method: "encodeSlice", Kind: reflect.String}}, } for _, tt := range testCases { got, err := tt.encodeFn(testValue) require.Error(t, err) require.Equal(t, tt.wantErr, err) require.Nil(t, got) } } func TestEncodeNonStringEncodedKey(t *testing.T) { enc := New(nil) testCase := []struct { Test map[string]any }{ { Test: map[string]any{ "test": map[TestEmptyStruct]TestSimpleStruct{ {Value: "key"}: {Value: "value"}, }, }, }, } got, err := enc.Encode(testCase) require.Error(t, err) require.ErrorIs(t, err, errNonStringEncodedKey) require.Nil(t, got) } func TestDuplicateKey(t *testing.T) { enc := New(&EncoderConfig{ EncodeHook: TextMarshalerHookFunc(), }) testCase := map[TestID]string{ "test": "value", "test_": "other value", } got, err := enc.Encode(testCase) require.Error(t, err) require.Nil(t, got) } func TestTextMarshalerError(t *testing.T) { enc := New(&EncoderConfig{ EncodeHook: TextMarshalerHookFunc(), }) testCase := map[TestID]string{ "error": "value", } got, err := enc.Encode(testCase) require.Error(t, err) require.Nil(t, got) } func TestEncodeStruct(t *testing.T) { enc := New(&EncoderConfig{ EncodeHook: testHookFunc(), }) testCase := TestSimpleStruct{ Value: "original", skipped: "final", } got, err := enc.Encode(testCase) require.NoError(t, err) require.Equal(t, "final", got) } func TestEncodeStructError(t *testing.T) { enc := New(&EncoderConfig{ EncodeHook: testHookFunc(), }) wantErr := errors.New("test") testCase := map[TestSimpleStruct]string{ {err: wantErr}: "value", } got, err := enc.Encode(testCase) require.Error(t, err) require.ErrorIs(t, err, wantErr) require.Nil(t, got) } func TestEncodeNil(t *testing.T) { enc := New(nil) got, err := enc.Encode(nil) require.NoError(t, err) require.Nil(t, got) } func testHookFunc() mapstructure.DecodeHookFuncValue { return func(from, _ reflect.Value) (any, error) { if from.Kind() != reflect.Struct { return from.Interface(), nil } got, ok := from.Interface().(TestSimpleStruct) if !ok { return from.Interface(), nil } if got.err != nil { return nil, got.err } return got.skipped, nil } } opentelemetry-collector-0.141.0/confmap/internal/mapstructure/package_test.go000066400000000000000000000003151511331344600275130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package mapstructure import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/internal/marshaloption.go000066400000000000000000000010111511331344600251750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" type MarshalOption interface { apply(*MarshalOptions) } // MarshalOptions is used by (*Conf).Marshal to toggle unmarshaling settings. // It is in the `internal` package so experimental options can be added in xconfmap. type MarshalOptions struct{} type MarshalOptionFunc func(*MarshalOptions) func (fn MarshalOptionFunc) apply(set *MarshalOptions) { fn(set) } opentelemetry-collector-0.141.0/confmap/internal/merge.go000066400000000000000000000044331511331344600234270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" import ( "reflect" "github.com/gobwas/glob" "github.com/knadh/koanf/maps" ) func mergeAppend(src, dest map[string]any) error { // mergeAppend recursively merges the src map into the dest map (left to right), // modifying and expanding the dest map in the process. // This function does not overwrite component lists, and ensures that the // final value is a name-aware copy of lists from src and dest. // Compile the globs once patterns := []string{ "service::extensions", "service::**::receivers", "service::**::exporters", } var globs []glob.Glob for _, p := range patterns { if g, err := glob.Compile(p); err == nil { globs = append(globs, g) } } // Flatten both source and destination maps srcFlat, _ := maps.Flatten(src, []string{}, KeyDelimiter) destFlat, _ := maps.Flatten(dest, []string{}, KeyDelimiter) for sKey, sVal := range srcFlat { if !isMatch(sKey, globs) { continue } dVal, dOk := destFlat[sKey] if !dOk { continue // Let maps.Merge handle missing keys } srcVal := reflect.ValueOf(sVal) destVal := reflect.ValueOf(dVal) // Only merge if the value is a slice or array; let maps.Merge handle other types if srcVal.Kind() == reflect.Slice || srcVal.Kind() == reflect.Array { srcFlat[sKey] = mergeSlice(srcVal, destVal) } } // Unflatten and merge mergedSrc := maps.Unflatten(srcFlat, KeyDelimiter) maps.Merge(mergedSrc, dest) return nil } // isMatch checks if a key matches any glob in the list func isMatch(key string, globs []glob.Glob) bool { for _, g := range globs { if g.Match(key) { return true } } return false } func mergeSlice(src, dest reflect.Value) any { slice := reflect.MakeSlice(src.Type(), 0, src.Cap()+dest.Cap()) for i := 0; i < dest.Len(); i++ { slice = reflect.Append(slice, dest.Index(i)) } for i := 0; i < src.Len(); i++ { if isPresent(slice, src.Index(i)) { continue } slice = reflect.Append(slice, src.Index(i)) } return slice.Interface() } func isPresent(slice, val reflect.Value) bool { for i := 0; i < slice.Len(); i++ { if reflect.DeepEqual(val.Interface(), slice.Index(i).Interface()) { return true } } return false } opentelemetry-collector-0.141.0/confmap/internal/testdata/000077500000000000000000000000001511331344600236065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/testdata/basic_types.yaml000066400000000000000000000002171511331344600267770ustar00rootroot00000000000000typed.options: floating.point.example: 3.14 integer.example: 1234 bool.example: false string.example: this is a string nil.example: opentelemetry-collector-0.141.0/confmap/internal/testdata/config.yaml000066400000000000000000000004761511331344600257460ustar00rootroot00000000000000receivers: nop: nop/myreceiver: processors: nop: nop/myprocessor: exporters: nop: nop/myexporter: extensions: nop: nop/myextension: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] opentelemetry-collector-0.141.0/confmap/internal/testdata/config2.yaml000066400000000000000000000002311511331344600260150ustar00rootroot00000000000000service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [nop] exporters: [nop2] opentelemetry-collector-0.141.0/confmap/internal/testdata/embedded_keys.yaml000066400000000000000000000002261511331344600272560ustar00rootroot00000000000000typed::options: floating::point::example: 3.14 integer::example: 1234 bool::example: false string::example: this is a string nil::example: opentelemetry-collector-0.141.0/confmap/internal/third_party/000077500000000000000000000000001511331344600243265ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/third_party/composehook/000077500000000000000000000000001511331344600266545ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/internal/third_party/composehook/compose_hook.go000066400000000000000000000061421511331344600316730ustar00rootroot00000000000000// Copyright (c) 2013 Mitchell Hashimoto // SPDX-License-Identifier: MIT // This code is a modified version of https://github.com/go-viper/mapstructure package composehook // import "go.opentelemetry.io/collector/confmap/internal/third_party/composehook" import ( "errors" "reflect" "github.com/go-viper/mapstructure/v2" ) // typedDecodeHook takes a raw DecodeHookFunc (an any) and turns // it into the proper DecodeHookFunc type, such as DecodeHookFuncType. func typedDecodeHook(h mapstructure.DecodeHookFunc) mapstructure.DecodeHookFunc { // Create variables here so we can reference them with the reflect pkg var f1 mapstructure.DecodeHookFuncType var f2 mapstructure.DecodeHookFuncKind var f3 mapstructure.DecodeHookFuncValue // Fill in the variables into this interface and the rest is done // automatically using the reflect package. potential := []any{f3, f1, f2} v := reflect.ValueOf(h) vt := v.Type() for _, raw := range potential { pt := reflect.ValueOf(raw).Type() if vt.ConvertibleTo(pt) { return v.Convert(pt).Interface() } } return nil } // cachedDecodeHook takes a raw DecodeHookFunc (an any) and turns // it into a closure to be used directly // if the type fails to convert we return a closure always erroring to keep the previous behavior func cachedDecodeHook(raw mapstructure.DecodeHookFunc) func(reflect.Value, reflect.Value) (any, error) { switch f := typedDecodeHook(raw).(type) { case mapstructure.DecodeHookFuncType: return func(from, to reflect.Value) (any, error) { // CHANGE FROM UPSTREAM: check if from is valid and return nil if not if !from.IsValid() { return nil, nil } return f(from.Type(), to.Type(), from.Interface()) } case mapstructure.DecodeHookFuncKind: return func(from, to reflect.Value) (any, error) { // CHANGE FROM UPSTREAM: check if from is valid and return nil if not if !from.IsValid() { return nil, nil } return f(from.Kind(), to.Kind(), from.Interface()) } case mapstructure.DecodeHookFuncValue: return func(from, to reflect.Value) (any, error) { return f(from, to) } default: return func(reflect.Value, reflect.Value) (any, error) { return nil, errors.New("invalid decode hook signature") } } } // ComposeDecodeHookFunc creates a single DecodeHookFunc that // automatically composes multiple DecodeHookFuncs. // // The composed funcs are called in order, with the result of the // previous transformation. // // This is a copy of [mapstructure.ComposeDecodeHookFunc] but with // validation added. func ComposeDecodeHookFunc(fs ...mapstructure.DecodeHookFunc) mapstructure.DecodeHookFunc { cached := make([]func(reflect.Value, reflect.Value) (any, error), 0, len(fs)) for _, f := range fs { cached = append(cached, cachedDecodeHook(f)) } return func(f, t reflect.Value) (any, error) { var err error // CHANGE FROM UPSTREAM: check if f is valid before calling f.Interface() var data any if f.IsValid() { data = f.Interface() } newFrom := f for _, c := range cached { data, err = c(newFrom, t) if err != nil { return nil, err } newFrom = reflect.ValueOf(data) } return data, nil } } opentelemetry-collector-0.141.0/confmap/internal/unmarshaloption.go000066400000000000000000000010601511331344600255440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/confmap/internal" type UnmarshalOption interface { apply(*UnmarshalOptions) } // UnmarshalOptions is used by (*Conf).Unmarshal to toggle unmarshaling settings. // It is in the `internal` package so experimental options can be added in xconfmap. type UnmarshalOptions struct { IgnoreUnused bool } type UnmarshalOptionFunc func(*UnmarshalOptions) func (fn UnmarshalOptionFunc) apply(set *UnmarshalOptions) { fn(set) } opentelemetry-collector-0.141.0/confmap/metadata.yaml000066400000000000000000000003501511331344600226230ustar00rootroot00000000000000type: confmap github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true codeowners: active: - mx-psi - evan-bradley class: pkg stability: stable: [logs, metrics, traces] opentelemetry-collector-0.141.0/confmap/provider.go000066400000000000000000000231371511331344600223500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap // import "go.opentelemetry.io/collector/confmap" import ( "context" "fmt" "time" "go.uber.org/zap" yaml "go.yaml.in/yaml/v3" ) // ProviderSettings are the settings to initialize a Provider. type ProviderSettings struct { // Logger is a zap.Logger that will be passed to Providers. // Providers should be able to rely on the Logger being non-nil; // when instantiating a Provider with a ProviderFactory, // nil Logger references should be replaced with a no-op Logger. Logger *zap.Logger // prevent unkeyed literal initialization _ struct{} } // ProviderFactory defines a factory that can be used to instantiate // new instances of a Provider. type ProviderFactory = moduleFactory[Provider, ProviderSettings] // CreateProviderFunc is a function that creates a Provider instance. type CreateProviderFunc = createConfmapFunc[Provider, ProviderSettings] // NewProviderFactory can be used to create a ProviderFactory. func NewProviderFactory(f CreateProviderFunc) ProviderFactory { return newConfmapModuleFactory(f) } // Provider is an interface that helps to retrieve a config map and watch for any // changes to the config map. Implementations may load the config from a file, // a database or any other source. // // The typical usage is the following: // // r, err := provider.Retrieve("file:/path/to/config") // // Use r.Map; wait for watcher to be called. // r.Close() // r, err = provider.Retrieve("file:/path/to/config") // // Use r.Map; wait for watcher to be called. // r.Close() // // repeat retrieve/wait/close cycle until it is time to shut down the Collector process. // // ... // provider.Shutdown() type Provider interface { // Retrieve goes to the configuration source and retrieves the selected data which // contains the value to be injected in the configuration and the corresponding watcher that // will be used to monitor for updates of the retrieved value. // // `uri` must follow the ":" format. This format is compatible // with the URI definition (see https://datatracker.ietf.org/doc/html/rfc3986). The "" // must be always included in the `uri`. The "" supported by any provider: // - MUST consist of a sequence of characters beginning with a letter and followed by any // combination of letters, digits, plus ("+"), period ("."), or hyphen ("-"). // See https://datatracker.ietf.org/doc/html/rfc3986#section-3.1. // - MUST be at least 2 characters long to avoid conflicting with a driver-letter identifier as specified // in https://tools.ietf.org/id/draft-kerwin-file-scheme-07.html#syntax. // - For testing, all implementation MUST check that confmaptest.ValidateProviderScheme returns no error. // // `watcher` callback is called when the config changes. watcher may be called from // a different go routine. After watcher is called, Provider.Retrieve should be called // to get the new config. See description of Retrieved for more details. // watcher may be nil, which indicates that the caller is not interested in // knowing about the changes. // // If ctx is cancelled should return immediately with an error. // Should never be called concurrently with itself or with Shutdown. Retrieve(ctx context.Context, uri string, watcher WatcherFunc) (*Retrieved, error) // Scheme returns the location scheme used by Retrieve. Scheme() string // Shutdown signals that the configuration for which this Provider was used to // retrieve values is no longer in use and the Provider should close and release // any resources that it may have created. // // This method must be called when the Collector service ends, either in case of // success or error. Retrieve cannot be called after Shutdown. // // Provider MUST shutdown and wait for any goroutine(s) that were created to call `watcher`, if any. // // Should never be called concurrently with itself or with Retrieve. // If ctx is cancelled should return immediately with an error. Shutdown(ctx context.Context) error } type WatcherFunc func(*ChangeEvent) // ChangeEvent describes the particular change event that happened with the config. type ChangeEvent struct { // Error is nil if the config is changed and needs to be re-fetched. // Any non-nil error indicates that there was a problem with watching the config changes. Error error // prevent unkeyed literal initialization _ struct{} } // Retrieved holds the result of a call to the Retrieve method of a Provider object. type Retrieved struct { rawConf any errorHint error closeFunc CloseFunc stringRepresentation string isSetString bool } type retrievedSettings struct { errorHint error stringRepresentation string isSetString bool closeFunc CloseFunc } // RetrievedOption options to customize Retrieved values. type RetrievedOption interface { apply(*retrievedSettings) } type retrievedOptionFunc func(*retrievedSettings) func (of retrievedOptionFunc) apply(e *retrievedSettings) { of(e) } // WithRetrievedClose overrides the default Retrieved.Close function. // The default Retrieved.Close function does nothing and always returns nil. func WithRetrievedClose(closeFunc CloseFunc) RetrievedOption { return retrievedOptionFunc(func(settings *retrievedSettings) { settings.closeFunc = closeFunc }) } func withStringRepresentation(stringRepresentation string) RetrievedOption { return retrievedOptionFunc(func(settings *retrievedSettings) { settings.stringRepresentation = stringRepresentation settings.isSetString = true }) } func withErrorHint(errorHint error) RetrievedOption { return retrievedOptionFunc(func(settings *retrievedSettings) { settings.errorHint = errorHint }) } // NewRetrievedFromYAML returns a new Retrieved instance that contains the deserialized data from the yaml bytes. // * yamlBytes the yaml bytes that will be deserialized. // * opts specifies options associated with this Retrieved value, such as CloseFunc. func NewRetrievedFromYAML(yamlBytes []byte, opts ...RetrievedOption) (*Retrieved, error) { var rawConf any if err := yaml.Unmarshal(yamlBytes, &rawConf); err != nil { // If the string is not valid YAML, we try to use it verbatim as a string. strRep := string(yamlBytes) return NewRetrieved(strRep, append(opts, withStringRepresentation(strRep), withErrorHint(fmt.Errorf("assuming string type since contents are not valid YAML: %w", err)), )...) } switch rawConf.(type) { case string: val := string(yamlBytes) return NewRetrieved(val, append(opts, withStringRepresentation(val))...) default: opts = append(opts, withStringRepresentation(string(yamlBytes))) } return NewRetrieved(rawConf, opts...) } // NewRetrieved returns a new Retrieved instance that contains the data from the raw deserialized config. // The rawConf can be one of the following types: // - Primitives: int, int32, int64, float32, float64, bool, string; // - []any; // - map[string]any; func NewRetrieved(rawConf any, opts ...RetrievedOption) (*Retrieved, error) { if err := checkRawConfType(rawConf); err != nil { return nil, err } set := retrievedSettings{} for _, opt := range opts { opt.apply(&set) } return &Retrieved{ rawConf: rawConf, errorHint: set.errorHint, closeFunc: set.closeFunc, stringRepresentation: set.stringRepresentation, isSetString: set.isSetString, }, nil } // AsConf returns the retrieved configuration parsed as a Conf. func (r *Retrieved) AsConf() (*Conf, error) { if r.rawConf == nil { return New(), nil } val, ok := r.rawConf.(map[string]any) if !ok { if r.errorHint != nil { return nil, fmt.Errorf("retrieved value (type=%T) cannot be used as a Conf: %w", r.rawConf, r.errorHint) } return nil, fmt.Errorf("retrieved value (type=%T) cannot be used as a Conf", r.rawConf) } return NewFromStringMap(val), nil } // AsRaw returns the retrieved configuration parsed as an any which can be one of the following types: // - Primitives: int, int32, int64, float32, float64, bool, string; // - []any - every member follows the same rules as the given any; // - map[string]any - every value follows the same rules as the given any; func (r *Retrieved) AsRaw() (any, error) { return r.rawConf, nil } // AsString returns the retrieved configuration as a string. // If the retrieved configuration is not convertible to a string unambiguously, an error is returned. // If the retrieved configuration is a string, the string is returned. // This method is used to resolve ${} references in inline position. func (r *Retrieved) AsString() (string, error) { if !r.isSetString { if str, ok := r.rawConf.(string); ok { return str, nil } return "", fmt.Errorf("retrieved value does not have unambiguous string representation: %v", r.rawConf) } return r.stringRepresentation, nil } // Close and release any watchers that Provider.Retrieve may have created. // // Should block until all resources are closed, and guarantee that `onChange` is not // going to be called after it returns except when `ctx` is cancelled. // // Should never be called concurrently with itself. func (r *Retrieved) Close(ctx context.Context) error { if r.closeFunc == nil { return nil } return r.closeFunc(ctx) } // CloseFunc a function equivalent to Retrieved.Close. type CloseFunc func(context.Context) error func checkRawConfType(rawConf any) error { if rawConf == nil { return nil } switch rawConf.(type) { case int, int32, int64, float32, float64, bool, string, []any, map[string]any, time.Time: return nil default: return fmt.Errorf( "unsupported type=%T for retrieved config,"+ " ensure that values are wrapped in quotes", rawConf) } } opentelemetry-collector-0.141.0/confmap/provider/000077500000000000000000000000001511331344600220135ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/envprovider/000077500000000000000000000000001511331344600243565ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/envprovider/Makefile000066400000000000000000000000411511331344600260110ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/confmap/provider/envprovider/README.md000066400000000000000000000037651511331344600256500ustar00rootroot00000000000000# Environment Variable Provider | Status | | | ------------- |-----------| | Stability | [stable] | | Distributions | [core], [contrib], [k8s], [otlp] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprovider%2Fenvprovider%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprovider%2Fenvprovider) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprovider%2Fenvprovider%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprovider%2Fenvprovider) | [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 [otlp]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp ## Usage The scheme for this provider is `env`. Usage looks like the following: ```text env:NAME_OF_ENVIRONMENT_VARIABLE ``` To use default values when the environment variable has not been set, you can include a suffix to specify it: ```text env:NAME_OF_ENVIRONMENT_VARIABLE:-default_value ``` Environment variables must match the following regular expression. That is, they must be at least one character, start with a letter or underscore, and can only include letters, numbers, and underscores. ```text ^[a-zA-Z_][a-zA-Z0-9_]*$ ``` opentelemetry-collector-0.141.0/confmap/provider/envprovider/generated_package_test.go000066400000000000000000000002521511331344600313540ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package envprovider import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/provider/envprovider/go.mod000066400000000000000000000021761511331344600254720ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap/provider/envprovider go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../ replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/confmap/provider/envprovider/go.sum000066400000000000000000000067421511331344600255220ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/confmap/provider/envprovider/metadata.yaml000066400000000000000000000003121511331344600270160ustar00rootroot00000000000000type: env github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: provider stability: stable: [provider] distributions: [core, contrib, k8s, otlp] opentelemetry-collector-0.141.0/confmap/provider/envprovider/provider.go000066400000000000000000000046221511331344600265430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package envprovider // import "go.opentelemetry.io/collector/confmap/provider/envprovider" import ( "context" "fmt" "os" "strings" "go.uber.org/zap" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/internal/envvar" ) const ( schemeName = "env" ) type provider struct { logger *zap.Logger } // NewFactory returns a factory for a confmap.Provider that reads the configuration from the given environment variable. // // This Provider supports "env" scheme, and can be called with a selector: // `env:NAME_OF_ENVIRONMENT_VARIABLE` // // A default value for unset variable can be provided after :- suffix, for example: // `env:NAME_OF_ENVIRONMENT_VARIABLE:-default_value` // // See also: https://opentelemetry.io/docs/specs/otel/configuration/data-model/#environment-variable-substitution func NewFactory() confmap.ProviderFactory { return confmap.NewProviderFactory(newProvider) } func newProvider(ps confmap.ProviderSettings) confmap.Provider { return &provider{ logger: ps.Logger, } } func (emp *provider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { if !strings.HasPrefix(uri, schemeName+":") { return nil, fmt.Errorf("%q uri is not supported by %q provider", uri, schemeName) } envVarName, defaultValuePtr := parseEnvVarURI(uri[len(schemeName)+1:]) if !envvar.ValidationRegexp.MatchString(envVarName) { return nil, fmt.Errorf("environment variable %q has invalid name: must match regex %s", envVarName, envvar.ValidationPattern) } val, exists := os.LookupEnv(envVarName) if !exists { if defaultValuePtr != nil { val = *defaultValuePtr } else { emp.logger.Warn("Configuration references unset environment variable", zap.String("name", envVarName)) } } else if val == "" { emp.logger.Info("Configuration references empty environment variable", zap.String("name", envVarName)) } return confmap.NewRetrievedFromYAML([]byte(val)) } func (*provider) Scheme() string { return schemeName } func (*provider) Shutdown(context.Context) error { return nil } // returns (var name, default value) func parseEnvVarURI(uri string) (string, *string) { const defaultSuffix = ":-" name, defaultValue, hasDefault := strings.Cut(uri, defaultSuffix) if hasDefault { return name, &defaultValue } return uri, nil } opentelemetry-collector-0.141.0/confmap/provider/envprovider/provider_test.go000066400000000000000000000137401511331344600276030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package envprovider import ( "context" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/internal/envvar" ) const envSchemePrefix = schemeName + ":" const validYAML = ` processors: testprocessor: exporters: otlp: endpoint: "localhost:4317" ` func TestValidateProviderScheme(t *testing.T) { assert.NoError(t, confmaptest.ValidateProviderScheme(createProvider())) } func TestEmptyName(t *testing.T) { env := createProvider() _, err := env.Retrieve(context.Background(), "", nil) require.Error(t, err) assert.NoError(t, env.Shutdown(context.Background())) } func TestUnsupportedScheme(t *testing.T) { env := createProvider() _, err := env.Retrieve(context.Background(), "https://", nil) require.Error(t, err) assert.NoError(t, env.Shutdown(context.Background())) } func TestInvalidYAML(t *testing.T) { const envName = "invalid_yaml" t.Setenv(envName, "[invalid,") env := createProvider() ret, err := env.Retrieve(context.Background(), envSchemePrefix+envName, nil) require.NoError(t, err) raw, err := ret.AsRaw() require.NoError(t, err) assert.IsType(t, "", raw) assert.NoError(t, env.Shutdown(context.Background())) } func TestEnv(t *testing.T) { const envName = "default_config" t.Setenv(envName, validYAML) env := createProvider() ret, err := env.Retrieve(context.Background(), envSchemePrefix+envName, nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) expectedMap := confmap.NewFromStringMap(map[string]any{ "processors::testprocessor": nil, "exporters::otlp::endpoint": "localhost:4317", }) assert.Equal(t, expectedMap.ToStringMap(), retMap.ToStringMap()) assert.NoError(t, env.Shutdown(context.Background())) } func TestEnvWithLogger(t *testing.T) { const envName = "default_config" t.Setenv(envName, validYAML) core, ol := observer.New(zap.WarnLevel) logger := zap.New(core) env := NewFactory().Create(confmap.ProviderSettings{Logger: logger}) ret, err := env.Retrieve(context.Background(), envSchemePrefix+envName, nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) expectedMap := confmap.NewFromStringMap(map[string]any{ "processors::testprocessor": nil, "exporters::otlp::endpoint": "localhost:4317", }) assert.Equal(t, expectedMap.ToStringMap(), retMap.ToStringMap()) require.NoError(t, env.Shutdown(context.Background())) assert.Equal(t, 0, ol.Len()) } func TestUnsetEnvWithLoggerWarn(t *testing.T) { const envName = "default_config" core, ol := observer.New(zap.WarnLevel) logger := zap.New(core) env := NewFactory().Create(confmap.ProviderSettings{Logger: logger}) ret, err := env.Retrieve(context.Background(), envSchemePrefix+envName, nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) expectedMap := confmap.NewFromStringMap(map[string]any{}) assert.Equal(t, expectedMap.ToStringMap(), retMap.ToStringMap()) require.NoError(t, env.Shutdown(context.Background())) assert.Equal(t, 1, ol.Len()) logLine := ol.All()[0] assert.Equal(t, "Configuration references unset environment variable", logLine.Message) assert.Equal(t, zap.WarnLevel, logLine.Level) assert.Equal(t, envName, logLine.Context[0].String) } func TestEnvVarNameRestriction(t *testing.T) { const envName = "default%config" t.Setenv(envName, validYAML) env := createProvider() ret, err := env.Retrieve(context.Background(), envSchemePrefix+envName, nil) assert.Equal(t, err, fmt.Errorf("environment variable \"default%%config\" has invalid name: must match regex %s", envvar.ValidationRegexp)) require.NoError(t, env.Shutdown(context.Background())) assert.Nil(t, ret) } func TestEmptyEnvWithLoggerWarn(t *testing.T) { const envName = "default_config" t.Setenv(envName, "") core, ol := observer.New(zap.InfoLevel) logger := zap.New(core) env := NewFactory().Create(confmap.ProviderSettings{Logger: logger}) ret, err := env.Retrieve(context.Background(), envSchemePrefix+envName, nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) expectedMap := confmap.NewFromStringMap(map[string]any{}) assert.Equal(t, expectedMap.ToStringMap(), retMap.ToStringMap()) require.NoError(t, env.Shutdown(context.Background())) assert.Equal(t, 1, ol.Len()) logLine := ol.All()[0] assert.Equal(t, "Configuration references empty environment variable", logLine.Message) assert.Equal(t, zap.InfoLevel, logLine.Level) assert.Equal(t, envName, logLine.Context[0].String) } func TestEnvWithDefaultValue(t *testing.T) { env := createProvider() tests := []struct { name string unset bool value string uri string expectedVal string expectedErr string }{ {name: "unset", unset: true, uri: "env:MY_VAR:-default % value", expectedVal: "default % value"}, {name: "unset2", unset: true, uri: "env:MY_VAR:-", expectedVal: ""}, // empty default still applies {name: "empty", value: "", uri: "env:MY_VAR:-foo", expectedVal: ""}, {name: "not empty", value: "value", uri: "env:MY_VAR:-", expectedVal: "value"}, {name: "syntax1", unset: true, uri: "env:-MY_VAR", expectedErr: "invalid name"}, {name: "syntax2", unset: true, uri: "env:MY_VAR:-test:-test", expectedVal: "test:-test"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if !tt.unset { t.Setenv("MY_VAR", tt.value) } ret, err := env.Retrieve(context.Background(), tt.uri, nil) if tt.expectedErr != "" { require.ErrorContains(t, err, tt.expectedErr) return } require.NoError(t, err) str, err := ret.AsString() require.NoError(t, err) assert.Equal(t, tt.expectedVal, str) }) } assert.NoError(t, env.Shutdown(context.Background())) } func createProvider() confmap.Provider { return NewFactory().Create(confmaptest.NewNopProviderSettings()) } opentelemetry-collector-0.141.0/confmap/provider/fileprovider/000077500000000000000000000000001511331344600245055ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/fileprovider/Makefile000066400000000000000000000000411511331344600261400ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/confmap/provider/fileprovider/README.md000066400000000000000000000033031511331344600257630ustar00rootroot00000000000000# File Provider | Status | | | ------------- |-----------| | Stability | [stable] | | Distributions | [core], [contrib], [k8s], [otlp] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprovider%2Ffileprovider%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprovider%2Ffileprovider) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprovider%2Ffileprovider%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprovider%2Ffileprovider) | [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 [otlp]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp ## Overview The File Provider takes paths to files and reads their contents as YAML to provide configuration to the Collector. ## Usage The scheme for this provider is `file`. Usage looks like the following: ```text file:/path/to/file.yaml ``` opentelemetry-collector-0.141.0/confmap/provider/fileprovider/generated_package_test.go000066400000000000000000000002531511331344600315040ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package fileprovider import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/provider/fileprovider/go.mod000066400000000000000000000022131511331344600256110ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap/provider/fileprovider go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../ replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/confmap/provider/fileprovider/go.sum000066400000000000000000000067421511331344600256510ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/confmap/provider/fileprovider/metadata.yaml000066400000000000000000000003131511331344600271460ustar00rootroot00000000000000type: file github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: provider stability: stable: [provider] distributions: [core, contrib, k8s, otlp] opentelemetry-collector-0.141.0/confmap/provider/fileprovider/provider.go000066400000000000000000000034411511331344600266700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package fileprovider // import "go.opentelemetry.io/collector/confmap/provider/fileprovider" import ( "context" "fmt" "os" "path/filepath" "strings" "go.opentelemetry.io/collector/confmap" ) const schemeName = "file" type provider struct{} // NewFactory returns a factory for a confmap.Provider that reads the configuration from a file. // // This Provider supports "file" scheme, and can be called with a "uri" that follows: // // file-uri = "file:" local-path // local-path = [ drive-letter ] file-path // drive-letter = ALPHA ":" // // The "file-path" can be relative or absolute, and it can be any OS supported format. // // Examples: // `file:path/to/file` - relative path (unix, windows) // `file:/path/to/file` - absolute path (unix, windows) // `file:c:/path/to/file` - absolute path including drive-letter (windows) // `file:c:\path\to\file` - absolute path including drive-letter (windows) func NewFactory() confmap.ProviderFactory { return confmap.NewProviderFactory(newProvider) } func newProvider(confmap.ProviderSettings) confmap.Provider { return &provider{} } func (fmp *provider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { if !strings.HasPrefix(uri, schemeName+":") { return nil, fmt.Errorf("%q uri is not supported by %q provider", uri, schemeName) } // Clean the path before using it. content, err := os.ReadFile(filepath.Clean(uri[len(schemeName)+1:])) if err != nil { return nil, fmt.Errorf("unable to read the file %v: %w", uri, err) } return confmap.NewRetrievedFromYAML(content) } func (*provider) Scheme() string { return schemeName } func (*provider) Shutdown(context.Context) error { return nil } opentelemetry-collector-0.141.0/confmap/provider/fileprovider/provider_test.go000066400000000000000000000061411511331344600277270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fileprovider import ( "context" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) const fileSchemePrefix = schemeName + ":" func TestValidateProviderScheme(t *testing.T) { assert.NoError(t, confmaptest.ValidateProviderScheme(createProvider())) } func TestEmptyName(t *testing.T) { fp := createProvider() _, err := fp.Retrieve(context.Background(), "", nil) require.Error(t, err) require.NoError(t, fp.Shutdown(context.Background())) } func TestUnsupportedScheme(t *testing.T) { fp := createProvider() _, err := fp.Retrieve(context.Background(), "https://", nil) require.Error(t, err) assert.NoError(t, fp.Shutdown(context.Background())) } func TestNonExistent(t *testing.T) { fp := createProvider() _, err := fp.Retrieve(context.Background(), fileSchemePrefix+filepath.Join("testdata", "non-existent.yaml"), nil) require.Error(t, err) _, err = fp.Retrieve(context.Background(), fileSchemePrefix+absolutePath(t, filepath.Join("testdata", "non-existent.yaml")), nil) require.Error(t, err) require.NoError(t, fp.Shutdown(context.Background())) } func TestInvalidYAML(t *testing.T) { fp := createProvider() ret, err := fp.Retrieve(context.Background(), fileSchemePrefix+filepath.Join("testdata", "invalid-yaml.yaml"), nil) require.NoError(t, err) raw, err := ret.AsRaw() require.NoError(t, err) assert.IsType(t, "", raw) ret, err = fp.Retrieve(context.Background(), fileSchemePrefix+absolutePath(t, filepath.Join("testdata", "invalid-yaml.yaml")), nil) require.NoError(t, err) raw, err = ret.AsRaw() require.NoError(t, err) assert.IsType(t, "", raw) require.NoError(t, fp.Shutdown(context.Background())) } func TestRelativePath(t *testing.T) { fp := createProvider() ret, err := fp.Retrieve(context.Background(), fileSchemePrefix+filepath.Join("testdata", "default-config.yaml"), nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) expectedMap := confmap.NewFromStringMap(map[string]any{ "processors::testprocessor": nil, "exporters::otlp::endpoint": "localhost:4317", }) assert.Equal(t, expectedMap, retMap) assert.NoError(t, fp.Shutdown(context.Background())) } func TestAbsolutePath(t *testing.T) { fp := createProvider() ret, err := fp.Retrieve(context.Background(), fileSchemePrefix+absolutePath(t, filepath.Join("testdata", "default-config.yaml")), nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) expectedMap := confmap.NewFromStringMap(map[string]any{ "processors::testprocessor": nil, "exporters::otlp::endpoint": "localhost:4317", }) assert.Equal(t, expectedMap, retMap) assert.NoError(t, fp.Shutdown(context.Background())) } func absolutePath(t *testing.T, relativePath string) string { dir, err := os.Getwd() require.NoError(t, err) return filepath.Join(dir, relativePath) } func createProvider() confmap.Provider { return NewFactory().Create(confmaptest.NewNopProviderSettings()) } opentelemetry-collector-0.141.0/confmap/provider/fileprovider/testdata/000077500000000000000000000000001511331344600263165ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/fileprovider/testdata/default-config.yaml000066400000000000000000000001171511331344600320700ustar00rootroot00000000000000processors: testprocessor: exporters: otlp: endpoint: "localhost:4317" opentelemetry-collector-0.141.0/confmap/provider/fileprovider/testdata/invalid-yaml.yaml000066400000000000000000000000111511331344600315600ustar00rootroot00000000000000[invalid,opentelemetry-collector-0.141.0/confmap/provider/httpprovider/000077500000000000000000000000001511331344600245455ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/httpprovider/Makefile000066400000000000000000000000411511331344600262000ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/confmap/provider/httpprovider/README.md000066400000000000000000000033451511331344600260310ustar00rootroot00000000000000# HTTP Provider | Status | | | ------------- |-----------| | Stability | [stable] | | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprovider%2Fhttpprovider%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprovider%2Fhttpprovider) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprovider%2Fhttpprovider%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprovider%2Fhttpprovider) | [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 ## Overview The HTTP Provider takes an HTTP URI to a file and reads its contents as YAML to provide configuration to the Collector. For HTTPS endpoints, please see the [HTTPS provider](../httpsprovider/README.md). ## Usage The scheme for this provider is `http`. Usage looks like the following passed to the Collector's command line invocation: ```text --config=http://example.com/config.yaml ``` opentelemetry-collector-0.141.0/confmap/provider/httpprovider/generated_package_test.go000066400000000000000000000002531511331344600315440ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package httpprovider import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/provider/httpprovider/go.mod000066400000000000000000000022131511331344600256510ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap/provider/httpprovider go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../ replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/confmap/provider/httpprovider/go.sum000066400000000000000000000067421511331344600257110ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/confmap/provider/httpprovider/metadata.yaml000066400000000000000000000003051511331344600272070ustar00rootroot00000000000000type: http github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: provider stability: stable: [provider] distributions: [core, contrib, k8s] opentelemetry-collector-0.141.0/confmap/provider/httpprovider/provider.go000066400000000000000000000014451511331344600267320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package httpprovider // import "go.opentelemetry.io/collector/confmap/provider/httpprovider" import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/internal/configurablehttpprovider" ) // NewFactory returns a factory for a confmap.Provider that reads the configuration from a http server. // // This Provider supports "http" scheme. // // One example for HTTP URI is: http://localhost:3333/getConfig func NewFactory() confmap.ProviderFactory { return confmap.NewProviderFactory(newProvider) } func newProvider(set confmap.ProviderSettings) confmap.Provider { return configurablehttpprovider.New(configurablehttpprovider.HTTPScheme, set) } opentelemetry-collector-0.141.0/confmap/provider/httpprovider/provider_test.go000066400000000000000000000007241511331344600277700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package httpprovider import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestSupportedScheme(t *testing.T) { fp := NewFactory().Create(confmaptest.NewNopProviderSettings()) assert.Equal(t, "http", fp.Scheme()) require.NoError(t, fp.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/000077500000000000000000000000001511331344600247305ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/Makefile000066400000000000000000000000411511331344600263630ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/README.md000066400000000000000000000040661511331344600262150ustar00rootroot00000000000000# HTTPS Provider | Status | | | ------------- |-----------| | Stability | [stable] | | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprovider%2Fhttpsprovider%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprovider%2Fhttpsprovider) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprovider%2Fhttpsprovider%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprovider%2Fhttpsprovider) | [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 ## Overview The HTTPS Provider takes an HTTPS URI to a file and reads its contents as YAML to provide configuration to the Collector. The validity of the certificate of the HTTPS endpoint is verified when making the connection. ## Usage The scheme for this provider is `https`. Usage looks like the following passed to the Collector's command line invocation: ```text --config=https://example.com/config.yaml ``` ### Notes The provider currently only supports communicating with servers whose certificate can be verified using the root CA certificates installed in the system. The process of adding more root CA certificates to the system is Operating System-dependent. For Linux, please refer to the `update-ca-trust` command. opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/generated_package_test.go000066400000000000000000000002541511331344600317300ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package httpsprovider import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/go.mod000066400000000000000000000022141511331344600260350ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap/provider/httpsprovider go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../ replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/go.sum000066400000000000000000000067421511331344600260740ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/metadata.yaml000066400000000000000000000003061511331344600273730ustar00rootroot00000000000000type: https github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: provider stability: stable: [provider] distributions: [core, contrib, k8s] opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/provider.go000066400000000000000000000017571511331344600271230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package httpsprovider // import "go.opentelemetry.io/collector/confmap/provider/httpsprovider" import ( "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/internal/configurablehttpprovider" ) // NewFactory returns a factory for a confmap.Provider that reads the configuration from a https server. // // This Provider supports "https" scheme. One example of an HTTPS URI is: https://localhost:3333/getConfig // // To add extra CA certificates you need to install certificates in the system pool. This procedure is operating system // dependent. E.g.: on Linux please refer to the `update-ca-trust` command. func NewFactory() confmap.ProviderFactory { return confmap.NewProviderFactory(newProvider) } func newProvider(set confmap.ProviderSettings) confmap.Provider { return configurablehttpprovider.New(configurablehttpprovider.HTTPSScheme, set) } opentelemetry-collector-0.141.0/confmap/provider/httpsprovider/provider_test.go000066400000000000000000000005551511331344600301550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package httpsprovider import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestSupportedScheme(t *testing.T) { fp := NewFactory().Create(confmaptest.NewNopProviderSettings()) assert.Equal(t, "https", fp.Scheme()) } opentelemetry-collector-0.141.0/confmap/provider/internal/000077500000000000000000000000001511331344600236275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/internal/configurablehttpprovider/000077500000000000000000000000001511331344600307425ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/internal/configurablehttpprovider/package_test.go000066400000000000000000000003311511331344600337200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configurablehttpprovider import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/provider/internal/configurablehttpprovider/provider.go000066400000000000000000000064521511331344600331320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configurablehttpprovider // import "go.opentelemetry.io/collector/confmap/provider/internal/configurablehttpprovider" import ( "context" "crypto/tls" "crypto/x509" "fmt" "io" "net/http" "net/url" "os" "path/filepath" "strings" "go.opentelemetry.io/collector/confmap" ) type SchemeType string const ( HTTPScheme SchemeType = "http" HTTPSScheme SchemeType = "https" ) type provider struct { scheme SchemeType caCertPath string // Used for tests insecureSkipVerify bool // Used for tests } // New returns a new provider that reads the configuration from http server using the configured transport mechanism // depending on the selected scheme. // There are two types of transport supported: PlainText (HTTPScheme) and TLS (HTTPSScheme). // // One example for http-uri: http://localhost:3333/getConfig // One example for https-uri: https://localhost:3333/getConfig // This is used by the http and https external implementations. func New(scheme SchemeType, _ confmap.ProviderSettings) confmap.Provider { return &provider{scheme: scheme} } // Create the client based on the type of scheme that was selected. func (fmp *provider) createClient() (*http.Client, error) { switch fmp.scheme { case HTTPScheme: return &http.Client{}, nil case HTTPSScheme: pool, err := x509.SystemCertPool() if err != nil { return nil, fmt.Errorf("unable to create a cert pool: %w", err) } if fmp.caCertPath != "" { cert, err := os.ReadFile(filepath.Clean(fmp.caCertPath)) if err != nil { return nil, fmt.Errorf("unable to read CA from %q URI: %w", fmp.caCertPath, err) } if ok := pool.AppendCertsFromPEM(cert); !ok { return nil, fmt.Errorf("unable to add CA from uri: %s into the cert pool", fmp.caCertPath) } } return &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ InsecureSkipVerify: fmp.insecureSkipVerify, RootCAs: pool, }, }, }, nil default: return nil, fmt.Errorf("invalid scheme type: %s", fmp.scheme) } } func (fmp *provider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { if !strings.HasPrefix(uri, string(fmp.scheme)+":") { return nil, fmt.Errorf("%q uri is not supported by %q provider", uri, string(fmp.scheme)) } if _, err := url.ParseRequestURI(uri); err != nil { return nil, fmt.Errorf("invalid uri %q: %w", uri, err) } client, err := fmp.createClient() if err != nil { return nil, fmt.Errorf("unable to configure http transport layer: %w", err) } // send a HTTP GET request resp, err := client.Get(uri) if err != nil { return nil, fmt.Errorf("unable to download the file via HTTP GET for uri %q: %w ", uri, err) } defer resp.Body.Close() // check the HTTP status code if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("failed to load resource from uri %q. status code: %d", uri, resp.StatusCode) } // read the response body body, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("fail to read the response body from uri %q: %w", uri, err) } return confmap.NewRetrievedFromYAML(body) } func (fmp *provider) Scheme() string { return string(fmp.scheme) } func (*provider) Shutdown(context.Context) error { return nil } opentelemetry-collector-0.141.0/confmap/provider/internal/configurablehttpprovider/provider_test.go000066400000000000000000000230061511331344600341630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configurablehttpprovider import ( "context" "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "fmt" "math/big" "net/http" "net/http/httptest" "net/url" "os" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/internal/testutil" ) func newConfigurableHTTPProvider(scheme SchemeType, set confmap.ProviderSettings) *provider { return New(scheme, set).(*provider) } func answerGet(w http.ResponseWriter, _ *http.Request) { f, err := os.ReadFile("./testdata/otel-config.yaml") if err != nil { w.WriteHeader(http.StatusNotFound) _, innerErr := w.Write([]byte("Cannot find the config file")) if innerErr != nil { fmt.Println("Write failed: ", innerErr) } return } w.WriteHeader(http.StatusOK) _, err = w.Write(f) if err != nil { fmt.Println("Write failed: ", err) } } // Generate a self signed certificate specific for the tests. Based on // https://go.dev/src/crypto/tls/generate_cert.go func generateCertificate(t *testing.T, hostname string) (cert, key string, err error) { testutil.SkipIfFIPSOnly(t, "x509.CreateCertificate uses SHA-1") priv, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return "", "", fmt.Errorf("Failed to generate private key: %w", err) } keyUsage := x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageCertSign notBefore := time.Now() notAfter := notBefore.Add(time.Hour * 12) serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) if err != nil { return "", "", fmt.Errorf("Failed to generate serial number: %w", err) } template := x509.Certificate{ SerialNumber: serialNumber, Subject: pkix.Name{ Organization: []string{"Httpprovider Co"}, }, NotBefore: notBefore, NotAfter: notAfter, KeyUsage: keyUsage, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, IsCA: true, DNSNames: []string{hostname}, } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) if err != nil { return "", "", fmt.Errorf("Failed to create certificate: %w", err) } tempDir := t.TempDir() certOut, err := os.CreateTemp(tempDir, "cert*.pem") if err != nil { return "", "", fmt.Errorf("Failed to open cert.pem for writing: %w", err) } defer certOut.Close() if err = pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { return "", "", fmt.Errorf("Failed to write data to cert.pem: %w", err) } keyOut, err := os.CreateTemp(tempDir, "key*.pem") if err != nil { return "", "", fmt.Errorf("Failed to open key.pem for writing: %w", err) } defer keyOut.Close() privBytes, err := x509.MarshalPKCS8PrivateKey(priv) if err != nil { return "", "", fmt.Errorf("Unable to marshal private key: %w", err) } if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil { return "", "", fmt.Errorf("Failed to write data to key.pem: %w", err) } return certOut.Name(), keyOut.Name(), nil } func TestFunctionalityDownloadFileHTTP(t *testing.T) { fp := newConfigurableHTTPProvider(HTTPScheme, confmaptest.NewNopProviderSettings()) ts := httptest.NewServer(http.HandlerFunc(answerGet)) defer ts.Close() _, err := fp.Retrieve(context.Background(), ts.URL, nil) assert.NoError(t, err) assert.NoError(t, fp.Shutdown(context.Background())) } func TestFunctionalityDownloadFileHTTPS(t *testing.T) { certPath, keyPath, err := generateCertificate(t, "localhost") require.NoError(t, err) invalidCert, err := os.CreateTemp(t.TempDir(), "cert*.crt") defer func() { require.NoError(t, invalidCert.Close()) }() require.NoError(t, err) _, err = invalidCert.Write([]byte{0, 1, 2}) require.NoError(t, err) cert, err := tls.LoadX509KeyPair(certPath, keyPath) require.NoError(t, err) ts := httptest.NewUnstartedServer(http.HandlerFunc(answerGet)) ts.TLS = &tls.Config{Certificates: []tls.Certificate{cert}} ts.StartTLS() defer ts.Close() tests := []struct { name string certPath string hostName string useCertificate bool skipHostnameValidation bool shouldError bool }{ { name: "Test valid certificate and name", certPath: certPath, hostName: "localhost", useCertificate: true, skipHostnameValidation: false, shouldError: false, }, { name: "Test valid certificate with invalid name", certPath: certPath, hostName: "127.0.0.1", useCertificate: true, skipHostnameValidation: false, shouldError: true, }, { name: "Test valid certificate with invalid name, skip validation", certPath: certPath, hostName: "127.0.0.1", useCertificate: true, skipHostnameValidation: true, shouldError: false, }, { name: "Test no certificate should fail", certPath: certPath, hostName: "localhost", useCertificate: false, skipHostnameValidation: false, shouldError: true, }, { name: "Test invalid cert", certPath: invalidCert.Name(), hostName: "localhost", useCertificate: true, skipHostnameValidation: false, shouldError: true, }, { name: "Test no cert", certPath: "no_certificate", hostName: "localhost", useCertificate: true, skipHostnameValidation: false, shouldError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fp := newConfigurableHTTPProvider(HTTPSScheme, confmaptest.NewNopProviderSettings()) // Parse url of the test server to get the port number. tsURL, err := url.Parse(ts.URL) require.NoError(t, err) if tt.useCertificate { fp.caCertPath = tt.certPath } fp.insecureSkipVerify = tt.skipHostnameValidation _, err = fp.Retrieve(context.Background(), fmt.Sprintf("https://%s:%s", tt.hostName, tsURL.Port()), nil) if tt.shouldError { assert.Error(t, err) } else { assert.NoError(t, err) } }) } } func TestUnsupportedScheme(t *testing.T) { fp := New(HTTPScheme, confmaptest.NewNopProviderSettings()) _, err := fp.Retrieve(context.Background(), "https://...", nil) require.Error(t, err) require.NoError(t, fp.Shutdown(context.Background())) fp = New(HTTPSScheme, confmaptest.NewNopProviderSettings()) _, err = fp.Retrieve(context.Background(), "http://...", nil) require.Error(t, err) assert.NoError(t, fp.Shutdown(context.Background())) } func TestEmptyURI(t *testing.T) { fp := New(HTTPScheme, confmaptest.NewNopProviderSettings()) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusBadRequest) })) defer ts.Close() _, err := fp.Retrieve(context.Background(), ts.URL, nil) require.Error(t, err) require.NoError(t, fp.Shutdown(context.Background())) } func TestRetrieveFromShutdownServer(t *testing.T) { fp := New(HTTPScheme, confmaptest.NewNopProviderSettings()) ts := httptest.NewServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})) ts.Close() _, err := fp.Retrieve(context.Background(), ts.URL, nil) require.Error(t, err) require.NoError(t, fp.Shutdown(context.Background())) } func TestNonExistent(t *testing.T) { fp := New(HTTPScheme, confmaptest.NewNopProviderSettings()) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotFound) })) defer ts.Close() _, err := fp.Retrieve(context.Background(), ts.URL, nil) require.Error(t, err) require.NoError(t, fp.Shutdown(context.Background())) } func TestInvalidYAML(t *testing.T) { fp := New(HTTPScheme, confmaptest.NewNopProviderSettings()) ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) _, err := w.Write([]byte("wrong : [")) if err != nil { fmt.Println("Write failed: ", err) } })) defer ts.Close() ret, err := fp.Retrieve(context.Background(), ts.URL, nil) require.NoError(t, err) raw, err := ret.AsRaw() require.NoError(t, err) assert.Equal(t, "wrong : [", raw) require.NoError(t, fp.Shutdown(context.Background())) } func TestScheme(t *testing.T) { fp := New(HTTPScheme, confmaptest.NewNopProviderSettings()) assert.Equal(t, "http", fp.Scheme()) require.NoError(t, fp.Shutdown(context.Background())) } func TestValidateProviderScheme(t *testing.T) { assert.NoError(t, confmaptest.ValidateProviderScheme(New(HTTPScheme, confmaptest.NewNopProviderSettings()))) } func TestInvalidURI(t *testing.T) { fp := New(HTTPScheme, confmaptest.NewNopProviderSettings()) tests := []struct { uri string err string }{ { uri: "foo://..", err: "uri is not supported by \"http\" provider", }, { uri: "http://", err: "no Host in request URL", }, { uri: "http://{}", err: "invalid character \"{\" in host name", }, } for _, tt := range tests { t.Run(tt.uri, func(t *testing.T) { _, err := fp.Retrieve(context.Background(), tt.uri, nil) assert.ErrorContains(t, err, tt.err) }) } } opentelemetry-collector-0.141.0/confmap/provider/internal/configurablehttpprovider/testdata/000077500000000000000000000000001511331344600325535ustar00rootroot00000000000000otel-config.yaml000066400000000000000000000010561511331344600355700ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/internal/configurablehttpprovider/testdataextensions: zpages: endpoint: 0.0.0.0:55679 receivers: otlp: protocols: grpc: http: processors: memory_limiter: # 75% of maximum memory up to 2G limit_mib: 1536 # 25% of limit up to 2G spike_limit_mib: 512 check_interval: 5s exporters: debug: verbosity: detailed service: pipelines: traces: receivers: [otlp] processors: [memory_limiter] exporters: [debug] metrics: receivers: [otlp] processors: [memory_limiter] exporters: [debug] extensions: [zpages] opentelemetry-collector-0.141.0/confmap/provider/internal/package_test.go000066400000000000000000000003111511331344600266030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/000077500000000000000000000000001511331344600245305ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/Makefile000066400000000000000000000000411511331344600261630ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/README.md000066400000000000000000000032111511331344600260040ustar00rootroot00000000000000# YAML Provider | Status | | | ------------- |-----------| | Stability | [stable] | | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprovider%2Fyamlprovider%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprovider%2Fyamlprovider) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprovider%2Fyamlprovider%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprovider%2Fyamlprovider) | [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 ## Overview The YAML Provider takes a literal YAML string as Collector configuration. ## Usage The scheme for this provider is `yaml`. Usage looks like the following passed to the Collector's command line invocation: ```text --config="yaml:exporters::otlphttp::sending_queue::batch::flush_timeout: 2s" ``` opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/generated_package_test.go000066400000000000000000000002531511331344600315270ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package yamlprovider import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/go.mod000066400000000000000000000022131511331344600256340ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap/provider/yamlprovider go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../ replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/go.sum000066400000000000000000000067421511331344600256740ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/metadata.yaml000066400000000000000000000003051511331344600271720ustar00rootroot00000000000000type: yaml github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: provider stability: stable: [provider] distributions: [core, contrib, k8s] opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/provider.go000066400000000000000000000025021511331344600267100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package yamlprovider // import "go.opentelemetry.io/collector/confmap/provider/yamlprovider" //go:generate mdatagen metadata.yaml import ( "context" "fmt" "strings" "go.opentelemetry.io/collector/confmap" ) const schemeName = "yaml" type provider struct{} // NewFactory returns a factory for a confmap.Provider that allows to provide yaml bytes. // // This Provider supports "yaml" scheme, and can be called with a "uri" that follows: // // bytes-uri = "yaml:" yaml-bytes // // Examples: // `yaml:exporters::otlphttp::sending_queue::batch::flush_timeout: 2s` // `yaml:exporters::otlphttp/foo::sending_queue::batch::flush_timeout: 2s` func NewFactory() confmap.ProviderFactory { return confmap.NewProviderFactory(newProvider) } func newProvider(confmap.ProviderSettings) confmap.Provider { return &provider{} } func (s *provider) Retrieve(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { if !strings.HasPrefix(uri, schemeName+":") { return nil, fmt.Errorf("%q uri is not supported by %q provider", uri, schemeName) } return confmap.NewRetrievedFromYAML([]byte(uri[len(schemeName)+1:])) } func (*provider) Scheme() string { return schemeName } func (s *provider) Shutdown(context.Context) error { return nil } opentelemetry-collector-0.141.0/confmap/provider/yamlprovider/provider_test.go000066400000000000000000000072751511331344600277630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package yamlprovider import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestValidateProviderScheme(t *testing.T) { assert.NoError(t, confmaptest.ValidateProviderScheme(createProvider())) } func TestEmpty(t *testing.T) { sp := createProvider() _, err := sp.Retrieve(context.Background(), "", nil) require.Error(t, err) assert.NoError(t, sp.Shutdown(context.Background())) } func TestInvalidYAML(t *testing.T) { sp := createProvider() ret, err := sp.Retrieve(context.Background(), "yaml:[invalid,", nil) require.NoError(t, err) raw, err := ret.AsRaw() require.NoError(t, err) assert.IsType(t, "", raw) assert.NoError(t, sp.Shutdown(context.Background())) } func TestOneValue(t *testing.T) { sp := createProvider() ret, err := sp.Retrieve(context.Background(), "yaml:processors::test::timeout: 2s", nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, map[string]any{ "processors": map[string]any{ "test": map[string]any{ "timeout": "2s", }, }, }, retMap.ToStringMap()) assert.NoError(t, sp.Shutdown(context.Background())) } func TestNamedComponent(t *testing.T) { sp := createProvider() ret, err := sp.Retrieve(context.Background(), "yaml:processors::test/foo::timeout: 3s", nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, map[string]any{ "processors": map[string]any{ "test/foo": map[string]any{ "timeout": "3s", }, }, }, retMap.ToStringMap()) assert.NoError(t, sp.Shutdown(context.Background())) } func TestMapEntry(t *testing.T) { sp := createProvider() ret, err := sp.Retrieve(context.Background(), "yaml:processors: {test/foo::timeout: 3s, test::timeout: 2s}", nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, map[string]any{ "processors": map[string]any{ "test/foo": map[string]any{ "timeout": "3s", }, "test": map[string]any{ "timeout": "2s", }, }, }, retMap.ToStringMap()) assert.NoError(t, sp.Shutdown(context.Background())) } func TestArrayEntry(t *testing.T) { sp := createProvider() ret, err := sp.Retrieve(context.Background(), "yaml:service::extensions: [zpages, zpages/foo]", nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, map[string]any{ "service": map[string]any{ "extensions": []any{ "zpages", "zpages/foo", }, }, }, retMap.ToStringMap()) assert.NoError(t, sp.Shutdown(context.Background())) } func TestNewLine(t *testing.T) { sp := createProvider() ret, err := sp.Retrieve(context.Background(), "yaml:processors::test/foo::timeout: 3s\nprocessors::test::timeout: 2s", nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, map[string]any{ "processors": map[string]any{ "test/foo": map[string]any{ "timeout": "3s", }, "test": map[string]any{ "timeout": "2s", }, }, }, retMap.ToStringMap()) assert.NoError(t, sp.Shutdown(context.Background())) } func TestDotSeparator(t *testing.T) { sp := createProvider() ret, err := sp.Retrieve(context.Background(), "yaml:processors.test.timeout: 4s", nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, map[string]any{"processors.test.timeout": "4s"}, retMap.ToStringMap()) assert.NoError(t, sp.Shutdown(context.Background())) } func createProvider() confmap.Provider { return NewFactory().Create(confmaptest.NewNopProviderSettings()) } opentelemetry-collector-0.141.0/confmap/provider_test.go000066400000000000000000000135501511331344600234050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap import ( "context" "errors" "fmt" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) // This is an example of a provider that calls a provided WatcherFunc to update configuration dynamically every second. // The example is useful for implementing Providers of configuration that changes over time. type UpdatingProvider struct{} func (p UpdatingProvider) getCurrentConfig(_ string) any { return "hello" } func (p UpdatingProvider) Retrieve(ctx context.Context, uri string, watcher WatcherFunc) (*Retrieved, error) { ticker := time.NewTicker(1 * time.Second) stop := make(chan bool, 1) retrieved, err := NewRetrieved(p.getCurrentConfig(uri), WithRetrievedClose(func(_ context.Context) error { // the retriever should call this function when it no longer wants config updates ticker.Stop() stop <- true return nil })) if err != nil { return nil, err } // it's necessary to start a go function that can notify the caller of changes asynchronously go func() { for { select { case <-ctx.Done(): // if the context is closed, then we should stop sending updates ticker.Stop() return case <-stop: // closeFunc was called, so stop updating the watcher return case <-ticker.C: // the configuration has "changed". Notify the watcher that a new config is available // the watcher is expected to call Provider.Retrieve again to get the update // note that the collector calls closeFunc before calling Retrieve for the second time, // so these go functions don't accumulate indefinitely. (see otelcol/collector.go, Collector.reloadConfiguration) watcher(&ChangeEvent{}) } } }() return retrieved, nil } func ExampleProvider() { provider := UpdatingProvider{} receivedNotification := make(chan bool) watcherFunc := func(_ *ChangeEvent) { fmt.Println("received notification of new config") receivedNotification <- true } retrieved, err := provider.Retrieve(context.Background(), "example", watcherFunc) if err != nil { fmt.Println("received an error") } else { fmt.Printf("received: %s\n", retrieved.rawConf) } // after one second, we should receive a notification that config has changed <-receivedNotification // signal that we no longer want updates retrieved.Close(context.Background()) // Output: // received: hello // received notification of new config } func TestNewRetrieved(t *testing.T) { ret, err := NewRetrieved(nil) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, New(), retMap) assert.NoError(t, ret.Close(context.Background())) } func TestNewRetrievedWithOptions(t *testing.T) { want := errors.New("my error") ret, err := NewRetrieved(nil, WithRetrievedClose(func(context.Context) error { return want })) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, New(), retMap) assert.Equal(t, want, ret.Close(context.Background())) } func TestNewRetrievedUnsupportedType(t *testing.T) { _, err := NewRetrieved(errors.New("my error")) require.Error(t, err) } func TestNewRetrievedFromYAML(t *testing.T) { ret, err := NewRetrievedFromYAML([]byte{}) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, New(), retMap) assert.NoError(t, ret.Close(context.Background())) } func TestNewRetrievedFromYAMLWithOptions(t *testing.T) { want := errors.New("my error") ret, err := NewRetrievedFromYAML([]byte{}, WithRetrievedClose(func(context.Context) error { return want })) require.NoError(t, err) retMap, err := ret.AsConf() require.NoError(t, err) assert.Equal(t, New(), retMap) assert.Equal(t, want, ret.Close(context.Background())) } func TestNewRetrievedFromYAMLInvalidYAMLBytes(t *testing.T) { ret, err := NewRetrievedFromYAML([]byte("[invalid:,")) require.NoError(t, err) _, err = ret.AsConf() require.EqualError(t, err, "retrieved value (type=string) cannot be used as a Conf: assuming string type since contents are not valid YAML: yaml: line 1: did not find expected node content", ) str, err := ret.AsString() require.NoError(t, err) assert.Equal(t, "[invalid:,", str) raw, err := ret.AsRaw() require.NoError(t, err) assert.Equal(t, "[invalid:,", raw) } func TestNewRetrievedFromYAMLInvalidAsMap(t *testing.T) { ret, err := NewRetrievedFromYAML([]byte("string")) require.NoError(t, err) _, err = ret.AsConf() require.EqualError(t, err, "retrieved value (type=string) cannot be used as a Conf") str, err := ret.AsString() require.NoError(t, err) assert.Equal(t, "string", str) } func TestNewRetrievedFromYAMLString(t *testing.T) { tests := []struct { yaml string value any altStrRepr string strReprErr string }{ { yaml: "string", value: "string", }, { yaml: "\"string\"", value: "\"string\"", altStrRepr: "\"string\"", }, { yaml: "123", value: 123, }, { yaml: "2023-03-20T03:17:55.432328Z", value: time.Date(2023, 3, 20, 3, 17, 55, 432328000, time.UTC), }, { yaml: "true", value: true, }, { yaml: "0123", value: 0o123, }, { yaml: "0x123", value: 0x123, }, { yaml: "0b101", value: 0b101, }, { yaml: "0.123", value: 0.123, }, { yaml: "{key: value}", value: map[string]any{"key": "value"}, }, } for _, tt := range tests { t.Run(tt.yaml, func(t *testing.T) { ret, err := NewRetrievedFromYAML([]byte(tt.yaml)) require.NoError(t, err) raw, err := ret.AsRaw() require.NoError(t, err) assert.Equal(t, tt.value, raw) str, err := ret.AsString() if tt.strReprErr != "" { assert.ErrorContains(t, err, tt.strReprErr) return } require.NoError(t, err) if tt.altStrRepr != "" { assert.Equal(t, tt.altStrRepr, str) } else { assert.Equal(t, tt.yaml, str) } }) } } opentelemetry-collector-0.141.0/confmap/resolver.go000066400000000000000000000207501511331344600223550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap // import "go.opentelemetry.io/collector/confmap" import ( "context" "errors" "fmt" "regexp" "strings" "go.uber.org/multierr" "go.uber.org/zap" "go.opentelemetry.io/collector/confmap/internal" ) // follows drive-letter specification: // https://datatracker.ietf.org/doc/html/draft-kerwin-file-scheme-07.html#section-2.2 var driverLetterRegexp = regexp.MustCompile("^[A-z]:") // Resolver resolves a configuration as a Conf. type Resolver struct { uris []location providers map[string]Provider defaultScheme string converters []Converter closers []CloseFunc watcher chan error } // ResolverSettings are the settings to configure the behavior of the Resolver. type ResolverSettings struct { // URIs locations from where the Conf is retrieved, and merged in the given order. // It is required to have at least one location. URIs []string // ProviderFactories is a slice of Provider factories. // It is required to have at least one factory. ProviderFactories []ProviderFactory // DefaultScheme is the scheme that is used if ${} syntax is used but no schema is provided. // If no DefaultScheme is set, ${} with no schema will not be expanded. // It is strongly recommended to set "env" as the default scheme to align with the // OpenTelemetry Configuration Specification DefaultScheme string // ProviderSettings contains settings that will be passed to Provider // factories when instantiating Providers. ProviderSettings ProviderSettings // ConverterFactories is a slice of Converter creation functions. ConverterFactories []ConverterFactory // ConverterSettings contains settings that will be passed to Converter // factories when instantiating Converters. ConverterSettings ConverterSettings // prevent unkeyed literal initialization _ struct{} } // NewResolver returns a new Resolver that resolves configuration from multiple URIs. // // To resolve a configuration the following steps will happen: // 1. Retrieves individual configurations from all given "URIs", and merge them in the retrieve order. // 2. Once the Conf is merged, apply the converters in the given order. // // After the configuration was resolved the `Resolver` can be used as a single point to watch for updates in // the configuration data retrieved via the config providers used to process the "initial" configuration and to generate // the "effective" one. The typical usage is the following: // // Resolver.Resolve(ctx) // Resolver.Watch() // wait for an event. // Resolver.Resolve(ctx) // Resolver.Watch() // wait for an event. // // repeat Resolve/Watch cycle until it is time to shut down the Collector process. // Resolver.Shutdown(ctx) // // `uri` must follow the ":" format. This format is compatible with the URI definition // (see https://datatracker.ietf.org/doc/html/rfc3986). An empty "" defaults to "file" schema. func NewResolver(set ResolverSettings) (*Resolver, error) { if len(set.URIs) == 0 { return nil, errors.New("invalid 'confmap.ResolverSettings' configuration: no URIs") } if len(set.ProviderFactories) == 0 { return nil, errors.New("invalid 'confmap.ResolverSettings' configuration: no Providers") } if set.ProviderSettings.Logger == nil { set.ProviderSettings.Logger = zap.NewNop() } if set.ConverterSettings.Logger == nil { set.ConverterSettings.Logger = zap.NewNop() } providers := make(map[string]Provider, len(set.ProviderFactories)) for _, factory := range set.ProviderFactories { provider := factory.Create(set.ProviderSettings) scheme := provider.Scheme() // Check that the scheme follows the pattern. if !regexp.MustCompile(schemePattern).MatchString(scheme) { return nil, fmt.Errorf("invalid 'confmap.Provider' scheme %q", scheme) } // Check that the scheme is unique. if _, ok := providers[scheme]; ok { return nil, fmt.Errorf("duplicate 'confmap.Provider' scheme %q", scheme) } providers[scheme] = provider } if set.DefaultScheme != "" { _, ok := providers[set.DefaultScheme] if !ok { return nil, errors.New("invalid 'confmap.ResolverSettings' configuration: DefaultScheme not found in providers list") } } converters := make([]Converter, len(set.ConverterFactories)) for i, factory := range set.ConverterFactories { converters[i] = factory.Create(set.ConverterSettings) } // Safe copy, ensures the slices and maps cannot be changed from the caller. uris := make([]location, len(set.URIs)) for i, uri := range set.URIs { // For backwards compatibility: // - empty url scheme means "file". // - "^[A-z]:" also means "file" if driverLetterRegexp.MatchString(uri) || !strings.Contains(uri, ":") { uris[i] = location{scheme: "file", opaqueValue: uri} continue } lURI, err := newLocation(uri) if err != nil { return nil, err } if _, ok := providers[lURI.scheme]; !ok { return nil, fmt.Errorf("unsupported scheme on URI %q", uri) } uris[i] = lURI } return &Resolver{ uris: uris, providers: providers, defaultScheme: set.DefaultScheme, converters: converters, watcher: make(chan error, 1), }, nil } // Resolve returns the configuration as a Conf, or error otherwise. // Should never be called concurrently with itself, Watch or Shutdown. func (mr *Resolver) Resolve(ctx context.Context) (*Conf, error) { // First check if already an active watching, close that if any. if err := mr.closeIfNeeded(ctx); err != nil { return nil, fmt.Errorf("cannot close previous watch: %w", err) } // Retrieves individual configurations from all URIs in the given order, and merge them in retMap. retMap := New() for _, uri := range mr.uris { ret, err := mr.retrieveValue(ctx, uri) if err != nil { return nil, fmt.Errorf("cannot retrieve the configuration: %w", err) } mr.closers = append(mr.closers, ret.Close) retCfgMap, err := ret.AsConf() if err != nil { return nil, err } if err := retMap.Merge(retCfgMap); err != nil { return nil, err } } cfgMap := make(map[string]any) for _, k := range retMap.AllKeys() { ug := internal.UnsanitizedGetter{Conf: retMap} val, err := mr.expandValueRecursively(ctx, ug.UnsanitizedGet(k)) if err != nil { return nil, err } cfgMap[k] = escapeDollarSigns(val) } retMap = NewFromStringMap(cfgMap) // Apply the converters in the given order. for _, confConv := range mr.converters { if err := confConv.Convert(ctx, retMap); err != nil { return nil, fmt.Errorf("cannot convert the confmap.Conf: %w", err) } } return retMap, nil } func escapeDollarSigns(val any) any { switch v := val.(type) { case string: return strings.ReplaceAll(v, "$$", "$") case internal.ExpandedValue: v.Original = strings.ReplaceAll(v.Original, "$$", "$") v.Value = escapeDollarSigns(v.Value) return v case []any: nslice := make([]any, len(v)) for i, x := range v { nslice[i] = escapeDollarSigns(x) } return nslice case map[string]any: nmap := make(map[string]any, len(v)) for k, x := range v { nmap[k] = escapeDollarSigns(x) } return nmap default: return val } } // Watch blocks until any configuration change was detected or an unrecoverable error // happened during monitoring the configuration changes. // // Error is nil if the configuration is changed and needs to be re-fetched. Any non-nil // error indicates that there was a problem with watching the configuration changes. // // Should never be called concurrently with itself or Get. func (mr *Resolver) Watch() <-chan error { return mr.watcher } // Shutdown signals that the provider is no longer in use and the that should close // and release any resources that it may have created. It terminates the Watch channel. // // Should never be called concurrently with itself or Get. func (mr *Resolver) Shutdown(ctx context.Context) error { var errs error errs = multierr.Append(errs, mr.closeIfNeeded(ctx)) for _, p := range mr.providers { errs = multierr.Append(errs, p.Shutdown(ctx)) } close(mr.watcher) return errs } func (mr *Resolver) onChange(event *ChangeEvent) { mr.watcher <- event.Error } func (mr *Resolver) closeIfNeeded(ctx context.Context) error { var err error for _, ret := range mr.closers { err = multierr.Append(err, ret(ctx)) } mr.closers = nil return err } func (mr *Resolver) retrieveValue(ctx context.Context, uri location) (*Retrieved, error) { p, ok := mr.providers[uri.scheme] if !ok { return nil, fmt.Errorf("scheme %q is not supported for uri %q", uri.scheme, uri.asString()) } return p.Retrieve(ctx, uri.asString(), mr.onChange) } opentelemetry-collector-0.141.0/confmap/resolver_test.go000066400000000000000000000364261511331344600234230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package confmap import ( "context" "encoding/json" "errors" "os" "path/filepath" "reflect" "sync" "sync/atomic" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" yaml "go.yaml.in/yaml/v3" "go.opentelemetry.io/collector/confmap/internal" "go.opentelemetry.io/collector/featuregate" ) type mockProvider struct { scheme string retM any errR error errS error errW error closeFunc func(ctx context.Context) error } func (m *mockProvider) Retrieve(_ context.Context, _ string, watcher WatcherFunc) (*Retrieved, error) { if m.errR != nil { return nil, m.errR } if m.retM == nil { return NewRetrieved(nil) } watcher(&ChangeEvent{Error: m.errW}) return NewRetrieved(m.retM, WithRetrievedClose(m.closeFunc)) } func (m *mockProvider) Scheme() string { if m.scheme == "" { return "mock" } return m.scheme } func (m *mockProvider) Shutdown(context.Context) error { return m.errS } func newMockProvider(m *mockProvider) ProviderFactory { return NewProviderFactory(func(_ ProviderSettings) Provider { return m }) } type fakeProvider struct { scheme string ret func(ctx context.Context, uri string, watcher WatcherFunc) (*Retrieved, error) logger *zap.Logger } func newFileProvider(tb testing.TB) ProviderFactory { return newFakeProvider("file", func(_ context.Context, uri string, _ WatcherFunc) (*Retrieved, error) { return NewRetrieved(newConfFromFile(tb, uri[5:])) }) } func newFakeProvider(scheme string, ret func(ctx context.Context, uri string, watcher WatcherFunc) (*Retrieved, error)) ProviderFactory { return NewProviderFactory(func(ps ProviderSettings) Provider { return &fakeProvider{ scheme: scheme, ret: ret, logger: ps.Logger, } }) } func newObservableFileProvider(tb testing.TB) (ProviderFactory, *fakeProvider) { return newObservableProvider("file", func(_ context.Context, uri string, _ WatcherFunc) (*Retrieved, error) { return NewRetrieved(newConfFromFile(tb, uri[5:])) }) } func newObservableProvider(scheme string, ret func(ctx context.Context, uri string, watcher WatcherFunc) (*Retrieved, error)) (ProviderFactory, *fakeProvider) { fp := &fakeProvider{ scheme: scheme, ret: ret, } return NewProviderFactory(func(ps ProviderSettings) Provider { fp.logger = ps.Logger return fp }), fp } func (f *fakeProvider) Retrieve(ctx context.Context, uri string, watcher WatcherFunc) (*Retrieved, error) { return f.ret(ctx, uri, watcher) } func (f *fakeProvider) Scheme() string { return f.scheme } func (f *fakeProvider) Shutdown(context.Context) error { return nil } type mockConverter struct { err error } func (m *mockConverter) Convert(context.Context, *Conf) error { return errors.New("converter_err") } func TestNewResolverInvalidSchemeInURI(t *testing.T) { _, err := NewResolver(ResolverSettings{URIs: []string{"s_3:has invalid char"}, ProviderFactories: []ProviderFactory{newMockProvider(&mockProvider{scheme: "s3"})}}) assert.EqualError(t, err, `invalid uri: "s_3:has invalid char"`) } func TestNewResolverDuplicateScheme(t *testing.T) { _, err := NewResolver(ResolverSettings{URIs: []string{"mock:something"}, ProviderFactories: []ProviderFactory{newMockProvider(&mockProvider{scheme: "mock"}), newMockProvider(&mockProvider{scheme: "mock"})}}) assert.EqualError(t, err, `duplicate 'confmap.Provider' scheme "mock"`) } func TestResolverErrors(t *testing.T) { tests := []struct { name string locations []string providers []Provider converters []Converter defaultScheme string expectBuildErr bool expectResolveErr bool expectWatchErr bool expectCloseErr bool expectShutdownErr bool }{ { name: "unsupported location scheme", locations: []string{"mock:", "notsupported:"}, providers: []Provider{&mockProvider{}}, expectBuildErr: true, }, { name: "default scheme not found", locations: []string{"mock:", "err:"}, providers: []Provider{ &mockProvider{}, &mockProvider{scheme: "err", errR: errors.New("retrieve_err")}, }, defaultScheme: "missing", expectBuildErr: true, }, { name: "retrieve location config error", locations: []string{"mock:", "err:"}, providers: []Provider{ &mockProvider{}, &mockProvider{scheme: "err", errR: errors.New("retrieve_err")}, }, expectResolveErr: true, }, { name: "retrieve location not convertible to Conf", locations: []string{"mock:", "err:"}, providers: []Provider{ &mockProvider{}, &mockProvider{scheme: "err", retM: "invalid value"}, }, expectResolveErr: true, }, { name: "converter error", locations: []string{"mock:"}, providers: []Provider{&mockProvider{}}, converters: []Converter{&mockConverter{err: errors.New("converter_err")}}, expectResolveErr: true, }, { name: "watch error", locations: []string{"mock:", "err:"}, providers: []Provider{ &mockProvider{}, &mockProvider{scheme: "err", retM: map[string]any{}, errW: errors.New("watch_err")}, }, expectWatchErr: true, }, { name: "close error", locations: []string{"mock:", "err:"}, providers: []Provider{ &mockProvider{}, &mockProvider{scheme: "err", retM: map[string]any{}, closeFunc: func(context.Context) error { return errors.New("close_err") }}, }, expectCloseErr: true, }, { name: "shutdown error", locations: []string{"mock:", "err:"}, providers: []Provider{ &mockProvider{}, &mockProvider{scheme: "err", retM: map[string]any{}, errS: errors.New("close_err")}, }, expectShutdownErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { mockProviderFuncs := make([]ProviderFactory, len(tt.providers)) for i, provider := range tt.providers { p := provider mockProviderFuncs[i] = NewProviderFactory(func(_ ProviderSettings) Provider { return p }) } converterFuncs := make([]ConverterFactory, len(tt.converters)) for i, converter := range tt.converters { c := converter converterFuncs[i] = NewConverterFactory(func(_ ConverterSettings) Converter { return c }) } resolver, err := NewResolver(ResolverSettings{URIs: tt.locations, ProviderFactories: mockProviderFuncs, DefaultScheme: tt.defaultScheme, ConverterFactories: converterFuncs}) if tt.expectBuildErr { assert.Error(t, err) return } require.NoError(t, err) _, errN := resolver.Resolve(context.Background()) if tt.expectResolveErr { assert.Error(t, errN) return } require.NoError(t, errN) errW := <-resolver.Watch() if tt.expectWatchErr { assert.Error(t, errW) return } require.NoError(t, errW) _, errC := resolver.Resolve(context.Background()) if tt.expectCloseErr { assert.Error(t, errC) return } require.NoError(t, errN) errS := resolver.Shutdown(context.Background()) if tt.expectShutdownErr { assert.Error(t, errS) return } assert.NoError(t, errC) }) } } func TestBackwardsCompatibilityForFilePath(t *testing.T) { tests := []struct { name string location string errMessage string expectBuildErr bool }{ { name: "unix", location: `/test`, errMessage: `file:/test`, }, { name: "file_unix", location: `file:/test`, errMessage: `file:/test`, }, { name: "windows_C", location: `c:\test`, errMessage: `file:c:\test`, }, { name: "windows_z", location: `z:\test`, errMessage: `file:z:\test`, }, { name: "file_windows", location: `file:c:\test`, errMessage: `file:c:\test`, }, { name: "invalid_scheme", location: `LL:\test`, expectBuildErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resolver, err := NewResolver(ResolverSettings{ URIs: []string{tt.location}, ProviderFactories: []ProviderFactory{ newFakeProvider("file", func(_ context.Context, uri string, _ WatcherFunc) (*Retrieved, error) { return nil, errors.New(uri) }), }, ConverterFactories: nil, }) if tt.expectBuildErr { assert.Error(t, err) return } require.NoError(t, err) _, err = resolver.Resolve(context.Background()) assert.ErrorContains(t, err, tt.errMessage, tt.name) }) } } func TestResolver(t *testing.T) { numCalls := atomic.Int32{} resolver, err := NewResolver(ResolverSettings{ URIs: []string{"mock:"}, ProviderFactories: []ProviderFactory{ newMockProvider(&mockProvider{retM: map[string]any{}, closeFunc: func(context.Context) error { numCalls.Add(1) return nil }}), }, ConverterFactories: nil, }) require.NoError(t, err) _, errN := resolver.Resolve(context.Background()) require.NoError(t, errN) assert.Equal(t, int32(0), numCalls.Load()) errW := <-resolver.Watch() require.NoError(t, errW) // Repeat Resolve/Watch. _, errN = resolver.Resolve(context.Background()) require.NoError(t, errN) assert.Equal(t, int32(1), numCalls.Load()) errW = <-resolver.Watch() require.NoError(t, errW) _, errN = resolver.Resolve(context.Background()) require.NoError(t, errN) assert.Equal(t, int32(2), numCalls.Load()) errC := resolver.Shutdown(context.Background()) require.NoError(t, errC) assert.Equal(t, int32(3), numCalls.Load()) } func TestResolverNewLinesInOpaqueValue(t *testing.T) { _, err := NewResolver(ResolverSettings{ URIs: []string{"mock:receivers:\n nop:\n"}, ProviderFactories: []ProviderFactory{newMockProvider(&mockProvider{retM: map[string]any{}})}, ConverterFactories: nil, }) assert.NoError(t, err) } func TestResolverNoLocations(t *testing.T) { _, err := NewResolver(ResolverSettings{ URIs: []string{}, ProviderFactories: []ProviderFactory{newMockProvider(&mockProvider{})}, ConverterFactories: nil, }) assert.Error(t, err) } func TestResolverNoProviders(t *testing.T) { _, err := NewResolver(ResolverSettings{ URIs: []string{filepath.Join("testdata", "config.yaml")}, ProviderFactories: nil, ConverterFactories: nil, }) assert.Error(t, err) } func TestResolverShutdownClosesWatch(t *testing.T) { resolver, err := NewResolver(ResolverSettings{ URIs: []string{filepath.Join("testdata", "config.yaml")}, ProviderFactories: []ProviderFactory{newFileProvider(t)}, ConverterFactories: nil, }) require.NoError(t, err) _, errN := resolver.Resolve(context.Background()) require.NoError(t, errN) var watcherWG sync.WaitGroup watcherWG.Add(1) go func() { errW, ok := <-resolver.Watch() // Channel is closed, no exception assert.NoError(t, errW) assert.False(t, ok) watcherWG.Done() }() require.NoError(t, resolver.Shutdown(context.Background())) watcherWG.Wait() } func TestProvidesDefaultLogger(t *testing.T) { factory, provider := newObservableFileProvider(t) _, err := NewResolver(ResolverSettings{ URIs: []string{filepath.Join("testdata", "config.yaml")}, ProviderFactories: []ProviderFactory{factory}, ConverterFactories: []ConverterFactory{NewConverterFactory(func(set ConverterSettings) Converter { assert.NotNil(t, set.Logger) return &mockConverter{} })}, }) require.NoError(t, err) require.NotNil(t, provider.logger) } func TestResolverDefaultProviderSet(t *testing.T) { envProvider := newEnvProvider() fileProvider := newFileProvider(t) r, err := NewResolver(ResolverSettings{ URIs: []string{"env:"}, ProviderFactories: []ProviderFactory{fileProvider, envProvider}, DefaultScheme: "env", }) require.NoError(t, err) assert.NotNil(t, r.defaultScheme) _, ok := r.providers["env"] assert.True(t, ok) } type mergeTest struct { Name string `yaml:"name"` AppendPaths []string `yaml:"append_paths"` Configs []map[string]any `yaml:"configs"` Expected map[string]any `yaml:"expected"` } func TestMergeFunctionality(t *testing.T) { tests := []struct { name string scenarioFile string flagEnabled bool }{ { name: "feature-flag-enabled", scenarioFile: "testdata/merge-append-scenarios.yaml", flagEnabled: true, }, { name: "feature-flag-disabled", scenarioFile: "testdata/merge-append-scenarios-featuregate-disabled.yaml", flagEnabled: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if tt.flagEnabled { require.NoError(t, featuregate.GlobalRegistry().Set(internal.EnableMergeAppendOption.ID(), true)) defer func() { // Restore previous value. require.NoError(t, featuregate.GlobalRegistry().Set(internal.EnableMergeAppendOption.ID(), false)) }() } runScenario(t, tt.scenarioFile) }) } } func runScenario(t *testing.T, path string) { yamlData, err := os.ReadFile(filepath.Clean(path)) require.NoError(t, err) var testcases []*mergeTest err = yaml.Unmarshal(yamlData, &testcases) require.NoError(t, err) for _, tt := range testcases { t.Run(tt.Name, func(t *testing.T) { configFiles := make([]string, 0) for _, c := range tt.Configs { // store configs into a temp file. This makes it easier for us to test feature gate functionality file, err := os.CreateTemp(t.TempDir(), "*.yaml") defer func() { require.NoError(t, file.Close()) }() require.NoError(t, err) b, err := json.Marshal(c) require.NoError(t, err) n, err := file.Write(b) require.NoError(t, err) require.Positive(t, n) configFiles = append(configFiles, file.Name()) } resolver, err := NewResolver(ResolverSettings{ URIs: configFiles, ProviderFactories: []ProviderFactory{newFileProvider(t)}, DefaultScheme: "file", }) require.NoError(t, err) conf, err := resolver.Resolve(context.Background()) require.NoError(t, err) mergedConf := conf.ToStringMap() require.Truef(t, reflect.DeepEqual(mergedConf, tt.Expected), "Exp: %s\nGot: %s", tt.Expected, mergedConf) }) } } // newConfFromFile creates a new Conf by reading the given file. func newConfFromFile(tb testing.TB, fileName string) map[string]any { content, err := os.ReadFile(filepath.Clean(fileName)) require.NoErrorf(tb, err, "unable to read the file %v", fileName) var data map[string]any require.NoError(tb, yaml.Unmarshal(content, &data), "unable to parse yaml") return NewFromStringMap(data).ToStringMap() } type provider struct { wg sync.WaitGroup } func newRaceDetectorProvider() ProviderFactory { return NewProviderFactory(func(_ ProviderSettings) Provider { return &provider{} }) } func (p *provider) Retrieve(_ context.Context, _ string, watcher WatcherFunc) (*Retrieved, error) { p.wg.Add(1) go func() { // mock a config change event and wait for goroutine to return. defer p.wg.Done() watcher(&ChangeEvent{}) }() return NewRetrieved(map[string]any{}) } func (p *provider) Scheme() string { return "race" } func (p *provider) Shutdown(context.Context) error { p.wg.Wait() return nil } func TestProviderRaceCondition(t *testing.T) { resolver, err := NewResolver(ResolverSettings{ URIs: []string{"race:"}, ProviderFactories: []ProviderFactory{ newRaceDetectorProvider(), }, ConverterFactories: nil, }) require.NoError(t, err) c, err := resolver.Resolve(context.Background()) require.NoError(t, err) require.NotNil(t, c) require.NoError(t, resolver.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/confmap/testdata/000077500000000000000000000000001511331344600217725ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/testdata/config.yaml000066400000000000000000000004761511331344600241320ustar00rootroot00000000000000receivers: nop: nop/myreceiver: processors: nop: nop/myprocessor: exporters: nop: nop/myexporter: extensions: nop: nop/myextension: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] opentelemetry-collector-0.141.0/confmap/testdata/expand-with-all-env.yaml000066400000000000000000000005001511331344600264350ustar00rootroot00000000000000test_map: extra: "${env:EXTRA}" extra_map: recv.1: "${env:EXTRA_MAP_VALUE_1}" recv.2: "${env:EXTRA_MAP_VALUE_2}" extra_list_map: - { recv.1: "${env:EXTRA_LIST_MAP_VALUE_1}",recv.2: "${env:EXTRA_LIST_MAP_VALUE_2}" } extra_list: - "${env:EXTRA_LIST_VALUE_1}" - "${env:EXTRA_LIST_VALUE_2}" opentelemetry-collector-0.141.0/confmap/testdata/expand-with-no-env.yaml000066400000000000000000000004121511331344600263030ustar00rootroot00000000000000test_map: extra: "some string" extra_map: recv.1: "some map value_1" recv.2: "some map value_2" extra_list_map: - { recv.1: "some list map value_1",recv.2: "some list map value_2" } extra_list: - "some list value_1" - "some list value_2" opentelemetry-collector-0.141.0/confmap/testdata/expand-with-partial-env.yaml000066400000000000000000000004431511331344600273270ustar00rootroot00000000000000test_map: extra: "${env:EXTRA}" extra_map: recv.1: "${env:EXTRA_MAP_VALUE_1}" recv.2: "some map value_2" extra_list_map: - { recv.1: "some list map value_1",recv.2: "${env:EXTRA_LIST_MAP_VALUE_2}" } extra_list: - "some list value_1" - "${env:EXTRA_LIST_VALUE_2}" opentelemetry-collector-0.141.0/confmap/testdata/merge-append-scenarios-featuregate-disabled.yaml000066400000000000000000000073771511331344600332630ustar00rootroot00000000000000- name: merge-mode-default configs: - receivers: nop: nop/myreceiver: processors: nop: nop/myprocessor: exporters: nop: nop/myexporter: extensions: nop: nop/myextension: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - receivers: nop2: exporters: nop2: extensions: nop2: service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [nop2] exporters: [nop2] expected: receivers: nop2: nop: nop/myreceiver: exporters: nop2: nop: nop/myexporter: processors: nop: nop/myprocessor: extensions: nop2: nop: nop/myextension: service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [nop2] exporters: [nop2] - name: merge-mode-append append_paths: ["service"] configs: - receivers: nop: key: val processors: nop: exporters: nop: key: 2 extensions: nop: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - receivers: nop2: exporters: nop2: nop: key: updated_value extensions: nop2: service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [nop2] exporters: [nop2] expected: receivers: nop2: nop: key: val exporters: nop2: nop: key: updated_value processors: nop: extensions: nop2: nop: service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [nop2] exporters: [nop2] - name: merge-mode-append-override-old-values append_paths: ["service"] configs: - receivers: nop: key1: "value" key2: 1 processors: nop: exporters: nop: extensions: nop: ext: key: 1 service: extensions: [nop, ext] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - receivers: nop2: exporters: nop2: extensions: ext: key: 2 service: extensions: [ext] pipelines: traces: receivers: [nop2] exporters: [nop2] expected: receivers: nop: key1: "value" key2: 1 nop2: exporters: nop2: nop: processors: nop: extensions: nop: ext: key: 2 service: extensions: [ext] pipelines: traces: receivers: [nop2] processors: [nop] exporters: [nop2] opentelemetry-collector-0.141.0/confmap/testdata/merge-append-scenarios.yaml000066400000000000000000000306011511331344600272060ustar00rootroot00000000000000- name: merge-mode-default configs: - receivers: nop: nop/myreceiver: processors: nop: nop/myprocessor: exporters: nop: nop/myexporter: extensions: nop: nop/myextension: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - receivers: nop2: exporters: nop2: extensions: nop2: service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [nop2] exporters: [nop2] expected: receivers: nop2: nop: nop/myreceiver: exporters: nop2: nop: nop/myexporter: processors: nop: nop/myprocessor: extensions: nop2: nop: nop/myextension: service: extensions: [nop, nop2] pipelines: traces: receivers: [nop, nop2] processors: [nop2] exporters: [nop, nop2] - name: merge-mode-append configs: - receivers: nop: key: val processors: nop: exporters: nop: key: 2 extensions: nop: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - receivers: nop2: exporters: nop2: nop: key: updated_value extensions: nop2: service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [nop2] exporters: [nop2] expected: receivers: nop2: nop: key: val exporters: nop2: nop: key: updated_value processors: nop: extensions: nop2: nop: service: extensions: [nop, nop2] pipelines: traces: receivers: [nop, nop2] processors: [nop2] exporters: [nop, nop2] - name: merge-mode-append-override-old-values configs: - receivers: nop: key1: "value" key2: 1 processors: nop: exporters: nop: extensions: nop: ext: key: 1 service: extensions: [nop, ext] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - receivers: nop2: exporters: nop2: extensions: ext: key: 2 service: extensions: [ext] pipelines: traces: receivers: [nop2] exporters: [nop2] expected: receivers: nop: key1: "value" key2: 1 nop2: exporters: nop2: nop: processors: nop: extensions: nop: ext: key: 2 service: extensions: [nop, ext] pipelines: traces: receivers: [nop, nop2] processors: [nop] exporters: [nop, nop2] - name: merge-mode-append-name-aware configs: - receivers: nop: exporters: nop: extensions: nop: ext: ext2: service: extensions: [nop, ext, ext2] pipelines: traces: receivers: [nop] exporters: [nop] - receivers: nop: exporters: nop: extensions: nop: key: 1 ext3: service: extensions: [nop, ext3] pipelines: traces: receivers: [nop] exporters: [nop] expected: receivers: nop: exporters: nop: extensions: nop: key: 1 ext: ext2: ext3: service: extensions: [nop, ext, ext2, ext3] pipelines: traces: receivers: [nop] exporters: [nop] - name: merge-mode-append-multiple configs: - receivers: nop: exporters: nop: extensions: nop: service: extensions: [nop] pipelines: traces: receivers: [nop] exporters: [nop] - receivers: nop2: exporters: nop2: extensions: nop2: service: extensions: [nop2] pipelines: traces: receivers: [nop2] exporters: [nop2] - receivers: nop3: exporters: nop3: extensions: nop3: service: extensions: [nop3] pipelines: traces: receivers: [nop3] exporters: [nop3] expected: receivers: nop: nop2: nop3: exporters: nop: nop2: nop3: extensions: nop: nop2: nop3: service: extensions: [nop, nop2, nop3] pipelines: traces: receivers: [nop, nop2, nop3] exporters: [nop, nop2, nop3] - name: merge-mode-append-processor-service configs: - receivers: nop: exporters: nop: extensions: nop: processors: processor: path: [path] service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [processor] exporters: [nop] - receivers: nop2: exporters: nop2: extensions: nop2: processors: processor: path: [path2] service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [processor] exporters: [nop2] expected: receivers: nop: nop2: exporters: nop: nop2: extensions: nop: nop2: processors: processor: path: [path2] service: extensions: [nop, nop2] pipelines: traces: receivers: [nop, nop2] processors: [processor] exporters: [nop, nop2] - name: merge-mode-append-entire-config configs: - receivers: nop: exporters: nop: extensions: nop: processors: processor: path: [path] service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [processor] exporters: [nop] - receivers: nop2: exporters: nop2: extensions: nop2: processors: processor: path: [path2] service: extensions: [nop2] pipelines: traces: receivers: [nop2] processors: [processor] exporters: [nop2] - receivers: nop3: exporters: nop3: extensions: nop3: processors: processor: path: [path3] processor2: service: extensions: [nop3] pipelines: traces: receivers: [nop3] processors: [processor, processor2] exporters: [nop3] expected: receivers: nop: nop2: nop3: exporters: nop: nop2: nop3: extensions: nop: nop2: nop3: processors: processor: path: [path3] processor2: service: extensions: [nop, nop2, nop3] pipelines: traces: receivers: [nop, nop2, nop3] processors: [processor, processor2] exporters: [nop, nop2, nop3] - name: merge-mode-append-different-kinds configs: - receivers: nop: key: val processors: nop: exporters: nop: key: 2 extensions: nop: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - receivers: nop: key: 1.2 expected: receivers: nop: key: 1.2 processors: nop: exporters: nop: key: 2 extensions: nop: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] - name: merge-mode-multiple-pipelines configs: - receivers: nop: key: val processors: nop: key: val exporters: nop: key: 2 extensions: nop: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [attributes/example] exporters: [nop] logs: receivers: [nop] processors: [attributes/example] exporters: [nop] - receivers: nop1: key: val processors: nop1: key: val exporters: nop1: key: 2 extensions: nop1: service: extensions: [nop1] pipelines: traces: receivers: [nop1] processors: [nop1] exporters: [nop1] logs: receivers: [nop1] processors: [nop1] exporters: [nop1] expected: receivers: nop: key: val nop1: key: val processors: nop: key: val nop1: key: val exporters: nop: key: 2 nop1: key: 2 extensions: nop: nop1: service: extensions: [nop, nop1] pipelines: traces: receivers: [nop, nop1] processors: [nop1] exporters: [nop, nop1] logs: receivers: [nop, nop1] processors: [nop1] exporters: [nop, nop1] - name: merge-mode-map configs: - processors: resource: attributes: - key: deployment.region value: "nl" action: upsert - processors: resource: attributes: - key: app value: "foo" action: upsert expected: processors: resource: attributes: # TODO: once merge append mode is configurable, comment this out. # - key: deployment.region # value: "nl" # action: upsert - key: app value: "foo" action: upsert opentelemetry-collector-0.141.0/confmap/xconfmap/000077500000000000000000000000001511331344600217745ustar00rootroot00000000000000opentelemetry-collector-0.141.0/confmap/xconfmap/Makefile000066400000000000000000000000361511331344600234330ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/confmap/xconfmap/config.go000066400000000000000000000112771511331344600236000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconfmap // import "go.opentelemetry.io/collector/confmap/xconfmap" import ( "errors" "fmt" "reflect" "strconv" "strings" "go.opentelemetry.io/collector/confmap" ) // As interface types are only used for static typing, a common idiom to find the reflection Type // for an interface type Foo is to use a *Foo value. var configValidatorType = reflect.TypeFor[Validator]() // Validator defines an optional interface for configurations to implement to do validation. type Validator interface { // Validate the configuration and returns an error if invalid. Validate() error } // Validate validates a config, by doing this: // - Call Validate on the config itself if the config implements ConfigValidator. func Validate(cfg any) error { var err error for _, validationErr := range validate(reflect.ValueOf(cfg)) { err = errors.Join(err, validationErr) } return err } type pathError struct { err error path []string } func (pe pathError) Error() string { if len(pe.path) > 0 { var path string sb := strings.Builder{} _, _ = sb.WriteString(pe.path[len(pe.path)-1]) for i := len(pe.path) - 2; i >= 0; i-- { _, _ = sb.WriteString(confmap.KeyDelimiter) _, _ = sb.WriteString(pe.path[i]) } path = sb.String() return fmt.Sprintf("%s: %s", path, pe.err) } return pe.err.Error() } func (pe pathError) Unwrap() error { return pe.err } func validate(v reflect.Value) []pathError { errs := []pathError{} // Validate the value itself. switch v.Kind() { case reflect.Invalid: return nil case reflect.Ptr, reflect.Interface: return validate(v.Elem()) case reflect.Struct: err := callValidateIfPossible(v) if err != nil { errs = append(errs, pathError{err: err}) } // Reflect on the pointed data and check each of its fields. for i := 0; i < v.NumField(); i++ { if !v.Type().Field(i).IsExported() { continue } field := v.Type().Field(i) path := fieldName(field) subpathErrs := validate(v.Field(i)) for _, err := range subpathErrs { errs = append(errs, pathError{ err: err.err, path: append(err.path, path), }) } } return errs case reflect.Slice, reflect.Array: err := callValidateIfPossible(v) if err != nil { errs = append(errs, pathError{err: err}) } // Reflect on the pointed data and check each of its fields. for i := 0; i < v.Len(); i++ { subPathErrs := validate(v.Index(i)) for _, err := range subPathErrs { errs = append(errs, pathError{ err: err.err, path: append(err.path, strconv.Itoa(i)), }) } } return errs case reflect.Map: err := callValidateIfPossible(v) if err != nil { errs = append(errs, pathError{err: err}) } iter := v.MapRange() for iter.Next() { keyErrs := validate(iter.Key()) valueErrs := validate(iter.Value()) key := stringifyMapKey(iter.Key()) for _, err := range keyErrs { errs = append(errs, pathError{err: err.err, path: append(err.path, key)}) } for _, err := range valueErrs { errs = append(errs, pathError{err: err.err, path: append(err.path, key)}) } } return errs default: err := callValidateIfPossible(v) if err != nil { return []pathError{{err: err}} } return nil } } func callValidateIfPossible(v reflect.Value) error { // If the value type implements ConfigValidator just call Validate if v.Type().Implements(configValidatorType) { return v.Interface().(Validator).Validate() } // If the pointer type implements ConfigValidator call Validate on the pointer to the current value. if reflect.PointerTo(v.Type()).Implements(configValidatorType) { // If not addressable, then create a new *V pointer and set the value to current v. if !v.CanAddr() { pv := reflect.New(reflect.PointerTo(v.Type()).Elem()) pv.Elem().Set(v) v = pv.Elem() } return v.Addr().Interface().(Validator).Validate() } return nil } func fieldName(field reflect.StructField) string { var fieldName string if tag, ok := field.Tag.Lookup(confmap.MapstructureTag); ok { tags := strings.Split(tag, ",") if len(tags) > 0 { fieldName = tags[0] } } // Even if the mapstructure tag exists, the field name may not // be available, so set it if it is still blank. if fieldName == "" { fieldName = strings.ToLower(field.Name) } return fieldName } func stringifyMapKey(val reflect.Value) string { switch v := val.Interface().(type) { case string: return v case fmt.Stringer: return v.String() default: switch val.Kind() { case reflect.Ptr, reflect.Interface, reflect.Struct, reflect.Slice, reflect.Array, reflect.Map: return fmt.Sprintf("[%T key]", val.Interface()) default: return fmt.Sprintf("%v", val.Interface()) } } } opentelemetry-collector-0.141.0/confmap/xconfmap/config_test.go000066400000000000000000000223331511331344600246320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconfmap import ( "errors" "testing" "github.com/stretchr/testify/assert" ) type configChildStruct struct { Child errValidateConfig ChildPtr *errValidateConfig } type configChildSlice struct { Child []errValidateConfig ChildPtr []*errValidateConfig } type configChildMapValue struct { Child map[string]errValidateConfig ChildPtr map[string]*errValidateConfig } type configChildMapKey struct { Child map[errType]string ChildPtr map[*errType]string } type configChildTypeDef struct { Child errType ChildPtr *errType } type config any type configChildInterface struct { Child config } type errValidateConfig struct { err error } func (e *errValidateConfig) Validate() error { return e.err } type errType string func (e errType) Validate() error { if e == "" { return nil } return errors.New(string(e)) } func newErrType(etStr string) *errType { et := errType(etStr) return &et } type errMapType map[string]string func (e errMapType) Validate() error { return errors.New(e["err"]) } type structKey struct { k string e error } func (s structKey) String() string { return s.k } func (s structKey) Validate() error { return s.e } type configChildMapCustomKey struct { Child map[structKey]errValidateConfig } func newErrMapType() *errMapType { et := errMapType(nil) return &et } type configMapstructure struct { Valid *errValidateConfig `mapstructure:"validtag,omitempty"` NoData *errValidateConfig `mapstructure:""` NoName *errValidateConfig `mapstructure:",remain"` } type configDeeplyNested struct { MapKeyChild map[configChildStruct]string MapValueChild map[string]configChildStruct SliceChild []configChildSlice MapIntKey map[int]errValidateConfig MapFloatKey map[float64]errValidateConfig } type sliceTypeAlias []configChildSlice func (sliceTypeAlias) Validate() error { return errors.New("sliceTypeAlias error") } func TestValidateConfig(t *testing.T) { tests := []struct { name string cfg any expected error }{ { name: "struct", cfg: errValidateConfig{err: errors.New("struct")}, expected: errors.New("struct"), }, { name: "pointer struct", cfg: &errValidateConfig{err: errors.New("pointer struct")}, expected: errors.New("pointer struct"), }, { name: "type", cfg: errType("type"), expected: errors.New("type"), }, { name: "pointer child", cfg: newErrType("pointer type"), expected: errors.New("pointer type"), }, { name: "child interface with nil", cfg: configChildInterface{}, expected: nil, }, { name: "pointer to child interface with nil", cfg: &configChildInterface{}, expected: nil, }, { name: "nil", cfg: nil, expected: nil, }, { name: "nil map type", cfg: errMapType(nil), expected: errors.New(""), }, { name: "nil pointer map type", cfg: newErrMapType(), expected: errors.New(""), }, { name: "child struct", cfg: configChildStruct{Child: errValidateConfig{err: errors.New("child struct")}}, expected: errors.New("child: child struct"), }, { name: "pointer child struct", cfg: &configChildStruct{Child: errValidateConfig{err: errors.New("pointer child struct")}}, expected: errors.New("child: pointer child struct"), }, { name: "child struct pointer", cfg: &configChildStruct{ChildPtr: &errValidateConfig{err: errors.New("child struct pointer")}}, expected: errors.New("childptr: child struct pointer"), }, { name: "child interface", cfg: configChildInterface{Child: errValidateConfig{err: errors.New("child interface")}}, expected: errors.New("child: child interface"), }, { name: "pointer to child interface", cfg: &configChildInterface{Child: errValidateConfig{err: errors.New("pointer to child interface")}}, expected: errors.New("child: pointer to child interface"), }, { name: "child interface with pointer", cfg: configChildInterface{Child: &errValidateConfig{err: errors.New("child interface with pointer")}}, expected: errors.New("child: child interface with pointer"), }, { name: "pointer to child interface with pointer", cfg: &configChildInterface{Child: &errValidateConfig{err: errors.New("pointer to child interface with pointer")}}, expected: errors.New("child: pointer to child interface with pointer"), }, { name: "child slice", cfg: configChildSlice{Child: []errValidateConfig{{}, {err: errors.New("child slice")}}}, expected: errors.New("child::1: child slice"), }, { name: "pointer child slice", cfg: &configChildSlice{Child: []errValidateConfig{{}, {err: errors.New("pointer child slice")}}}, expected: errors.New("child::1: pointer child slice"), }, { name: "child slice pointer", cfg: &configChildSlice{ChildPtr: []*errValidateConfig{{}, {err: errors.New("child slice pointer")}}}, expected: errors.New("childptr::1: child slice pointer"), }, { name: "child map value", cfg: configChildMapValue{Child: map[string]errValidateConfig{"test": {err: errors.New("child map")}}}, expected: errors.New("child::test: child map"), }, { name: "pointer child map value", cfg: &configChildMapValue{Child: map[string]errValidateConfig{"test": {err: errors.New("pointer child map")}}}, expected: errors.New("child::test: pointer child map"), }, { name: "child map value pointer", cfg: &configChildMapValue{ChildPtr: map[string]*errValidateConfig{"test": {err: errors.New("child map pointer")}}}, expected: errors.New("childptr::test: child map pointer"), }, { name: "child map key", cfg: configChildMapKey{Child: map[errType]string{"child_map_key": ""}}, expected: errors.New("child::child_map_key: child_map_key"), }, { name: "pointer child map key", cfg: &configChildMapKey{Child: map[errType]string{"pointer_child_map_key": ""}}, expected: errors.New("child::pointer_child_map_key: pointer_child_map_key"), }, { name: "child map key pointer", cfg: &configChildMapKey{ChildPtr: map[*errType]string{newErrType("child map key pointer"): ""}}, expected: errors.New("childptr::[*xconfmap.errType key]: child map key pointer"), }, { name: "map with stringified non-string key type", cfg: &configChildMapCustomKey{Child: map[structKey]errValidateConfig{{k: "struct_key", e: errors.New("custom key error")}: {err: errors.New("value error")}}}, expected: errors.New("child::struct_key: custom key error\nchild::struct_key: value error"), }, { name: "child type", cfg: configChildTypeDef{Child: "child type"}, expected: errors.New("child: child type"), }, { name: "pointer child type", cfg: &configChildTypeDef{Child: "pointer child type"}, expected: errors.New("child: pointer child type"), }, { name: "child type pointer", cfg: &configChildTypeDef{ChildPtr: newErrType("child type pointer")}, expected: errors.New("childptr: child type pointer"), }, { name: "valid mapstructure tag", cfg: configMapstructure{Valid: &errValidateConfig{errors.New("test")}}, expected: errors.New("validtag: test"), }, { name: "zero-length mapstructure tag", cfg: configMapstructure{NoData: &errValidateConfig{errors.New("test")}}, expected: errors.New("nodata: test"), }, { name: "no field name in mapstructure tag", cfg: configMapstructure{NoName: &errValidateConfig{errors.New("test")}}, expected: errors.New("noname: test"), }, { name: "nested map key error", cfg: configDeeplyNested{MapKeyChild: map[configChildStruct]string{{Child: errValidateConfig{err: errors.New("child key error")}}: "val"}}, expected: errors.New("mapkeychild::[xconfmap.configChildStruct key]::child: child key error"), }, { name: "nested map value error", cfg: configDeeplyNested{MapValueChild: map[string]configChildStruct{"key": {Child: errValidateConfig{err: errors.New("child key error")}}}}, expected: errors.New("mapvaluechild::key::child: child key error"), }, { name: "nested slice value error", cfg: configDeeplyNested{SliceChild: []configChildSlice{{Child: []errValidateConfig{{err: errors.New("child key error")}}}}}, expected: errors.New("slicechild::0::child::0: child key error"), }, { name: "nested map with int key", cfg: configDeeplyNested{MapIntKey: map[int]errValidateConfig{1: {err: errors.New("int key error")}}}, expected: errors.New("mapintkey::1: int key error"), }, { name: "nested map with float key", cfg: configDeeplyNested{MapFloatKey: map[float64]errValidateConfig{1.2: {err: errors.New("float key error")}}}, expected: errors.New("mapfloatkey::1.2: float key error"), }, { name: "slice type alias", cfg: sliceTypeAlias{}, expected: errors.New("sliceTypeAlias error"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := Validate(tt.cfg) if tt.expected != nil { assert.EqualError(t, err, tt.expected.Error()) } else { assert.NoError(t, err) } }) } } opentelemetry-collector-0.141.0/confmap/xconfmap/example_test.go000066400000000000000000000026271511331344600250240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconfmap import ( "errors" "fmt" "time" ) // Config represents the receiver config settings within the collector's config.yaml type Config struct { Interval time.Duration `mapstructure:"interval"` NumberOfTraces int `mapstructure:"number_of_traces"` } // Validate checks if the receiver configuration is valid // this function is automatically called by the collector when it loads the configurations // for a component func (cfg *Config) Validate() error { if cfg.Interval.Minutes() < 1 { return errors.New("when defined, the interval has to be set to at least 1 minute (1m)") } if cfg.NumberOfTraces < 1 { return errors.New("number_of_traces must be greater or equal to 1") } return nil } // Example usage validated configuration func Example() { // invalid number of traces myCfg := Config{ Interval: time.Minute, NumberOfTraces: 0, } err := myCfg.Validate() fmt.Println(err) // invalid interval myCfg = Config{ Interval: time.Second, NumberOfTraces: 1, } err = myCfg.Validate() fmt.Println(err) // valid config myCfg = Config{ Interval: time.Minute, NumberOfTraces: 1, } err = myCfg.Validate() fmt.Println(err) // Output: // number_of_traces must be greater or equal to 1 // when defined, the interval has to be set to at least 1 minute (1m) // } opentelemetry-collector-0.141.0/confmap/xconfmap/go.mod000066400000000000000000000021321511331344600231000ustar00rootroot00000000000000module go.opentelemetry.io/collector/confmap/xconfmap go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../ replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/confmap/xconfmap/go.sum000066400000000000000000000067421511331344600231400ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/connector/000077500000000000000000000000001511331344600205305ustar00rootroot00000000000000opentelemetry-collector-0.141.0/connector/Makefile000066400000000000000000000000331511331344600221640ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/connector/README.md000066400000000000000000000121711511331344600220110ustar00rootroot00000000000000# Connectors A connector is both an exporter and receiver. As the name suggests a Connector connects two pipelines: it emits data as an exporter at the end of one pipeline and consumes data as a receiver at the start of another pipeline. It may consume and emit data of the same data type, or of different data types. A connector may generate and emit data to summarize the consumed data, or it may simply replicate or route data. ## Supported Data Types Each type of connector is designed to work with one or more _pairs_ of data types and may only be used to connect pipelines accordingly. (Recall that every pipeline is associated with a single data type, either traces, metrics, or logs.) For example, the `count` connector counts traces, metrics, and logs, and reports the counts as a metric. Therefore, it may be used to connect the following types of pipelines. | [Exporter Pipeline Type] | [Receiver Pipeline Type] | | ------------------------ | ------------------------ | | traces | metrics | | metrics | metrics | | logs | metrics | Another example, the `router` connector, is useful for routing data onto the appropriate pipeline so that it may be processed in distinct ways and/or exported to an appropriate backend. It does not alter the data it consumes in any ways, nor does it produce any additional data. Therefore, it may be used to connect the following types of pipelines. | [Exporter Pipeline Type] | [Receiver Pipeline Type] | | ------------------------ | ------------------------ | | traces | traces | | metrics | metrics | | logs | logs | ## Configuration ### Declaration Connectors are defined within a dedicated `connectors` section at the top level of the collector config. The count connector may be used with default settings. ```yaml receivers: foo: exporters: bar: connectors: count: router: ``` ### Usage Recall that a connector _is_ an exporter _and_ a receiver and that each connector MUST be used as both, in separate pipelines. ```yaml receivers: foo: exporters: bar: connectors: count: service: pipelines: traces: receivers: [foo] exporters: [count] metrics: receivers: [count] exporters: [bar] ``` Connectors can be used alongside traditional exporters. ```yaml receivers: foo: exporters: bar/traces_backend: bar/metrics_backend: connectors: count: service: pipelines: traces: receivers: [foo] exporters: [bar/traces_backend, count] metrics: receivers: [count] exporters: [bar/metrics_backend] ``` Connectors can be used alongside traditional receivers. ```yaml receivers: foo/traces: foo/metrics: exporters: bar: connectors: count: service: pipelines: traces: receivers: [foo/traces] exporters: [count] metrics: receivers: [foo/metrics, count] exporters: [bar] ``` A connector can be an exporter in multiple pipelines. ```yaml receivers: foo/traces: foo/metrics: foo/logs: exporters: bar/traces_backend: bar/metrics_backend: bar/logs_backend: connectors: count: service: pipelines: traces: receivers: [foo/traces] exporters: [bar/traces_backend, count] metrics: receivers: [foo/metrics] exporters: [bar/metrics_backend, count] logs: receivers: [foo/logs] exporters: [bar/logs_backend, count] metrics/counts: receivers: [count] exporters: [bar/metrics_backend] ``` A connector can be a receiver in multiple pipelines. ```yaml receivers: foo/traces: foo/metrics: exporters: bar/traces_backend: bar/metrics_backend: bar/metrics_backend/2: connectors: count: service: pipelines: traces: receivers: [foo/traces] exporters: [bar/traces_backend, count] metrics: receivers: [count] exporters: [bar/metrics_backend] metrics/2: receivers: [count] exporters: [bar/metrics_backend/2] ``` Multiple connectors can be used in sequence. ```yaml receivers: foo: exporters: bar: connectors: count: count/the_counts: service: pipelines: traces: receivers: [foo] exporters: [count] metrics: receivers: [count] exporters: [bar/metrics_backend, count/the_counts] metrics/count_the_counts: receivers: [count/the_counts] exporters: [bar] ``` A connector can only be used in a pair of pipelines when it supports the combination of [Exporter Pipeline Type] and [Receiver Pipeline Type]. ```yaml receivers: foo: exporters: bar: connectors: count: service: pipelines: traces: receivers: [foo] exporters: [count] logs: receivers: [count] # Invalid. The count connector does not support traces -> logs. exporters: [bar] ``` #### Exporter Pipeline Type The type of pipeline in which a connector is used as an exporter. #### Receiver Pipeline Type The type of pipeline in which the connector is used as a receiver. [Exporter Pipeline Type]:#exporter-pipeline-type [Receiver Pipeline Type]:#receiver-pipeline-type opentelemetry-collector-0.141.0/connector/connector.go000066400000000000000000000415071511331344600230600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector // import "go.opentelemetry.io/collector/connector" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pipeline" ) // A Traces connector acts as an exporter from a traces pipeline and a receiver // to one or more traces, metrics, or logs pipelines. // Traces feeds a consumer.Traces, consumer.Metrics, or consumer.Logs with data. // // Examples: // - Traces could be collected in one pipeline and routed to another traces pipeline // based on criteria such as attributes or other content of the trace. The second // pipeline can then process and export the trace to the appropriate backend. // - Traces could be summarized by a metrics connector that emits statistics describing // the number of traces observed. // - Traces could be analyzed by a logs connector that emits events when particular // criteria are met. type Traces interface { component.Component consumer.Traces } // A Metrics connector acts as an exporter from a metrics pipeline and a receiver // to one or more traces, metrics, or logs pipelines. // Metrics feeds a consumer.Traces, consumer.Metrics, or consumer.Logs with data. // // Examples: // - Latency between related data points could be modeled and emitted as traces. // - Metrics could be collected in one pipeline and routed to another metrics pipeline // based on criteria such as attributes or other content of the metric. The second // pipeline can then process and export the metric to the appropriate backend. // - Metrics could be analyzed by a logs connector that emits events when particular // criteria are met. type Metrics interface { component.Component consumer.Metrics } // A Logs connector acts as an exporter from a logs pipeline and a receiver // to one or more traces, metrics, or logs pipelines. // Logs feeds a consumer.Traces, consumer.Metrics, or consumer.Logs with data. // // Examples: // - Structured logs containing span information could be consumed and emitted as traces. // - Metrics could be extracted from structured logs that contain numeric data. // - Logs could be collected in one pipeline and routed to another logs pipeline // based on criteria such as attributes or other content of the log. The second // pipeline can then process and export the log to the appropriate backend. type Logs interface { component.Component consumer.Logs } // Settings configures Connector creators. type Settings struct { // ID returns the ID of the component that will be created. ID component.ID component.TelemetrySettings // BuildInfo can be used by components for informational purposes BuildInfo component.BuildInfo // prevent unkeyed literal initialization _ struct{} } // Factory is a factory interface for connectors. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. type Factory interface { component.Factory // CreateDefaultConfig creates the default configuration for the Connector. // This method can be called multiple times depending on the pipeline // configuration and should not cause side-effects that prevent the creation // of multiple instances of the Connector. // The object returned by this method needs to pass the checks implemented by // 'configtest.CheckConfigStruct'. It is recommended to have these checks in the // tests of any implementation of the Factory interface. CreateDefaultConfig() component.Config CreateTracesToTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Traces, error) CreateTracesToMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Traces, error) CreateTracesToLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Traces, error) CreateMetricsToTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Metrics, error) CreateMetricsToMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Metrics, error) CreateMetricsToLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Metrics, error) CreateLogsToTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Logs, error) CreateLogsToMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Logs, error) CreateLogsToLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Logs, error) TracesToTracesStability() component.StabilityLevel TracesToMetricsStability() component.StabilityLevel TracesToLogsStability() component.StabilityLevel MetricsToTracesStability() component.StabilityLevel MetricsToMetricsStability() component.StabilityLevel MetricsToLogsStability() component.StabilityLevel LogsToTracesStability() component.StabilityLevel LogsToMetricsStability() component.StabilityLevel LogsToLogsStability() component.StabilityLevel unexportedFactoryFunc() } // FactoryOption applies changes to Factory. type FactoryOption interface { // apply applies the option. apply(o *factory) } var _ FactoryOption = (*factoryOptionFunc)(nil) // factoryOptionFunc is an FactoryOption created through a function. type factoryOptionFunc func(*factory) func (f factoryOptionFunc) apply(o *factory) { f(o) } // CreateTracesToTracesFunc is the equivalent of Factory.CreateTracesToTraces(). type CreateTracesToTracesFunc func(context.Context, Settings, component.Config, consumer.Traces) (Traces, error) // CreateTracesToMetricsFunc is the equivalent of Factory.CreateTracesToMetrics(). type CreateTracesToMetricsFunc func(context.Context, Settings, component.Config, consumer.Metrics) (Traces, error) // CreateTracesToLogsFunc is the equivalent of Factory.CreateTracesToLogs(). type CreateTracesToLogsFunc func(context.Context, Settings, component.Config, consumer.Logs) (Traces, error) // CreateMetricsToTracesFunc is the equivalent of Factory.CreateMetricsToTraces(). type CreateMetricsToTracesFunc func(context.Context, Settings, component.Config, consumer.Traces) (Metrics, error) // CreateMetricsToMetricsFunc is the equivalent of Factory.CreateMetricsToTraces(). type CreateMetricsToMetricsFunc func(context.Context, Settings, component.Config, consumer.Metrics) (Metrics, error) // CreateMetricsToLogsFunc is the equivalent of Factory.CreateMetricsToLogs(). type CreateMetricsToLogsFunc func(context.Context, Settings, component.Config, consumer.Logs) (Metrics, error) // CreateLogsToTracesFunc is the equivalent of Factory.CreateLogsToTraces(). type CreateLogsToTracesFunc func(context.Context, Settings, component.Config, consumer.Traces) (Logs, error) // CreateLogsToMetricsFunc is the equivalent of Factory.CreateLogsToMetrics(). type CreateLogsToMetricsFunc func(context.Context, Settings, component.Config, consumer.Metrics) (Logs, error) // CreateLogsToLogsFunc is the equivalent of Factory.CreateLogsToLogs(). type CreateLogsToLogsFunc func(context.Context, Settings, component.Config, consumer.Logs) (Logs, error) // WithTracesToTraces overrides the default "error not supported" implementation for WithTracesToTraces and the default "undefined" stability level. func WithTracesToTraces(createTracesToTraces CreateTracesToTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.tracesToTracesStabilityLevel = sl o.createTracesToTracesFunc = createTracesToTraces }) } // WithTracesToMetrics overrides the default "error not supported" implementation for WithTracesToMetrics and the default "undefined" stability level. func WithTracesToMetrics(createTracesToMetrics CreateTracesToMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.tracesToMetricsStabilityLevel = sl o.createTracesToMetricsFunc = createTracesToMetrics }) } // WithTracesToLogs overrides the default "error not supported" implementation for WithTracesToLogs and the default "undefined" stability level. func WithTracesToLogs(createTracesToLogs CreateTracesToLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.tracesToLogsStabilityLevel = sl o.createTracesToLogsFunc = createTracesToLogs }) } // WithMetricsToTraces overrides the default "error not supported" implementation for WithMetricsToTraces and the default "undefined" stability level. func WithMetricsToTraces(createMetricsToTraces CreateMetricsToTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.metricsToTracesStabilityLevel = sl o.createMetricsToTracesFunc = createMetricsToTraces }) } // WithMetricsToMetrics overrides the default "error not supported" implementation for WithMetricsToMetrics and the default "undefined" stability level. func WithMetricsToMetrics(createMetricsToMetrics CreateMetricsToMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.metricsToMetricsStabilityLevel = sl o.createMetricsToMetricsFunc = createMetricsToMetrics }) } // WithMetricsToLogs overrides the default "error not supported" implementation for WithMetricsToLogs and the default "undefined" stability level. func WithMetricsToLogs(createMetricsToLogs CreateMetricsToLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.metricsToLogsStabilityLevel = sl o.createMetricsToLogsFunc = createMetricsToLogs }) } // WithLogsToTraces overrides the default "error not supported" implementation for WithLogsToTraces and the default "undefined" stability level. func WithLogsToTraces(createLogsToTraces CreateLogsToTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.logsToTracesStabilityLevel = sl o.createLogsToTracesFunc = createLogsToTraces }) } // WithLogsToMetrics overrides the default "error not supported" implementation for WithLogsToMetrics and the default "undefined" stability level. func WithLogsToMetrics(createLogsToMetrics CreateLogsToMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.logsToMetricsStabilityLevel = sl o.createLogsToMetricsFunc = createLogsToMetrics }) } // WithLogsToLogs overrides the default "error not supported" implementation for WithLogsToLogs and the default "undefined" stability level. func WithLogsToLogs(createLogsToLogs CreateLogsToLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.logsToLogsStabilityLevel = sl o.createLogsToLogsFunc = createLogsToLogs }) } // factory implements the Factory interface. type factory struct { cfgType component.Type component.CreateDefaultConfigFunc createTracesToTracesFunc CreateTracesToTracesFunc createTracesToMetricsFunc CreateTracesToMetricsFunc createTracesToLogsFunc CreateTracesToLogsFunc createMetricsToTracesFunc CreateMetricsToTracesFunc createMetricsToMetricsFunc CreateMetricsToMetricsFunc createMetricsToLogsFunc CreateMetricsToLogsFunc createLogsToTracesFunc CreateLogsToTracesFunc createLogsToMetricsFunc CreateLogsToMetricsFunc createLogsToLogsFunc CreateLogsToLogsFunc tracesToTracesStabilityLevel component.StabilityLevel tracesToMetricsStabilityLevel component.StabilityLevel tracesToLogsStabilityLevel component.StabilityLevel metricsToTracesStabilityLevel component.StabilityLevel metricsToMetricsStabilityLevel component.StabilityLevel metricsToLogsStabilityLevel component.StabilityLevel logsToTracesStabilityLevel component.StabilityLevel logsToMetricsStabilityLevel component.StabilityLevel logsToLogsStabilityLevel component.StabilityLevel } // Type returns the type of component. func (f *factory) Type() component.Type { return f.cfgType } func (f *factory) unexportedFactoryFunc() {} func (f *factory) TracesToTracesStability() component.StabilityLevel { return f.tracesToTracesStabilityLevel } func (f *factory) TracesToMetricsStability() component.StabilityLevel { return f.tracesToMetricsStabilityLevel } func (f *factory) TracesToLogsStability() component.StabilityLevel { return f.tracesToLogsStabilityLevel } func (f *factory) MetricsToTracesStability() component.StabilityLevel { return f.metricsToTracesStabilityLevel } func (f *factory) MetricsToMetricsStability() component.StabilityLevel { return f.metricsToMetricsStabilityLevel } func (f *factory) MetricsToLogsStability() component.StabilityLevel { return f.metricsToLogsStabilityLevel } func (f *factory) LogsToTracesStability() component.StabilityLevel { return f.logsToTracesStabilityLevel } func (f *factory) LogsToMetricsStability() component.StabilityLevel { return f.logsToMetricsStabilityLevel } func (f *factory) LogsToLogsStability() component.StabilityLevel { return f.logsToLogsStabilityLevel } func (f *factory) CreateTracesToTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Traces, error) { if f.createTracesToTracesFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalTraces, pipeline.SignalTraces) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createTracesToTracesFunc(ctx, set, cfg, next) } func (f *factory) CreateTracesToMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Traces, error) { if f.createTracesToMetricsFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalTraces, pipeline.SignalMetrics) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createTracesToMetricsFunc(ctx, set, cfg, next) } func (f *factory) CreateTracesToLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Traces, error) { if f.createTracesToLogsFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalTraces, pipeline.SignalLogs) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createTracesToLogsFunc(ctx, set, cfg, next) } func (f *factory) CreateMetricsToTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Metrics, error) { if f.createMetricsToTracesFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalMetrics, pipeline.SignalTraces) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createMetricsToTracesFunc(ctx, set, cfg, next) } func (f *factory) CreateMetricsToMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Metrics, error) { if f.createMetricsToMetricsFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalMetrics, pipeline.SignalMetrics) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createMetricsToMetricsFunc(ctx, set, cfg, next) } func (f *factory) CreateMetricsToLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Metrics, error) { if f.createMetricsToLogsFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalMetrics, pipeline.SignalLogs) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createMetricsToLogsFunc(ctx, set, cfg, next) } func (f *factory) CreateLogsToTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Logs, error) { if f.createLogsToTracesFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalLogs, pipeline.SignalTraces) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createLogsToTracesFunc(ctx, set, cfg, next) } func (f *factory) CreateLogsToMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Logs, error) { if f.createLogsToMetricsFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalLogs, pipeline.SignalMetrics) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createLogsToMetricsFunc(ctx, set, cfg, next) } func (f *factory) CreateLogsToLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Logs, error) { if f.createLogsToLogsFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalLogs, pipeline.SignalLogs) } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createLogsToLogsFunc(ctx, set, cfg, next) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { f := &factory{ cfgType: cfgType, CreateDefaultConfigFunc: createDefaultConfig, } for _, opt := range options { opt.apply(f) } return f } opentelemetry-collector-0.141.0/connector/connector_test.go000066400000000000000000000315041511331344600241130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector // import "go.opentelemetry.io/collector/connector" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pipeline" ) var ( testType = component.MustNewType("test") testID = component.MustNewIDWithName("test", "name") ) func TestNewFactoryNoOptions(t *testing.T) { defaultCfg := struct{}{} factory := NewFactory(testType, func() component.Config { return &defaultCfg }) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) _, err := factory.CreateTracesToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalTraces, pipeline.SignalTraces)) _, err = factory.CreateTracesToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalTraces, pipeline.SignalMetrics)) _, err = factory.CreateTracesToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalTraces, pipeline.SignalLogs)) _, err = factory.CreateMetricsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalMetrics, pipeline.SignalTraces)) _, err = factory.CreateMetricsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalMetrics, pipeline.SignalMetrics)) _, err = factory.CreateMetricsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalMetrics, pipeline.SignalLogs)) _, err = factory.CreateLogsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalLogs, pipeline.SignalTraces)) _, err = factory.CreateLogsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalLogs, pipeline.SignalMetrics)) _, err = factory.CreateLogsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalLogs, pipeline.SignalLogs)) } func TestNewFactoryWithSameTypes(t *testing.T) { defaultCfg := struct{}{} factory := NewFactory(testType, func() component.Config { return &defaultCfg }, WithTracesToTraces(createTracesToTraces, component.StabilityLevelAlpha), WithMetricsToMetrics(createMetricsToMetrics, component.StabilityLevelBeta), WithLogsToLogs(createLogsToLogs, component.StabilityLevelUnmaintained)) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) wrongID := component.MustNewID("wrong") wrongIDErrStr := internal.ErrIDMismatch(wrongID, testType).Error() assert.Equal(t, component.StabilityLevelAlpha, factory.TracesToTracesStability()) _, err := factory.CreateTracesToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) _, err = factory.CreateTracesToTraces(context.Background(), Settings{ID: wrongID}, &defaultCfg, consumertest.NewNop()) require.ErrorContains(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelBeta, factory.MetricsToMetricsStability()) _, err = factory.CreateMetricsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) _, err = factory.CreateMetricsToMetrics(context.Background(), Settings{ID: wrongID}, &defaultCfg, consumertest.NewNop()) require.ErrorContains(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelUnmaintained, factory.LogsToLogsStability()) _, err = factory.CreateLogsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) _, err = factory.CreateLogsToLogs(context.Background(), Settings{ID: wrongID}, &defaultCfg, consumertest.NewNop()) require.ErrorContains(t, err, wrongIDErrStr) _, err = factory.CreateTracesToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalTraces, pipeline.SignalMetrics)) _, err = factory.CreateTracesToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalTraces, pipeline.SignalLogs)) _, err = factory.CreateMetricsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalMetrics, pipeline.SignalTraces)) _, err = factory.CreateMetricsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalMetrics, pipeline.SignalLogs)) _, err = factory.CreateLogsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalLogs, pipeline.SignalTraces)) _, err = factory.CreateLogsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalLogs, pipeline.SignalMetrics)) } func TestNewFactoryWithTranslateTypes(t *testing.T) { defaultCfg := struct{}{} factory := NewFactory(testType, func() component.Config { return &defaultCfg }, WithTracesToMetrics(createTracesToMetrics, component.StabilityLevelDevelopment), WithTracesToLogs(createTracesToLogs, component.StabilityLevelAlpha), WithMetricsToTraces(createMetricsToTraces, component.StabilityLevelBeta), WithMetricsToLogs(createMetricsToLogs, component.StabilityLevelStable), WithLogsToTraces(createLogsToTraces, component.StabilityLevelDeprecated), WithLogsToMetrics(createLogsToMetrics, component.StabilityLevelUnmaintained)) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) _, err := factory.CreateTracesToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalTraces, pipeline.SignalTraces)) _, err = factory.CreateMetricsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalMetrics, pipeline.SignalMetrics)) _, err = factory.CreateLogsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalLogs, pipeline.SignalLogs)) assert.Equal(t, component.StabilityLevelDevelopment, factory.TracesToMetricsStability()) _, err = factory.CreateTracesToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelAlpha, factory.TracesToLogsStability()) _, err = factory.CreateTracesToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelBeta, factory.MetricsToTracesStability()) _, err = factory.CreateMetricsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelStable, factory.MetricsToLogsStability()) _, err = factory.CreateMetricsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelDeprecated, factory.LogsToTracesStability()) _, err = factory.CreateLogsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelUnmaintained, factory.LogsToMetricsStability()) _, err = factory.CreateLogsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.NoError(t, err) } func TestNewFactoryWithAllTypes(t *testing.T) { defaultCfg := struct{}{} factory := NewFactory(testType, func() component.Config { return &defaultCfg }, WithTracesToTraces(createTracesToTraces, component.StabilityLevelAlpha), WithTracesToMetrics(createTracesToMetrics, component.StabilityLevelDevelopment), WithTracesToLogs(createTracesToLogs, component.StabilityLevelAlpha), WithMetricsToTraces(createMetricsToTraces, component.StabilityLevelBeta), WithMetricsToMetrics(createMetricsToMetrics, component.StabilityLevelBeta), WithMetricsToLogs(createMetricsToLogs, component.StabilityLevelStable), WithLogsToTraces(createLogsToTraces, component.StabilityLevelDeprecated), WithLogsToMetrics(createLogsToMetrics, component.StabilityLevelUnmaintained), WithLogsToLogs(createLogsToLogs, component.StabilityLevelUnmaintained)) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelAlpha, factory.TracesToTracesStability()) _, err := factory.CreateTracesToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelDevelopment, factory.TracesToMetricsStability()) _, err = factory.CreateTracesToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelAlpha, factory.TracesToLogsStability()) _, err = factory.CreateTracesToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelBeta, factory.MetricsToTracesStability()) _, err = factory.CreateMetricsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelBeta, factory.MetricsToMetricsStability()) _, err = factory.CreateMetricsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelStable, factory.MetricsToLogsStability()) _, err = factory.CreateMetricsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelDeprecated, factory.LogsToTracesStability()) _, err = factory.CreateLogsToTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelUnmaintained, factory.LogsToMetricsStability()) _, err = factory.CreateLogsToMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelUnmaintained, factory.LogsToLogsStability()) _, err = factory.CreateLogsToLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.NoError(t, err) } var nopInstance = &nopConnector{ Consumer: consumertest.NewNop(), } // nopConnector stores consumed traces and metrics for testing purposes. type nopConnector struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createTracesToTraces(context.Context, Settings, component.Config, consumer.Traces) (Traces, error) { return nopInstance, nil } func createTracesToMetrics(context.Context, Settings, component.Config, consumer.Metrics) (Traces, error) { return nopInstance, nil } func createTracesToLogs(context.Context, Settings, component.Config, consumer.Logs) (Traces, error) { return nopInstance, nil } func createMetricsToTraces(context.Context, Settings, component.Config, consumer.Traces) (Metrics, error) { return nopInstance, nil } func createMetricsToMetrics(context.Context, Settings, component.Config, consumer.Metrics) (Metrics, error) { return nopInstance, nil } func createMetricsToLogs(context.Context, Settings, component.Config, consumer.Logs) (Metrics, error) { return nopInstance, nil } func createLogsToTraces(context.Context, Settings, component.Config, consumer.Traces) (Logs, error) { return nopInstance, nil } func createLogsToMetrics(context.Context, Settings, component.Config, consumer.Metrics) (Logs, error) { return nopInstance, nil } func createLogsToLogs(context.Context, Settings, component.Config, consumer.Logs) (Logs, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/connector/connectortest/000077500000000000000000000000001511331344600234225ustar00rootroot00000000000000opentelemetry-collector-0.141.0/connector/connectortest/Makefile000066400000000000000000000000361511331344600250610ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/connector/connectortest/connector.go000066400000000000000000000140401511331344600257420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connectortest // import "go.opentelemetry.io/collector/connector/connectortest" import ( "context" "github.com/google/uuid" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" ) var NopType = component.MustNewType("nop") // NewNopSettings returns a new nop settings for Create* functions with the given type. func NewNopSettings(typ component.Type) connector.Settings { return connector.Settings{ ID: component.NewIDWithName(typ, uuid.NewString()), TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } type nopConfig struct{} // NewNopFactory returns a connector.Factory that constructs nop processors. func NewNopFactory() connector.Factory { return xconnector.NewFactory( NopType, func() component.Config { return &nopConfig{} }, xconnector.WithTracesToTraces(createTracesToTracesConnector, component.StabilityLevelDevelopment), xconnector.WithTracesToMetrics(createTracesToMetricsConnector, component.StabilityLevelDevelopment), xconnector.WithTracesToLogs(createTracesToLogsConnector, component.StabilityLevelDevelopment), xconnector.WithTracesToProfiles(createTracesToProfilesConnector, component.StabilityLevelAlpha), xconnector.WithMetricsToTraces(createMetricsToTracesConnector, component.StabilityLevelDevelopment), xconnector.WithMetricsToMetrics(createMetricsToMetricsConnector, component.StabilityLevelDevelopment), xconnector.WithMetricsToLogs(createMetricsToLogsConnector, component.StabilityLevelDevelopment), xconnector.WithMetricsToProfiles(createMetricsToProfilesConnector, component.StabilityLevelAlpha), xconnector.WithLogsToTraces(createLogsToTracesConnector, component.StabilityLevelDevelopment), xconnector.WithLogsToMetrics(createLogsToMetricsConnector, component.StabilityLevelDevelopment), xconnector.WithLogsToLogs(createLogsToLogsConnector, component.StabilityLevelDevelopment), xconnector.WithLogsToProfiles(createLogsToProfilesConnector, component.StabilityLevelAlpha), xconnector.WithProfilesToTraces(createProfilesToTracesConnector, component.StabilityLevelAlpha), xconnector.WithProfilesToMetrics(createProfilesToMetricsConnector, component.StabilityLevelAlpha), xconnector.WithProfilesToLogs(createProfilesToLogsConnector, component.StabilityLevelAlpha), xconnector.WithProfilesToProfiles(createProfilesToProfilesConnector, component.StabilityLevelAlpha), ) } func createTracesToTracesConnector(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Traces, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createTracesToMetricsConnector(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Traces, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createTracesToLogsConnector(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Traces, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createTracesToProfilesConnector(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Traces, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createMetricsToTracesConnector(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Metrics, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createMetricsToMetricsConnector(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Metrics, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createMetricsToLogsConnector(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Metrics, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createMetricsToProfilesConnector(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Metrics, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createLogsToTracesConnector(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Logs, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createLogsToMetricsConnector(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Logs, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createLogsToLogsConnector(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Logs, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createLogsToProfilesConnector(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Logs, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createProfilesToTracesConnector(context.Context, connector.Settings, component.Config, consumer.Traces) (xconnector.Profiles, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createProfilesToMetricsConnector(context.Context, connector.Settings, component.Config, consumer.Metrics) (xconnector.Profiles, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createProfilesToLogsConnector(context.Context, connector.Settings, component.Config, consumer.Logs) (xconnector.Profiles, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } func createProfilesToProfilesConnector(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (xconnector.Profiles, error) { return &nopConnector{Consumer: consumertest.NewNop()}, nil } // nopConnector stores consumed traces and metrics for testing purposes. type nopConnector struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } opentelemetry-collector-0.141.0/connector/connectortest/connector_test.go000066400000000000000000000164771511331344600270210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connectortest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestNewNopConnectorFactory(t *testing.T) { factory := NewNopFactory() require.NotNil(t, factory) assert.Equal(t, component.MustNewType("nop"), factory.Type()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &nopConfig{}, cfg) tracesToTraces, err := factory.CreateTracesToTraces(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, tracesToTraces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tracesToTraces.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, tracesToTraces.Shutdown(context.Background())) tracesToMetrics, err := factory.CreateTracesToMetrics(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, tracesToMetrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tracesToMetrics.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, tracesToMetrics.Shutdown(context.Background())) tracesToLogs, err := factory.CreateTracesToLogs(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, tracesToLogs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tracesToLogs.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, tracesToLogs.Shutdown(context.Background())) tracesToProfiles, err := factory.(xconnector.Factory).CreateTracesToProfiles(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, tracesToProfiles.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tracesToProfiles.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, tracesToProfiles.Shutdown(context.Background())) metricsToTraces, err := factory.CreateMetricsToTraces(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, metricsToTraces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metricsToTraces.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metricsToTraces.Shutdown(context.Background())) metricsToMetrics, err := factory.CreateMetricsToMetrics(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, metricsToMetrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metricsToMetrics.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metricsToMetrics.Shutdown(context.Background())) metricsToLogs, err := factory.CreateMetricsToLogs(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, metricsToLogs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metricsToLogs.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metricsToLogs.Shutdown(context.Background())) metricsToProfiles, err := factory.(xconnector.Factory).CreateMetricsToProfiles(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, metricsToProfiles.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metricsToProfiles.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metricsToProfiles.Shutdown(context.Background())) logsToTraces, err := factory.CreateLogsToTraces(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, logsToTraces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logsToTraces.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logsToTraces.Shutdown(context.Background())) logsToMetrics, err := factory.CreateLogsToMetrics(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, logsToMetrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logsToMetrics.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logsToMetrics.Shutdown(context.Background())) logsToLogs, err := factory.CreateLogsToLogs(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, logsToLogs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logsToLogs.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logsToLogs.Shutdown(context.Background())) logsToProfiles, err := factory.(xconnector.Factory).CreateLogsToProfiles(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, logsToProfiles.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logsToProfiles.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logsToProfiles.Shutdown(context.Background())) profilesToTraces, err := factory.(xconnector.Factory).CreateProfilesToTraces(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, profilesToTraces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, profilesToTraces.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, profilesToTraces.Shutdown(context.Background())) profilesToMetrics, err := factory.(xconnector.Factory).CreateProfilesToMetrics(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, profilesToMetrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, profilesToMetrics.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, profilesToMetrics.Shutdown(context.Background())) profilesToLogs, err := factory.(xconnector.Factory).CreateProfilesToProfiles(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, profilesToLogs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, profilesToLogs.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, profilesToLogs.Shutdown(context.Background())) profilesToProfiles, err := factory.(xconnector.Factory).CreateProfilesToProfiles(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, profilesToProfiles.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, profilesToProfiles.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, profilesToProfiles.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/connector/connectortest/go.mod000066400000000000000000000057341511331344600245410ustar00rootroot00000000000000module go.opentelemetry.io/collector/connector/connectortest go 1.24.0 require ( github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/connector/xconnector v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/connector => ../../connector replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/connector/xconnector => ../xconnector replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/connector/connectortest/go.sum000066400000000000000000000140451511331344600245610ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/connector/connectortest/package_test.go000066400000000000000000000003161511331344600264030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connectortest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/connector/forwardconnector/000077500000000000000000000000001511331344600241075ustar00rootroot00000000000000opentelemetry-collector-0.141.0/connector/forwardconnector/Makefile000066400000000000000000000000361511331344600255460ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/connector/forwardconnector/README.md000066400000000000000000000075701511331344600253770ustar00rootroot00000000000000# Forward Connector | Status | | | ------------- |-----------| | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aconnector%2Fforward%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aconnector%2Fforward) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aconnector%2Fforward%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aconnector%2Fforward) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [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 ## Supported Pipeline Types | [Exporter Pipeline Type] | [Receiver Pipeline Type] | [Stability Level] | | ------------------------ | ------------------------ | ----------------- | | profiles | profiles | [development] | | traces | traces | [beta] | | metrics | metrics | [beta] | | logs | logs | [beta] | [Exporter Pipeline Type]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/connector/README.md#exporter-pipeline-type [Receiver Pipeline Type]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/connector/README.md#receiver-pipeline-type [Stability Level]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stability-levels The `forward` connector can merge or fork pipelines of the same type. ## Configuration If you are not already familiar with connectors, you may find it helpful to first visit the [Connectors README]. The `forward` connector does not have any configuration settings. ```yaml receivers: foo: exporters: bar: connectors: forward: ``` ### Example Usage Annotate distinct log streams, then merge them together, and export. ```yaml receivers: foo/blue: foo/green: processors: attributes/blue: attributes/green: exporters: bar: connectors: forward: service: pipelines: logs/blue: receivers: [foo/blue] processors: [attributes/blue] exporters: [forward] logs/green: receivers: [foo/green] processors: [attributes/green] exporters: [forward] logs: receivers: [forward] exporters: [bar] ``` Preprocess data, then replicate and handle in distinct ways. ```yaml receivers: foo: processors: resourcedetection: sample: attributes: exporters: bar/hot: bar/cold: connectors: forward: service: pipelines: traces: receivers: [foo] processors: [resourcedetection] exporters: [forward] traces/hot: receivers: [forward] processors: [sample] exporters: [bar/hot] traces/cold: receivers: [forward] processors: [attributes] exporters: [bar/cold] ``` Add a temporary debugging exporter. (Uncomment to enable.) ```yaml receivers: foo: processors: filter: exporters: bar: # connectors: # forward: service: pipelines: traces: receivers: - foo processors: - filter exporters: - bar # - forward # traces/log: # receivers: [forward] # exporters: [debug] ``` [Connectors README]:../README.md opentelemetry-collector-0.141.0/connector/forwardconnector/doc.go000066400000000000000000000004341511331344600252040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package forwardconnector passes signals from one pipeline to another. package forwardconnector // import "go.opentelemetry.io/collector/connector/forwardconnector" opentelemetry-collector-0.141.0/connector/forwardconnector/forward.go000066400000000000000000000053011511331344600261010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package forwardconnector // import "go.opentelemetry.io/collector/connector/forwardconnector" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/forwardconnector/internal/metadata" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" ) // NewFactory returns a connector.Factory. func NewFactory() xconnector.Factory { return xconnector.NewFactory( metadata.Type, createDefaultConfig, xconnector.WithTracesToTraces(createTracesToTraces, metadata.TracesToTracesStability), xconnector.WithMetricsToMetrics(createMetricsToMetrics, metadata.MetricsToMetricsStability), xconnector.WithLogsToLogs(createLogsToLogs, metadata.LogsToLogsStability), xconnector.WithProfilesToProfiles(createProfilesToProfiles, metadata.ProfilesToProfilesStability), ) } type Config struct{} // createDefaultConfig creates the default configuration. func createDefaultConfig() component.Config { return &Config{} } // createTracesToTraces creates a trace receiver based on provided config. func createTracesToTraces( _ context.Context, _ connector.Settings, _ component.Config, nextConsumer consumer.Traces, ) (connector.Traces, error) { return &forward{Traces: nextConsumer}, nil } // createMetricsToMetrics creates a metrics receiver based on provided config. func createMetricsToMetrics( _ context.Context, _ connector.Settings, _ component.Config, nextConsumer consumer.Metrics, ) (connector.Metrics, error) { return &forward{Metrics: nextConsumer}, nil } // createLogsToLogs creates a log receiver based on provided config. func createLogsToLogs( _ context.Context, _ connector.Settings, _ component.Config, nextConsumer consumer.Logs, ) (connector.Logs, error) { return &forward{Logs: nextConsumer}, nil } // createProfilesToProfiles creates a profile receiver based on provided config. func createProfilesToProfiles( _ context.Context, _ connector.Settings, _ component.Config, nextConsumer xconsumer.Profiles, ) (xconnector.Profiles, error) { return &forward{Profiles: nextConsumer}, nil } // forward is used to pass signals directly from one pipeline to another. // This is useful when there is a need to replicate data and process it in more // than one way. It can also be used to join pipelines together. type forward struct { consumer.Traces consumer.Metrics consumer.Logs xconsumer.Profiles component.StartFunc component.ShutdownFunc } func (c *forward) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: false} } opentelemetry-collector-0.141.0/connector/forwardconnector/forward_test.go000066400000000000000000000050711511331344600271440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package forwardconnector import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestForward(t *testing.T) { f := NewFactory() cfg := f.CreateDefaultConfig() assert.Equal(t, &Config{}, cfg) ctx := context.Background() set := connectortest.NewNopSettings(f.Type()) host := componenttest.NewNopHost() tracesSink := new(consumertest.TracesSink) tracesToTraces, err := f.CreateTracesToTraces(ctx, set, cfg, tracesSink) require.NoError(t, err) assert.NotNil(t, tracesToTraces) metricsSink := new(consumertest.MetricsSink) metricsToMetrics, err := f.CreateMetricsToMetrics(ctx, set, cfg, metricsSink) require.NoError(t, err) assert.NotNil(t, metricsToMetrics) logsSink := new(consumertest.LogsSink) logsToLogs, err := f.CreateLogsToLogs(ctx, set, cfg, logsSink) require.NoError(t, err) assert.NotNil(t, logsToLogs) profilesSink := new(consumertest.ProfilesSink) profilesToProfiles, err := f.CreateProfilesToProfiles(ctx, set, cfg, profilesSink) require.NoError(t, err) assert.NotNil(t, profilesToProfiles) assert.NoError(t, tracesToTraces.Start(ctx, host)) assert.NoError(t, metricsToMetrics.Start(ctx, host)) assert.NoError(t, logsToLogs.Start(ctx, host)) assert.NoError(t, profilesToProfiles.Start(ctx, host)) assert.NoError(t, tracesToTraces.ConsumeTraces(ctx, ptrace.NewTraces())) assert.NoError(t, metricsToMetrics.ConsumeMetrics(ctx, pmetric.NewMetrics())) assert.NoError(t, metricsToMetrics.ConsumeMetrics(ctx, pmetric.NewMetrics())) assert.NoError(t, logsToLogs.ConsumeLogs(ctx, plog.NewLogs())) assert.NoError(t, logsToLogs.ConsumeLogs(ctx, plog.NewLogs())) assert.NoError(t, logsToLogs.ConsumeLogs(ctx, plog.NewLogs())) assert.NoError(t, profilesToProfiles.ConsumeProfiles(ctx, pprofile.NewProfiles())) assert.NoError(t, tracesToTraces.Shutdown(ctx)) assert.NoError(t, metricsToMetrics.Shutdown(ctx)) assert.NoError(t, logsToLogs.Shutdown(ctx)) assert.NoError(t, profilesToProfiles.Shutdown(ctx)) assert.Len(t, tracesSink.AllTraces(), 1) assert.Len(t, metricsSink.AllMetrics(), 2) assert.Len(t, logsSink.AllLogs(), 3) assert.Len(t, profilesSink.AllProfiles(), 1) } opentelemetry-collector-0.141.0/connector/forwardconnector/generated_component_test.go000066400000000000000000000070371511331344600315240ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package forwardconnector import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pipeline" ) var typ = component.MustNewType("forward") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs_to_logs", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewLogsRouter(map[pipeline.ID]consumer.Logs{pipeline.NewID(pipeline.SignalLogs): consumertest.NewNop()}) return factory.CreateLogsToLogs(ctx, set, cfg, router) }, }, { name: "metrics_to_metrics", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewMetricsRouter(map[pipeline.ID]consumer.Metrics{pipeline.NewID(pipeline.SignalMetrics): consumertest.NewNop()}) return factory.CreateMetricsToMetrics(ctx, set, cfg, router) }, }, { name: "traces_to_traces", createFn: func(ctx context.Context, set connector.Settings, cfg component.Config) (component.Component, error) { router := connector.NewTracesRouter(map[pipeline.ID]consumer.Traces{pipeline.NewID(pipeline.SignalTraces): consumertest.NewNop()}) return factory.CreateTracesToTraces(ctx, set, cfg, router) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstConnector.Start(context.Background(), host)) require.NoError(t, firstConnector.Shutdown(context.Background())) secondConnector, err := tt.createFn(context.Background(), connectortest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondConnector.Start(context.Background(), host)) require.NoError(t, secondConnector.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/connector/forwardconnector/generated_package_test.go000066400000000000000000000002571511331344600311120ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package forwardconnector import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/connector/forwardconnector/go.mod000066400000000000000000000073421511331344600252230ustar00rootroot00000000000000module go.opentelemetry.io/collector/connector/forwardconnector go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/connector/connectortest v0.141.0 go.opentelemetry.io/collector/connector/xconnector v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.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/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/connector => ../ replace go.opentelemetry.io/collector/connector/connectortest => ../connectortest replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/confmap => ../../confmap retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/connector/xconnector => ../xconnector replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/connector/forwardconnector/go.sum000066400000000000000000000166571511331344600252610ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/connector/forwardconnector/internal/000077500000000000000000000000001511331344600257235ustar00rootroot00000000000000opentelemetry-collector-0.141.0/connector/forwardconnector/internal/metadata/000077500000000000000000000000001511331344600275035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/connector/forwardconnector/internal/metadata/generated_status.go000066400000000000000000000007661511331344600334040ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("forward") ScopeName = "go.opentelemetry.io/collector/connector/forwardconnector" ) const ( ProfilesToProfilesStability = component.StabilityLevelDevelopment TracesToTracesStability = component.StabilityLevelBeta MetricsToMetricsStability = component.StabilityLevelBeta LogsToLogsStability = component.StabilityLevelBeta ) opentelemetry-collector-0.141.0/connector/forwardconnector/metadata.yaml000066400000000000000000000004311511331344600265510ustar00rootroot00000000000000type: forward github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: connector stability: development: [profiles_to_profiles] beta: [traces_to_traces, metrics_to_metrics, logs_to_logs] distributions: [core, contrib, k8s] opentelemetry-collector-0.141.0/connector/go.mod000066400000000000000000000041421511331344600216370ustar00rootroot00000000000000module go.opentelemetry.io/collector/connector go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/consumer => ../consumer replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../consumer/consumertest replace go.opentelemetry.io/collector/pipeline => ../pipeline replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../internal/fanoutconsumer replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/connector/go.sum000066400000000000000000000124431511331344600216670ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/connector/internal/000077500000000000000000000000001511331344600223445ustar00rootroot00000000000000opentelemetry-collector-0.141.0/connector/internal/factory.go000066400000000000000000000011411511331344600243370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/connector/internal" import ( "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pipeline" ) func ErrDataTypes(id component.ID, from, to pipeline.Signal) error { return fmt.Errorf("connector %q cannot connect from %s to %s: %w", id, from, to, pipeline.ErrSignalNotSupported) } func ErrIDMismatch(id component.ID, typ component.Type) error { return fmt.Errorf("component type mismatch: component ID %q does not have type %q", id, typ) } opentelemetry-collector-0.141.0/connector/internal/router.go000066400000000000000000000025101511331344600242110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/connector/internal" import ( "errors" "fmt" "maps" "go.uber.org/multierr" "go.opentelemetry.io/collector/pipeline" ) type BaseRouter[T any] struct { fanout func([]T) T Consumers map[pipeline.ID]T } func NewBaseRouter[T any](fanout func([]T) T, cm map[pipeline.ID]T) BaseRouter[T] { consumers := make(map[pipeline.ID]T, len(cm)) maps.Copy(consumers, cm) return BaseRouter[T]{fanout: fanout, Consumers: consumers} } func (r *BaseRouter[T]) PipelineIDs() []pipeline.ID { ids := make([]pipeline.ID, 0, len(r.Consumers)) for id := range r.Consumers { ids = append(ids, id) } return ids } func (r *BaseRouter[T]) Consumer(pipelineIDs ...pipeline.ID) (T, error) { var ret T if len(pipelineIDs) == 0 { return ret, errors.New("missing consumers") } consumers := make([]T, 0, len(pipelineIDs)) var errors error for _, pipelineID := range pipelineIDs { c, ok := r.Consumers[pipelineID] if ok { consumers = append(consumers, c) } else { errors = multierr.Append(errors, fmt.Errorf("missing consumer: %q", pipelineID)) } } if errors != nil { // TODO potentially this could return a NewTraces with the valid consumers return ret, errors } return r.fanout(consumers), nil } opentelemetry-collector-0.141.0/connector/logs_router.go000066400000000000000000000035451511331344600234320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector // import "go.opentelemetry.io/collector/connector" import ( "errors" "fmt" "go.uber.org/multierr" "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/internal/fanoutconsumer" "go.opentelemetry.io/collector/pipeline" ) // LogsRouterAndConsumer feeds the first consumer.Logs in each of the specified pipelines. type LogsRouterAndConsumer interface { consumer.Logs Consumer(...pipeline.ID) (consumer.Logs, error) PipelineIDs() []pipeline.ID privateFunc() } type logsRouter struct { consumer.Logs internal.BaseRouter[consumer.Logs] } func NewLogsRouter(cm map[pipeline.ID]consumer.Logs) LogsRouterAndConsumer { consumers := make([]consumer.Logs, 0, len(cm)) for _, cons := range cm { consumers = append(consumers, cons) } return &logsRouter{ Logs: fanoutconsumer.NewLogs(consumers), BaseRouter: internal.NewBaseRouter(fanoutconsumer.NewLogs, cm), } } func (r *logsRouter) PipelineIDs() []pipeline.ID { ids := make([]pipeline.ID, 0, len(r.Consumers)) for id := range r.Consumers { ids = append(ids, id) } return ids } func (r *logsRouter) Consumer(pipelineIDs ...pipeline.ID) (consumer.Logs, error) { if len(pipelineIDs) == 0 { return nil, errors.New("missing consumers") } consumers := make([]consumer.Logs, 0, len(pipelineIDs)) var errors error for _, pipelineID := range pipelineIDs { c, ok := r.Consumers[pipelineID] if ok { consumers = append(consumers, c) } else { errors = multierr.Append(errors, fmt.Errorf("missing consumer: %q", pipelineID)) } } if errors != nil { // TODO potentially this could return a NewLogs with the valid consumers return nil, errors } return fanoutconsumer.NewLogs(consumers), nil } func (r *logsRouter) privateFunc() {} opentelemetry-collector-0.141.0/connector/logs_router_test.go000066400000000000000000000103701511331344600244630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector import ( "context" "fmt" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pipeline" ) type mutatingLogsSink struct { *consumertest.LogsSink } func (mts *mutatingLogsSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } func TestLogsRouterMultiplexing(t *testing.T) { num := 20 for numIDs := 1; numIDs < num; numIDs++ { for numCons := 1; numCons < num; numCons++ { for numLogs := 1; numLogs < num; numLogs++ { t.Run( fmt.Sprintf("%d-ids/%d-cons/%d-logs", numIDs, numCons, numLogs), fuzzLogs(numIDs, numCons, numLogs), ) } } } } func fuzzLogs(numIDs, numCons, numLogs int) func(*testing.T) { return func(t *testing.T) { allIDs := make([]pipeline.ID, 0, numCons) allCons := make([]consumer.Logs, 0, numCons) allConsMap := make(map[pipeline.ID]consumer.Logs) // If any consumer is mutating, the router must report mutating for i := range numCons { allIDs = append(allIDs, pipeline.NewIDWithName(pipeline.SignalLogs, "sink_"+strconv.Itoa(numCons))) // Random chance for each consumer to be mutating if (numCons+numLogs+i)%4 == 0 { allCons = append(allCons, &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)}) } else { allCons = append(allCons, new(consumertest.LogsSink)) } allConsMap[allIDs[i]] = allCons[i] } r := NewLogsRouter(allConsMap) ld := testdata.GenerateLogs(1) // Keep track of how many logs each consumer should receive. // This will be validated after every call to RouteLogs. expected := make(map[pipeline.ID]int, numCons) for i := range numLogs { // Build a random set of ids (no duplicates) randCons := make(map[pipeline.ID]bool, numIDs) for j := range numIDs { // This number should be pretty random and less than numCons conNum := (numCons + numIDs + i + j) % numCons randCons[allIDs[conNum]] = true } // Convert to slice, update expectations conIDs := make([]pipeline.ID, 0, len(randCons)) for id := range randCons { conIDs = append(conIDs, id) expected[id]++ } // Route to list of consumers fanout, err := r.Consumer(conIDs...) assert.NoError(t, err) assert.NoError(t, fanout.ConsumeLogs(context.Background(), ld)) // Validate expectations for all consumers for id := range expected { logs := []plog.Logs{} switch con := allConsMap[id].(type) { case *consumertest.LogsSink: logs = con.AllLogs() case *mutatingLogsSink: logs = con.AllLogs() } assert.Len(t, logs, expected[id]) for n := 0; n < len(logs); n++ { assert.Equal(t, ld, logs[n]) } } } } } func TestLogsRouterConsumers(t *testing.T) { ctx := context.Background() ld := testdata.GenerateLogs(1) fooID := pipeline.NewIDWithName(pipeline.SignalLogs, "foo") barID := pipeline.NewIDWithName(pipeline.SignalLogs, "bar") foo := new(consumertest.LogsSink) bar := new(consumertest.LogsSink) r := NewLogsRouter(map[pipeline.ID]consumer.Logs{fooID: foo, barID: bar}) rcs := r.PipelineIDs() assert.Len(t, rcs, 2) assert.ElementsMatch(t, []pipeline.ID{fooID, barID}, rcs) assert.Empty(t, foo.AllLogs()) assert.Empty(t, bar.AllLogs()) both, err := r.Consumer(fooID, barID) assert.NotNil(t, both) assert.NoError(t, err) assert.NoError(t, both.ConsumeLogs(ctx, ld)) assert.Len(t, foo.AllLogs(), 1) assert.Len(t, bar.AllLogs(), 1) fooOnly, err := r.Consumer(fooID) assert.NotNil(t, fooOnly) assert.NoError(t, err) assert.NoError(t, fooOnly.ConsumeLogs(ctx, ld)) assert.Len(t, foo.AllLogs(), 2) assert.Len(t, bar.AllLogs(), 1) barOnly, err := r.Consumer(barID) assert.NotNil(t, barOnly) assert.NoError(t, err) assert.NoError(t, barOnly.ConsumeLogs(ctx, ld)) assert.Len(t, foo.AllLogs(), 2) assert.Len(t, bar.AllLogs(), 2) none, err := r.Consumer() assert.Nil(t, none) require.Error(t, err) fake, err := r.Consumer(pipeline.NewIDWithName(pipeline.SignalLogs, "fake")) assert.Nil(t, fake) assert.Error(t, err) } opentelemetry-collector-0.141.0/connector/metrics_router.go000066400000000000000000000021101511331344600241170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector // import "go.opentelemetry.io/collector/connector" import ( "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/internal/fanoutconsumer" "go.opentelemetry.io/collector/pipeline" ) // MetricsRouterAndConsumer feeds the first consumer.Metrics in each of the specified pipelines. type MetricsRouterAndConsumer interface { consumer.Metrics Consumer(...pipeline.ID) (consumer.Metrics, error) PipelineIDs() []pipeline.ID privateFunc() } type metricsRouter struct { consumer.Metrics internal.BaseRouter[consumer.Metrics] } func NewMetricsRouter(cm map[pipeline.ID]consumer.Metrics) MetricsRouterAndConsumer { consumers := make([]consumer.Metrics, 0, len(cm)) for _, cons := range cm { consumers = append(consumers, cons) } return &metricsRouter{ Metrics: fanoutconsumer.NewMetrics(consumers), BaseRouter: internal.NewBaseRouter(fanoutconsumer.NewMetrics, cm), } } func (r *metricsRouter) privateFunc() {} opentelemetry-collector-0.141.0/connector/metrics_router_test.go000066400000000000000000000106461511331344600251730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector import ( "context" "fmt" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pipeline" ) type mutatingMetricsSink struct { *consumertest.MetricsSink } func (mts *mutatingMetricsSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } func TestMetricsRouterMultiplexing(t *testing.T) { num := 20 for numIDs := 1; numIDs < num; numIDs++ { for numCons := 1; numCons < num; numCons++ { for numMetrics := 1; numMetrics < num; numMetrics++ { t.Run( fmt.Sprintf("%d-ids/%d-cons/%d-logs", numIDs, numCons, numMetrics), fuzzMetrics(numIDs, numCons, numMetrics), ) } } } } func fuzzMetrics(numIDs, numCons, numMetrics int) func(*testing.T) { return func(t *testing.T) { allIDs := make([]pipeline.ID, 0, numCons) allCons := make([]consumer.Metrics, 0, numCons) allConsMap := make(map[pipeline.ID]consumer.Metrics) // If any consumer is mutating, the router must report mutating for i := range numCons { allIDs = append(allIDs, pipeline.NewIDWithName(pipeline.SignalMetrics, "sink_"+strconv.Itoa(numCons))) // Random chance for each consumer to be mutating if (numCons+numMetrics+i)%4 == 0 { allCons = append(allCons, &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)}) } else { allCons = append(allCons, new(consumertest.MetricsSink)) } allConsMap[allIDs[i]] = allCons[i] } r := NewMetricsRouter(allConsMap) md := testdata.GenerateMetrics(1) // Keep track of how many logs each consumer should receive. // This will be validated after every call to RouteMetrics. expected := make(map[pipeline.ID]int, numCons) for i := range numMetrics { // Build a random set of ids (no duplicates) randCons := make(map[pipeline.ID]bool, numIDs) for j := range numIDs { // This number should be pretty random and less than numCons conNum := (numCons + numIDs + i + j) % numCons randCons[allIDs[conNum]] = true } // Convert to slice, update expectations conIDs := make([]pipeline.ID, 0, len(randCons)) for id := range randCons { conIDs = append(conIDs, id) expected[id]++ } // Route to list of consumers fanout, err := r.Consumer(conIDs...) assert.NoError(t, err) assert.NoError(t, fanout.ConsumeMetrics(context.Background(), md)) // Validate expectations for all consumers for id := range expected { metrics := []pmetric.Metrics{} switch con := allConsMap[id].(type) { case *consumertest.MetricsSink: metrics = con.AllMetrics() case *mutatingMetricsSink: metrics = con.AllMetrics() } assert.Len(t, metrics, expected[id]) for n := 0; n < len(metrics); n++ { assert.Equal(t, md, metrics[n]) } } } } } func TestMetricsRouterConsumers(t *testing.T) { ctx := context.Background() md := testdata.GenerateMetrics(1) fooID := pipeline.NewIDWithName(pipeline.SignalMetrics, "foo") barID := pipeline.NewIDWithName(pipeline.SignalMetrics, "bar") foo := new(consumertest.MetricsSink) bar := new(consumertest.MetricsSink) r := NewMetricsRouter(map[pipeline.ID]consumer.Metrics{fooID: foo, barID: bar}) rcs := r.PipelineIDs() assert.Len(t, rcs, 2) assert.ElementsMatch(t, []pipeline.ID{fooID, barID}, rcs) assert.Empty(t, foo.AllMetrics()) assert.Empty(t, bar.AllMetrics()) both, err := r.Consumer(fooID, barID) assert.NotNil(t, both) assert.NoError(t, err) assert.NoError(t, both.ConsumeMetrics(ctx, md)) assert.Len(t, foo.AllMetrics(), 1) assert.Len(t, bar.AllMetrics(), 1) fooOnly, err := r.Consumer(fooID) assert.NotNil(t, fooOnly) assert.NoError(t, err) assert.NoError(t, fooOnly.ConsumeMetrics(ctx, md)) assert.Len(t, foo.AllMetrics(), 2) assert.Len(t, bar.AllMetrics(), 1) barOnly, err := r.Consumer(barID) assert.NotNil(t, barOnly) assert.NoError(t, err) assert.NoError(t, barOnly.ConsumeMetrics(ctx, md)) assert.Len(t, foo.AllMetrics(), 2) assert.Len(t, bar.AllMetrics(), 2) none, err := r.Consumer() assert.Nil(t, none) require.Error(t, err) fake, err := r.Consumer(pipeline.NewIDWithName(pipeline.SignalMetrics, "fake")) assert.Nil(t, fake) assert.Error(t, err) } opentelemetry-collector-0.141.0/connector/package_test.go000066400000000000000000000003121511331344600235050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/connector/traces_router.go000066400000000000000000000020701511331344600237370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector // import "go.opentelemetry.io/collector/connector" import ( "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/internal/fanoutconsumer" "go.opentelemetry.io/collector/pipeline" ) // TracesRouterAndConsumer feeds the first consumer.Traces in each of the specified pipelines. type TracesRouterAndConsumer interface { consumer.Traces Consumer(...pipeline.ID) (consumer.Traces, error) PipelineIDs() []pipeline.ID privateFunc() } type tracesRouter struct { consumer.Traces internal.BaseRouter[consumer.Traces] } func NewTracesRouter(cm map[pipeline.ID]consumer.Traces) TracesRouterAndConsumer { consumers := make([]consumer.Traces, 0, len(cm)) for _, cons := range cm { consumers = append(consumers, cons) } return &tracesRouter{ Traces: fanoutconsumer.NewTraces(consumers), BaseRouter: internal.NewBaseRouter(fanoutconsumer.NewTraces, cm), } } func (r *tracesRouter) privateFunc() {} opentelemetry-collector-0.141.0/connector/traces_router_test.go000066400000000000000000000105531511331344600250030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package connector import ( "context" "fmt" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pipeline" ) type mutatingTracesSink struct { *consumertest.TracesSink } func (mts *mutatingTracesSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } func TestTracesRouterMultiplexing(t *testing.T) { num := 20 for numIDs := 1; numIDs < num; numIDs++ { for numCons := 1; numCons < num; numCons++ { for numTraces := 1; numTraces < num; numTraces++ { t.Run( fmt.Sprintf("%d-ids/%d-cons/%d-logs", numIDs, numCons, numTraces), fuzzTraces(numIDs, numCons, numTraces), ) } } } } func fuzzTraces(numIDs, numCons, numTraces int) func(*testing.T) { return func(t *testing.T) { allIDs := make([]pipeline.ID, 0, numCons) allCons := make([]consumer.Traces, 0, numCons) allConsMap := make(map[pipeline.ID]consumer.Traces) // If any consumer is mutating, the router must report mutating for i := range numCons { allIDs = append(allIDs, pipeline.NewIDWithName(pipeline.SignalTraces, "sink_"+strconv.Itoa(numCons))) // Random chance for each consumer to be mutating if (numCons+numTraces+i)%4 == 0 { allCons = append(allCons, &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)}) } else { allCons = append(allCons, new(consumertest.TracesSink)) } allConsMap[allIDs[i]] = allCons[i] } r := NewTracesRouter(allConsMap) td := testdata.GenerateTraces(1) // Keep track of how many logs each consumer should receive. // This will be validated after every call to RouteTraces. expected := make(map[pipeline.ID]int, numCons) for i := range numTraces { // Build a random set of ids (no duplicates) randCons := make(map[pipeline.ID]bool, numIDs) for j := range numIDs { // This number should be pretty random and less than numCons conNum := (numCons + numIDs + i + j) % numCons randCons[allIDs[conNum]] = true } // Convert to slice, update expectations conIDs := make([]pipeline.ID, 0, len(randCons)) for id := range randCons { conIDs = append(conIDs, id) expected[id]++ } // Route to list of consumers fanout, err := r.Consumer(conIDs...) assert.NoError(t, err) assert.NoError(t, fanout.ConsumeTraces(context.Background(), td)) // Validate expectations for all consumers for id := range expected { traces := []ptrace.Traces{} switch con := allConsMap[id].(type) { case *consumertest.TracesSink: traces = con.AllTraces() case *mutatingTracesSink: traces = con.AllTraces() } assert.Len(t, traces, expected[id]) for n := 0; n < len(traces); n++ { assert.Equal(t, td, traces[n]) } } } } } func TestTracesRouterConsumer(t *testing.T) { ctx := context.Background() td := testdata.GenerateTraces(1) fooID := pipeline.NewIDWithName(pipeline.SignalTraces, "foo") barID := pipeline.NewIDWithName(pipeline.SignalTraces, "bar") foo := new(consumertest.TracesSink) bar := new(consumertest.TracesSink) r := NewTracesRouter(map[pipeline.ID]consumer.Traces{fooID: foo, barID: bar}) rcs := r.PipelineIDs() assert.Len(t, rcs, 2) assert.ElementsMatch(t, []pipeline.ID{fooID, barID}, rcs) assert.Empty(t, foo.AllTraces()) assert.Empty(t, bar.AllTraces()) both, err := r.Consumer(fooID, barID) assert.NotNil(t, both) assert.NoError(t, err) assert.NoError(t, both.ConsumeTraces(ctx, td)) assert.Len(t, foo.AllTraces(), 1) assert.Len(t, bar.AllTraces(), 1) fooOnly, err := r.Consumer(fooID) assert.NotNil(t, fooOnly) assert.NoError(t, err) assert.NoError(t, fooOnly.ConsumeTraces(ctx, td)) assert.Len(t, foo.AllTraces(), 2) assert.Len(t, bar.AllTraces(), 1) barOnly, err := r.Consumer(barID) assert.NotNil(t, barOnly) assert.NoError(t, err) assert.NoError(t, barOnly.ConsumeTraces(ctx, td)) assert.Len(t, foo.AllTraces(), 2) assert.Len(t, bar.AllTraces(), 2) none, err := r.Consumer() assert.Nil(t, none) require.Error(t, err) fake, err := r.Consumer(pipeline.NewIDWithName(pipeline.SignalTraces, "fake")) assert.Nil(t, fake) assert.Error(t, err) } opentelemetry-collector-0.141.0/connector/xconnector/000077500000000000000000000000001511331344600227125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/connector/xconnector/Makefile000066400000000000000000000000361511331344600243510ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/connector/xconnector/connector.go000066400000000000000000000370331511331344600252410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconnector // import "go.opentelemetry.io/collector/connector/xconnector" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" ) type Factory interface { connector.Factory CreateTracesToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (connector.Traces, error) CreateMetricsToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (connector.Metrics, error) CreateLogsToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (connector.Logs, error) TracesToProfilesStability() component.StabilityLevel MetricsToProfilesStability() component.StabilityLevel LogsToProfilesStability() component.StabilityLevel CreateProfilesToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) CreateProfilesToTraces(ctx context.Context, set connector.Settings, cfg component.Config, next consumer.Traces) (Profiles, error) CreateProfilesToMetrics(ctx context.Context, set connector.Settings, cfg component.Config, next consumer.Metrics) (Profiles, error) CreateProfilesToLogs(ctx context.Context, set connector.Settings, cfg component.Config, next consumer.Logs) (Profiles, error) ProfilesToProfilesStability() component.StabilityLevel ProfilesToTracesStability() component.StabilityLevel ProfilesToMetricsStability() component.StabilityLevel ProfilesToLogsStability() component.StabilityLevel } // A Profiles connector acts as an exporter from a profiles pipeline and a receiver // to one or more traces, metrics, logs, or profiles pipelines. // Profiles feeds a consumer.Traces, consumer.Metrics, consumer.Logs, or xconsumer.Profiles with data. // // Examples: // - Profiles could be collected in one pipeline and routed to another profiles pipeline // based on criteria such as attributes or other content of the profile. The second // pipeline can then process and export the profile to the appropriate backend. // - Profiles could be summarized by a metrics connector that emits statistics describing // the number of profiles observed. // - Profiles could be analyzed by a logs connector that emits events when particular // criteria are met. type Profiles interface { component.Component xconsumer.Profiles } // CreateTracesToProfilesFunc is the equivalent of Factory.CreateTracesToProfiles(). type CreateTracesToProfilesFunc func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Traces, error) // CreateMetricsToProfilesFunc is the equivalent of Factory.CreateMetricsToProfiles(). type CreateMetricsToProfilesFunc func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Metrics, error) // CreateLogsToProfilesFunc is the equivalent of Factory.CreateLogsToProfiles(). type CreateLogsToProfilesFunc func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Logs, error) // CreateProfilesToProfilesFunc is the equivalent of Factory.CreateProfilesToProfiles(). type CreateProfilesToProfilesFunc func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (Profiles, error) // CreateProfilesToTracesFunc is the equivalent of Factory.CreateProfilesToTraces(). type CreateProfilesToTracesFunc func(context.Context, connector.Settings, component.Config, consumer.Traces) (Profiles, error) // CreateProfilesToMetricsFunc is the equivalent of Factory.CreateProfilesToMetrics(). type CreateProfilesToMetricsFunc func(context.Context, connector.Settings, component.Config, consumer.Metrics) (Profiles, error) // CreateProfilesToLogsFunc is the equivalent of Factory.CreateProfilesToLogs(). type CreateProfilesToLogsFunc func(context.Context, connector.Settings, component.Config, consumer.Logs) (Profiles, error) // FactoryOption apply changes to ReceiverOptions. type FactoryOption interface { // applyOption applies the option. applyOption(o *factoryOpts) } // factoryOptionFunc is an ReceiverFactoryOption created through a function. type factoryOptionFunc func(*factoryOpts) func (f factoryOptionFunc) applyOption(o *factoryOpts) { f(o) } type factoryOpts struct { opts []connector.FactoryOption *factory } // WithTracesToTraces overrides the default "error not supported" implementation for WithTracesToTraces and the default "undefined" stability level. func WithTracesToTraces(createTracesToTraces connector.CreateTracesToTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithTracesToTraces(createTracesToTraces, sl)) }) } // WithTracesToMetrics overrides the default "error not supported" implementation for WithTracesToMetrics and the default "undefined" stability level. func WithTracesToMetrics(createTracesToMetrics connector.CreateTracesToMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithTracesToMetrics(createTracesToMetrics, sl)) }) } // WithTracesToLogs overrides the default "error not supported" implementation for WithTracesToLogs and the default "undefined" stability level. func WithTracesToLogs(createTracesToLogs connector.CreateTracesToLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithTracesToLogs(createTracesToLogs, sl)) }) } // WithMetricsToTraces overrides the default "error not supported" implementation for WithMetricsToTraces and the default "undefined" stability level. func WithMetricsToTraces(createMetricsToTraces connector.CreateMetricsToTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithMetricsToTraces(createMetricsToTraces, sl)) }) } // WithMetricsToMetrics overrides the default "error not supported" implementation for WithMetricsToMetrics and the default "undefined" stability level. func WithMetricsToMetrics(createMetricsToMetrics connector.CreateMetricsToMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithMetricsToMetrics(createMetricsToMetrics, sl)) }) } // WithMetricsToLogs overrides the default "error not supported" implementation for WithMetricsToLogs and the default "undefined" stability level. func WithMetricsToLogs(createMetricsToLogs connector.CreateMetricsToLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithMetricsToLogs(createMetricsToLogs, sl)) }) } // WithLogsToTraces overrides the default "error not supported" implementation for WithLogsToTraces and the default "undefined" stability level. func WithLogsToTraces(createLogsToTraces connector.CreateLogsToTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithLogsToTraces(createLogsToTraces, sl)) }) } // WithLogsToMetrics overrides the default "error not supported" implementation for WithLogsToMetrics and the default "undefined" stability level. func WithLogsToMetrics(createLogsToMetrics connector.CreateLogsToMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithLogsToMetrics(createLogsToMetrics, sl)) }) } // WithLogsToLogs overrides the default "error not supported" implementation for WithLogsToLogs and the default "undefined" stability level. func WithLogsToLogs(createLogsToLogs connector.CreateLogsToLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, connector.WithLogsToLogs(createLogsToLogs, sl)) }) } // WithTracesToProfiles overrides the default "error not supported" implementation for WithTracesToProfiles and the default "undefined" stability level. func WithTracesToProfiles(createTracesToProfiles CreateTracesToProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.tracesToProfilesStabilityLevel = sl o.createTracesToProfilesFunc = createTracesToProfiles }) } // WithMetricsToProfiles overrides the default "error not supported" implementation for WithMetricsToProfiles and the default "undefined" stability level. func WithMetricsToProfiles(createMetricsToProfiles CreateMetricsToProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.metricsToProfilesStabilityLevel = sl o.createMetricsToProfilesFunc = createMetricsToProfiles }) } // WithLogsToProfiles overrides the default "error not supported" implementation for WithLogsToProfiles and the default "undefined" stability level. func WithLogsToProfiles(createLogsToProfiles CreateLogsToProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.logsToProfilesStabilityLevel = sl o.createLogsToProfilesFunc = createLogsToProfiles }) } // WithProfilesToProfiles overrides the default "error not supported" implementation for WithProfilesToProfiles and the default "undefined" stability level. func WithProfilesToProfiles(createProfilesToProfiles CreateProfilesToProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesToProfilesStabilityLevel = sl o.createProfilesToProfilesFunc = createProfilesToProfiles }) } // WithProfilesToTraces overrides the default "error not supported" implementation for WithProfilesToTraces and the default "undefined" stability level. func WithProfilesToTraces(createProfilesToTraces CreateProfilesToTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesToTracesStabilityLevel = sl o.createProfilesToTracesFunc = createProfilesToTraces }) } // WithProfilesToMetrics overrides the default "error not supported" implementation for WithProfilesToMetrics and the default "undefined" stability level. func WithProfilesToMetrics(createProfilesToMetrics CreateProfilesToMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesToMetricsStabilityLevel = sl o.createProfilesToMetricsFunc = createProfilesToMetrics }) } // WithProfilesToLogs overrides the default "error not supported" implementation for WithProfilesToLogs and the default "undefined" stability level. func WithProfilesToLogs(createProfilesToLogs CreateProfilesToLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesToLogsStabilityLevel = sl o.createProfilesToLogsFunc = createProfilesToLogs }) } // factory implements the Factory interface. type factory struct { connector.Factory createTracesToProfilesFunc CreateTracesToProfilesFunc createMetricsToProfilesFunc CreateMetricsToProfilesFunc createLogsToProfilesFunc CreateLogsToProfilesFunc createProfilesToProfilesFunc CreateProfilesToProfilesFunc createProfilesToTracesFunc CreateProfilesToTracesFunc createProfilesToMetricsFunc CreateProfilesToMetricsFunc createProfilesToLogsFunc CreateProfilesToLogsFunc tracesToProfilesStabilityLevel component.StabilityLevel metricsToProfilesStabilityLevel component.StabilityLevel logsToProfilesStabilityLevel component.StabilityLevel profilesToProfilesStabilityLevel component.StabilityLevel profilesToTracesStabilityLevel component.StabilityLevel profilesToMetricsStabilityLevel component.StabilityLevel profilesToLogsStabilityLevel component.StabilityLevel } func (f *factory) TracesToProfilesStability() component.StabilityLevel { return f.tracesToProfilesStabilityLevel } func (f *factory) MetricsToProfilesStability() component.StabilityLevel { return f.metricsToProfilesStabilityLevel } func (f *factory) LogsToProfilesStability() component.StabilityLevel { return f.logsToProfilesStabilityLevel } func (f *factory) ProfilesToProfilesStability() component.StabilityLevel { return f.profilesToProfilesStabilityLevel } func (f *factory) ProfilesToTracesStability() component.StabilityLevel { return f.profilesToTracesStabilityLevel } func (f *factory) ProfilesToMetricsStability() component.StabilityLevel { return f.profilesToMetricsStabilityLevel } func (f *factory) ProfilesToLogsStability() component.StabilityLevel { return f.profilesToLogsStabilityLevel } func (f *factory) CreateTracesToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (connector.Traces, error) { if f.createTracesToProfilesFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalTraces, xpipeline.SignalProfiles) } return f.createTracesToProfilesFunc(ctx, set, cfg, next) } func (f *factory) CreateMetricsToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (connector.Metrics, error) { if f.createMetricsToProfilesFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalMetrics, xpipeline.SignalProfiles) } return f.createMetricsToProfilesFunc(ctx, set, cfg, next) } func (f *factory) CreateLogsToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (connector.Logs, error) { if f.createLogsToProfilesFunc == nil { return nil, internal.ErrDataTypes(set.ID, pipeline.SignalLogs, xpipeline.SignalProfiles) } return f.createLogsToProfilesFunc(ctx, set, cfg, next) } func (f *factory) CreateProfilesToProfiles(ctx context.Context, set connector.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) { if f.createProfilesToProfilesFunc == nil { return nil, internal.ErrDataTypes(set.ID, xpipeline.SignalProfiles, xpipeline.SignalProfiles) } return f.createProfilesToProfilesFunc(ctx, set, cfg, next) } func (f *factory) CreateProfilesToTraces(ctx context.Context, set connector.Settings, cfg component.Config, next consumer.Traces) (Profiles, error) { if f.createProfilesToTracesFunc == nil { return nil, internal.ErrDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalTraces) } return f.createProfilesToTracesFunc(ctx, set, cfg, next) } func (f *factory) CreateProfilesToMetrics(ctx context.Context, set connector.Settings, cfg component.Config, next consumer.Metrics) (Profiles, error) { if f.createProfilesToMetricsFunc == nil { return nil, internal.ErrDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalMetrics) } return f.createProfilesToMetricsFunc(ctx, set, cfg, next) } func (f *factory) CreateProfilesToLogs(ctx context.Context, set connector.Settings, cfg component.Config, next consumer.Logs) (Profiles, error) { if f.createProfilesToLogsFunc == nil { return nil, internal.ErrDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalLogs) } return f.createProfilesToLogsFunc(ctx, set, cfg, next) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { opts := factoryOpts{factory: &factory{}} for _, opt := range options { opt.applyOption(&opts) } opts.Factory = connector.NewFactory(cfgType, createDefaultConfig, opts.opts...) return opts.factory } opentelemetry-collector-0.141.0/connector/xconnector/connector_test.go000066400000000000000000000165021511331344600262760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconnector // import "go.opentelemetry.io/collector/connector/xconnector" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" ) var ( testType = component.MustNewType("test") testID = component.MustNewIDWithName("type", "name") ) func TestNewFactoryNoOptions(t *testing.T) { defaultCfg := struct{}{} factory := NewFactory(testType, func() component.Config { return &defaultCfg }) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) _, err := factory.CreateTracesToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalTraces, xpipeline.SignalProfiles)) _, err = factory.CreateMetricsToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalMetrics, xpipeline.SignalProfiles)) _, err = factory.CreateLogsToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, pipeline.SignalLogs, xpipeline.SignalProfiles)) _, err = factory.CreateProfilesToTraces(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, xpipeline.SignalProfiles, pipeline.SignalTraces)) _, err = factory.CreateProfilesToMetrics(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, xpipeline.SignalProfiles, pipeline.SignalMetrics)) _, err = factory.CreateProfilesToLogs(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, xpipeline.SignalProfiles, pipeline.SignalLogs)) } func TestNewFactoryWithSameTypes(t *testing.T) { defaultCfg := struct{}{} factory := NewFactory(testType, func() component.Config { return &defaultCfg }, WithProfilesToProfiles(createProfilesToProfiles, component.StabilityLevelAlpha), ) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelAlpha, factory.ProfilesToProfilesStability()) _, err := factory.CreateProfilesToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) _, err = factory.CreateProfilesToTraces(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, xpipeline.SignalProfiles, pipeline.SignalTraces)) _, err = factory.CreateProfilesToMetrics(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, xpipeline.SignalProfiles, pipeline.SignalMetrics)) _, err = factory.CreateProfilesToLogs(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, xpipeline.SignalProfiles, pipeline.SignalLogs)) } func TestNewFactoryWithTranslateTypes(t *testing.T) { defaultCfg := struct{}{} factory := NewFactory(testType, func() component.Config { return &defaultCfg }, WithTracesToProfiles(createTracesToProfiles, component.StabilityLevelBeta), WithMetricsToProfiles(createMetricsToProfiles, component.StabilityLevelDevelopment), WithLogsToProfiles(createLogsToProfiles, component.StabilityLevelAlpha), WithProfilesToTraces(createProfilesToTraces, component.StabilityLevelBeta), WithProfilesToMetrics(createProfilesToMetrics, component.StabilityLevelDevelopment), WithProfilesToLogs(createProfilesToLogs, component.StabilityLevelAlpha), ) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) _, err := factory.CreateProfilesToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.Equal(t, err, internal.ErrDataTypes(testID, xpipeline.SignalProfiles, xpipeline.SignalProfiles)) assert.Equal(t, component.StabilityLevelBeta, factory.TracesToProfilesStability()) _, err = factory.CreateTracesToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelDevelopment, factory.MetricsToProfilesStability()) _, err = factory.CreateMetricsToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelAlpha, factory.LogsToProfilesStability()) _, err = factory.CreateLogsToProfiles(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelBeta, factory.ProfilesToTracesStability()) _, err = factory.CreateProfilesToTraces(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelDevelopment, factory.ProfilesToMetricsStability()) _, err = factory.CreateProfilesToMetrics(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, component.StabilityLevelAlpha, factory.ProfilesToLogsStability()) _, err = factory.CreateProfilesToLogs(context.Background(), connector.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) assert.NoError(t, err) } var nopInstance = &nopConnector{ Consumer: consumertest.NewNop(), } // nopConnector stores consumed traces and metrics for testing purposes. type nopConnector struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createTracesToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Traces, error) { return nopInstance, nil } func createMetricsToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Metrics, error) { return nopInstance, nil } func createLogsToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Logs, error) { return nopInstance, nil } func createProfilesToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (Profiles, error) { return nopInstance, nil } func createProfilesToTraces(context.Context, connector.Settings, component.Config, consumer.Traces) (Profiles, error) { return nopInstance, nil } func createProfilesToMetrics(context.Context, connector.Settings, component.Config, consumer.Metrics) (Profiles, error) { return nopInstance, nil } func createProfilesToLogs(context.Context, connector.Settings, component.Config, consumer.Logs) (Profiles, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/connector/xconnector/go.mod000066400000000000000000000045561511331344600240320ustar00rootroot00000000000000module go.opentelemetry.io/collector/connector/xconnector go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/connector => ../ replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/connector/xconnector/go.sum000066400000000000000000000124431511331344600240510ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/connector/xconnector/metadata.yaml000066400000000000000000000003371511331344600253610ustar00rootroot00000000000000type: xconnector github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg codeowners: active: - mx-psi - dmathieu stability: development: [profiles] opentelemetry-collector-0.141.0/connector/xconnector/profiles_router.go000066400000000000000000000020211511331344600264570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconnector // import "go.opentelemetry.io/collector/connector/xconnector" import ( "go.opentelemetry.io/collector/connector/internal" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/fanoutconsumer" "go.opentelemetry.io/collector/pipeline" ) type ProfilesRouterAndConsumer interface { xconsumer.Profiles Consumer(...pipeline.ID) (xconsumer.Profiles, error) PipelineIDs() []pipeline.ID privateFunc() } type profilesRouter struct { xconsumer.Profiles internal.BaseRouter[xconsumer.Profiles] } func NewProfilesRouter(cm map[pipeline.ID]xconsumer.Profiles) ProfilesRouterAndConsumer { consumers := make([]xconsumer.Profiles, 0, len(cm)) for _, cons := range cm { consumers = append(consumers, cons) } return &profilesRouter{ Profiles: fanoutconsumer.NewProfiles(consumers), BaseRouter: internal.NewBaseRouter(fanoutconsumer.NewProfiles, cm), } } func (r *profilesRouter) privateFunc() {} opentelemetry-collector-0.141.0/connector/xconnector/profiles_router_test.go000066400000000000000000000111201511331344600275160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconnector import ( "context" "fmt" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" ) type mutatingProfilesSink struct { *consumertest.ProfilesSink } func (mts *mutatingProfilesSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } func TestProfilesRouterMultiplexing(t *testing.T) { num := 20 for numIDs := 1; numIDs < num; numIDs++ { for numCons := 1; numCons < num; numCons++ { for numProfiles := 1; numProfiles < num; numProfiles++ { t.Run( fmt.Sprintf("%d-ids/%d-cons/%d-logs", numIDs, numCons, numProfiles), fuzzProfiles(numIDs, numCons, numProfiles), ) } } } } func fuzzProfiles(numIDs, numCons, numProfiles int) func(*testing.T) { return func(t *testing.T) { allIDs := make([]pipeline.ID, 0, numCons) allCons := make([]xconsumer.Profiles, 0, numCons) allConsMap := make(map[pipeline.ID]xconsumer.Profiles) // If any consumer is mutating, the router must report mutating for i := range numCons { allIDs = append(allIDs, pipeline.NewIDWithName(xpipeline.SignalProfiles, "sink_"+strconv.Itoa(numCons))) // Random chance for each consumer to be mutating if (numCons+numProfiles+i)%4 == 0 { allCons = append(allCons, &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)}) } else { allCons = append(allCons, new(consumertest.ProfilesSink)) } allConsMap[allIDs[i]] = allCons[i] } r := NewProfilesRouter(allConsMap) td := testdata.GenerateProfiles(1) // Keep track of how many logs each consumer should receive. // This will be validated after every call to RouteProfiles. expected := make(map[pipeline.ID]int, numCons) for i := range numProfiles { // Build a random set of ids (no duplicates) randCons := make(map[pipeline.ID]bool, numIDs) for j := range numIDs { // This number should be pretty random and less than numCons conNum := (numCons + numIDs + i + j) % numCons randCons[allIDs[conNum]] = true } // Convert to slice, update expectations conIDs := make([]pipeline.ID, 0, len(randCons)) for id := range randCons { conIDs = append(conIDs, id) expected[id]++ } // Route to list of consumers fanout, err := r.Consumer(conIDs...) assert.NoError(t, err) assert.NoError(t, fanout.ConsumeProfiles(context.Background(), td)) // Validate expectations for all consumers for id := range expected { profiles := []pprofile.Profiles{} switch con := allConsMap[id].(type) { case *consumertest.ProfilesSink: profiles = con.AllProfiles() case *mutatingProfilesSink: profiles = con.AllProfiles() } assert.Len(t, profiles, expected[id]) for n := 0; n < len(profiles); n++ { assert.Equal(t, td, profiles[n]) } } } } } func TestProfilessRouterConsumer(t *testing.T) { ctx := context.Background() td := testdata.GenerateProfiles(1) fooID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "foo") barID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "bar") foo := new(consumertest.ProfilesSink) bar := new(consumertest.ProfilesSink) r := NewProfilesRouter(map[pipeline.ID]xconsumer.Profiles{fooID: foo, barID: bar}) rcs := r.PipelineIDs() assert.Len(t, rcs, 2) assert.ElementsMatch(t, []pipeline.ID{fooID, barID}, rcs) assert.Empty(t, foo.AllProfiles()) assert.Empty(t, bar.AllProfiles()) both, err := r.Consumer(fooID, barID) assert.NotNil(t, both) assert.NoError(t, err) assert.NoError(t, both.ConsumeProfiles(ctx, td)) assert.Len(t, foo.AllProfiles(), 1) assert.Len(t, bar.AllProfiles(), 1) fooOnly, err := r.Consumer(fooID) assert.NotNil(t, fooOnly) assert.NoError(t, err) assert.NoError(t, fooOnly.ConsumeProfiles(ctx, td)) assert.Len(t, foo.AllProfiles(), 2) assert.Len(t, bar.AllProfiles(), 1) barOnly, err := r.Consumer(barID) assert.NotNil(t, barOnly) assert.NoError(t, err) assert.NoError(t, barOnly.ConsumeProfiles(ctx, td)) assert.Len(t, foo.AllProfiles(), 2) assert.Len(t, bar.AllProfiles(), 2) none, err := r.Consumer() assert.Nil(t, none) require.Error(t, err) fake, err := r.Consumer(pipeline.NewIDWithName(xpipeline.SignalProfiles, "fake")) assert.Nil(t, fake) assert.Error(t, err) } opentelemetry-collector-0.141.0/consumer/000077500000000000000000000000001511331344600203715ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/Makefile000066400000000000000000000000331511331344600220250ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/consumer/consumer.go000066400000000000000000000013451511331344600225560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer // import "go.opentelemetry.io/collector/consumer" import ( "errors" "go.opentelemetry.io/collector/consumer/internal" ) // Capabilities describes the capabilities of a Processor. type Capabilities = internal.Capabilities var errNilFunc = errors.New("nil consumer func") // Option to construct new consumers. type Option = internal.Option // WithCapabilities overrides the default GetCapabilities function for a processor. // The default GetCapabilities function returns mutable capabilities. func WithCapabilities(capabilities Capabilities) Option { return internal.OptionFunc(func(o *internal.BaseImpl) { o.Cap = capabilities }) } opentelemetry-collector-0.141.0/consumer/consumererror/000077500000000000000000000000001511331344600232765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/consumererror/Makefile000066400000000000000000000000361511331344600247350ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/consumer/consumererror/doc.go000066400000000000000000000024461511331344600244000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package consumererror provides wrappers to easily classify errors. This allows // appropriate action by error handlers without the need to know each individual // error type/instance. These errors are returned by the Consume*() functions of // the consumer interfaces. // // # Error handling // // The consumererror package provides a way to classify errors into two categories: Permanent and // NonPermanent. The Permanent errors are those that are not expected to be resolved by retrying the // same data. // // If the error is Permanent, then the Consume*() call should not be retried with the same data. // This typically happens when the data cannot be serialized by the exporter that is attached to the // pipeline or when the destination refuses the data because it cannot decode it. // // If the error is non-Permanent then the Consume*() call should be retried with the same data. This // may be done by the component itself, however typically it is done by the original sender, after // the receiver in the pipeline returns a response to the sender indicating that the Collector is // currently overloaded and the request must be retried. package consumererror // import "go.opentelemetry.io/collector/consumer/consumererror" opentelemetry-collector-0.141.0/consumer/consumererror/downstream.go000066400000000000000000000021471511331344600260140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror // import "go.opentelemetry.io/collector/consumer/consumererror" import "errors" type downstreamError struct { inner error } var _ error = downstreamError{} func (de downstreamError) Error() string { return de.inner.Error() } func (de downstreamError) Unwrap() error { return de.inner } // NewDownstream wraps an error to indicate that it is a downstream error, i.e. an // error that does not come from the current component, but from one further downstream. // This is used by pipeline instrumentation to determine whether an operation's outcome // was an internal failure, or if it successfully produced data that was later refused. // This wrapper is not intended to be used manually inside components. func NewDownstream(err error) error { return downstreamError{ inner: err, } } // IsDownstream checks if an error was wrapped with the NewDownstream function, // or if it contains one such error in its Unwrap() tree. func IsDownstream(err error) bool { var de downstreamError return errors.As(err, &de) } opentelemetry-collector-0.141.0/consumer/consumererror/downstream_test.go000066400000000000000000000026001511331344600270450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror import ( "errors" "testing" "github.com/stretchr/testify/assert" ) //nolint:testifylint // Testing properties of errors, no reason to use require func TestDownstream(t *testing.T) { err1 := errors.New("test error") assert.False(t, IsDownstream(err1)) err2 := errors.New("test error 2") assert.False(t, IsDownstream(err2)) errDownstream1 := NewDownstream(err1) assert.True(t, IsDownstream(errDownstream1)) assert.Equal(t, err1.Error(), errDownstream1.Error()) assert.ErrorIs(t, errDownstream1, err1) assert.NotErrorIs(t, errDownstream1, err2) // we can access downstream wrappers through other wrappers errWrapDownstream := NewRetryableError(errDownstream1) assert.True(t, IsDownstream(errWrapDownstream)) errorStruct := new(Error) assert.ErrorAs(t, errWrapDownstream, &errorStruct) // we can access other wrappers through downstream wrappers errDownstreamWrap := NewDownstream(NewRetryableError(err1)) assert.True(t, IsDownstream(errDownstreamWrap)) assert.ErrorAs(t, errDownstreamWrap, &errorStruct) // downstream + downstream = downstream errJoin2 := errors.Join(errDownstream1, NewDownstream(err2)) assert.True(t, IsDownstream(errJoin2)) // downstream + not downstream = downstream errJoin1 := errors.Join(errDownstream1, err2) assert.True(t, IsDownstream(errJoin1)) } opentelemetry-collector-0.141.0/consumer/consumererror/error.go000066400000000000000000000131231511331344600247560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror // import "go.opentelemetry.io/collector/consumer/consumererror" import ( "errors" "fmt" "net/http" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/consumer/consumererror/internal/statusconversion" ) // Error is intended to be used to encapsulate various information that can add // context to an error that occurred within a pipeline component. Error objects // are constructed through calling `New` with the relevant options to capture // data around the error that occurred. // // Error should be obtained from a given `error` object using `errors.As`. type Error struct { error httpStatus int grpcStatus *status.Status isRetryable bool } var _ error = (*Error)(nil) // NewOTLPHTTPError records an HTTP status code that was received from a server // during data submission. // // NOTE: This function will panic if passed an HTTP status between 200 and 299 inclusive. // This is to reserve the behavior for handling these codes for the future. func NewOTLPHTTPError(origErr error, httpStatus int) error { // Matches what is considered a successful response in the OTLP/HTTP Exporter. if httpStatus >= 200 && httpStatus <= 299 { panic("NewOTLPHTTPError should not be called with a success code") } var retryable bool switch httpStatus { case http.StatusTooManyRequests, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: retryable = true } return &Error{error: origErr, httpStatus: httpStatus, isRetryable: retryable} } // NewOTLPGRPCError records a gRPC status code that was received from a server // during data submission. // // NOTE: This function will panic if passed a *status.Status with an underlying // code of codes.OK. This is to reserve the behavior for handling this code for // the future. func NewOTLPGRPCError(origErr error, status *status.Status) error { var retryable bool if status != nil { switch status.Code() { case codes.Canceled, codes.DeadlineExceeded, codes.Aborted, codes.OutOfRange, codes.Unavailable, codes.DataLoss: retryable = true // Matches what is considered a successful response in the OTLP Exporter. case codes.OK: panic("NewOTLPGRPCError should not be called with an OK code") } } return &Error{error: origErr, grpcStatus: status, isRetryable: retryable} } // NewRetryableError records that this error is retryable according to OTLP specification. func NewRetryableError(origErr error) error { return &Error{error: origErr, isRetryable: true} } // Error implements the error interface. // // If an error object was given, that is used. // Otherwise, the gRPC error from the status.Status is used, // or an error message containing the HTTP status code is given. func (e *Error) Error() string { if e.error != nil { return e.error.Error() } if e.grpcStatus != nil { return e.grpcStatus.Err().Error() } else if e.httpStatus > 0 { return fmt.Sprintf("network error: received HTTP status %d", e.httpStatus) } return "uninitialized consumererror.Error" } // Unwrap returns the wrapped error for use by `errors.Is` and `errors.As`. // // If an error object was not passed but a gRPC `status.Status` was passed, // the underlying error from the status is returned. func (e *Error) Unwrap() error { if e.error != nil { return e.error } if e.grpcStatus != nil { return e.grpcStatus.Err() } return nil } // IsRetryable returns true if the error was created with NewRetryableError, if // the HTTP status code is retryable according to OTLP, or if the gRPC status is // retryable according to OTLP. Otherwise, returns false. // // See https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md for retryable // HTTP and gRPC codes. func (e *Error) IsRetryable() bool { return e.isRetryable } // ToHTTPStatus returns an HTTP status code either directly set by the source on // an [Error] object, derived from a gRPC status code set by the source, or // derived from Retryable. When deriving the value, the OTLP specification is // used to map to HTTP. See // https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md // for more details. // // If a http status code cannot be derived from these three sources then 500 is // returned. func ToHTTPStatus(err error) int { var e *Error if errors.As(err, &e) { if e.httpStatus != 0 { return e.httpStatus } if e.grpcStatus != nil { return statusconversion.GetHTTPStatusCodeFromStatus(e.grpcStatus) } if e.isRetryable { return http.StatusServiceUnavailable } } return http.StatusInternalServerError } // ToGRPCStatus returns a gRPC status code either directly set by the source on // an [Error] object, derived from an HTTP status code set by the // source, or derived from Retryable. When deriving the value, the OTLP // specification is used to map to gRPC. See // https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md // for more details. // // If an [Error] object is not present, then we attempt to get a status.Status from the // error tree. // // If a status.Status cannot be derived from these sources then INTERNAL is // returned. func ToGRPCStatus(err error) *status.Status { var e *Error if errors.As(err, &e) { if e.grpcStatus != nil { return e.grpcStatus } if e.httpStatus != 0 { return statusconversion.NewStatusFromMsgAndHTTPCode(e.Error(), e.httpStatus) } if e.isRetryable { return status.New(codes.Unavailable, e.Error()) } } if st, ok := status.FromError(err); ok { return st } return status.New(codes.Unknown, e.Error()) } opentelemetry-collector-0.141.0/consumer/consumererror/error_test.go000066400000000000000000000210541511331344600260170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror import ( "errors" "net/http" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) var errTest = errors.New("consumererror testing error") func Test_NewOTLPHTTPError(t *testing.T) { httpStatus := 500 wantErr := &Error{ error: errTest, httpStatus: httpStatus, } newErr := NewOTLPHTTPError(errTest, httpStatus) require.Equal(t, wantErr, newErr) } func Test_NewOTLPGRPCError(t *testing.T) { grpcStatus := status.New(codes.Aborted, "aborted") wantErr := &Error{ error: errTest, grpcStatus: grpcStatus, isRetryable: true, } newErr := NewOTLPGRPCError(errTest, grpcStatus) require.Equal(t, wantErr, newErr) } func Test_NewRetryableError(t *testing.T) { wantErr := &Error{ error: errTest, isRetryable: true, } newErr := NewRetryableError(errTest) require.Equal(t, wantErr, newErr) } func Test_Error(t *testing.T) { newErr := Error{error: errTest} require.Equal(t, errTest.Error(), newErr.Error()) } func TestUnwrap(t *testing.T) { grpcErr := status.New(codes.InvalidArgument, "not allowed") testCases := []struct { name string err *Error expected error }{ { name: "Error object", err: &Error{ error: errTest, grpcStatus: grpcErr, }, expected: errTest, }, { name: "gRPC error", err: &Error{ grpcStatus: grpcErr, }, expected: grpcErr.Err(), }, { name: "zero value struct", err: &Error{}, expected: nil, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { require.Equal(t, tt.expected, tt.err.Unwrap()) }) } } func TestAs(t *testing.T) { err := &Error{ error: errTest, } secondError := errors.Join(errors.New("test"), err) var e *Error require.ErrorAs(t, secondError, &e) assert.Equal(t, errTest.Error(), e.Error()) } func TestError_Error(t *testing.T) { testCases := []struct { name string err *Error expected string }{ { name: "Error object", err: &Error{ error: errTest, grpcStatus: status.New(codes.InvalidArgument, "not allowed"), httpStatus: 400, }, expected: errTest.Error(), }, { name: "gRPC error", err: &Error{ grpcStatus: status.New(codes.InvalidArgument, "not allowed"), }, expected: "rpc error: code = InvalidArgument desc = not allowed", }, { name: "HTTP error", err: &Error{ httpStatus: 400, }, expected: "network error: received HTTP status 400", }, { name: "zero value struct", err: &Error{}, expected: "uninitialized consumererror.Error", }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { require.Equal(t, tt.expected, tt.err.Error()) }) } } func TestError_Unwrap(t *testing.T) { err := &Error{ error: errTest, } require.Equal(t, errTest, err.Unwrap()) } func TestError_ToHTTPStatus(t *testing.T) { serverErr := http.StatusTooManyRequests testCases := []struct { name string httpStatus int grpcStatus *status.Status retryable bool want int hasCode bool }{ { name: "Passes through HTTP status", httpStatus: serverErr, want: serverErr, hasCode: true, }, { name: "Converts gRPC status", grpcStatus: status.New(codes.ResourceExhausted, errTest.Error()), want: serverErr, hasCode: true, }, { name: "Passes through HTTP status when gRPC status also present", httpStatus: serverErr, grpcStatus: status.New(codes.OK, errTest.Error()), want: serverErr, hasCode: true, }, { name: "Passes through HTTP status when retryable also present", httpStatus: serverErr, retryable: true, want: serverErr, }, { name: "No statuses set with retryable", retryable: true, want: http.StatusServiceUnavailable, }, { name: "No statuses set", want: http.StatusInternalServerError, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { err := &Error{ error: errTest, httpStatus: tt.httpStatus, grpcStatus: tt.grpcStatus, isRetryable: tt.retryable, } s := ToHTTPStatus(err) require.Equal(t, tt.want, s) }) } } func TestError_ToGRPCStatus(t *testing.T) { httpStatus := http.StatusTooManyRequests otherOTLPHTTPStatus := http.StatusOK serverErr := status.New(codes.ResourceExhausted, errTest.Error()) testCases := []struct { name string httpStatus int grpcStatus *status.Status retryable bool want *status.Status hasCode bool }{ { name: "Converts HTTP status", httpStatus: httpStatus, want: serverErr, hasCode: true, }, { name: "Passes through gRPC status", grpcStatus: serverErr, want: serverErr, hasCode: true, }, { name: "Passes through gRPC status when HTTP status also present", httpStatus: otherOTLPHTTPStatus, grpcStatus: serverErr, want: serverErr, hasCode: true, }, { name: "Passes through gRPC status when retryable also present", grpcStatus: serverErr, retryable: true, want: serverErr, }, { name: "No statuses set with retryable", retryable: true, want: status.New(codes.Unavailable, errTest.Error()), }, { name: "No statuses set", want: status.New(codes.Unknown, errTest.Error()), }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { err := &Error{ error: errTest, httpStatus: tt.httpStatus, grpcStatus: tt.grpcStatus, isRetryable: tt.retryable, } s := ToGRPCStatus(err) require.Equal(t, tt.want, s) }) } } func TestStatus_ToGRPCStatus(t *testing.T) { st := status.New(codes.ResourceExhausted, errTest.Error()) require.Equal(t, st, ToGRPCStatus(st.Err())) } func TestError_Retryable(t *testing.T) { retryableCodes := []codes.Code{codes.Canceled, codes.DeadlineExceeded, codes.Aborted, codes.OutOfRange, codes.Unavailable, codes.DataLoss} retryableStatuses := []*status.Status{} for _, code := range retryableCodes { retryableStatuses = append(retryableStatuses, status.New(code, errTest.Error())) } nonretryableCodes := []codes.Code{codes.Unauthenticated, codes.Unknown, codes.NotFound, codes.InvalidArgument} nonretryableStatuses := []*status.Status{} for _, code := range nonretryableCodes { nonretryableStatuses = append(nonretryableStatuses, status.New(code, errTest.Error())) } testCases := []struct { name string httpStatuses []int grpcStatuses []*status.Status want bool }{ { name: "HTTP statuses: retryable", httpStatuses: []int{http.StatusTooManyRequests, http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout}, want: true, }, { name: "HTTP statuses: non-retryable", httpStatuses: []int{0, http.StatusInternalServerError, http.StatusNotFound, http.StatusUnauthorized}, want: false, }, { name: "gRPC statuses: retryable", grpcStatuses: retryableStatuses, want: true, }, { name: "gRPC statuses: non-retryable", grpcStatuses: nonretryableStatuses, want: false, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { for _, httpStatus := range tt.httpStatuses { err := NewOTLPHTTPError(errTest, httpStatus) var httpErr *Error if errors.As(err, &httpErr) { require.Equal(t, tt.want, httpErr.IsRetryable(), "Expected %d to be retryable=%t", httpStatus, tt.want) } else { require.Fail(t, "NewOTLPHTTPError didn't return an *Error") } } for _, grpcStatus := range tt.grpcStatuses { err := NewOTLPGRPCError(errTest, grpcStatus) var grpcErr *Error if errors.As(err, &grpcErr) { require.Equal(t, tt.want, grpcErr.IsRetryable(), "Expected %q to be retryable=%t", grpcStatus.Code().String(), tt.want) } else { require.Fail(t, "NewOTLPGRPCError didn't return an *Error") } } }) } } func TestSuccessCodes(t *testing.T) { require.Panics(t, func() { _ = NewOTLPHTTPError(nil, 200) }) require.Panics(t, func() { _ = NewOTLPHTTPError(nil, 299) }) require.NotPanics(t, func() { require.Error(t, NewOTLPHTTPError(nil, 199)) }) require.NotPanics(t, func() { require.Error(t, NewOTLPHTTPError(nil, 300)) }) require.Panics(t, func() { _ = NewOTLPGRPCError(nil, status.New(codes.OK, "")) }) require.NotPanics(t, func() { require.Error(t, NewOTLPGRPCError(nil, status.New(codes.AlreadyExists, ""))) }) } opentelemetry-collector-0.141.0/consumer/consumererror/go.mod000066400000000000000000000026341511331344600244110ustar00rootroot00000000000000module go.opentelemetry.io/collector/consumer/consumererror go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.uber.org/goleak v1.3.0 google.golang.org/grpc v1.77.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kr/text v0.2.0 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/consumer/consumererror/go.sum000066400000000000000000000124541511331344600244370ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/consumer/consumererror/internal/000077500000000000000000000000001511331344600251125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/consumererror/internal/retryable.go000066400000000000000000000015371511331344600274400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/consumer/consumererror/internal" import ( "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) type Retryable[V ptrace.Traces | pmetric.Metrics | plog.Logs | pprofile.Profiles] struct { Err error Value V } // Error provides the error message func (err Retryable[V]) Error() string { return err.Err.Error() } // Unwrap returns the wrapped error for functions Is and As in standard package errors. func (err Retryable[V]) Unwrap() error { return err.Err } // Data returns the telemetry data that failed to be processed or sent. func (err Retryable[V]) Data() V { return err.Value } opentelemetry-collector-0.141.0/consumer/consumererror/internal/statusconversion/000077500000000000000000000000001511331344600305435ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/consumererror/internal/statusconversion/conversion.go000066400000000000000000000040101511331344600332520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package statusconversion // import "go.opentelemetry.io/collector/consumer/consumererror/internal/statusconversion" import ( "net/http" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func GetHTTPStatusCodeFromStatus(s *status.Status) int { // See https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#failures // to see if a code is retryable. // See https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#failures-1 // to see a list of retryable http status codes. switch s.Code() { // Retryable case codes.Canceled, codes.DeadlineExceeded, codes.Aborted, codes.OutOfRange, codes.Unavailable, codes.DataLoss: return http.StatusServiceUnavailable // Retryable case codes.ResourceExhausted: return http.StatusTooManyRequests // Not Retryable case codes.InvalidArgument: return http.StatusBadRequest // Not Retryable case codes.Unauthenticated: return http.StatusUnauthorized // Not Retryable case codes.PermissionDenied: return http.StatusForbidden // Not Retryable case codes.Unimplemented: return http.StatusNotFound // Not Retryable default: return http.StatusInternalServerError } } func NewStatusFromMsgAndHTTPCode(errMsg string, statusCode int) *status.Status { var c codes.Code // Mapping based on https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md // 429 mapping to ResourceExhausted and 400 mapping to StatusBadRequest are exceptions. switch statusCode { case http.StatusBadRequest: c = codes.InvalidArgument case http.StatusUnauthorized: c = codes.Unauthenticated case http.StatusForbidden: c = codes.PermissionDenied case http.StatusNotFound: c = codes.Unimplemented case http.StatusTooManyRequests: c = codes.ResourceExhausted case http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: c = codes.Unavailable default: c = codes.Unknown } return status.New(c, errMsg) } opentelemetry-collector-0.141.0/consumer/consumererror/internal/statusconversion/conversion_test.go000066400000000000000000000054621511331344600343250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package statusconversion // import "go.opentelemetry.io/collector/consumer/consumererror/internal/statusconversion" import ( "net/http" "testing" "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) func Test_GetHTTPStatusCodeFromStatus(t *testing.T) { tests := []struct { name string input *status.Status expected int }{ { name: "Retryable Status", input: status.New(codes.Unavailable, "test"), expected: http.StatusServiceUnavailable, }, { name: "Non-retryable Status", input: status.New(codes.InvalidArgument, "test"), expected: http.StatusBadRequest, }, { name: "Specifically 429", input: status.New(codes.ResourceExhausted, "test"), expected: http.StatusTooManyRequests, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := GetHTTPStatusCodeFromStatus(tt.input) assert.Equal(t, tt.expected, result) }) } } func Test_ErrorMsgAndHTTPCodeToStatus(t *testing.T) { tests := []struct { name string errMsg string statusCode int expected *status.Status }{ { name: "Bad Request", errMsg: "test", statusCode: http.StatusBadRequest, expected: status.New(codes.InvalidArgument, "test"), }, { name: "Unauthorized", errMsg: "test", statusCode: http.StatusUnauthorized, expected: status.New(codes.Unauthenticated, "test"), }, { name: "Forbidden", errMsg: "test", statusCode: http.StatusForbidden, expected: status.New(codes.PermissionDenied, "test"), }, { name: "Not Found", errMsg: "test", statusCode: http.StatusNotFound, expected: status.New(codes.Unimplemented, "test"), }, { name: "Too Many Requests", errMsg: "test", statusCode: http.StatusTooManyRequests, expected: status.New(codes.ResourceExhausted, "test"), }, { name: "Bad Gateway", errMsg: "test", statusCode: http.StatusBadGateway, expected: status.New(codes.Unavailable, "test"), }, { name: "Service Unavailable", errMsg: "test", statusCode: http.StatusServiceUnavailable, expected: status.New(codes.Unavailable, "test"), }, { name: "Gateway Timeout", errMsg: "test", statusCode: http.StatusGatewayTimeout, expected: status.New(codes.Unavailable, "test"), }, { name: "Unsupported Media Type", errMsg: "test", statusCode: http.StatusUnsupportedMediaType, expected: status.New(codes.Unknown, "test"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := NewStatusFromMsgAndHTTPCode(tt.errMsg, tt.statusCode) assert.Equal(t, tt.expected, result) }) } } opentelemetry-collector-0.141.0/consumer/consumererror/package_test.go000066400000000000000000000003161511331344600262570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/consumer/consumererror/permanent.go000066400000000000000000000020761511331344600256230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror // import "go.opentelemetry.io/collector/consumer/consumererror" import "errors" // permanent is an error that will be always returned if its source // receives the same inputs. type permanent struct { err error } // NewPermanent wraps an error to indicate that it is a permanent error, i.e. an // error that will be always returned if its source receives the same inputs. func NewPermanent(err error) error { return permanent{err: err} } func (p permanent) Error() string { return "Permanent error: " + p.err.Error() } // Unwrap returns the wrapped error for functions Is and As in standard package errors. func (p permanent) Unwrap() error { return p.err } // IsPermanent checks if an error was wrapped with the NewPermanent function, which // is used to indicate that a given error will always be returned in the case // that its sources receives the same input. func IsPermanent(err error) bool { if err == nil { return false } return errors.As(err, &permanent{}) } opentelemetry-collector-0.141.0/consumer/consumererror/permanent_test.go000066400000000000000000000020311511331344600266510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror import ( "errors" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type testErrorType struct { s string } func (t testErrorType) Error() string { return "" } func TestIsPermanent(t *testing.T) { var err error assert.False(t, IsPermanent(err)) err = errors.New("testError") assert.False(t, IsPermanent(err)) err = NewPermanent(err) assert.True(t, IsPermanent(err)) err = fmt.Errorf("%w", err) assert.True(t, IsPermanent(err)) } func TestPermanent_Unwrap(t *testing.T) { var err error = testErrorType{"testError"} require.False(t, IsPermanent(err)) // Wrapping testErrorType err with permanent error. permanentErr := NewPermanent(err) require.True(t, IsPermanent(permanentErr)) target := testErrorType{} require.NotEqual(t, err, target) isTestErrorTypeWrapped := errors.As(permanentErr, &target) require.True(t, isTestErrorTypeWrapped) require.Equal(t, err, target) } opentelemetry-collector-0.141.0/consumer/consumererror/signalerrors.go000066400000000000000000000033571511331344600263470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror // import "go.opentelemetry.io/collector/consumer/consumererror" import ( "go.opentelemetry.io/collector/consumer/consumererror/internal" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) // Traces is an error that may carry associated Trace data for a subset of received data // that failed to be processed or sent. type Traces struct { internal.Retryable[ptrace.Traces] } // NewTraces creates a Traces that can encapsulate received data that failed to be processed or sent. func NewTraces(err error, data ptrace.Traces) error { return Traces{ Retryable: internal.Retryable[ptrace.Traces]{ Err: NewRetryableError(err), Value: data, }, } } // Logs is an error that may carry associated Log data for a subset of received data // that failed to be processed or sent. type Logs struct { internal.Retryable[plog.Logs] } // NewLogs creates a Logs that can encapsulate received data that failed to be processed or sent. func NewLogs(err error, data plog.Logs) error { return Logs{ Retryable: internal.Retryable[plog.Logs]{ Err: NewRetryableError(err), Value: data, }, } } // Metrics is an error that may carry associated Metrics data for a subset of received data // that failed to be processed or sent. type Metrics struct { internal.Retryable[pmetric.Metrics] } // NewMetrics creates a Metrics that can encapsulate received data that failed to be processed or sent. func NewMetrics(err error, data pmetric.Metrics) error { return Metrics{ Retryable: internal.Retryable[pmetric.Metrics]{ Err: NewRetryableError(err), Value: data, }, } } opentelemetry-collector-0.141.0/consumer/consumererror/signalerrors_test.go000066400000000000000000000051511511331344600274000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumererror import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/testdata" ) func TestTraces(t *testing.T) { td := testdata.GenerateTraces(1) err := errors.New("some error") traceErr := NewTraces(err, td) require.EqualError(t, err, traceErr.Error()) var target Traces assert.NotErrorAs(t, nil, &target) assert.NotErrorAs(t, err, &target) require.ErrorAs(t, traceErr, &target) assert.Equal(t, td, target.Data()) } func TestTraces_Unwrap(t *testing.T) { td := testdata.GenerateTraces(1) var err error = testErrorType{"some error"} // Wrapping err with error Traces. traceErr := NewTraces(err, td) target := testErrorType{} require.NotEqual(t, err, target) // Unwrapping traceErr for err and assigning to target. require.ErrorAs(t, traceErr, &target) require.Equal(t, err, target) var e *Error require.ErrorAs(t, traceErr, &e) assert.True(t, e.IsRetryable()) } func TestLogs(t *testing.T) { td := testdata.GenerateLogs(1) err := errors.New("some error") logsErr := NewLogs(err, td) require.EqualError(t, err, logsErr.Error()) var target Logs assert.NotErrorAs(t, nil, &target) assert.NotErrorAs(t, err, &target) require.ErrorAs(t, logsErr, &target) assert.Equal(t, td, target.Data()) } func TestLogs_Unwrap(t *testing.T) { td := testdata.GenerateLogs(1) var err error = testErrorType{"some error"} // Wrapping err with error Logs. logsErr := NewLogs(err, td) target := testErrorType{} require.NotEqual(t, err, target) // Unwrapping logsErr for err and assigning to target. require.ErrorAs(t, logsErr, &target) require.Equal(t, err, target) var e *Error require.ErrorAs(t, logsErr, &e) assert.True(t, e.IsRetryable()) } func TestMetrics(t *testing.T) { td := testdata.GenerateMetrics(1) err := errors.New("some error") metricErr := NewMetrics(err, td) require.EqualError(t, err, metricErr.Error()) var target Metrics assert.NotErrorAs(t, nil, &target) assert.NotErrorAs(t, err, &target) require.ErrorAs(t, metricErr, &target) assert.Equal(t, td, target.Data()) } func TestMetrics_Unwrap(t *testing.T) { td := testdata.GenerateMetrics(1) var err error = testErrorType{"some error"} // Wrapping err with error Metrics. metricErr := NewMetrics(err, td) target := testErrorType{} require.NotEqual(t, err, target) // Unwrapping metricErr for err and assigning to target. require.ErrorAs(t, metricErr, &target) require.Equal(t, err, target) var e *Error require.ErrorAs(t, metricErr, &e) assert.True(t, e.IsRetryable()) } opentelemetry-collector-0.141.0/consumer/consumererror/xconsumererror/000077500000000000000000000000001511331344600263735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/consumererror/xconsumererror/Makefile000066400000000000000000000000411511331344600300260ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/consumer/consumererror/xconsumererror/go.mod000066400000000000000000000025071511331344600275050ustar00rootroot00000000000000module go.opentelemetry.io/collector/consumer/consumererror/xconsumererror go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumererror replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/consumer/consumererror/xconsumererror/go.sum000066400000000000000000000077271511331344600275430ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/consumer/consumererror/xconsumererror/signalerrors.go000066400000000000000000000014171511331344600314370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconsumererror // import "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" import ( "go.opentelemetry.io/collector/consumer/consumererror/internal" "go.opentelemetry.io/collector/pdata/pprofile" ) // Profiles is an error that may carry associated Profile data for a subset of received data // that failed to be processed or sent. type Profiles struct { internal.Retryable[pprofile.Profiles] } // NewProfiles creates a Profiles that can encapsulate received data that failed to be processed or sent. func NewProfiles(err error, data pprofile.Profiles) error { return Profiles{ Retryable: internal.Retryable[pprofile.Profiles]{ Err: err, Value: data, }, } } opentelemetry-collector-0.141.0/consumer/consumererror/xconsumererror/signalerrors_test.go000066400000000000000000000022461511331344600324770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconsumererror // import "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/testdata" ) func TestProfiles(t *testing.T) { td := testdata.GenerateProfiles(1) err := errors.New("some error") profileErr := NewProfiles(err, td) assert.Equal(t, err.Error(), profileErr.Error()) var target Profiles assert.NotErrorAs(t, nil, &target) assert.NotErrorAs(t, err, &target) require.ErrorAs(t, profileErr, &target) assert.Equal(t, td, target.Data()) } func TestProfiles_Unwrap(t *testing.T) { td := testdata.GenerateProfiles(1) var err error = testErrorType{"some error"} // Wrapping err with error Profiles. profileErr := NewProfiles(err, td) target := testErrorType{} require.NotEqual(t, err, target) // Unwrapping profileErr for err and assigning to target. require.ErrorAs(t, profileErr, &target) require.Equal(t, err, target) } type testErrorType struct { s string } func (t testErrorType) Error() string { return "" } opentelemetry-collector-0.141.0/consumer/consumertest/000077500000000000000000000000001511331344600231245ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/consumertest/Makefile000066400000000000000000000000361511331344600245630ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/consumer/consumertest/consumer.go000066400000000000000000000035211511331344600253070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest // import "go.opentelemetry.io/collector/consumer/consumertest" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) // Consumer is a convenience interface that implements all consumer interfaces. // It has a private function on it to forbid external users from implementing it // and, as a result, to allow us to add extra functions without breaking // compatibility. type Consumer interface { // Capabilities to implement the base consumer functionality. Capabilities() consumer.Capabilities // ConsumeTraces to implement the consumer.Traces. ConsumeTraces(context.Context, ptrace.Traces) error // ConsumeMetrics to implement the consumer.Metrics. ConsumeMetrics(context.Context, pmetric.Metrics) error // ConsumeLogs to implement the consumer.Logs. ConsumeLogs(context.Context, plog.Logs) error // ConsumeProfiles to implement the xconsumer.Profiles. ConsumeProfiles(context.Context, pprofile.Profiles) error unexported() } var ( _ consumer.Logs = Consumer(nil) _ consumer.Metrics = Consumer(nil) _ consumer.Traces = Consumer(nil) _ xconsumer.Profiles = Consumer(nil) ) type nonMutatingConsumer struct{} // Capabilities returns the base consumer capabilities. func (bc nonMutatingConsumer) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: false} } type baseConsumer struct { nonMutatingConsumer consumer.ConsumeTracesFunc consumer.ConsumeMetricsFunc consumer.ConsumeLogsFunc xconsumer.ConsumeProfilesFunc } func (bc baseConsumer) unexported() {} opentelemetry-collector-0.141.0/consumer/consumertest/doc.go000066400000000000000000000004441511331344600242220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package consumertest defines types and functions used to help test packages // implementing the consumer package interfaces. package consumertest // import "go.opentelemetry.io/collector/consumer/consumertest" opentelemetry-collector-0.141.0/consumer/consumertest/err.go000066400000000000000000000015611511331344600242460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest // import "go.opentelemetry.io/collector/consumer/consumertest" import ( "context" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) // NewErr returns a Consumer that just drops all received data and returns the specified error to Consume* callers. func NewErr(err error) Consumer { return &baseConsumer{ ConsumeTracesFunc: func(context.Context, ptrace.Traces) error { return err }, ConsumeMetricsFunc: func(context.Context, pmetric.Metrics) error { return err }, ConsumeLogsFunc: func(context.Context, plog.Logs) error { return err }, ConsumeProfilesFunc: func(context.Context, pprofile.Profiles) error { return err }, } } opentelemetry-collector-0.141.0/consumer/consumertest/err_test.go000066400000000000000000000015601511331344600253040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestErr(t *testing.T) { err := errors.New("my error") ec := NewErr(err) require.NotNil(t, ec) assert.NotPanics(t, ec.unexported) assert.Equal(t, err, ec.ConsumeLogs(context.Background(), plog.NewLogs())) assert.Equal(t, err, ec.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.Equal(t, err, ec.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.Equal(t, err, ec.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) } opentelemetry-collector-0.141.0/consumer/consumertest/go.mod000066400000000000000000000026171511331344600242400ustar00rootroot00000000000000module go.opentelemetry.io/collector/consumer/consumertest go 1.24.0 replace go.opentelemetry.io/collector/consumer => ../ require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/consumer/xconsumer => ../xconsumer replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/consumer/consumertest/go.sum000066400000000000000000000077271511331344600242740ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/consumer/consumertest/nop.go000066400000000000000000000015121511331344600242460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest // import "go.opentelemetry.io/collector/consumer/consumertest" import ( "context" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) // NewNop returns a Consumer that just drops all received data and returns no error. func NewNop() Consumer { return &baseConsumer{ ConsumeTracesFunc: func(context.Context, ptrace.Traces) error { return nil }, ConsumeMetricsFunc: func(context.Context, pmetric.Metrics) error { return nil }, ConsumeLogsFunc: func(context.Context, plog.Logs) error { return nil }, ConsumeProfilesFunc: func(context.Context, pprofile.Profiles) error { return nil }, } } opentelemetry-collector-0.141.0/consumer/consumertest/nop_test.go000066400000000000000000000014701511331344600253100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestNop(t *testing.T) { nc := NewNop() require.NotNil(t, nc) assert.NotPanics(t, nc.unexported) assert.NoError(t, nc.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, nc.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, nc.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, nc.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) } opentelemetry-collector-0.141.0/consumer/consumertest/package_test.go000066400000000000000000000003151511331344600261040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/consumer/consumertest/sink.go000066400000000000000000000147451511331344600244320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest // import "go.opentelemetry.io/collector/consumer/consumertest" import ( "context" "sync" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) // TracesSink is a consumer.Traces that acts like a sink that // stores all traces and allows querying them for testing. type TracesSink struct { nonMutatingConsumer mu sync.Mutex traces []ptrace.Traces contexts []context.Context spanCount int } var _ consumer.Traces = (*TracesSink)(nil) // ConsumeTraces stores traces to this sink. func (ste *TracesSink) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { ste.mu.Lock() defer ste.mu.Unlock() ste.traces = append(ste.traces, td) ste.contexts = append(ste.contexts, ctx) ste.spanCount += td.SpanCount() return nil } // AllTraces returns the traces stored by this sink since last Reset. func (ste *TracesSink) AllTraces() []ptrace.Traces { ste.mu.Lock() defer ste.mu.Unlock() copyTraces := make([]ptrace.Traces, len(ste.traces)) copy(copyTraces, ste.traces) return copyTraces } // Contexts returns the contexts stored by this sink since last Reset. func (ste *TracesSink) Contexts() []context.Context { ste.mu.Lock() defer ste.mu.Unlock() copyContexts := make([]context.Context, len(ste.contexts)) copy(copyContexts, ste.contexts) return copyContexts } // SpanCount returns the number of spans sent to this sink. func (ste *TracesSink) SpanCount() int { ste.mu.Lock() defer ste.mu.Unlock() return ste.spanCount } // Reset deletes any stored data. func (ste *TracesSink) Reset() { ste.mu.Lock() defer ste.mu.Unlock() ste.traces = nil ste.contexts = nil ste.spanCount = 0 } // MetricsSink is a consumer.Metrics that acts like a sink that // stores all metrics and allows querying them for testing. type MetricsSink struct { nonMutatingConsumer mu sync.Mutex metrics []pmetric.Metrics contexts []context.Context dataPointCount int } var _ consumer.Metrics = (*MetricsSink)(nil) // ConsumeMetrics stores metrics to this sink. func (sme *MetricsSink) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { sme.mu.Lock() defer sme.mu.Unlock() sme.metrics = append(sme.metrics, md) sme.contexts = append(sme.contexts, ctx) sme.dataPointCount += md.DataPointCount() return nil } // AllMetrics returns the metrics stored by this sink since last Reset. func (sme *MetricsSink) AllMetrics() []pmetric.Metrics { sme.mu.Lock() defer sme.mu.Unlock() copyMetrics := make([]pmetric.Metrics, len(sme.metrics)) copy(copyMetrics, sme.metrics) return copyMetrics } // Contexts returns the contexts stored by this sink since last Reset. func (sme *MetricsSink) Contexts() []context.Context { sme.mu.Lock() defer sme.mu.Unlock() copyContexts := make([]context.Context, len(sme.contexts)) copy(copyContexts, sme.contexts) return copyContexts } // DataPointCount returns the number of metrics stored by this sink since last Reset. func (sme *MetricsSink) DataPointCount() int { sme.mu.Lock() defer sme.mu.Unlock() return sme.dataPointCount } // Reset deletes any stored data. func (sme *MetricsSink) Reset() { sme.mu.Lock() defer sme.mu.Unlock() sme.metrics = nil sme.contexts = nil sme.dataPointCount = 0 } // LogsSink is a consumer.Logs that acts like a sink that // stores all logs and allows querying them for testing. type LogsSink struct { nonMutatingConsumer mu sync.Mutex logs []plog.Logs contexts []context.Context logRecordCount int } var _ consumer.Logs = (*LogsSink)(nil) // ConsumeLogs stores logs to this sink. func (sle *LogsSink) ConsumeLogs(ctx context.Context, ld plog.Logs) error { sle.mu.Lock() defer sle.mu.Unlock() sle.logs = append(sle.logs, ld) sle.logRecordCount += ld.LogRecordCount() sle.contexts = append(sle.contexts, ctx) return nil } // AllLogs returns the logs stored by this sink since last Reset. func (sle *LogsSink) AllLogs() []plog.Logs { sle.mu.Lock() defer sle.mu.Unlock() copyLogs := make([]plog.Logs, len(sle.logs)) copy(copyLogs, sle.logs) return copyLogs } // LogRecordCount returns the number of log records stored by this sink since last Reset. func (sle *LogsSink) LogRecordCount() int { sle.mu.Lock() defer sle.mu.Unlock() return sle.logRecordCount } // Reset deletes any stored data. func (sle *LogsSink) Reset() { sle.mu.Lock() defer sle.mu.Unlock() sle.logs = nil sle.contexts = nil sle.logRecordCount = 0 } // Contexts returns the contexts stored by this sink since last Reset. func (sle *LogsSink) Contexts() []context.Context { sle.mu.Lock() defer sle.mu.Unlock() copyContexts := make([]context.Context, len(sle.contexts)) copy(copyContexts, sle.contexts) return copyContexts } // ProfilesSink is a xconsumer.Profiles that acts like a sink that // stores all profiles and allows querying them for testing. type ProfilesSink struct { nonMutatingConsumer mu sync.Mutex profiles []pprofile.Profiles contexts []context.Context sampleCount int } var _ xconsumer.Profiles = (*ProfilesSink)(nil) // ConsumeProfiles stores profiles to this sink. func (ste *ProfilesSink) ConsumeProfiles(ctx context.Context, td pprofile.Profiles) error { ste.mu.Lock() defer ste.mu.Unlock() ste.profiles = append(ste.profiles, td) ste.contexts = append(ste.contexts, ctx) ste.sampleCount += td.SampleCount() return nil } // AllProfiles returns the profiles stored by this sink since last Reset. func (ste *ProfilesSink) AllProfiles() []pprofile.Profiles { ste.mu.Lock() defer ste.mu.Unlock() copyProfiles := make([]pprofile.Profiles, len(ste.profiles)) copy(copyProfiles, ste.profiles) return copyProfiles } // SampleCount returns the number of profiles stored by this sink since last Reset. func (ste *ProfilesSink) SampleCount() int { ste.mu.Lock() defer ste.mu.Unlock() return ste.sampleCount } // Reset deletes any stored data. func (ste *ProfilesSink) Reset() { ste.mu.Lock() defer ste.mu.Unlock() ste.profiles = nil ste.contexts = nil ste.sampleCount = 0 } // Contexts returns the contexts stored by this sink since last Reset. func (ste *ProfilesSink) Contexts() []context.Context { ste.mu.Lock() defer ste.mu.Unlock() copyContexts := make([]context.Context, len(ste.contexts)) copy(copyContexts, ste.contexts) return copyContexts } opentelemetry-collector-0.141.0/consumer/consumertest/sink_test.go000066400000000000000000000237301511331344600254630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumertest import ( "context" "fmt" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) type ( ctxKey string testKey int ) func TestTracesSink(t *testing.T) { sink := new(TracesSink) td := testdata.GenerateTraces(1) want := make([]ptrace.Traces, 0, 7) for range 7 { require.NoError(t, sink.ConsumeTraces(context.Background(), td)) want = append(want, td) } assert.Equal(t, want, sink.AllTraces()) assert.Equal(t, len(want), sink.SpanCount()) sink.Reset() assert.Empty(t, sink.AllTraces()) assert.Equal(t, 0, sink.SpanCount()) } func TestMetricsSink(t *testing.T) { sink := new(MetricsSink) md := testdata.GenerateMetrics(1) want := make([]pmetric.Metrics, 0, 7) for range 7 { require.NoError(t, sink.ConsumeMetrics(context.Background(), md)) want = append(want, md) } assert.Equal(t, want, sink.AllMetrics()) assert.Equal(t, 2*len(want), sink.DataPointCount()) sink.Reset() assert.Empty(t, sink.AllMetrics()) assert.Equal(t, 0, sink.DataPointCount()) } func TestLogsSink(t *testing.T) { sink := new(LogsSink) md := testdata.GenerateLogs(1) want := make([]plog.Logs, 0, 7) for range 7 { require.NoError(t, sink.ConsumeLogs(context.Background(), md)) want = append(want, md) } assert.Equal(t, want, sink.AllLogs()) assert.Equal(t, len(want), sink.LogRecordCount()) sink.Reset() assert.Empty(t, sink.AllLogs()) assert.Equal(t, 0, sink.LogRecordCount()) } func TestProfilesSink(t *testing.T) { sink := new(ProfilesSink) td := testdata.GenerateProfiles(1) want := make([]pprofile.Profiles, 0, 7) for range 7 { require.NoError(t, sink.ConsumeProfiles(context.Background(), td)) want = append(want, td) } assert.Equal(t, want, sink.AllProfiles()) assert.Equal(t, len(want), sink.SampleCount()) sink.Reset() assert.Empty(t, sink.AllProfiles()) assert.Empty(t, sink.SampleCount()) } func TestTracesSinkWithContext(t *testing.T) { sink := new(TracesSink) td := testdata.GenerateTraces(1) want := make([]ptrace.Traces, 0, 7) wantCtx := make([]context.Context, 0, 7) for i := range 7 { ctx := context.WithValue(context.Background(), testKey(i), fmt.Sprintf("value-%d", i)) require.NoError(t, sink.ConsumeTraces(ctx, td)) want = append(want, td) wantCtx = append(wantCtx, ctx) } assert.Equal(t, want, sink.AllTraces()) assert.Equal(t, len(want), sink.SpanCount()) // Verify contexts gotCtx := sink.Contexts() assert.Len(t, gotCtx, len(wantCtx)) for i, ctx := range gotCtx { assert.Equal(t, fmt.Sprintf("value-%d", i), ctx.Value(testKey(i))) } sink.Reset() assert.Empty(t, sink.AllTraces()) assert.Empty(t, sink.Contexts()) assert.Equal(t, 0, sink.SpanCount()) } func TestMetricsSinkWithContext(t *testing.T) { sink := new(MetricsSink) md := testdata.GenerateMetrics(1) want := make([]pmetric.Metrics, 0, 7) wantCtx := make([]context.Context, 0, 7) for i := range 7 { ctx := context.WithValue(context.Background(), testKey(i), fmt.Sprintf("value-%d", i)) require.NoError(t, sink.ConsumeMetrics(ctx, md)) want = append(want, md) wantCtx = append(wantCtx, ctx) } assert.Equal(t, want, sink.AllMetrics()) assert.Equal(t, 2*len(want), sink.DataPointCount()) // Verify contexts gotCtx := sink.Contexts() assert.Len(t, gotCtx, len(wantCtx)) for i, ctx := range gotCtx { assert.Equal(t, fmt.Sprintf("value-%d", i), ctx.Value(testKey(i))) } sink.Reset() assert.Empty(t, sink.AllMetrics()) assert.Empty(t, sink.Contexts()) assert.Equal(t, 0, sink.DataPointCount()) } func TestLogsSinkWithContext(t *testing.T) { sink := new(LogsSink) md := testdata.GenerateLogs(1) want := make([]plog.Logs, 0, 7) wantCtx := make([]context.Context, 0, 7) for i := range 7 { ctx := context.WithValue(context.Background(), testKey(i), fmt.Sprintf("value-%d", i)) require.NoError(t, sink.ConsumeLogs(ctx, md)) want = append(want, md) wantCtx = append(wantCtx, ctx) } assert.Equal(t, want, sink.AllLogs()) assert.Equal(t, len(want), sink.LogRecordCount()) // Verify contexts gotCtx := sink.Contexts() assert.Len(t, gotCtx, len(wantCtx)) for i, ctx := range gotCtx { assert.Equal(t, fmt.Sprintf("value-%d", i), ctx.Value(testKey(i))) } sink.Reset() assert.Empty(t, sink.AllLogs()) assert.Empty(t, sink.Contexts()) assert.Equal(t, 0, sink.LogRecordCount()) } func TestProfilesSinkWithContext(t *testing.T) { sink := new(ProfilesSink) td := testdata.GenerateProfiles(1) want := make([]pprofile.Profiles, 0, 7) wantCtx := make([]context.Context, 0, 7) for i := range 7 { ctx := context.WithValue(context.Background(), testKey(i), fmt.Sprintf("value-%d", i)) require.NoError(t, sink.ConsumeProfiles(ctx, td)) want = append(want, td) wantCtx = append(wantCtx, ctx) } assert.Equal(t, want, sink.AllProfiles()) assert.Equal(t, len(want), sink.SampleCount()) // Verify contexts gotCtx := sink.Contexts() assert.Len(t, gotCtx, len(wantCtx)) for i, ctx := range gotCtx { assert.Equal(t, fmt.Sprintf("value-%d", i), ctx.Value(testKey(i))) } sink.Reset() assert.Empty(t, sink.AllProfiles()) assert.Empty(t, sink.Contexts()) assert.Equal(t, 0, sink.SampleCount()) } // TestSinkContextTransformation verifies that the context is stored and transformed correctly func TestSinkContextTransformation(t *testing.T) { testCases := []struct { name string sink interface { Contexts() []context.Context } consumeFunc func(any, context.Context) error testData any }{ { name: "TracesSink", sink: new(TracesSink), consumeFunc: func(sink any, ctx context.Context) error { return sink.(*TracesSink).ConsumeTraces(ctx, testdata.GenerateTraces(1)) }, }, { name: "MetricsSink", sink: new(MetricsSink), consumeFunc: func(sink any, ctx context.Context) error { return sink.(*MetricsSink).ConsumeMetrics(ctx, testdata.GenerateMetrics(1)) }, }, { name: "LogsSink", sink: new(LogsSink), consumeFunc: func(sink any, ctx context.Context) error { return sink.(*LogsSink).ConsumeLogs(ctx, testdata.GenerateLogs(1)) }, }, { name: "ProfilesSink", sink: new(ProfilesSink), consumeFunc: func(sink any, ctx context.Context) error { return sink.(*ProfilesSink).ConsumeProfiles(ctx, testdata.GenerateProfiles(1)) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { // Create a context with initial values initialCtx := context.WithValue(context.Background(), ctxKey("initial-key"), "initial-value") // Create a context chain to simulate transformation transformedCtx := context.WithValue(initialCtx, ctxKey("transformed-key"), "transformed-value") // Consume data with the transformed context err := tc.consumeFunc(tc.sink, transformedCtx) require.NoError(t, err) // Verify context storage and transformation storedContexts := tc.sink.Contexts() assert.Len(t, storedContexts, 1, "Should have stored exactly one context") storedCtx := storedContexts[0] // Verify both initial and transformed values are preserved assert.Equal(t, "initial-value", storedCtx.Value(ctxKey("initial-key")), "Initial context value should be preserved") assert.Equal(t, "transformed-value", storedCtx.Value(ctxKey("transformed-key")), "Transformed context value should be stored") }) } } // TestContextTransformationChain verifies that the context is stored and transformed correctly in a chain of transformations func TestContextTransformationChain(t *testing.T) { sink := new(TracesSink) // Create a context transformation chain baseCtx := context.Background() ctx1 := context.WithValue(baseCtx, ctxKey("step1"), "value1") ctx2 := context.WithValue(ctx1, ctxKey("step2"), "value2") ctx3 := context.WithValue(ctx2, ctxKey("step3"), "value3") // Consume traces with the transformed context td := testdata.GenerateTraces(1) err := sink.ConsumeTraces(ctx3, td) require.NoError(t, err) // Verify the complete transformation chain storedContexts := sink.Contexts() require.Len(t, storedContexts, 1) finalCtx := storedContexts[0] // Verify each transformation step assert.Equal(t, "value1", finalCtx.Value(ctxKey("step1")), "First transformation should be preserved") assert.Equal(t, "value2", finalCtx.Value(ctxKey("step2")), "Second transformation should be preserved") assert.Equal(t, "value3", finalCtx.Value(ctxKey("step3")), "Third transformation should be preserved") } // TestConcurrentContextTransformations verifies context handling under concurrent operations func TestConcurrentContextTransformations(t *testing.T) { sink := new(TracesSink) const numGoroutines = 10 errChan := make(chan error, numGoroutines) var wg sync.WaitGroup wg.Add(numGoroutines) for i := range numGoroutines { go func(idx int) { defer wg.Done() key := ctxKey(fmt.Sprintf("goroutine-%d", idx)) value := fmt.Sprintf("value-%d", idx) ctx := context.WithValue(context.Background(), key, value) td := testdata.GenerateTraces(1) if err := sink.ConsumeTraces(ctx, td); err != nil { errChan <- err } }(i) } wg.Wait() close(errChan) // Check for any errors that occurred in goroutines for err := range errChan { t.Errorf("Error in goroutine: %v", err) } // Verify all contexts were stored correctly storedContexts := sink.Contexts() assert.Len(t, storedContexts, numGoroutines) // Create a map to verify all expected values are present contextValues := make(map[string]bool) for _, ctx := range storedContexts { for i := range numGoroutines { key := ctxKey(fmt.Sprintf("goroutine-%d", i)) expectedValue := fmt.Sprintf("value-%d", i) if val := ctx.Value(key); val == expectedValue { contextValues[fmt.Sprintf("goroutine-%d", i)] = true } } } // Verify all goroutines' contexts were preserved assert.Len(t, contextValues, numGoroutines, "Should have stored contexts from all goroutines") } opentelemetry-collector-0.141.0/consumer/doc.go000066400000000000000000000003321511331344600214630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package consumer contains interfaces that receive and process data. package consumer // import "go.opentelemetry.io/collector/consumer" opentelemetry-collector-0.141.0/consumer/go.mod000066400000000000000000000020461511331344600215010ustar00rootroot00000000000000module go.opentelemetry.io/collector/consumer go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/pdata v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kr/text v0.2.0 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../pdata retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/consumer/go.sum000066400000000000000000000100531511331344600215230ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/consumer/internal/000077500000000000000000000000001511331344600222055ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/internal/consumer.go000066400000000000000000000023031511331344600243650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/consumer/internal" // Capabilities describes the capabilities of a Processor. type Capabilities struct { // MutatesData is set to true if Consume* function of the // processor modifies the input Traces, Logs or Metrics argument. // Processors which modify the input data MUST set this flag to true. If the processor // does not modify the data it MUST set this flag to false. If the processor creates // a copy of the data before modifying then this flag can be safely set to false. MutatesData bool } type BaseConsumer interface { Capabilities() Capabilities } type BaseImpl struct { Cap Capabilities } // Option to construct new consumers. type Option interface { apply(*BaseImpl) } type OptionFunc func(*BaseImpl) func (of OptionFunc) apply(e *BaseImpl) { of(e) } // Capabilities returns the capabilities of the component func (bs BaseImpl) Capabilities() Capabilities { return bs.Cap } func NewBaseImpl(options ...Option) *BaseImpl { bs := &BaseImpl{ Cap: Capabilities{MutatesData: false}, } for _, op := range options { op.apply(bs) } return bs } opentelemetry-collector-0.141.0/consumer/logs.go000066400000000000000000000024321511331344600216650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer // import "go.opentelemetry.io/collector/consumer" import ( "context" "go.opentelemetry.io/collector/consumer/internal" "go.opentelemetry.io/collector/pdata/plog" ) // Logs is an interface that receives plog.Logs, processes it // as needed, and sends it to the next processing node if any or to the destination. type Logs interface { internal.BaseConsumer // ConsumeLogs processes the logs. After the function returns, the logs are no longer accessible, // and accessing them is considered undefined behavior. ConsumeLogs(ctx context.Context, ld plog.Logs) error } // ConsumeLogsFunc is a helper function that is similar to ConsumeLogs. type ConsumeLogsFunc func(ctx context.Context, ld plog.Logs) error // ConsumeLogs calls f(ctx, ld). func (f ConsumeLogsFunc) ConsumeLogs(ctx context.Context, ld plog.Logs) error { return f(ctx, ld) } type baseLogs struct { *internal.BaseImpl ConsumeLogsFunc } // NewLogs returns a Logs configured with the provided options. func NewLogs(consume ConsumeLogsFunc, options ...Option) (Logs, error) { if consume == nil { return nil, errNilFunc } return &baseLogs{ BaseImpl: internal.NewBaseImpl(options...), ConsumeLogsFunc: consume, }, nil } opentelemetry-collector-0.141.0/consumer/logs_test.go000066400000000000000000000030041511331344600227200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/plog" ) func TestDefaultLogs(t *testing.T) { cp, err := NewLogs(func(context.Context, plog.Logs) error { return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeLogs(context.Background(), plog.NewLogs())) assert.Equal(t, Capabilities{MutatesData: false}, cp.Capabilities()) } func TestNilFuncLogs(t *testing.T) { _, err := NewLogs(nil) assert.Equal(t, errNilFunc, err) } func TestWithCapabilitiesLogs(t *testing.T) { cp, err := NewLogs( func(context.Context, plog.Logs) error { return nil }, WithCapabilities(Capabilities{MutatesData: true})) assert.NoError(t, err) assert.NoError(t, cp.ConsumeLogs(context.Background(), plog.NewLogs())) assert.Equal(t, Capabilities{MutatesData: true}, cp.Capabilities()) } func TestConsumeLogs(t *testing.T) { consumeCalled := false cp, err := NewLogs(func(context.Context, plog.Logs) error { consumeCalled = true; return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeLogs(context.Background(), plog.NewLogs())) assert.True(t, consumeCalled) } func TestConsumeLogs_ReturnError(t *testing.T) { want := errors.New("my_error") cp, err := NewLogs(func(context.Context, plog.Logs) error { return want }) require.NoError(t, err) assert.Equal(t, want, cp.ConsumeLogs(context.Background(), plog.NewLogs())) } opentelemetry-collector-0.141.0/consumer/metrics.go000066400000000000000000000025671511331344600224000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer // import "go.opentelemetry.io/collector/consumer" import ( "context" "go.opentelemetry.io/collector/consumer/internal" "go.opentelemetry.io/collector/pdata/pmetric" ) // Metrics is an interface that receives pmetric.Metrics, processes it // as needed, and sends it to the next processing node if any or to the destination. type Metrics interface { internal.BaseConsumer // ConsumeMetrics processes the metrics. After the function returns, the metrics are no longer accessible, // and accessing them is considered undefined behavior. ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error } // ConsumeMetricsFunc is a helper function that is similar to ConsumeMetrics. type ConsumeMetricsFunc func(ctx context.Context, md pmetric.Metrics) error // ConsumeMetrics calls f(ctx, md). func (f ConsumeMetricsFunc) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { return f(ctx, md) } type baseMetrics struct { *internal.BaseImpl ConsumeMetricsFunc } // NewMetrics returns a Metrics configured with the provided options. func NewMetrics(consume ConsumeMetricsFunc, options ...Option) (Metrics, error) { if consume == nil { return nil, errNilFunc } return &baseMetrics{ BaseImpl: internal.NewBaseImpl(options...), ConsumeMetricsFunc: consume, }, nil } opentelemetry-collector-0.141.0/consumer/metrics_test.go000066400000000000000000000031411511331344600234240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pmetric" ) func TestDefaultMetrics(t *testing.T) { cp, err := NewMetrics(func(context.Context, pmetric.Metrics) error { return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.Equal(t, Capabilities{MutatesData: false}, cp.Capabilities()) } func TestNilFuncMetrics(t *testing.T) { _, err := NewMetrics(nil) assert.Equal(t, errNilFunc, err) } func TestWithCapabilitiesMetrics(t *testing.T) { cp, err := NewMetrics( func(context.Context, pmetric.Metrics) error { return nil }, WithCapabilities(Capabilities{MutatesData: true})) assert.NoError(t, err) assert.NoError(t, cp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.Equal(t, Capabilities{MutatesData: true}, cp.Capabilities()) } func TestConsumeMetrics(t *testing.T) { consumeCalled := false cp, err := NewMetrics(func(context.Context, pmetric.Metrics) error { consumeCalled = true; return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.True(t, consumeCalled) } func TestConsumeMetrics_ReturnError(t *testing.T) { want := errors.New("my_error") cp, err := NewMetrics(func(context.Context, pmetric.Metrics) error { return want }) require.NoError(t, err) assert.Equal(t, want, cp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) } opentelemetry-collector-0.141.0/consumer/package_test.go000066400000000000000000000003111511331344600233450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/consumer/traces.go000066400000000000000000000025301511331344600222010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer // import "go.opentelemetry.io/collector/consumer" import ( "context" "go.opentelemetry.io/collector/consumer/internal" "go.opentelemetry.io/collector/pdata/ptrace" ) // Traces is an interface that receives ptrace.Traces, processes it // as needed, and sends it to the next processing node if any or to the destination. type Traces interface { internal.BaseConsumer // ConsumeTraces processes the traces. After the function returns, the traces are no longer accessible, // and accessing them is considered undefined behavior. ConsumeTraces(ctx context.Context, td ptrace.Traces) error } // ConsumeTracesFunc is a helper function that is similar to ConsumeTraces. type ConsumeTracesFunc func(ctx context.Context, td ptrace.Traces) error // ConsumeTraces calls f(ctx, td). func (f ConsumeTracesFunc) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { return f(ctx, td) } type baseTraces struct { *internal.BaseImpl ConsumeTracesFunc } // NewTraces returns a Traces configured with the provided options. func NewTraces(consume ConsumeTracesFunc, options ...Option) (Traces, error) { if consume == nil { return nil, errNilFunc } return &baseTraces{ BaseImpl: internal.NewBaseImpl(options...), ConsumeTracesFunc: consume, }, nil } opentelemetry-collector-0.141.0/consumer/traces_test.go000066400000000000000000000031021511331344600232340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package consumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestDefaultTraces(t *testing.T) { cp, err := NewTraces(func(context.Context, ptrace.Traces) error { return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.Equal(t, Capabilities{MutatesData: false}, cp.Capabilities()) } func TestNilFuncTraces(t *testing.T) { _, err := NewTraces(nil) assert.Equal(t, errNilFunc, err) } func TestWithCapabilitiesTraces(t *testing.T) { cp, err := NewTraces( func(context.Context, ptrace.Traces) error { return nil }, WithCapabilities(Capabilities{MutatesData: true})) assert.NoError(t, err) assert.NoError(t, cp.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.Equal(t, Capabilities{MutatesData: true}, cp.Capabilities()) } func TestConsumeTraces(t *testing.T) { consumeCalled := false cp, err := NewTraces(func(context.Context, ptrace.Traces) error { consumeCalled = true; return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.True(t, consumeCalled) } func TestConsumeTraces_ReturnError(t *testing.T) { want := errors.New("my_error") cp, err := NewTraces(func(context.Context, ptrace.Traces) error { return want }) require.NoError(t, err) assert.Equal(t, want, cp.ConsumeTraces(context.Background(), ptrace.NewTraces())) } opentelemetry-collector-0.141.0/consumer/xconsumer/000077500000000000000000000000001511331344600224145ustar00rootroot00000000000000opentelemetry-collector-0.141.0/consumer/xconsumer/Makefile000066400000000000000000000000361511331344600240530ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/consumer/xconsumer/go.mod000066400000000000000000000021631511331344600235240ustar00rootroot00000000000000module go.opentelemetry.io/collector/consumer/xconsumer go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer => ../ replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/consumer/xconsumer/go.sum000066400000000000000000000077271511331344600235640ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/consumer/xconsumer/metadata.yaml000066400000000000000000000003431511331344600250600ustar00rootroot00000000000000type: xconsumer github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: consumer codeowners: active: - mx-psi - dmathieu stability: development: [profiles] opentelemetry-collector-0.141.0/consumer/xconsumer/profiles.go000066400000000000000000000030201511331344600245610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconsumer // import "go.opentelemetry.io/collector/consumer/xconsumer" import ( "context" "errors" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/internal" "go.opentelemetry.io/collector/pdata/pprofile" ) var errNilFunc = errors.New("nil consumer func") // Profiles is an interface that receives pprofile.Profiles, processes it // as needed, and sends it to the next processing node if any or to the destination. type Profiles interface { internal.BaseConsumer // ConsumeProfiles processes the profiles. After the function returns, the profiles are no longer accessible, // and accessing them is considered undefined behavior. ConsumeProfiles(ctx context.Context, td pprofile.Profiles) error } // ConsumeProfilesFunc is a helper function that is similar to ConsumeProfiles. type ConsumeProfilesFunc func(ctx context.Context, td pprofile.Profiles) error // ConsumeProfiles calls f(ctx, td). func (f ConsumeProfilesFunc) ConsumeProfiles(ctx context.Context, td pprofile.Profiles) error { return f(ctx, td) } type baseProfiles struct { *internal.BaseImpl ConsumeProfilesFunc } // NewProfiles returns a Profiles configured with the provided options. func NewProfiles(consume ConsumeProfilesFunc, options ...consumer.Option) (Profiles, error) { if consume == nil { return nil, errNilFunc } return &baseProfiles{ BaseImpl: internal.NewBaseImpl(options...), ConsumeProfilesFunc: consume, }, nil } opentelemetry-collector-0.141.0/consumer/xconsumer/profiles_test.go000066400000000000000000000033171511331344600256310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xconsumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pprofile" ) func TestDefaultProfiles(t *testing.T) { cp, err := NewProfiles(func(context.Context, pprofile.Profiles) error { return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.Equal(t, consumer.Capabilities{MutatesData: false}, cp.Capabilities()) } func TestNilFuncProfiles(t *testing.T) { _, err := NewProfiles(nil) assert.Equal(t, errNilFunc, err) } func TestWithCapabilitiesProfiles(t *testing.T) { cp, err := NewProfiles( func(context.Context, pprofile.Profiles) error { return nil }, consumer.WithCapabilities(consumer.Capabilities{MutatesData: true})) assert.NoError(t, err) assert.NoError(t, cp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.Equal(t, consumer.Capabilities{MutatesData: true}, cp.Capabilities()) } func TestConsumeProfiles(t *testing.T) { consumeCalled := false cp, err := NewProfiles(func(context.Context, pprofile.Profiles) error { consumeCalled = true; return nil }) assert.NoError(t, err) assert.NoError(t, cp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.True(t, consumeCalled) } func TestConsumeProfiles_ReturnError(t *testing.T) { want := errors.New("my_error") cp, err := NewProfiles(func(context.Context, pprofile.Profiles) error { return want }) require.NoError(t, err) assert.Equal(t, want, cp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) } opentelemetry-collector-0.141.0/distributions.yaml000066400000000000000000000014321511331344600223240ustar00rootroot00000000000000# A collection of distributions that can be referenced in the metadata.yaml files. # The rules below apply to every distribution added to this list: # - The distribution is open source and maintained by the OpenTelemetry project. # - The link must point to a publicly accessible repository. - name: core url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol - name: contrib url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib - name: k8s url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-k8s - name: otlp url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp opentelemetry-collector-0.141.0/docs/000077500000000000000000000000001511331344600174665ustar00rootroot00000000000000opentelemetry-collector-0.141.0/docs/README.md000066400000000000000000000055761511331344600207620ustar00rootroot00000000000000# OpenTelemetry Collector **Status**: [Beta](https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/0232-maturity-of-otel.md#beta) The OpenTelemetry Collector consists of the following components: * A mechanism that _MUST_ be able to load and parse an [OpenTelemetry Collector configuration file](#configuration-file). * A mechanism that _MUST_ be able to include compatible [Collector components](#opentelemetry-collector-components) that the user wishes to include. These combined provide users the ability to easily switch between [OpenTelemetry Collector Distributions](#opentelemetry-collector-distribution) while also ensuring that components produced by the OpenTelemetry Collector SIG are able to work with any vendor who claims support for an OpenTelemetry Collector. ## Configuration file An OpenTelemetry Collector configuration file is defined as YAML and _MUST_ support the following [minimum structure](https://pkg.go.dev/go.opentelemetry.io/collector/otelcol#Config): ```yaml receivers: processors: exporters: connectors: extensions: service: telemetry: pipelines: ``` ## OpenTelemetry Collector components For a library to be considered an OpenTelemetry Collector component, it _MUST_ implement a [Component interface](https://pkg.go.dev/go.opentelemetry.io/collector/component#Component) defined by the OpenTelemetry Collector SIG. Components require a [unique identifier](https://pkg.go.dev/go.opentelemetry.io/collector/component#ID) to be included in an OpenTelemetry Collector. In the event of a name collision, the components resulting in the collision cannot be used simultaneously in a single OpenTelemetry Collector. In order to resolve this, the clashing components must use different identifiers. ### Compatibility requirements A component is defined as compatible with an OpenTelemetry Collector when its dependencies are source- and version-compatible with the Component interfaces of that Collector. For example, a Collector derived from version tag v0.100.0 of the [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector) _MUST_ support all components that are version-compatible with the Golang Component API defined in the `github.com/open-telemetry/opentelemetry-collector/component` module found in that repository for that version tag. ## OpenTelemetry Collector Distribution An OpenTelemetry Collector Distribution (Distro) is a compiled instance of an OpenTelemetry Collector with a specific set of components and features. A Distribution author _MAY_ choose to produce a distribution by utilizing tools and/or documentation supported by the OpenTelemetry project. Alternatively, a Distribution author _MUST_ provide end users with the capability for adding their own components to the Distribution's components. Note that the resulting binary from updating a Distribution to include new components is a different Distribution. opentelemetry-collector-0.141.0/docs/coding-guidelines.md000066400000000000000000000772211511331344600234120ustar00rootroot00000000000000# Coding guidelines We consider the OpenTelemetry Collector to be close to production quality and the quality bar for contributions is set accordingly. Contributions must have readable code written with maintainability in mind (if in doubt check [Effective Go](https://golang.org/doc/effective_go.html) for coding advice). The code must adhere to the following robustness principles that are important for software that runs autonomously and continuously without direct interaction with a human (such as this Collector). ## Naming convention To keep naming patterns consistent across the project, naming patterns are enforced to make intent clear by: - Methods that return a variable that uses the zero value or values provided via the method MUST have the prefix `New`. For example: - `func NewKinesisExporter(kpl aws.KinesisProducerLibrary)` allocates a variable that uses the variables passed on creation. - `func NewKeyValueBuilder()` SHOULD allocate internal variables to a safe zero value. - Methods that return a variable that uses non-zero value(s) that impacts business logic MUST use the prefix `NewDefault`. For example: - `func NewDefaultKinesisConfig()` would return a configuration that is the suggested default and can be updated without concern of causing a race condition. - Methods that act upon an input variable MUST have a signature that reflects concisely the logic being done. For example: - `func FilterAttributes(attrs []Attribute, match func(attr Attribute) bool) []Attribute` MUST only filter attributes out of the passed input slice and return a new slice with values that `match` returns true. It may not do more work than what the method name implies, ie, it must not key a global history of all the slices that have been filtered. - Methods that get the value of a field i.e. a getterMethod MUST use an uppercase first letter and NOT a `get` prefix. For example: - `func (p *Person) Name() string {return p.name} ` Name (with an uppercase N, exported) method is used here to get the value of the name field and not `getName`.The use of upper-case names for export provides the hook to discriminate the field from the method. - Methods that set the value of a field i.e. a setterMethod MUST use a `set` prefix. For example: - `func (p *Person) SetName(newName string) {p.name = newName}` SetName method here sets the value of the name field. - Variable assigned in a package's global scope that is preconfigured with a default set of values MUST use `Default` as the prefix. For example: - `var DefaultMarshallers = map[string]pdata.Marshallers{...}` is defined with an exporter package that allows for converting an encoding name, `zipkin`, and return the preconfigured marshaller to be used in the export process. - Types that are specific to a signal MUST be worded with the signal used as an adjective, i.e. `SignalType`. For example: - `type TracesSink interface {...}` - Types that deal with multiple signal types should use the relationship between the signals to describe the type, e.g. `SignalToSignalType` or `SignalAndSignalType`. For example: - `type TracesToTracesFunc func(...) ...` - Functions dealing with specific signals or signal-specific types MUST be worded with the signal or type as a direct object, i.e. `VerbSignal`, or `VerbType` where `Type` is the full name of the type including the signal name. For example: - `func ConsumeTraces(...) {...}` - `func CreateTracesExport(...) {...}` - `func CreateTracesToTracesFunc(...) {...}` ### Configuration structs When naming configuration structs, use the following guidelines: - Separate the configuration set by end users in their YAML configuration from the configuration set by developers in the code into different structs. - Use the `Config` suffix for configuration structs that have end user configuration (i.e. that set in their YAML configuration). For example, `configgrpc.ClientConfig` ends in `Config` since it contains end user configuration. - Use the `Settings` suffix for configuration structs that are set by developers in the code. For example, `component.TelemetrySettings` ends in `Settings` since it is set by developers in the code. - Avoid redundant prefixes that are already implied by the package name. For example, use`configgrpc.ClientConfig` instead of `configgrpc.GRPCClientConfig`. ## Module organization As usual in Go projects, organize your code into packages grouping related functionality. To ensure that we can evolve different parts of the API independently, you should also group related packages into modules. We use the following rules for some common situations where we split into separate modules: 1. Each top-level directory should be a separate module. 1. Each component referenceable by the OpenTelemetry Collector Builder should be in a separate module. For example, the OTLP receiver is in its own module, different from that of other receivers. 1. Consider splitting into separate modules if the API may evolve independently in separate groups of packages. For example, the configuration related to HTTP and gRPC evolve independently, so `config/configgrpc` and `config/confighttp` are separate modules. 1. For component names, add the component kind as a suffix for the module name. For example, the OTLP receiver is in the `receiver/otlpreceiver` module. 1. Modules that add specific functionality related to a parent folder should have a prefix in the name that relates to the parent module. For example, `configauth` has the `config` prefix since it is part of the `config` folder, and `extensionauth` has `extension` as a prefix since it is part of the `extension` module. 1. Testing helpers should be in a separate submodule with the suffix `test`. For example, if you have a module `component`, the helpers should be in `component/componenttest`. Testing helpers that are used across multiple modules should be in the [`internal/testutil`](https://github.com/open-telemetry/opentelemetry-collector/tree/main/internal/testutil) module. 1. Experimental packages that will later be added to another module should be in their own module, named as they will be after integration. For example, if adding a `pprofile` package to `pdata`, you should add a separate module `pdata/pprofile` for the experimental code. 1. Experimental code that will be added to an existing package in a stable module can be a submodule with the same name, but prefixed with an `x`. For example, `config/confighttp` module can have an experimental module named `config/confighttp/xconfighttp` that contains experimental APIs. When adding a new module remember to update the following: 1. Add a changelog note for the new module. 1. Add the module in `versions.yaml`. 1. Use `make crosslink` to make sure the module replaces are added correctly throughout the codebase. You may also have to manually add some of the replaces. 1. Update the [otelcorecol manifest](https://github.com/open-telemetry/opentelemetry-collector/blob/main/cmd/otelcorecol/builder-config.yaml) and [builder tests](https://github.com/open-telemetry/opentelemetry-collector/blob/main/cmd/builder/internal/builder/main_test.go). 1. Open a follow up PR to update pseudo-versions in all go.mod files. See [this example PR](https://github.com/open-telemetry/opentelemetry-collector/pull/11668). ## Enumerations To keep naming patterns consistent across the project, enumeration patterns are enforced to make intent clear: - Enumerations should be defined using a type definition, such as `type Level int32`. - Enumerations should use either `int` or `string` as the underlying type - The enumeration name should succinctly describe its purpose - If the package name represents the entity described by the enumeration then the package name should be factored into the name of the enumeration. For example, `component.Type` instead of `component.ComponentType`. - The name should convey a sense of limited categorization. For example, `pcommon.ValueType` is better than `pcommon.Value` and `component.Kind` is better than `component.KindType`, since `Kind` already conveys categorization. - Constant values of an enumeration should be prefixed with the enumeration type name in the name: - `pcommon.ValueTypeStr` for `pcommon.ValueType` - `pmetric.MetricTypeGauge` for `pmetric.MetricType` ## Recommended Libraries / Defaults In order to simplify development within the project, we have made certain library recommendations that should be followed. | Scenario | Recommended | Rationale | |------------|------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------| | Hashing | ["hashing/fnv"](https://pkg.go.dev/hash/fnv) | The project adopted this as the default hashing method due to the efficiency and is reasonable for non-cryptographic use | | Testing | Use `t.Parallel()` where possible | Enabling more tests to be run in parallel will speed up the feedback process when working on the project. | Within the project, there are some packages that have yet to follow the recommendations and are being addressed. However, any new code should adhere to the recommendations. ## Default Configuration To guarantee backward-compatible behavior, all configuration packages should supply a `NewDefault[config name]` functions that create a default version of the config. The package does not need to guarantee that `NewDefault[config name]` returns a usable configurationโ€”only that default values will be set. For example, if the configuration requires that a field, such as `Endpoint` be set, but there is no valid default value, then `NewDefault[config name]` may set that value to `""` with the expectation that the user will set a valid value. Users should always initialize the config struct with this function and overwrite anything as needed. ## Startup Error Handling Verify configuration during startup and fail fast if the configuration is invalid. This will bring the attention of a human to the problem as it is more typical for humans to notice problems when the process is starting as opposed to problems that may arise sometime (potentially long time) after process startup. Monitoring systems are likely to automatically flag processes that exit with failure during startup, making it easier to notice the problem. The Collector should print a reasonable log message to explain the problem and exit with a non-zero code. It is acceptable to crash the process during startup if there is no good way to exit cleanly but do your best to log and exit cleanly with a process exit code. ## Propagate Errors to the Caller Do not crash or exit outside the `main()` function, e.g. via `log.Fatal` or `os.Exit`, even during startup. Instead, return detailed errors to be handled appropriately by the caller. The code in packages other than `main` may be imported and used by third-party applications, and they should have full control over error handling and process termination. ## Do not Crash after Startup Do not crash or exit the Collector process after the startup sequence is finished. A running Collector typically contains data that is received but not yet exported further (e.g. data that is stored in the queues and other processors). Crashing or exiting the Collector process will result in losing this data since typically the receiver has already acknowledged the receipt for this data and the senders of the data will not send that data again. ## Bad Input Handling Do not crash on bad input in receivers or elsewhere in the pipeline. [Crash-only software](https://en.wikipedia.org/wiki/Crash-only_software) is valid in certain cases; however, this is not a correct approach for Collector (except during startup, see above). The reason is that many senders from which the Collector receives data have built-in automatic retries of the _same_ data if no acknowledgment is received from the Collector. If you crash on bad input chances are high that after the Collector is restarted it will see the same data in the input and will crash again. This will likely result in an infinite crashing loop if you have automatic retries in place. Typically bad input when detected in a receiver should be reported back to the sender. If it is elsewhere in the pipeline it may be too late to send a response to the sender (particularly in processors which are not synchronously processing data). In either case, it is recommended to keep a metric that counts bad input data. ## Error Handling and Retries Be rigorous in error handling. Don't ignore errors. Think carefully about each error and decide if it is a fatal problem or a transient problem that may go away when retried. Fatal errors should be logged or recorded in an internal metric to provide visibility to users of the Collector. For transient errors come up with a retrying strategy and implement it. Typically you will want to implement retries with some sort of exponential back-off strategy. For connection or sending retries use jitter for back-off intervals to avoid overwhelming your destination when the network is restored or the destination is recovered. [Exponential Backoff](https://github.com/cenkalti/backoff) is a good library that provides all this functionality. ## Logging Log your component startup and shutdown, including successful outcomes (but don't overdo it, and keep the number of success messages to a minimum). This can help to understand the context of failures if they occur elsewhere after your code is successfully executed. Use logging carefully for events that can happen frequently to avoid flooding the logs. Avoid outputting logs per a received or processed data item since this can amount to a very large number of log entries (Collector is designed to process many thousands of spans and metrics per second). For such high-frequency events instead of logging consider adding an internal metric and incrementing it when the event happens. Make log messages human readable and also include data that is needed for easier understanding of what happened and in what context. ## Executing External Processes The components should avoid executing arbitrary external processes with arbitrary command line arguments based on user input, including input received from the network or input read from the configuration file. Failure to follow this rule can result in arbitrary remote code execution, compelled by malicious actors that can craft the input. The following limitations are recommended: - If an external process needs to be executed limit and hard-code the location where the executable file may be located, instead of allowing the input to dictate the full path to the executable. - If possible limit the name of the executable file to be pulled from a hard-coded list defined at compile time. - If command line arguments need to be passed to the process do not take the arguments from the user input directly. Instead, compose the command line arguments indirectly, if necessary, deriving the value from the user input. Limit as much as possible the size of the possible space of values for command line arguments. ## Observability Out of the box, your users should be able to observe the state of your component. See [observability.md](observability.md) for more details. When using the regular helpers, you should have some metrics added around key events automatically. For instance, exporters should have `otelcol_exporter_sent_spans` tracked without your exporter doing anything. Custom metrics can be defined as part of the `metadata.yaml` for your component. The authoritative source of information for this is [the schema](https://github.com/open-telemetry/opentelemetry-collector/blob/main/cmd/mdatagen/metadata-schema.yaml), but here are a few examples for reference, adapted from the tail sampling processor: ```yaml telemetry: metrics: # example of a histogram processor.tailsampling.samplingdecision.latency: description: Latency (in microseconds) of a given sampling policy. unit: ยตs # from https://ucum.org/ucum enabled: true histogram: value_type: int # bucket boundaries can be overridden bucket_boundaries: [1, 2, 5, 10, 25, 50, 75, 100, 150, 200, 300, 400, 500, 750, 1000, 2000, 3000, 4000, 5000, 10000, 20000, 30000, 50000] # example of a counter processor.tailsampling.policyevaluation.errors: description: Count of sampling policy evaluation errors. unit: "{errors}" enabled: true sum: value_type: int monotonic: true # example of a gauge processor.tailsampling.tracesonmemory: description: Tracks the number of traces current on memory. unit: "{traces}" enabled: true gauge: value_type: int ``` Running `go generate ./...` at the root of your component should generate the following files: - `documentation.md`, with the metrics and their descriptions - `internal/metadata/generated_telemetry.go`, with code that defines the metric using the OTel API - `internal/metadata/generated_telemetry_test.go`, with sanity tests for the generated code On your component's code, you can use the metric by initializing the telemetry builder and storing it on a component's field: ```go type tailSamplingSpanProcessor struct { ctx context.Context telemetry *metadata.TelemetryBuilder } func newTracesProcessor(ctx context.Context, settings component.TelemetrySettings, nextConsumer consumer.Traces, cfg Config, opts ...Option) (processor.Traces, error) { telemetry, err := metadata.NewTelemetryBuilder(settings) if err != nil { return nil, err } tsp := &tailSamplingSpanProcessor{ ctx: ctx, telemetry: telemetry, } } ``` To record the measurement, you can then call the metric stored in the telemetry builder: ```go tsp.telemetry.ProcessorTailsamplingSamplingdecisionLatency.Record(ctx, ...) ``` ## Resource Usage Limit usage of CPU, RAM, and other resources that the code can use. Do not write code that consumes resources in an uncontrolled manner. For example, if you have a queue that can contain unprocessed messages always limit the size of the queue unless you have other ways to guarantee that the queue will be consumed faster than items are added to it. Performance test the code for both normal use-cases under acceptable load and also for abnormal use-cases when the load exceeds acceptable limits many times over. Ensure that your code performs predictably under abnormal use. For example, if the code needs to process received data and cannot keep up with the receiving rate it is not acceptable to keep allocating more memory for received data until the Collector runs out of memory. Instead have protections for these situations, e.g. when hitting resource limits drop the data and record the fact that it was dropped in a metric that is exposed to users. ## Graceful Shutdown Collector does not yet support graceful shutdown but we plan to add it. All components must be ready to shutdown gracefully via `Shutdown()` function that all component interfaces require. If components contain any temporary data they need to process and export it out of the Collector before shutdown is completed. The shutdown process will have a maximum allowed duration so put a limit on how long your shutdown operation can take. ## Unit Tests Cover important functionality with unit tests. We require that contributions do not decrease the overall code coverage of the codebase - this is aligned with our goal to increase coverage over time. Keep track of execution time for your unit tests and try to keep them as short as possible. ## Semantic Conventions compatibility When adding new metrics, attributes or entity attributes to a Collector's component (receiver, processor etc), the [Semantic Conventions](https://github.com/open-telemetry/semantic-conventions) project should be checked first to see if those are already defined as Semantic Conventions. It's also important to check for any open issues that may already propose these or similar Semantic Conventions. If no such Semantic Conventions are defined in the Semantic Conventions project, the componentโ€™s code owners should consider initiating that process first (refer to Semantic Conventions' [contribution guidelines](https://github.com/open-telemetry/semantic-conventions/blob/main/CONTRIBUTING.md) for specific details). The implementation of the component can still be submitted as a draft PR to demonstrate how the proposed Semantic Conventions would be used while working in parallel to contribute the relevant updates to the Semantic Conventions project. The components's code owners can review the Semantic Conventions PR in collaboration with any existing domain-specific SemConv approvers. At their discretion, the code owners may choose to block the componentโ€™s implementation PR until the related Semantic Conventions changes are completed. ### Testing Library Recommendations To keep testing practices consistent across the project, it is advised to use these libraries under these circumstances: - For assertions to validate expectations, use `"github.com/stretchr/testify/assert"` - For assertions that are required to continue the test, use `"github.com/stretchr/testify/require"` - For mocking external resources, use `"github.com/stretchr/testify/mock"` - For validating HTTP traffic interactions, `"net/http/httptest"` ## Integration Testing Integration testing is encouraged throughout the project, container images can be used in order to facilitate a local version. In their absence, it is strongly advised to mock the integration. ## Using CGO Using CGO is prohibited due to the lack of portability and complexity that comes with managing external libraries with different operating systems and configurations. However, if the package MUST use CGO, this should be explicitly called out within the readme with clear instructions on how to install the required libraries. Furthermore, if your package requires CGO, it MUST be able to compile and operate in a no-op mode or report a warning back to the collector with a clear error saying CGO is required to work. ## Breaking changes Whenever possible, we adhere to [semver](https://semver.org/) as our minimum standards. Even before v1, we strive not to break compatibility without a good reason. Hence, when a change is known to cause a breaking change, we intend to follow these principles: - Breaking changes MUST have migration guidelines that clearly explain how to adapt to them. - Users SHOULD be able to adopt the breaking change at their own pace, independent of other Collector updates. - Users SHOULD be proactively notified about the breaking change before a migration is required. - Users SHOULD be able to easily tell whether they have completed the migration for a breaking change. Not all changes have the same effects on users, so some of the steps may be unnecessary for some changes. ### API breaking changes We strive to perform API breaking changes in two stages, deprecating it first (`vM.N`) and breaking it in a subsequent version (`vM.N+1`). - when we need to remove something, we MUST mark a feature as deprecated in one version and MAY remove it in a subsequent one - when renaming or refactoring types, functions, or attributes, we MUST create the new name and MUST deprecate the old one in one version (step 1), and MAY remove it in a subsequent version (step 2). For simple renames, the old name SHALL call the new one. - when a feature is being replaced in favor of an existing one, we MUST mark a feature as deprecated in one version, and MAY remove it in a subsequent one. Deprecation notice SHOULD contain a version starting from which the deprecation takes effect for tracking purposes. For example, if `GetFoo` function is going to be deprecated in `v0.45.0` version, it gets the following godoc line: ```golang package test // Deprecated: [v0.45.0] Use MustDoFoo instead. func DoFoo() {} ``` #### Example #1 - Renaming a function 1. Current version `v0.N` has `func GetFoo() Bar` 1. We now decided that `GetBar` is a better name. As such, on `v0.N+1` we add a new `func GetBar() Bar` function, changing the existing `func GetFoo() Bar` to be an alias of the new function. Additionally, a log entry with a warning is added to the old function, along with an entry to the changelog. 1. On `v0.N+2`, we MAY remove `func GetFoo() Bar`. #### Example #2 - Changing the return values of a function 1. Current version `v0.N` has `func GetFoo() Foo` 1. We now need to also return an error. We do it by creating a new function that will be equivalent to the existing one so that current users can easily migrate to that: `func MustGetFoo() Foo`, which panics on errors. We release this in `v0.N+1`, deprecating the existing `func GetFoo() Foo` with it, adding an entry to the changelog and perhaps a log entry with a warning. 1. On `v0.N+2`, we change `func GetFoo() Foo` to `func GetFoo() (Foo, error)`. #### Example #3 - Changing the arguments of a function 1. Current version `v0.N` has `func GetFoo() Foo` 2. We now decide to do something that might be blocking as part of `func GetFoo() Foo`, so, we start accepting a context: `func GetFooWithContext(context.Context) Foo`. We release this in `v0.N+1`, deprecating the existing `func GetFoo() Foo` with it, adding an entry to the changelog and perhaps a log entry with a warning. The existing `func GetFoo() Foo` is changed to call `func GetFooWithContext(context.Background()) Foo`. 3. On `v0.N+2`, we change `func GetFoo() Foo` to `func GetFoo(context.Context) Foo` if desired or remove it entirely if needed. #### Exceptions For changes to modules that do not have a version of `v1` or higher, we may skip the deprecation process described above for the following situations. Note that these changes should still be recorded as breaking changes in the changelog. * **Variadic arguments.** Functions that are not already variadic may have a variadic parameter added as a method of supporting optional parameters, particularly through the functional options pattern. If a variadic parameter is added to a function with no change in functionality when no variadic arguments are passed, the deprecation process may be skipped. Calls to updated functions without the new argument will continue to work before, but users who depend on the exact function signature as a type, for example as an argument to another function, will experience a breaking change. For this reason, the deprecation process should only be skipped when it is not expected that the function is commonly passed as a value. ### End-user impacting changes For end user breaking changes, we follow the [feature gate](https://github.com/open-telemetry/opentelemetry-collector/tree/main/featuregate#feature-lifecycle) approach. This is a well-known approach in other projects such as Kubernetes. A feature gate has three stages: alpha, beta and stable. The intent of these stages is to decouple other software changes from the breaking change; some users may adopt the change early, while other users may delay its adoption. #### Feature gate IDs Feature gate IDs should be namespaced using dots to denote the hierarchy. The namespace should be as specific as possible; in particular, for feature gates specific to a certain component the ID should have the following structure: `..`. The "base ID" should be written with a verb that describes what happens when the feature gate is enabled. For example, if you want to add a feature gate for the OTLP receiver that changes the default endpoint to bind to an unspecified host, you could name your feature gate `receiver.otlp.UseUnspecifiedHostAsDefaultHost`. #### Lifecycle of a breaking change ##### Alpha stage At the alpha stage, the change is opt-in. At this stage we want to notify users that a change is coming, so they can start preparing for it and we have some early adopters that provide us with feedback. Consider the following items before the initial release of an alpha feature gate: * If **docs and examples** can be updated in a way that prevents the breaking change from affecting users, this is the time to update them! * Provide users with tools to understand the breaking change * (Optional) Create or update a **Github issue** to document what the change is about, who it affects and what its effects are * (Optional) Consider adding **telemetry** that allows users to track their migration. For example, you can add a counter for the times that you see a payload that would be affected by the breaking change. * Notify users about the upcoming change * Add a **changelog entry** that describes the feature gate. It should include its name, when you may want to use it, and what its effects are. The changelog entry can be given the `enhancement` classification at this stage. * (Optional but strongly recommended) Log a **warning** if the user is using the software in a way that would be affected by the breaking change. Point the user to the feature gate and any official docs. * (Optional) Try to **test this in a realistic setting.** If this solves an issue, ask the poster to try to use it and check that everything works. ##### Beta stage At the beta stage, the change is opt-out. At this stage we want to notify users that the change is happening, and help them understand how to revert back to the previous behavior temporarily if they need to do so. You may directly start from this stage for breaking changes that are less impactful or for changes that should not have a functional impact such as performance changes. Consider the following items before moving from alpha to beta: * Schedule the **docs and examples** update to align with the breaking change release if you couldnโ€™t do it before * Provide users with tools to understand the breaking change * Update the **Github issue** with the new default behavior (or create one if starting from here) * Update the feature gate to add the โ€˜to versionโ€™ to the feature gate * Notify users about the change * Add a second **changelog entry** that describes the change one more time and is marked as โ€˜breakingโ€™. * If applicable, add an **error message** that tells you this is the result of a breaking change that can be temporarily reverted disabling the feature gate and points to any issue or docs about it. ##### Stable stage At the stable stage, the change cannot be reverted. In some cases, you may directly start here and just do the change, in which case you do not need a feature gate, but you should still follow the checklist below (notify, update docs and examples). Consider the following items before moving from beta to stable: * Remove the dead code * Provide users with tools to understand the breaking change * Update the **documentation** **and examples** to remove any references to the feature gate and the previous behavior. Close the **Github issue** if you opened one before. * Notify users about the change * Add one last **changelog entry** so users know the range where the feature gate was in beta * Amend the **error message** to remove any references to the feature gate. ## Specification Tracking The [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification) can be a rapidly moving target at times. While it may seem efficient to get an early start on implementing new features or functionality under development in the specification, this can also lead to significant churn and a risk that changes in the specification can result in breaking changes to the implementation. For this reason, it is the policy of the Collector SIG to not implement, or accept implementations of, new or changed specification language prior to inclusion in a stable release of the specification. opentelemetry-collector-0.141.0/docs/component-stability.md000066400000000000000000000443611511331344600240240ustar00rootroot00000000000000# Stability Levels and versioning ## Stability levels The Collector components and implementation are in different stages of stability, and usually split between functionality and configuration. While we intend to provide high-quality components as part of this repository, we acknowledge that not all of them are ready for prime time. Moreover, the stability of components that can handle multiple signals can depend on the signal in question. As such, each component should list its current stability level for each telemetry signal in its README file, according to the following definitions: ### Development Not all pieces of the component are in place yet and it might not be available as part of any distributions yet. Bugs and performance issues should be reported, but it is likely that the component owners might not give them much attention. Your feedback is still desired, especially when it comes to the user-experience (configuration options, component observability, technical implementation details, ...). Configuration options might break often depending on how things evolve. The component should not be used in production. ### Alpha The component is ready to be used for limited non-critical workloads and the authors of this component would welcome your feedback. Bugs and performance problems should be reported, but component owners might not work on them right away. #### Configuration changes Configuration for alpha components can be changed with minimal notice. Documenting them as part of the changelog is sufficient. We still recommend giving users one or two minor versions' notice before breaking the configuration, such as when removing or renaming a configuration option. Providing a migration path in the component's repository is NOT required for alpha components, although it is still recommended. - when adding a new configuration option, components MAY mark the new option as required and are not required to provide a reasonable default. - when renaming a configuration option, components MAY treat the old name as an alias to the new one and log a WARN level message in case the old option is being used. - when removing a configuration option, components MAY keep the old option for a few minor releases and log a WARN level message instructing users to remove the option. #### Documentation requirements Alpha components should document how to use them in the most common situations, including: - One or more example configuration snippets for the most common use cases. ### Beta Same as Alpha, but the configuration options are deemed stable. While there might be breaking changes between releases, component owners should try to minimize them. A component at this stage is expected to have had exposure to non-critical production workloads already during its **Alpha** phase, making it suitable for broader usage. #### Configuration changes Backward incompatible changes should be rare events for beta components. Users of those components are not expecting to have their Collector instances failing at startup because of a configuration change. When doing backward incompatible changes, component owners should add the migration path to a place within the component's repository, linked from the component's main README. This is to ensure that people using older instructions can understand how to migrate to the latest version of the component. When adding a new required option: - the option MUST come with a sensible default value When renaming or removing a configuration option: - the option MUST be deprecated in one version - a WARN level message should be logged, with a link to a place within the component's repository where the change is documented and a migration path is provided - the option MUST be kept for at least N+1 version and MAY be hidden behind a feature gate in N+2 - the option and the WARN level message MUST NOT be removed earlier than N+2 or 6 months, whichever comes later Additionally, when removing an option: - the option MAY be made non-operational already by the same version where it is deprecated #### Documentation requirements Beta components should have a set of documentation that documents its usage in most cases, including: - One or more example configuration snippets for the most common use cases. - Advanced configuration options that are known to be used in common environments. - All component-specific feature gates including a description for them and when they should be used. - Warnings about known limitations and ways to misuse the component. Receivers that produce a fixed set of telemetry should document the telemetry they produce, including: - For all signals, the resource attributes that are expected to be present in telemetry. - For metrics, the name, description, type, units and attributes of each metric. ### Stable The component is ready for general availability. Bugs and performance problems should be reported and there's an expectation that the component owners will work on them. Breaking changes, including configuration options and the component's output are not expected to happen without prior notice, unless under special circumstances. #### Configuration changes Stable components MUST be compatible between minor versions unless critical security issues are found. In that case, the component owner MUST provide a migration path and a reasonable time frame for users to upgrade. The same rules from beta components apply to stable when it comes to configuration changes. #### Testing requirements Stable components MUST have a comprehensive test suite. In particular they MUST have: 1. A **test coverage** that exceeds the highest between 80% coverage and the repository-wide minimum. The unit test suite SHOULD cover all configuration options. The coverage MUST be shown as part of the component documentation. 2. At least one **lifecycle test** that tests the component's initialization with a valid configuration and ensures proper context propagation if applicable. 3. At least one **benchmark test** for each stable signal. The component's documentation MUST include a link to the latest run of benchmark results. #### Documentation requirements Stable components should have a complete set of documentation, including: - One or more example configuration snippets for the most common use cases. - All configuration options supported by the component and a description for each of them. - All component-specific feature gates including a description for them and when they should be used. - All component-specific self-observability features that are not available for other components and what they provide. - Compatibility guarantees with external dependencies including the versions it is compatible with and under what conditions. - Guidance related to the component's usage in production environments, including how to scale a deployment of this component properly if it needs special considerations. - If stateful, how to configure the component to use persistent storage and how to gracefully shutdown and restart the component. - Warnings about known limitations and ways to misuse the component. Receivers that produce a fixed set of telemetry should document the telemetry they produce, including: - For all signals, the resource attributes that are expected to be present in telemetry. - For metrics, the name, description, type, units and attributes of each metric. #### Observability requirements Stable components should emit enough internal telemetry to let users detect errors, as well as data loss and performance issues inside the component, and to help diagnose them if possible. For extension components, this means some way to monitor errors (for example through logs or span events), and some way to monitor performance (for example through spans or histograms). Because extensions can be so diverse, the details will be up to the component authors, and no further constraints are set out in this document. For pipeline components however, this section details the kinds of values that should be observable via internal telemetry for all stable components. > [!NOTE] > - The following categories MUST all be covered, unless justification is given as to why one may > not be applicable. > - However, for each category, many reasonable implementations are possible, as long as the > relevant information can be derived from the emitted telemetry; everything after the basic > category description is a recommendation, and is not normative. > - Of course, a component may define additional internal telemetry which is not in this list. > - Some of this internal telemetry may already be provided by pipeline auto-instrumentation or > helper modules (such as `receiverhelper`, `scraperhelper`, `processorhelper`, or > `exporterhelper`). Please check the documentation to verify which parts, if any, need to be > implemented manually. **Definition:** In the following, an "item" refers generically to a single log record, metric point, or span. The internal telemetry of a stable pipeline component should allow observing the following: 1. How much data the component receives. For receivers, this could be a metric counting requests, received bytes, scraping attempts, etc. For other components, this would typically be the number of items received through the `Consumer` API. 2. How much data the component outputs. For exporters, this could be a metric counting requests, sent bytes, etc. For other components, this would typically be the number of items forwarded to the next component through the `Consumer` API. 3. How much data is dropped because of errors. For receivers, this could include a metric counting payloads that could not be parsed in. For receivers and exporters that interact with an external service, this could include a metric counting requests that failed because of network errors. For processors, this could be an `outcome` (`success` or `failure`) attribute on a "received items" metric defined for point 1. The goal is to be able to easily pinpoint the source of data loss in the Collector pipeline, so this should either: - only include errors internal to the component, or; - allow distinguishing said errors from ones originating in an external service, or propagated from downstream Collector components. 4. Details for error conditions. This could be in the form of logs or spans detailing the reason for an error. As much detail as necessary should be provided to ease debugging. Processed signal data should not be included for security and privacy reasons. 5. Other possible discrepancies between input and output, if any. This may include: - How much data is dropped as part of normal operation (eg. filtered out). - How much data is created by the component. - How much data is currently held by the component, and how much can be held if there is a fixed capacity. This would typically be an UpDownCounter keeping track of the size of an internal queue, along with a gauge exposing the queue's capacity. 6. Processing performance. This could include spans for each operation of the component, or a histogram of end-to-end component latency. The goal is to be able to easily pinpoint the source of latency in the Collector pipeline, so this should either: - only include time spent processing inside the component, or; - allow distinguishing this latency from that caused by an external service, or from time spent in downstream Collector components. As an application of this, components which hold items in a queue should allow differentiating between time spent processing a batch of data and time where the batch is simply waiting in the queue. If multiple spans are emitted for a given batch (before and after a queue for example), they should either belong to the same trace, or have span links between them, so that they can be correlated. When measuring amounts of data, it is recommended to use "items" as your unit of measure. Where this can't easily be done, any relevant unit may be used, as long as zero is a reliable indicator of the absence of data. In any case, all metrics should have a defined unit (not "1"). All internal telemetry emitted by a component should have attributes identifying the specific component instance that it originates from. This should follow the same conventions as the [pipeline universal telemetry](rfcs/component-universal-telemetry.md). If data can be dropped/created/held at multiple distinct points in a component's pipeline (eg. scraping, validation, processing, etc.), it is recommended to define additional attributes to help diagnose the specific source of the discrepancy, or to define different signals for each. The breakdown of emitted telemetry per telemetry level (basic / normal / detailed) should follow the guidelines in [the Go package documentation for `configtelemetry`](/config/configtelemetry/doc.go). ### Deprecated The component is planned to be removed in a future version and no further support will be provided. Note that new issues will likely not be worked on. When a component enters "deprecated" mode, it is expected to exist for at least two minor releases. See the component's readme file for more details on when a component will cease to exist. ### Unmaintained A component identified as unmaintained does not have an active code owner. Such component may have never been assigned a code owner or a previously active code owner has not responded to requests for feedback within 6 weeks of being contacted. Issues and pull requests for unmaintained components will be labelled as such. After 3 months of being unmaintained, these components will be removed from official distribution. Components that are unmaintained are actively seeking contributors to become code owners. Components that were accepted based on being vendor-specific components will be marked as unmaintained if they have no active code owners from the vendor even if there are other code owners listed. As part of being marked unmaintained, we'll attempt to contact the vendor to notify them of the change. Other active code owners may petition for its continued maintenance if they want, at which point the component will no longer be considered vendor-specific. ## Moving between stability levels Components can move between stability levels. The valid transitions are described in the following diagram: ```mermaid stateDiagram-v2 state Maintained { InDevelopment --> Alpha Alpha --> Beta Beta --> Stable } InDevelopment: In Development Maintained --> Unmaintained Unmaintained --> Maintained Maintained --> Deprecated Deprecated --> Maintained: (should be rare) ``` To move within the 'Maintained' ladder ("graduate"), the process for doing so is as follows: 1. One of the component owners should file an issue with the 'Graduation' issue template to request the graduation. 2. An approver is assigned in a rotating basis to evaluate the request and provide feedback. For vendor specific components, the approver should be from a different employer to the one owning the component. 3. If approved, a PR to change the stability level should be opened and MUST be approved by all listed code owners. ## Graduation criteria In addition to the requirements outlined above, additional criteria should be met before a component can graduate to a higher stability level. These ensure that the component is ready for the increased usage and scrutiny that comes with a higher stability level, and that the community around it is sufficiently healthy. If the graduation criteria are not met, the approver should provide feedback on what is missing and how to address it. The component owners can then address the feedback and re-request graduation on the same issue. ## In development to alpha No additional criteria are required to graduate from development to alpha. The component still needs to meet the general requirements for alpha components. ## Alpha to beta To graduate any signal from alpha to beta on a component: 1. The component MUST have at least two active code owners. 3. Within the 30 days prior to the graduation request, the code owners MUST have reviewed and replied to at least 80% of the issues and pull requests opened against the component. This excludes general PRs or issues that are not specific to the component itself (e.g. repo-wide API updates). It is not necessary that the issues and PRs are closed or merged, but that they have been reviewed and replied to appropriately. ## Beta to stable To graduate any signal from beta to stable on a component: 1. The component MUST have at least three active code owners. 2. The component benchmark results MUST have been updated within the last 30 days and published in the component's README. 3. Within the 60 days prior to the graduation request, the code owners MUST have reviewed and replied to at least 80% of the issues and pull requests opened against the component. This excludes general PRs or issues that are not specific to the component itself (e.g. repo-wide API updates). It is not necessary that the issues and PRs are closed or merged, but that they have been reviewed and replied to appropriately. ## Deprecation Information When a component is moved to deprecated, a deprecation section should indicate the date it was deprecated as well as any migration guidance. In some occasions might not be offered migration guidance but reviewers should explicitly agree on this, and use a "No migration is offered for this component" hint. ## Versioning For a component to be marked as 1.x it MUST be stable for at least one signal. Even if a component has a 1.x or greater version, its behavior for specific signals might change in ways that break end users if the component is not stable for a particular signal. However, components are Go modules and as such follow [semantic versioning](https://semver.org/). Go API stability guarantees are covered in the [VERSIONING.md](../VERSIONING.md) document. The versioning of a component, and the Go API stability guarantees that come with it, apply to ALL signals simultaneously, regardless of their stability level. This means that, once a component is marked as 1.x, signal-specific configuration options MUST NOT be removed or changed in a way that breaks our Go API compatibility promise, even if the signal is not stable. opentelemetry-collector-0.141.0/docs/component-status.md000066400000000000000000000200001511331344600233230ustar00rootroot00000000000000# Component Status Reporting Component status reporting is a collector feature that allows components to report their status (aka health) via status events to extensions. In order for an extension receive these events it must implement the [StatusWatcher interface](https://github.com/open-telemetry/opentelemetry-collector/blob/f05f556780632d12ef7dbf0656534d771210aa1f/extension/extension.go#L54-L63). ### Status Definitions The system defines six statuses, listed in the table below: | Status | Meaning | | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | Starting | The component is starting. | | OK | The component is running without issue. | | RecoverableError | The component has experienced a transient error and may recover. | | PermanentError | The component has detected a condition at runtime that will need human intervention to fix. The collector will continue to run in a degraded mode. | | FatalError | A component has experienced a fatal error and the collector will shutdown. | | Stopping | The component is in the process of shutting down. | | Stopped | The component has completed shutdown. | Statuses can be categorized into two groups: lifecycle and runtime. **Lifecycle Statuses** - Starting - Stopping - Stopped **Runtime Statuses** - OK - RecoverableError - PermanentError - FatalError ### Transitioning Between Statuses There is a finite state machine underlying the status reporting API that governs the allowable state transitions. See the state diagram below: ![State Diagram](img/component-status-state-diagram.png) The finite state machine ensures that components progress through the lifecycle properly and it manages transitions through runtime states so that components do not need to track their state internally. Only changes in status result in new events being generated; repeat reports of the same status are ignored. PermanentError is a permanent runtime state. A component in a PermanentError state cannot transition to OK or RecoverableError, but it can transition to Stopping. FatalError is a final state. A component in a FatalError state cannot make any further state transitions. ![Status Event Generation](img/component-status-event-generation.png) ### Automation The collector's service implementation is responsible for starting and stopping components. Since it knows when these events occur and their outcomes, it can automate status reporting of lifecycle events for components. **Start** The collector will report a Starting event when starting a component. If an error is returned from Start, the collector will report a PermanentError event. If start returns without an error and the component hasn't reported status itself, the collector will report an OK event. **Shutdown** The collector will report a Stopping event when shutting down a component. If Shutdown returns an error, the collector will report a PermanentError event. If Shutdown completes without an error, the collector will report a Stopped event. ### Best Practices **Start** Under most circumstances, a component does not need to report explicit status during component.Start. An exception to this rule is components that start async work (e.g. spawn a go routine). This is because async work may or may not complete before start returns and timing can vary between executions. A component can halt startup by returning an error from start. If start returns an error, automated status reporting will report a PermanentError on behalf of the component. If start returns without an error automated status reporting will report OK, so long has the component hasn't already reported for itself. **Runtime** ![Runtime State Diagram](img/component-status-runtime-states.png) During runtime a component should not have to keep track of its state. A component should report status as operations succeed or fail and the finite state machine will handle the rest. Changes in status will result in new status events being emitted. Repeat reports of the same status will no-op. Similarly, attempts to make an invalid state transition, such as PermanentError to OK, will have no effect. We intend to define guidelines to help component authors distinguish between recoverable and permanent errors on a per-component type basis and we'll update this document as we make decisions. See [this issue](https://github.com/open-telemetry/opentelemetry-collector/issues/9957) for current thoughts and discussions. **Shutdown** A component should never have to report explicit status during shutdown. Automated status reporting should handle all cases. To recap, the collector will report Stopping before Shutdown is called. If a component returns an error from shutdown the collector will report a PermanentError and it will report Stopped if Shutdown returns without an error. ### Implementation Details There are a couple of implementation details that are worth discussing for those who work on or wish to understand the collector internals. **component.TelemetrySettings** The API for components to report status is the ReportStatus method on the component.TelemetrySettings instance that is part of the CreateSettings passed to a component's factory during creation. It takes a single argument, a status event. The StatusWatcher interface takes both a component instance ID and a status event. The ReportStatus function is customized for each component and passes along the instance ID with each event. A component doesn't know its instance ID, but its ReportStatus method does. **servicetelemetry.TelemetrySettings** The service gets a slightly different TelemetrySettings object, a servicetelemetry.TelemetrySettings, which references the ReportStatus method on a status.Reporter. Unlike the ReportStatus method on component.TelemetrySettings, this version takes two arguments, a component instance ID and a status event. The service uses this function to report status on behalf of the components it manages. This is what the collector uses for the automated status reporting of lifecycle events. **sharedcomponent** The collector has the concept of a shared component. A shared component is represented as a single component to the collector, but represents multiple logical components elsewhere. The most common usage of this is the OTLP receiver, where a single shared component represents a logical instance for each signal: traces, metrics, and logs (although this can vary based on configuration). When a shared component reports status it must report an event for each of the logical instances it represents. In the current implementation, shared component reports status for all its logical instances during [Start](https://github.com/open-telemetry/opentelemetry-collector/blob/31ac3336d956d93abede6db76453730613e1f076/internal/sharedcomponent/sharedcomponent.go#L89-L98) and [Shutdown](https://github.com/open-telemetry/opentelemetry-collector/blob/31ac3336d956d93abede6db76453730613e1f076/internal/sharedcomponent/sharedcomponent.go#L105-L117). It also [modifies the ReportStatus method](https://github.com/open-telemetry/opentelemetry-collector/blob/31ac3336d956d93abede6db76453730613e1f076/internal/sharedcomponent/sharedcomponent.go#L34-L44) on component.TelemetrySettings to report status for each logical instance when called. opentelemetry-collector-0.141.0/docs/ga-roadmap.md000066400000000000000000000102501511331344600220160ustar00rootroot00000000000000# Collector v1 Roadmap This document contains the roadmap for the Collector. The main goal of this roadmap is to provide clarity on the areas of focus in order to release a v1 of the Collector. ## Proposal The proposed approach to delivering a stable release of the OpenTelemetry Collector is to produce a distribution of the Collector that contains a minimum set of components which have been stabilized. By doing so, the project contributors will ensure dependencies of those components have also been released under a stable version. The proposed distribution is set to include the following components only: - OTLP receiver - OTLP exporter - OTLP HTTP exporter These modules depend on a list of other modules, the full list is available in issue [#9375](https://github.com/open-telemetry/opentelemetry-collector/issues/9375). All stabilized modules will conform to the API expectations outlined in the [VERSIONING.md](../VERSIONING.md) document. ### Scope within each module The Collector is already used in production at scale and has been tested in a variety of environments. The focus of the stabilization is primarily not to add missing features but to ensure the maintainability of the project and to provide a predictable and consistent experience for end-users. In particular when considering enhancement proposals we will focus on: 1. Binary end-users impact above other audiences. 2. Parts of the proposals that imply breaking changes to end-users. 3. Small, predictable or self-contained changes that don't imply a major change in the end-user experience. Additionally, when considering bug reports we will prioritize: 1. [Critical bugs](release.md#bugfix-release-criteria) that affect the stability of the Collector. 2. Regressions from previous behavior caused by 1.0-related changes. ## Out of scope Explicitly, the following are not in the scope of v1 for the purposes of this document: * stabilization of additional components/APIs needed by distribution maintainers. Vendors are not the audience * This explicitly excludes the `service` and `otelcol` modules, for which we will only guarantee that there are no breaking changes impacting end-users of the binary after 1.0, while Go API only changes will continue to be admissible until these modules are tagged as 1.0. * Collector Builder * telemetrygen * mdatagen * Operator Those components are free to pursue v1 at their own pace and may be the focus of future stability work. ## Additional Requirements The following is a list of requirements for this minimal Collector distribution to be deemed as 1.0: * The Collector must be observable * Metrics and traces should be produced for data in the hot path * Metrics should be documented in the end-user documentation * Metrics, or a subset of them, should be marked as stable in the documentation * Logs should be produced for Collector lifecycle events * Stability expectations and lifecycle for telemetry should be documented, so that users can know what they can rely on for their dashboards and alerts * The Collector must be scalable * Backpressure from the exporter all the way back to the receiver should be supported * Queueing must be supported to handle increased loads * Performance metrics are in place and follow best practices for benchmarking * Individual components must: * Have their lifecycle expectations enshrined in tests * Have goleak enabled * End-user documentation should be provided as part of the official projectโ€™s documentation under opentelemetry.io, including: * Getting started with the Collector * Available (stable) components and how to use them * Blueprints for common use cases * Error scenarios and error propagation * Troubleshooting and how to obtain telemetry from the Collector for the purposes of bug reporting * Queueing, batching, and handling of backpressure * The Collector must be supported * Processes, workflows and expectations regarding support, bug reporting and questions should be documented. * A minimum support period for 1.0 is documented, similarly to [API and SDK](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/versioning-and-stability.md#api-support) stability guarantees. opentelemetry-collector-0.141.0/docs/img/000077500000000000000000000000001511331344600202425ustar00rootroot00000000000000opentelemetry-collector-0.141.0/docs/img/component-status-event-generation.png000066400000000000000000005113561511331344600275560ustar00rootroot00000000000000‰PNG  IHDRJ ’นกeiCCPICC ProfilehํšyTSWวฟ/ ‰,‚! Pˆ€;„l„ฤศขE* j*„˜„ลฅ€๛ฺฉh]fดZญ jjuิqรตญฺชuึฝฃT\FFํจc๏ใฬHmํร๑˜/็๗ๅ๛ป๗๓~7๏พ๓{@—€ ณ9Ÿ˜lCBœxะ›o‰yืภ…<ษŸ รh5ว๖๋—ขฦ๊IP๔x8}ฎๆ๕ฟ)๗ฌlซ ฤฤd4[lฤo$>คฤfฆiโ…า)โoะ>งมณ่c…™Œ6ด`ˆ'พ3๑™ŒWำ>‡๑ฝi_lฬ!็d ุ=ใฅRภ%฿๎ๅ€kiณo@|?า†฿:อ๔ญAnI โ= beŸpyc฿}‘„ˆั=a {%๚ Mีอ๕k'๙ฃฒe—ฺ่}|กyค%/'ื&Ž%ิณล‰&ฃ$L,—ส•}™ึwk™{๓s๕ำฒ b’Ÿ–%ว_่๏Oห:˜ฯh`W+c‘ฅุ~yŠฅ~๏†ณ]lา ลbs8.\ฯ•/ดrs๗๐lํๅฆะGไ๋ืถภkAโ๖ม!ก:v๊ฅkทฐpI„T&W(#ฃTjMดVื]฿#&.พgฏืz'พั')9ฅoฟ†ิด้ครo๒ฮะa™ฦฌ์wsr฿ž_`*4ฐXmEล%ฅ#G๓~Yyลุqใ'Lœ4yสิiำg|๐งgVฮšัœน๓ๆ๙/ ~ผhัโO–,tู๒+ซVญ^๓ฺูฟ~พn6nฆอ[พu๖;ซwํณw฿š}๙ีื‡ๆcวO|w๒ิ้3gฯใ๛ฮ_ธx้๒•ซ?๓zํO7๊nบ}็nฟ๏๐Ÿ‡?i6~;o/B ถ#ฟ† ๏…4ƒฐ๘์…k4šยฟ†๛๔๘4ฐ‡€!รภ(8bpไเ OQ4ฒh„ัHƒมa็มaˆ0H™0PจะX>YbวยpฑG‡Œ=<šศ4กqdใœฮ9แœฯฮ‰ฦg™ฎGiAพธ8bอ+4u–Iคมโl“ฑ0+ฯ”ำ=8mภ๋แ๊เz])ฒXฒถ์,ฝฮ ิHขT™Vฎ–(” •V*‘Gษไบƒ^— WDIคjTซVI4š(•VFj52ฉ."Aฏ‹ำหU’HนTก•‘KI5JญLฉ"&Rญ‹ˆำ๋า๕2™šญ’ierนDฆVศตฒHฉD#SE๊"า๕บวŽ0๋…นหXฉฐˆ’_๔™N?ขฟYŒ"ำpSa‰IlตYศศลŠgy:ดgู๗ิ3mX๖ํู2Zึ1pDn‰XIFำผQ2i”Šึ๓๚)WJeR…Lฃ”+•/โฝศ1Ž›)˜โคช€Z บ+‰(เV0 ุขๆก0ชhC๊ถฑpl0… ฤ Grp'Œ…’๎ภสต\œQฑa$ๅษ|ไใ`j nฅfทๆbYตXวดฦแKแวม{ง๘0PธฒSฮธใl5…๖›y}๊{tฎ๚๛ay ชเบ;“–ฑQธล7ฅQ๗>RQ์ฮ•เ`ž ขฯ‹ Z ‚ฅ” มƒv่ธ$ลKyุ]„จฅI8qี‡Dก่๒$oZฅS/กใy8P›,xHิ๚i*๗e™$๖ืฒ–Naว€๚ป:ฒเrจ h™”ˆaŽฏiD.R˜‘๋ ษ#tหBไข คเแ yFl”vAฺื|ผใฦA[‰ขn/๊ส|ฟฉ<.ฦ MA฿๙^8 แ!p๏ผU-ห๊ ล\Cฒ—ฯk* ˜่แฌVMอni”Nฝ„rŒLใฝŒ€r)OขP‘Fแะ —:ณ1ดs:qฐตฮล\Tlเมปšr‘œ๙n`/๑@Dจ'ึ็ ๏๑Bจฃ}ฐฬุฏอ๐วฒt- มฬ!จนŠดซแ8Z†ne\ญมใI*eiภ‘$เผ0ๅo๖B;j ŽŸ้ Ÿลx๔{!ีC`ป= ฝKa”๓3ฮuš๋ฒQtฏ ฺ} [ฅS/กš rู๏zyddใ๛ ฝ๑แ\;๕jหนv๊U–sํิซ,‘˜Fลํ4๐่ ฉฺ็เ๚&k8๐-tCšซ;๖_tCfบ๖j‹ะ‡~๐๏„๚ะ.๕ํ ใN5vViq>9ห๖EึนT„?๊q๒‘"ฒเpRa ิ)งšKก`กc=ํ(ค T‰˜rzNฅอr!Mข์bัbำโp่ฤ›‹ —หๅัู7W>Ÿ/ZัYHwwO: G็"}|D"_&วd$ƒฤํ้t\CR’ษว9ค%›๒’ฑM™Y&วคโ่Dะaฦฌ์œผแ๙…f‹ตจธtไ่1eๅcวŸ8yสด้|X9k๖œy๓,\ดxษาๅ+ชVถv๚ 7oูบmg๕žฝ5ฟ๊ศัcวOž:{๎‡๓—.xญ๖ง›ท๎ึ฿๐๐๑็๘_ํ๑S#F๓ เ๓ผ)’fฒๅู๒ณณ`s๘Nแ#Mศ((ศห%๗วY/นž~žฆi้ฎดˆRDลธ&…Kตs๑ Pcว5ิŠeXIfMM*>F(‡iN’†x J  ASCIIScreenshot:Ÿ&{ pHYs%%IR$๐ืiTXtXML:com.adobe.xmp 778 1098 Screenshot œ\ภ^iDOT…(……eพถท@IDATx์€UE†?RAEAม๎ฦ@ AD,์๎ภV์ ;ฑป[lฑฑปA,Tย<ณ๛]fฯ-ุฝ{๗w๔๎œ33gโ9g—;๏๙ๆ›F%มD@D@D@D@D@D@D@D@ฌ‘„=" " " " " " " "PB@B‰ž(% กD‚ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€”PขGAD@D@D@D@D@D@D@J H(ัฃ " " " " " " " ฅ$”่QRJ๔(ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@) %zD@D@D@D@D@D@D@D ”€„= " " " " " " " "PJ@B‰(% กD‚ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€”PขGAD@D@D@D@D@D@D@J H(ัฃ " " " " " " " ฅ$”่QRy'”L™2ลFm+ฎธขญฝ๖ฺบQ" " " " " " " "3y'”<๘เƒvะAูข‹.jO=๕”5n8g0ิˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@qศ;กไ๛๏ทC9$•—^zษX`โพCฝˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ฮไPrฯ=๗ุแ‡<๑ฤถไ’K†ใ3fศบ$g…โ$wBษ 7`งžzjธํท๑„ ์ฏฟ วK,ฑ„3ฦๆwโผcตˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@จwกไ๎ป๏ถงŸ~ฺ~๑G{๗w3‚HE#nูฒฅaiาถmŠŠ(]D@D@D@D@D@D@D@f‰@ฝ %_ตuํฺตาŽฏฑฦถๆšk†]pฐ0YvูemŽ9ๆจ๔eŠ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆภฌจWกไณฯ>ณ๎ปg๚บukรbไ›oพ iฃFาม::จk๕*”0ธgžyฦ}[๕mตีVณ>๘ภz๗๎ฦ=z๔h๋ะกC]3P" " " " " " " "ิปP’พ?๐ƒmฐม!yไศ‘ถษ&›ค‹่\D@D@D@D@D@D@D@๊„@ %“'OถŽ;†ม^tัEึณgฯ:ธ*4ผJ&Nœh:u >|ธ๕๊ี+g‹€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ศ;กdาคIฎgu–๕๏฿?3๐๋ฎปฮฦŽk\pตjี*“ฎจ y'”๗฿ถ๒ห‡ฑ 2ฤv฿}๗ฬ8W_}u๛๋ฏฟ์๒ห/ทnบeาu " " " " " " " ตA ๏„ตัF…-‚ฑ&มช„๐ไ“Oฺ^{ํŽ๏ฟ~[iฅ•ยฑ~ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@mศKกdmทต7xรZถli๛์ณ}๗w6jิจ0ๆ5ื\ำ๎ธใŽฺฟ๊ ผJ๐E2t่ะL'แไฮ;๏ดVXม“‹€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@ญศKกไŸฑญทฺ>๘ใ0ะึญ[งฎปํถ›ตkืฎึฏŠD@D@D@D@D@D@D@D &—B œ2eŠฝ๒ส+ึขE ๛฿gM›6๛ญcจuy+”ิ๚HUกˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€TA@BI€”-" " " " " " "P<$”ฯฝึHE@D@D@D@D@D@D@ช กค @ส(JŠ็^kค" " " " " " " UPR e‹€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ %ลsฏ5R*H(ฉฒE@D@D@D@D@D@D@Ї€„’โนืฉˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@$”THู" " " " " " " ลC@BI๑kTD@D@D@D@D@D@D  Jชคlโ! กคx๎ตF*" " " " " " "P %URถˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@๑PR<๗Z#จ‚€„’*)[D@D@D@D@D@D@D xH()ž{ญ‘Š€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€TA@BI€”-" " " " " " "P<$”ฯฝึHE@D@D@D@D@D@D@ช กค @ส(JŠ็^kค" " " " " " " UPR e‹€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ %ลsฏ5R*H(ฉฒE@D@D@D@D@D@D@Ї€„’โนืฉˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@$”THู" " " " " " " ลC@BI๑kTD@D@D@D@D@D@D  Jชคlโ! กคx๎ตF*" " " " " " "P %URถˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@๑PR<๗Z#จ‚€„’*)[D@D@D@D@D@D@D xH()ž{ญ‘Š€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€TA@BI€”-" " " " " " "P<$”ฯฝึHE@D@D@D@D@D@D@ช กค @ส(JŠ็^kค" " " " " " " UPR e‹€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ %ลsฏ5R*H(ฉฒE@D@D@D@D@D@D@Ї€„’โนืฉˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@$”THู" " " " " " " ลC@BI๑kTD@D@D@D@D@D@D  Jชคlโ! กคx๎ตF*" " " " " " "P %URถˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ@๑ศ+กไค“Nฒuื]ืบvํj-Zด(žป ‘Š€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ไผJh:tฐ+ฎธย^yๅkำฆM^@R'D@D@D@D@D@D@D@Šƒ@^ %;ํดSJFŽiฯ?ผ-ธเ‚ลq4Jผ WBษ;์`kฎนฆ!”ผ๐ย ึฎ]ปผ€คNˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ˆ€ผJ `;v Ko^|๑EkถmqRD@D@D@D@D@D@D /ไ•Pฒ๖[งN์ฒห.ณ—_~ูๆŸผ€คNˆ€ˆ€ˆ€ˆ€4๗ŸMŸ>fฬ˜>~ฎ3ฮ็8พฦ๓š4iา๚8ๆ8yœF=^—ง{šทWัy\ฟืแqEuั_ฏ/]ฦฯ‰ ›@^ %nปญญทzv้ฅ—J()์็Nฃศ /ผะV^yๅ2ห๔D<ž0#&๘9๚X\๐cา=4๊ห–็ๅาqบฌืๅ๕๛5~L์๒่c\ฦฯฝLmใe๒ไ“ค๔$ส๓ศ๗Iว๑'พ&ฎ']ฦ๓<ฏ#&ฤฑ—!=}]œว5~๎ฑืใ็้˜: ค{์eโ๓๘˜{PU™ธ<ว้เํQW:x^uำำๅ8Oื๋็ิํว~]Mฮฝ,q๚ุ๋NงงฯำKื๗+วs๏iq์uฦi{๙t~|{yษ๓cฉ7N๑๖ใฒ้๒žGLˆฏ๑ดธLœ๏u… s๐ƒ{๊ฟWqœํุห’็๙qZ|\Qพ]๑|ฏ+}๎‹NOฒำ็๔'–>หxq|œญ i„ธ\|Lž‹^ฑ3Žำโใluzพ็๙9qœงหธPง๛q|]บ\œ็ๅ‰ฝ\ถ8ฯำืธhJ>?'ๆœเว~ญ—‰ฏแุ๓=ใสฎ๗k<๖kา็qq๓k<Žำ8ฆ||Ÿ{Z|ž>๖vI๋J—ห–.ˆฺ๗2้tฏ7N๗ใฺŽ๙;มิvตY๋ห+กคo฿พถัFูˆ#์ีW_ตึญ[gํดE@D@D@D@ช&pฯ=๗ุแ‡vlผyๆห6_หฌ๓ๅ;พฮฯ‰Zฤำ(ว์ธ|๚8.๋วs-ว๑'[šทใๅโ๓lๅ=-Žใcฏ'N‹ใ|าำyœ(Wูฑ็U}7‹ท„ .•จจLšo๚ผฒ:•W5ธปจGiฮใ็ r^Žุหฦi^ฏงQ&ๆyqบท—.๏้\“ญผงงฏ๓๔8Žใบ<๋๐6ฝŒว^.Ž9๖s/็qœNZ\ฟ็eป>.—ญ.„เt™tœgKKท—ญŠฎ๓:=๖1ค๋ ภ๏ํ Aƒ์๗฿ทgŸ}6คี๕ผJบvํjผ7nœอ;๏ผu=~ี/" " " KเถnณใŽ;ฮ>๘ใ๐ผ`ฺภ–MLabเ้ฤาใy~žฮ๗tbฯ๓8ฮK31ษv_[8[=๑ต{๐๖ใšฆs]|Oฒผพ๘<>&Vฯiฯฏ%Žใzณฅ“–พพ:ืฤืqœxคg;Ž'ฃq™ธlœฮฑ_“ญLhD?D Ž lนๅ–๖วุ3ฯ}l“M6)xกไฯ? ๔๙ƒ“-ฤเณๅgKซ่ฐฅะyšวฺฯฝ|ถv”& ™o๙b๙๏ฟฺ\sอี‡ขพ‹€ˆ@ต\wu6t่P๛ไ“OชU^…D@D@D  lพ๙ๆแ;“O>™“๎ๅ•Pาปwo๋ึญ[J^ukีชUN ไฒ‘พ๛zvY3—Mฮb[,\šH/uโดไ8“ŽฌQ"„hˆฉฅ4JCJi~ฃฦฅๅC]%ว%‚MI]ก|Rvๆu3M๎่XVฃF\Cc3๋i’ิŸฯ,ฯ:ใPxๆุธ:๙ๆX“zธ>TY๛8Jญqi฿าeยyi}Tส…s๚VšK?ใ2กญ$ณค) ีYํฆjOQ%ฏaแ’ทVผ} ๓ๆชิdุ๓JหQฟศœธ‘อ]'y๛5#1ทž‘8๚›Žูt'uฯภ๑1iำ9.5๗๓คŽ3Jw+Hาจ“23’บBJ ้าBŸ’Ž’๚0๓8$D?ธฯฃžะ:.’เQป:\ธโŠ+์ผ๓ฮ %นlWm‰€ˆ€ˆ@m@' <๘ใตYm…uๅ•PาซW/๋ฝป]tัE๖ฦoุ<๓ฬSaวjฦธ “m๛nmฃพป"หฌlำงMต้SตiS“xZiœLง%i%yq๚ิLน้SูฮฏฃŒ—+I/ษOา’zง…ผฉ•"kาฌน5m’89รัYำf™ธq“™วMB>็อฌqrœข…ฒ%็มูYr‹Œ€LษCh=%qษ1ข@ษ$ตD0เœKโpฒรคhI\Z"”-ญธtlN้i&*MOฮ™6—œ1ฅ. ิ๚_iีแ8™ภ า8sฬแข(Ÿ*ผ|’™†‰|2ฃOG0pณู’ษ>u•”ค—”ใโไ<|จ‡ฦB…™ใ’kiด4Ÿ๚(รฯ๙qI;qบื็ํ—ิ]ZOจ/ิส’>๘’๓า๓กขDฤBE’_1’8ˆ!Iืฐ&=;Jฺ ี–๛Dฑฦษl8๓+9n˜็tœ๒๙s™วฯ#ฯฯa3žษๆแนlšค5Mžๅ&ค5›#“ึ,Y—฿4œ'iษ๑ใท]fS˜lCGฝdฝVศnูUฎณJH`๘๐แa7ม>๚จ๖^]ฌำก‡ tษ„<‰รqI&L๎ฃ4&>/ Jฯฝ\R–‰wจฺ๋  ิ>ย0yว:๋>‰@ำ8:O:RฆฟXFA ๔ กขvCบ?Xง4JDฉฦˆPก%}m(I/MรbขDด*อ๓๑dา$Rื‡2MฌDpขCt\"B :” .F ด•~J„ ‹ขY——”k–\ว9ข[}„aoe:ัNพqฌ๕^QBI}ต)"gŸ}ถ]sอ5๖แ‡ๆฆAต"" " u@€M_Zถli=๔Pิ^พสผJz๖์i|x๛๑ึ[oคwพ๛ื๚vio;~žญูuซ๒wD)ี&NQSฐ^ %BK‰(S*ฌ_Z.-ัy\.ิ•+›‡Xƒ•H‰Cซ D X$โB,ค„๓ŒQโ%:ˆก\I๙™็.b Zp์HIzษน[าT VAเœฝปa๐„kŸฑญV’PR.e‹€4`งœrŠ5ชNถSœ4i’ฑT๚๛๏ฟท5ื\ำฺทo_†ิ;๏ผc/พ๘ขํพ๛๎ม ตLf๐เัGต)Sฆุึ[o]Gญจฺ4๚ธื้>่\D ฐ t๎9l๖๒ภไd y%”lฑลฦ๒›aร†ฎP๒T๋yeณmญM๛ๆไ&ซฒ†๎ฺ%Xณ๕“Jสขั™ˆ@`ว›ป๎บหZ[>๓ฦn:q`'‚E]4“ด้ฆ›ฺ_||คไJด๘้งŸlฝ๕ึ }x๊ฉงl๑ลฯ๔'_~๙ๅ{๏ฝ๗์›oพI,}งฺK,akญตVƒzaX๗:_๏ง๚%"P7ึ_}›๙ํพ๛๎ซ›Rตๆ•PาฃGjซญ‚P๒๖oำšT้[฿Mณ~]Vฒํ:ึl? @"ฌe-็™ฯ†\๕ธ๕‘EICผ…๊ณˆ@5 qฤ๖เƒ†‰x5/ษZ์ณฯ>ณัฃGํท฿nX’d ?ฐ-ทr™,Ÿ<๏ผ๓ฮvโ‰'fา๋๒๋:FŒ–tืe{ณR7ึชH8$ผ็ž{ฒZ๛,นไ’Aเšwygฅ‰œ_S๗:็ƒTƒ" ๕J`uึฑ…^ุ๎พ๛๎œ๔#ฏ„’อ6ฬ๚๖ํk\paยืขE‹œ@ศe#o?ถ้ผข๕฿T[g๓นlZm‰€”8บo{›ฟbv๔ฺึ+k้ ย%pเ–๏พ๛๎, ๒ห/ฟ ปŽ3ฆ๕ป์ฒ‹ 0 8ืc๛๕e—]ถLึ“c%5 ;๏XCภV]ฺฃ]ยYge๛๗วˆ,qญฏภ๎C—\r‰ตm6ˆ$ี้ขิ๗ฟ๊ญ๗2๕qฏ๋}ะ๊€ˆ@N `i‡ลV’นy%”ฐๅOฟ~์๓ฯ ฯ9็œน`ำ6แ?fƒๅญ๏>'ู๚[๎”ำถี˜ˆ€ู?nวo฿ัฺ.บดu๙#A(ฉ›ฏ๋ข-" ๕O`๏ฝ๗~BฐิญI`)ศฑวkใว/sY๋ึญƒฯ‘ํท฿ฺดiS&/>a fาXŸเ|o5ึBดร;ฬvuืp^[?>๘เƒฐŒ›๚\pมฐ๔ๆำO?อXมะD‹\ Jฏฝ๖Z™aาDคuื]ืVXakีชUXzร๎ทr‹ถาJ+•น&O๊๋^็# ๕ID ๎t์ุั–YfปใŽ;๊ฎ‘จๆผJุ๒gmท B 0ฯ1วQW ใ๐อ๏ณ—ทญ๗:6่ฝsa JฃDเ็o'ุู‰3ืv‹-mG^–%ษา›:zฑู€จจซ" N –;4”%๏ŠbฉŽ7.๘~ซจLถ๔ร?<, ๑วฌถE@๊Ÿ‚;โ๑ญทš“ฮไPฒv๓Ld4o<'rูศ฿gvYz>ฦ6z๗\6ญถD@g—3ะฺ.ฒDJ๐Q’์’ฌ " ภUW]–llผ๑ฦaูำr4hP˜`ณ;MMยฉงžj7pCๆ–FŸ|๒ษ:=ๆ˜c์ฮ;๏ฬ”O`=“ีUW]ีV^ye[qลญ]ปv้b5>฿`ƒ ์‡~จ๐:>bฎM›ซฌฒJฐ˜{๎น+,_“Œ &‡ถlUษ’qฐ:๗s4ฤ7฿|ณtาIแแช&BŸุ๕ื_AXB`ช( 2ฤpช{ๅ•W–…ˆkจใวดล[l–—ฺธืˆUXฬ\xแ…eW4.ฅ‹€ˆภjซญf|ฐธหEศ+ก„/%˜rฒŽ๏์อš5หƒœถ๑๚ทู๖ญ`[์|˜m๏œถญฦD@ฬ}้1ปm๘16฿ ฺแ—๏ฝ๗^Nรา'œ"zฐๆ฿ร?c๘sq๛oฐ๔ฆฯ={๖ Kไg๗^Ož<ู0ก'0แ้ิฉ“7ฏXD@*$€ุอV๔5๗คย ซศศ+กsBAG(แ‹๚6-ฌ‚,eK„’‰Pา}วƒฌ€gฉ]$"0๋^~๘V{lิ›งu[;x๘๋%M%”ฬ:P])L€e8ร† หlEธศ"‹ห„YฮO.๓Kšฑ|x๕ีWkM&อื_}ฐNH๏tร๗58,ฝ๔าก?๘รฎฝ๖ฺpฮ๒,&๖oฟ`qม๗ปซฏพบZํ#rฐCNฺŸV!Xeคล–ฐU$&ูXฌ๐‘c,'าbAบŒก…ฒื‘#Gฆ‹„๓K/ฝ4ฤŒqdเภeส!ะ`y„†ฐึกC‡rŽm{์1w฿}รu,๚๗฿ํท฿~ [-?๑ฤกe*-=้ปwฐไ)$ |es†;x๐เ`MB™'Ÿ|2๓ŒฒQE‚–>l๓LŒ@ยฎpมโื=๒ศ#T– ๐{๛‘y๙ๅ—รvŸ^ฟbจˆ–โ๏P.B^ %nธa๘ว็œsฮฑ?ฐ?†นRืmผ๚๕ qใญ๖๛Y๗fo]n]๗U๕‹@!x๖๎kl์}7ุผ๓/d๛Ÿsซ๕J„’fJ ๑VkL"PkxฮฤO๛nญภา‘mถูฦุฑ/ŸEœ…โ฿ข"๋‡๊@ยช€ๅ%ื\sM9็ฎ๘a2mโŽเลoูทชภ๒ œปบ @yฒา>B ึ|AฎjูŠoU‹๕ …ทz+XHฯDกtภช,,ุjy่ะก™bˆ@)U๙ีcวDทส‚ ยฯ>JฦŽำžqฦAฤแ๛1ฅ5๘9‰ฮzy ๑ธcK๒ถฺjซ0VฦA=„ณฯ>;p`Gขๅ—_>คฑๅท฿~›ูญ($&?*”jrฏ๙}:่ ƒ‚ล m+ˆ€ˆ@u๐๏.ซ๙ท(ABI.(Gmผœ%7^ษบ๖รz๎rD”ฃC\xึK์ต'๎ฒึ .f{ฝ^BI. ซ ( lณ‹hย{–D๒Y4้ีซWž๙Zน ˆˆLด=ฐ4้ฬ3ฯ,็[Ž4,I–\rIรjขฒ€ ;รG#q,พR๐™Bภj‚x* Œซ…vฺษN9ๅ” ‹"ธฟ–“ธลG|มmทfวw\Hย o4้g์“?(Xฏ ะTN8แ5jTนlฌ66฿|sc็G๊ฮ&8qQผ\ฆ4Xบƒ ฦ˜ฑ y๚้งƒ/ฎqKDv๛ม๊†€…VAD >„ีW_=U๑า)๎ว\sอœๅR6๋คš๋ะ~ˆ€ˆ@ ,ทr†ซ|0ๅ"ไ•PยZIผ‚ฃ˜๓ฦ&ํ1<@๊บ ”lฒ’mธี.ึkpๅะืu_Tฟ#‡n8฿๛pุ๕fทGฺ–+4ถๆ37(F$ณˆภ,`IหxkฯาBพ‰&[lฑE่sฯ=7‹ฃฬ~  ๎H52—ำN;-XiT%”0ัGdภ_zD|x`ทธู,*ผ,1พ4๘‰@* ๘9๘ใC6หa\D๐๒Xฒภ๏‹/พฤ‹/พ–๖ะ฿ัฃG๘๚๘น†-‡=๔ะr๕‡‹K,ฉูgŸ}ย๓B~u‚o1œ‹่–+๎€K”๘อ+๗ซB์C…๕๘‘a\้ํˆนŒ•ๅ8ˆ18ดm6๛๊k/ฏXD@jB€ฟวํทV ๚ๆ"ไPฒห.ปภŠึ_ๆJ]ถ๑าW3lะฆ+ู=wด>{ŸX—ML>ษ>?ฮ~๛ๅ[rๅ5mัeฺ—WฟmŸผ๕bุEจIำfe๒๒แ$฿๛—Œrู‡{Fตว=g /ฝข :ๆ" %น„ฏถD € š0L[š`)ภ๒œ๚rK๛SงNอ,ณจฮ-`น K qฒYู’’Ÿ~๚)|ieฉL6?$>yฦ"!ถhA\8๊จฃย2~๚V*์zH๐Iป๗3ฮ๓ดlปสxฑ %้r,?BP@แ 7"พ4‡eUXSฤแโ‹/N}Iร/GzWพธ#ถP.๖แBY,Ubซ๚‚ส์l‰ฬไ€t/๐ํรีxi G,y"ภ?tBb้6Q8๔ำรYผฬศหธ€ฤฒžฦ‰,UโP{ํืผ๒ส+Addฉีโ‹/๎ษŠE@D +)Sฆก—O/ป์ฒฌej;1ฏ„ึ€๒‹’ดG๐ฺx}ี๗ย—3l—D(Yw๓ํl›JฬH๋ซ/๙๎๔้ำ์“7Ÿท—นy๑ฑ2]r๕Sึบฬตนgํูอ~๙Kpุ9ึqใ’ทe.จ็“|๏_=ใษy๓w^|\"ผฝfKฎุมถ?๔๋™X”ฬั$็Pƒ" L ๒wหฎ$นM0Sf9Nuƒ[.เƒ%Lณ9ุ๏ฝ๗‚ุAฝู||เีjฤ฿๋๐ยฤšๅXY<๐ภa[๊AL๐Wkpœ‹”!~๛ํม‚ฃไฌ์Oท@I›hปsY๒YNรd|XTฐคˆqโิ”]ฐฮ๐ –ดd[ƒ%>XaฐŠ๑€ๅB ื๘’– ม—-๙โCW|ศLœ81œ#p4o<๘aม_ ข‹ท‰ใฺ๎ป‡๊Y^„U ,UX‹`%โ์b‰%F”Aเ`ู ŽdฉŸ&,›๒๚ใ๛I#{œ{`„™xฉŽ็U๗^SF."as๖๚‹€ˆ@L€ฟaๅo ;ุŽ๓๋โ8ฏ„L๑ ฮ?ชX”b๛ล ญŠถึ&[v‡ศU๚๔อg๖๊ใwู+aNž”ฮ็G\๒€-ธฤ๒™<"6่5ะถฮC+๊๖๏ทIษผืžตeW_วฺ,จท+™\หทœwธ}ษปถ๊๋&bๅ)Jj™ฏช(K€sุUk&ฺ„\Š&8สว*„]Wช|B์ๅ๑Kม๒hT`ย2#ฤ Xภo 6ฦ๑฿_.ƒจภไAฤ'ษฑ`มš7†lu`ตมŽ2ผP๓€…E6ฟ C† BJlษ‚?ฺให6Bฐ`Fมน)พ=BŒmกำป๎๏ึ 'Ÿ|r่'E<06ถ฿Edq6๛๏ฟฐ"I/i๑kชŠ๙N์NZ){ฤGุw฿]๎2'„'ˆ>๎t๖7์<ฏข๘๑วหศฯf!ไK|ฒm๗\{M,ฃBฌ" ๖Tๅไ6ิข&€ธฬŽb๏F.`ไ•Pยv?x๊ฦฌะฝส็B.xnย๔ ”ฌนQ/๑ˆ rูt^ท๕หw_Xpฒ๙d๙;๗d๋๔ุš6kn3K“v‹/Wf,g๎ฑฑMแ›ฤšคObUrnศรD”เoIยI=จn.2ศ>}็ek>gK;์ข{l…—ฌงvณืŸพŸ๐ๅงึพSืเ'h๓ๅ[‹f…=fND fxซฯค—ย;xLZ๚หVิ ๅฉ๓๏ฟปฦฐส็Ÿn,]iึฌ™-ผ๐ย5ฒ๘จจl้Xzดjี*์Z“-?["ูl–้๒,ม:ห„t`)า AƒB2K5ฐฦ๊a๘๑!อ…อฦ…งง๋ม…q๐—?๘ถC‰-^†n#FŒEDๆž{๎ บฐ„2Q๗sฐtม๒ร… ฏ—แ„บ7‡/S‰ว… €‚XˆPึ๋D๔ม‚ฃ:แŸeฐ6mฺุ{๏œผ๚ต?s`/ฅษ&!\นำ[ฌZ๘~]U@ผb‰฿;ห.ปl™Kุ…ว…*ฦW1“ส๎5ๅนห*ขO.-ฌBฃ๚!"ะเธP‚฿(„๓\„ผJ๘‰ท็w^X› นnใฉOฑ={ฌbซฎป™ํrL“ฮ\๗#_ฺ๛ๆณ๗์Ž‹†ุ7ŸพWฆKsอฺบ๔ลึb€อีชM™ผ๘dฺิm่n]‚๕ รษrЉษ2„i›<ุบ๔)ys_›‹ใš๔๏ฒcwฒฯ}5tซbKมรฦ„็ขŸลิฦ•'์ž<_ูni=bJŠ้๎kฌณC€Iพ‹๘f`๒๏งวb‚งงำใธ.!˜<{;^.nk€๊ค{้˜บจร๛‰1+k &้|X6แ1้,…hาคIHง,๙๔{ย„ a"Mป -ด=๛์ณณา|•ื๐๖๙็ห[ช, _๔ k˜๗฿?๘ธpFXv ๎ |ฐ4ฆ]ปvั•3)%J6มลE/ลขD์ด•ญh๑eยNq`หaถฃ%`ํB?}ษ i้%$คyเ;ฆ žฦ๎0—_~y+Ž[1ํฦฯ ึ"Cฌqx‰Gฺ!‡๎_ึฑN‰}!ฤใ% ๅ6q@Pภšภ,ณมา(|โฒ๑1/;์ฐ๐ฒซฯฺkฏg‡c๚€ˆใ}d|๘ซษฐ๚๚๋ฏmพ๙ๆ ฿ฟ™0ึlQ v1šsฮ93Ejrฏyaห฿,ช3ๆLC:(JBp.Zก„?๔(็#ๆf…๖$<๚มŸถ_ฏถโบุง\]hรซ๑xF„ฝ๔ฝ™๋–๋ฐžuIv‚O6วฌฟO๚ษปๅb๛๕็๏lา฿ุ๗_~’นถขƒn๖ท;\QvญฆฯNธ๖้ปฎฒqO„Ÿ}ฯผษ–YตSญ๖O•™]z๔๖ฤญำfm“ํ๖ต‰EIKY”่ั˜E๘๐ษ{ถIปO๚}’๎“sสฦๅษwQภ๋#-๕>ฑฏ๗ดธt=๑น—ำZ|b<‹xf้2˜ฎร-<อห๘ไ>žญผืํฑ q~L์ว”็ hพ&]L\\๐s๒<4?'vภล D€๘SYzœG^ทวฅy_ˆฝ/ณ":ไ}จจ?,ca‹Vœ`b%ƒƒQส็jน฿ญh๊+ฐผGค8โรz&ึ๘มŸbQ61ฅ6๚ LXJ…CVฌmฐฬ`ฌˆ8>ิg`7ฌrชฐ–9เ€ชSดย2๕qฏ+์Œ2D@ †BsวŽmห-ทฬ์FVืƒ“PRื„S๕฿๓ฦ/v๘ถ๋„%"žwG*ท๘Nู๚๗Šใvฑo?/qค–หlดอ`[o‹lž๙(%mฒะหeฌJfE|ย*๋‚ฆอ็ฐนๆ™ฯZ%ขJใไห{eแๅ‡oต;/ษพต๓+ฌn_~๔vๆ๒ูํM๛๗Ÿไห๕ k6G‹P๏ิไ‘›†ู๗_|lบ๔ดตป๕หดงƒช œป๏ๆ6๕Ÿฟญkฟ=m-wฒอ–mls7ฏ๚บู-xภ„'๒ว“๐Šา(ใ“yสx=~mวๅโ๚โ๔Šส“๎y^ฯฉ ั![z}Xฬ๎ˆฏgยO๎}๒ว~์“๛๔นง#>TVŸ[&ะn,6 ๐มG๕SฮหxL~์ ‡Ž๓‡_่๐๑€o vna™ ะบถษF็คห,ณL๐ํ‘-_i…OฑnิจQๅห๒–่๘ r” " y@€ๅ„ฌ>aว/Pๅ"ไ•P‚Jฤึm,ฝa=l!†ป^Žฺกณ-ฒ๔Šv่E๕c›o\žป๗:{ๆ๎kสํtณๆlรพปู‹,บ๗Ÿฟ%eoฐถ‹.•,ฯ้l-ซ‹ฮุ?l!\“ๅL฿๑‘u้I๖๙{ใสเXบ}วฤา็ฆ ล’ฯฦฟj—ณS™kา' .พl"๔์‘๘กูt–๛็ub]rสฮ๋%๛์ภ๓nKv๛Yมn<๓€2[&ณ„‹ฑงร”ฤjโWŸ"ิ๒kฌŸตL๚šb8?kฯM ฿1=v:ศึl[๋–%๓ิ‘Pย๖e\ะฐœ63!g’ฯ„Ÿ8ฦ'ษq™tY?'fย๏މษ#Žำh›บ=อฏ‹cฤฟึ๋Š๓=ฏขุ๋.d †b๘=ฮื1พ๐ย มi(;Ÿบvํ–{ฐคพ– ์ธยvบ ลM+œภ2แภQ,พe๒ม้}q฿^D :ฐุร:0—;eๅ•Pยบ#ธ ”เˆซรญ/|iว๏ผ‰-ฐ๐’v๔ศ๊oีWˆ,าcยRโ็ถg๏นถœsื๎;d๘ษ๖๚˜D๐xแกQaนอ!รห๏š“ngย๛ใ์สฟฯtยึชMปไM๚ิ ิ,ถjถืiW‘#}ญ‹2คoฒํมฯEซ๙Jฌ;>ด—บ5ูึ๘ฮpษ6๛žd๋๕,Tjาฟฑ๗^o/>tKาu6๏ 3ํฃถZ1ินใแ็ูฤฤๆแ‡…sัพำฦถ W๘iนix๐w’ILึO,t๚&แ{@(๙gส_ถีวฺš]ทชSกไซฏพ2>5 ฑ8Qc~7ผ||Nz|ND ู'ภ๖ฟ์ฤยาf`๑รN,์๊ฑฤKฬ~ณYรjซญ–๙dณ&˜อชuนˆ€ˆ€ไ„ภ/ฟb์[ดB žl:่ ;๓+".'wขน๑™Oํ”ม=’%ํ์„๋วึaK ปjฤŒฑ‰ๅศ[cส ไษคถง[ณd™L๎ฟๆ,{fฬ56BKุ1W>g•;Ž-Bธ๖?5ใ8๖…๛oด1Wœฎูจ๏๎ึk๗cส\ฐrถ%๛แๅ ๓G—ณ<๙้›ฯยา›%W\#ฑ‚Y*\_“]uา`๛๐๕็ฌ๏>'&หB†๋i“ถใe<๔}ฮ–sู_n๘e9๙ฆ—Cูษฟ|oืžถO9ก‰Lvา9๒ฒG์ํDŒ"ฌฒnทdb4ำณ๖์fSœljซญ฿ร6M,JZี‘EI1qีXE ุ<๐รA ม๗มณฒ›K>…UVY%์p๓อ7็Sทิจ6JถฺjซœYk็•EI‡ยถkX”Œ?พฺเRมkภN฿ง—ต˜kn;๕ึืRื๋ฅฏ_}ถ]7tฟเG„lน๋‘มทD™{Fžfc๏ปฑJกd๚ดฉvฮ>รึม๘A9|ฤ}ึfมล3UนHแ Cฎ~สZท[ิOƒใึ๓๖฿2œow๐™ี๖ RQฑ[ฌธPCŸ้ปJฆะ๗ฯปฐภน่ฐ$'0ึZตng#Žฮพ๘ d๛มE–^ษz>ฦ–Nvฮ๙๓ท‰ฦ2š0NBEKvBf8{ฏอ์ษฟุ‰…N๛N›ุ&ห4ถyหjo}‚QE.ฦWB ๋h=๔ะฐ๔ฆP…’+zฮ>p›ฤ<พ‰}Oa๚aฉ๎ƒ;yโ๖„lูd"3ีŠยo“~ดณ๗๊ฌ*ฒ๙!นgไะD(นกœ•ฮoIท ;ฦึุจW5ฐRนไจB3๛œ~ƒ-ป๚บ™&ใO๎NDDƒร/yะ|๖~ป๙รBwพ•ูE"—ทs9GฒœQถิสร5,‰qkŒ‡c7.%Bf%?ช?ชxlิ{๔–‹Bmg๕nฐb๑ฑ“ธAg$H๛‡|~\sสž๖kฯุf;`ซoฐน@‰xำฮฝๆi6”ๅ๛/ํูdyา ฮฑJ9๙ฆ3 Bb‘8g๏๎6๙—l็!#ยฒ+ %Erใ5Lจ!ด๕พGrฝตo ปœต8ขปš\yๅ•Y๓•(" " ๙NGิlฐ๕ํืฮ=๗œt7ฏ„Žvุaaั;๏ผ“นnไข1ฏฺˆcูŒ้ำ์ฤŸOถฟ-™ศๆบ๙ะžO๒ฝ/๘ฺ@™#™ฤOO๘็๏๖อg๏…ฅ2^ๆ€soณ%WZำOC๚S๗ุจ Ž วCฎ~2Y.ณXธ~ฤืŸผcซญทY2)พฤ>{๗ป์ุฟXฆๅ‡oู+ฮิ‡•มœ-็ษ"d์rฅษ6’džฒkN;”|เ!ถ้๖๛eฎซ์ บฃŽx๋แฎฮพ๚๘ฐ๔ˆผlึ4Žบุปๅbckไฝ+™ ํ[ฦ? พT~Ÿ๔sf้๕pŽ‹ธRŒแ}{ุคŸพตŽฟ–OžทฎK7ถึลซWใ# 1‹@•๐32nธเ˜qคGak฿*/ฬรห-ทœmบ้ฆvล3~็a7ี%จภ๗฿o;wึœ็œ3ำโฟย j!#ฏ„Žqฤ6lุ0{๛ํทkax๙Wล๐ั/ูๅ' 6ถฤ=๖ช'ส๘ศศฟึmฎ>eฌ–้–ฑ€่—์ุ๒ฟ๛คณ’ฅ$/ุว๏า–K–ิผ๙ม ^ช’โส๖<๕[aอฮ!้ีD<นยc3ู๔ฤˆฮ<0คญฑแ–ถำ‘ewŸษNTท\[ญ`q๔—%~HJ,HŽผ๔Akท๘rejหŸv๋k‰/’I6๒„]หˆKe.(=9)ฑ&™{๙ณe|ฺฐƒ๛ุ_}jƒ“ฅGหญพžmดT#kำขQม[จ>ถ๕๎ฝ{ุ-ฆ๚Wๅ_ษiำฆ…ญ •+ˆ€ˆ€ˆ@C$๐w฿Y—.]ฌ_ฟ~v๖ูg็dy'”yไ‘มขคP…’๓n›์JฒŸ“์brฤ%ุ‚K,Ÿ“ฏ }๐๚ณ6ลว์ฯ?>9ฆ๓O่๎œ-็ถ๙ฺ.œผ๕_?ูjwG›ทอ‚Y‡ACw฿0ซเฒN๗mรN9~แไŸฟณ;.>>žฦ๖บ=w9ขฝx1Yฆrืe'‡bXป์๖จฤ์ๆแผ&%5้฿ิฆุ้ƒปฺœ-ๆษ์เ๓แธglส_ุ]Jษzฟ=f9ะw>ดcF>–r๕๛ฏ6๎ษ1‰X๒ตM๙๛ฤqp+›/qJ๛7FKฎดFX–ใื[|๑mฏำฎฑeV]ว6\ฒ‘อ฿RBIฑ=ฏ’Oy ตล[ุล_\ CึE@D@ ภท฿~knธก๕๏฿฿ฮ:๋ฌœŒ0ฏ„’๖ํQG,Jz๋ญœศu#g฿๒ดt๖aษ๖คฟูมรFbหญ–๋.d{๑๒ˆ3Tฌ@V]wณฌใล™็฿–้4mV๑ฐฟ&K4Xƒๅม-ๆ ]วฟ๔ธm6`rŽRณ6TšX“M็๏DH๛ณฺ,Sjจฑ5jธฒ.„ญูfxฃพƒ“ญฎดl!g^q ไ>พf๛œqฃ-~- %…|ณ56(r๕—แ(ฟWฏ^6|๘๐"งกแ‹€ˆ€4T_ตuํฺ58Q?๓ฬ3s2ŒผJุย๎่ฃ˜ฟ๙fษง9กฃFKฺ9๋ฦ'์ึaG'แ)ถWฒิc้UึฮQ๋…฿ฬ_~l?}๓น-พย๊6๏ ๅ€๋ณS๘ีNกS`ฒ๓ฑj๋๗ศ;>น๊ะี'๏aฝ๙ผฑ๓ฟฒ(ษyต#"klaผๆšk†-ŒYึะยคI“์๕ื_7ึฆ3^จลv/พ๘ขํพ๛๎ึดiำ8ซฮŽ๛๏?{๔ัGmส”)ฦ๎ ลฐTโพเ๐ธ]ปva๒าจัLหL๎ืฝ๗บEY$'ˆ๒}ก๏lb๑้งŸฺŒ3ฌgฯž6็œ3งๅ๛ุ๘]=ztXๆทึZkๅไ~ซ‘โ#เ%์6W”B [ุsฬ1vแ…ฺoผQpOภŒD)9ใ๚Gm๔ˆmฺิmงฃ†7P (๏เๆขร๚…~ํ36๏ ็]sีกฮุ฿{๕i3ูR™-ข;/ัศฺฮ5๓ ^ฎ๚กvD@D ฎ Lœ8ั:u๊d}๚๔1vlฟ*ฯ?ผฑ%3‚Džyๆ[tัE3I8ฉโ‹/ยV‘น-~๚้'[oฝ๕Bžz๊)[|๑ล3)๔ƒ๗{ฯ๎ธใŽ0)ฦZษ>}ถฺj+?ต“N:ษnพ๙ๆœšศ7ฤ๛‚ 4fฬป๕ึ[ํ›oพษ๐ร™๔้งŸž9ฯ๗ฑ=๔ะCvเ†฿M~'Waแœ˜D |ื›ขJ.บ่ข Tื€]ƒ(:u†ู™ื>d๗$[ึ—(ฦ}๗;นยฅ! b@๊dƒ!เ[#ใkๅไ›^n0ฎ‹ŽŽ:p{๛๙Glท.ฮ{%”ิeี)"|‚•หํguŸ}๖Y˜€฿~๛ํ†%Iถ๐๐รป๘xpกd็wถO<ั“๋4๖hdฤˆ v7ค๊Bโ^sฯ=ฦ}๙่ฃฒ^6t่P0`@&๏„NฐQฃFู2ห,SN์สชๅƒ†r_ฆNj<๒HxึŸ{๎นฌz๗๎xfพํ๛๏ทC9$t๗ฅ—^ฒXภป^.เƒl๘๑แฦ3\ฆ@IDAT๗fฎนๆ*—ฏจˆภฯ?l๋ฎปnNุผZzณย +ุ!C‚ร1ถๅ+ด๐๏๔ฤขไ๊๛ํkฯถ้ษ %…v‡๓c<ฟM๚ั>O|pฌ”์4Gฒี1แ๑[/ฑGnพะV฿ ‡ :ฆธ๚I๔พ๒ุถKฒe๔Jkmd$%ํdQ’ฏz!"Pซ๊c—€š€ๅ8šๅอz:์ฒห.aฌY3›>}บ-ป์ฒeŠlดัFแM<ึ$็w^ศc™!^ j้oi—€CA X2QHoาYถuuืู•W^iฑ๕cํึญ›ํถnแ~pX๓ๆป<ยJ๋ึญํีW_ๅ’๊’Qพ฿,ฅxเฐaEl=,๊๗ูgŸฐฃbิjซญVf้Mพ !ํ๐ร๗๘‰'žฐ%—\2๋f‰c#c5ึผyล~CARn!Yดป,ฟ๒vqวดP2๔สปํ‘›.ด%๖?ีVYท›~D ึ1๙;e`‰I0Ž‚๗;๋ฆd'œฦr“w’…ถ๕Hฺ๋oฯZkฏ!V๔๐ุ3cฎIฃ ญ}งM%”4ฤ›จ>‹€T‹€Oฐriช\ญŽ%…Xฦq์ฑว†ทห๑5Lฎ๑9ย๒ƒ6mฺฤYeŽy3ฟ๚๋๋“–-[ฺkฌ–แ๘$”ดร;ฬvuื2ือ๎ oฤqŽKXpมรา|Kธ ฟโŠ+์๛฿์6U/ืOž<ูุ๒ษ'Ÿ,ืŽ;๎hˆWiม*.ˆr๐มห1#,"ฐ๒ะฃGปไ’KดVโ|ฝ/w็œsNXŠ”œ6xใ๐ฌ๛RฎŠ@ไุ๋ผฟ7pƒz๊ฉแ”]ถŸyF`C8น๋ฎป ม็าbำำ‹@E~๛ํท๐wu›mถ ฟS•ซอ๔ผฒ(มœ๒๘ใฆŒฏฝ๖ZmŽ3/๊๚'ฑ(9ํ๒ั๖ฤm—…W๚pšญฒŽ„’ผธ9า‰ุ CZd้•ย๎?l‰LtฬE‰UIษว!กJŠ๐QะE เ เฟƒๅ)iŸ๙0p@๓&ฺjฌบt้’ี1+fื๘ฐcาRั2ฏฟ Lฺg'ฐนภ7hผอdฒ๏BLeub‰ันs็สŠิ8‹ฺฦiํย /\gึ+๘ Aภ๒ภ$wฯ=๗ F[ตjๅษ™˜~!zp?pถˆƒช?๑ห1;!_๎ cเ™Dม_ b@&L˜,p< o=๖0&{‹-ถ˜'—‰๓ile:Vzr๗wำO?m?๘cpB›€าื0f„7–ไ Ž9าXฎC@ส•#ๆtฟtฐ๙็ŸึกC‡๐ปƒ๘˜‹7B Š+%…,”55๑Qrๅ]๖ุจK‚Pาภำกdำ\gตQDnv”ฝ๖ไYG|ย๕ฯYซ6 fอ+–ฤWฝร๎J–฿์p๘นึกsO[oฑD(™GBIฑSЉou7lณฐ|?๙xอ›h๘Q9๙ไ“ญ"ฟ8๛ฟ๓ฮ;ฝxนKฬฏบ๊ชฦ.Š+ฎธbุ‘ฅ\ม&lฐม†มŠ~8˜๘ำ&oำYF>๗sWTผF้Lฒqh‹uF,@Tไs†‰+พ"่๓๛๏_ฃถผ0~`8เ? หB.ฟ๒ '๕Lš8โˆL๙๔“ไŽ;† KL๘,ฑฤณ-๔ิ็}ม๊†๛+–นPภณ€๘ืขE‹ ๗ซเ ๐ภโจ2+’๚›๗“1Ž;6/ดะBม14ปฑEke๋.–cqฏ๙ฝเExz‰อฟvŽšwy+ซJy"!ภ๏IหฌลƒผJX{ส?j%(ำ๑šฦZoฝV๕g"”œwv฿ีg†]oถ=่Œฤ๔“zํ“/Lใ_~n9๏ˆd‰ืLฏ๔:oaพฐ0\ƒQฝ๓โ#vำู‡ุ€Cฯฑ57๊m๋&BษยJj@PEE@ –„ฐฬa‡vฐำN;-ฏบอR•Aƒ…7ส1ฮดCศด ‚„[•เเ๏ฆ›n๒jชcฐ0วsุ|๓อ–ั4iาคตkฏฝvfY ร ภE”ˆE…r' ดรd™ฦ่le=ทํX\เ3[`๊oไใ||ฆ\uีUaB{ห-ทฤYี>ๆ๛๘ัGm qุnปํ‚ล/5ใ€Ÿ –อ{ภ'ย.ิิb W๗ๅ?ฯาK/m๓ฯ?ฟwฟา๘ญท2ฌ…๎ป๏พ หฝ๒ส+ๅ–Œq/™฿ฤ *,uฐ<ŠปPfvŸนธ‚เG†ท๑<็l็\•‡0ย฿ ฮใ๚Aฐx๑€@ษ๏๗€_๚_ำภ`Kdท.ม:‰บ๐•ƒ่‡%Bq`[rฤ่ขJ0ใ! %kvแจวํŽ‹†„ ์๎'Ž “๗cฏัืษฐฏ=ื^๚^[rฅ5l๗ฏฐ–๓ดฎซๆLฝŸพ๓’]qฎึ?Y๚ึฉ๛ถJฬSGE@jJเใ?ถ-ถุย‡@M๋จห๒|๑ฝ๚๋ƒรP๗๑แํ1QรW Yฉkฏฝ6œณ<‡7ั๛ํท_xณsีซฏพฺ/ญ4f๒ว9้%X…ฐฅmZ,aน c&ˆX0‘ใ!AษnE๑1iค์&›l–d+{้ฅ—†dฦƒ82pเภ2ล˜ˆ"xa-3ฯ<๓„Ic6?!L(ูQฅ6vยZ‚](ำ“eX๏ฝ๗AŒก“X„รฐแ†k๎ฉ sŸ|๒Iศซ๊G.๏ }ูkฏฝยrุ2๑ฯๆˆ๗๑ว7ถคๆ>s/๑)โ<<Xสฌณฮ:žU&~๗wรฤ?ฝำ <ทrหŒH0;ฯœ7Šฏ,๘ค๛ฬ๏Š;$๖๒qŒถ่ฎ( .า_žSœฒ"†ฑSa๔่ั55\ะEdใ๙Eิaปi_ธG8‰mถmน.ม•e=๔‰ฟู–‡•ปH ’€kน๔m“7%>x„ม@‘-ด๐{"”\6๚9ปแฬ“ฅ7ุa฿k /ตRก Sใษ3&๓๙r›๘–|๛๙๛6์ >ึ{๗ฃmรพƒญำขlัVZz3าฑˆ@a๘๐ร3–ตไkภ Ÿๅ%ื\sM9็ฎ๘มj#ึฑ x`9ม[ฦุ฿IEใ|๕ืƒsืxโˆCVฺGจaา‡ล@Uห|[b|Mฐ$จข€;4XN€Xต`]@xแ…์มดx™Zพ3ฌ*`๎5Kf7 ‚ ะoDƒ8 >s<ฐ๗]‹่[#่0ัtk(๚…0วRœ8\pมaFึ(lฤ3,ผฐ*!๘n$ณี7Vl•|–ุ.ท X๕์ู3ค!zŽ?>ณsฟg๚ฆ]tXp_ฯบ๋]kาฌy]฿cี/""pิV+Zว๛ุ๖‰Ÿ’ต‹’ลdQ’"คSB ภ„ƒ/•ตฑ#ื8:e%SูB}_๊AŸ*ฺ ‹Œ1cฦ„nณฤ—:q˜ฐว~:๗…7๎c#xณฅมเŒ3ฮศˆ5ˆ/ˆGiแฅบฯ\,ผฅEฟ7xรุ*Cถ%y[~?Seหoผbv„๊ิฉSHbg*Pโ2๑19?๚$r3D8ฦ‚ีขฆŽ#๎๐๗ฬึ)๛๗>Xๆ…ฅtธ?ˆB•9€๖:7๘Hb™‚^.B%(”จˆX”\vูe:ฐส”บjcb"”๖๔๛vฝmŽ9[ฺะ;f:Cชซ6Uฏˆ@yC๚ฏnหฏพฎํ–๘ ’PRžRD@ ƒbbฒžv&YŸ#ฤTŸๅLฎ*[Rย›&Uู&ไ.”ค'uˆ X`MราฌT˜<X๖€๓WqžงUๅ,ะ'ญ้rL๘7`อห?&iพ4็ฎป๎ ;6xฤผ}gbIศ6ฉCHAlก\์ร…ฒL๐ำ~&๐ํ€ รR—ดŸ“ะH?Z€พg๓แ—3นg’ ;Bฺษc=–ฑža ๆฐh@๐ยฯ หฆb๖นผ/พm6}โฐ„*Xตc-ไ?8ใB0๑ฅ,ไ๑ฒLŒ‰ปo์ฮ]Š"ฎ#>>๏ผ๓‚iู|T๗™s"Xสฐ”-nา‚ mqฏ็ˆˆ.LVUเูt+˜ณฯ>;ณŒ๋ฐCpabห}'๘2"ฌqิโฅZไรX*๑lmพ๙ๆ$Kูฐโ้ถH‹Ÿฉ๔’<žฟlพhธNกa@รบช่„’ฟ;8ฉโถอBฑ-ด๐ห_ู˜—>ทณ๖๊n‹.ปŠ2ผDฉ.ดqj<"๏Nฉ“ต]tiœlญEูโ๓6ส๗.ซ" "PcผUๅ 2“^DๅK`i oอฑฺ`๙ ‚I<ก๓~๚า!ฮณ๙๘9rคsฮ9กx;ม0IFP ฮ0idœLุHุๅั,๐‘อ ย>X?„_ƒล}ฟ†{ฬา‚/k๐ฒี‰ฉŸผนลย!ฐ €›;zM๛๘เนC, ฐ{Nh ๏ฟ~ฦ้็ธqใย๖ณ๕q_ๅ,}ย’‡„˜œb‘'$$?ธ/ฑ’งป8ๆ6ค๑<๓l"ฐธ`ลฝย9ฑทC9฿c=6cม’ํูซ๎3็"\}ู๕๓{/๒ถy†yAํฟ7๎ฌฎE ห}|7$ž{๚๊มญGโeถช๖฿gฯGhen`”ฝฏŠ๓ŸKต ‡ –“ฮๆE WแD ก„?.จ™…~N„’๛ว}kCw(lKบใ%kํ mœไ;3olอ[ดดรG<`กd %๙~หิ?Y ภีํท฿>๏„vЉ52Ye›ินๆšห๐Y‡&™๎ปกc‚ŸvPŠx€๏‚/—aRˆ8„ ‚3NฤˆXฐ`’ดูf›…ษ`l–ีoผc‡‘ผธcโ™C† BJ<™๎ป๏B{Lส,xณฯ$ซท:`อ Šาม—็เฟ‡ฌ๔ำ฿ฆS–ฑ{๏ฝAdq6์tรฒ‚Or9Ž—‹p^ภ$’ e๐๓€u “aฦ† ๅใก\6‹ ถve–,I!P7m พฐ .$ๅ๒พะ„ ƒฐžภ–Nฑิ™ˆ—็ฐL,ปŠญกxฦxหํ๗•eRฬiฐ่Šป+แsq‹นฯ๗฿ŸYฦD9„ ๆA.~๙ตี}ๆ\„เ:๎ ฯ KXฐข!ะ>พ Yฒโs-|๕เƒ฿?–๊นด*จเ๗g’gmช Ž๛ฎPˆQ,ง!๐ผยูญVโ{‘ํy๒1quธ๊โw?+ฑOาyฦึU๑าž๘yคœBร"ภgนbั %๑Euไ ๊|uUฬ†t{งอ0๛ป‰ถลFl๐พู๛”8๘ช‹1$žู”iuQs๙:g$mฃถ’ฆlสิ๒}จ‹พ$ร>uq_jฃฮ ์์<๕ป น๚i๛฿ยlษ๙dQR\U‡ˆ@~@(มzgฎ๙dQ‚ย[g๓[5&<,ฑa—X36“=P3!๓‰ž {ฮdำำ๕๐ฆ‹&ผ‰๖€5“TใN:;0ฑ$ ˆ0Ctaษล฿‰๏œƒฐ€5 แขา'ิํBข“ฦx\L@C˜x{`rMYฏำญi๊ ฒญˆฝŽl1;‘ ฅ'ูส’ฦธ`•^ฮเ~)รd˜{„เK&XžยDฝ>๏ b8b฿4๔—ภไ‘ ซ ฌ}โโq!v0qGฬ๒g๋x–“๘8ฑฆa",Dชx†YฮำฆM›rลซ๛ฬลโDบฤ ,™x?b‹^'œ>ปฅPMฤ6–ถ๑๗†็฿Bˆenฤณ3๐eFพฬ-Jเฬ๎Jพlษ๛…ธร uฦฤ,ผL:ๆูฤJ‡;ฮ&ธฆฏีy@(A<ๆศEศ‹ึUv่ะ!%xะ;vl.ฦŸ๓6๘รฤถ!ใใŠ1q๚ร?<้4ฮIO็ลi~์1ƒค-ฟ†ุฯฝŒวq:ว้๓๘ฺ8?}ฬ?^6ฮ๓4ฝ~โlc%PQ๕TU†|1๖r^_จธ๔Gœ—ฮŸี<๊ก8Ž=ฏ:iฟฦcฟ–s๐๖ ขtฟฮหS>>็Zาา้^ฦ๓โ|O๓๚|Fขข“(„3fL}š™^าๆŒ้ำmบ’7eผ-›:mjO/9N,N้Iœ”#Ÿiำ“:)็uP๗ดไ3=I๛/ษ m—ด=ฝดญ0ฮไ<๓ิd7LŸใC›gŽF6gำะ=‚"ภ{&CL๖y•OS๙gŸ}6L*Y’ศ@หŽ…^8,]H๏ฬแใ <–(ูผ,ˆ๑ฤA_&iLn๑กAภฺ…~๚rาโ%Aœว!k–0fโฝ{๗`>ฮ~พ/ฑใsฯ i ผ5ๅ%b่ !/iผ1็{”‹>&ฯCE้ไ{๑ฌ†ชฎ๕ล๕งำผŽtบ_SUzถ|O๓˜บโใ๔yœ{฿ผ/ฤžFLYโ8-}œ-฿หฤ๕ฆc1ใ๘ใ‚1Bฯ1ใ˜tฮ‰๙๐ฅ'a•m๋˜๎‡ฮE@D ก`“#่็›PR[,ใๅ7ิ‰U ใๅMถภdŠํLq0สฟˆ39erฦ’„t€'“gX…เƒGจต&L˜ฌVฐJจ(๐ท9๖2_u…4ผL.bv–มูญOึฑภ` Ÿ๔Ž.๔งกพ?เ$•%D>ถ4Oฤ„‰ฝ๖ฺ+5[็5yๆXย๖ีW_ัฑ*วผXE!ุ >bMร„ดข฿กlƒเ:๎ท[ฃ ฮ ึaๅ”ญ}D%ไฦdถz= kžlฯ็ใรไไdษแ‹1าŠ๛‚ƒk…†K h…ทดภ4”ฅ7…jQาpอส{๎ฑ @แอr^™ไbO|}u+ชื… œ๒Lฬ๓ฝ=?'๖ดธ<วqžGLˆ…?๖˜2~—อ–*+QQพงง๗ผธ๘ธบ๙ิ‹ลขƒ ฤ|ฑŒฯษ๗r^–2๛yeq\Žy+ใŸชQŒY้XD@D ,&@XdฒPยˆy๓ฯ[{–p#‚็"๐o$–|e M61ฅ6๚ ‚ื็Ÿถaลฺfพ๙ๆ cEฤแ฿฿| Xฃ0a]b‰%2)๊บฏนบ/X9เAQ ?๗e้ฅ—~mช+ิ„GฎฦV“>ลe๑น‚cว:„๏wน ๘AฤB”๓ๅOดฯŽ<3พิ'—}R[ตKC,๑)•‹7%จ๛R!”`Q›Fๆ„ฺB"ภค‘คะ…’Bบg‹ˆภฌp'ั๑ฒ;Oq๚ฌต ซ๊›Kณ๐๏V—}สกeถcวŽA(มœ๕  " " " " ณF฿ป&ฮ9Y~“Oฮ\gm4บJD@*&เ[#ว>zโ-ฉ๑7ƒฟ&…†K€ๅa8ฦ็S.B%˜Daล?ไJrq๋ี†ˆ€ˆ€ˆ@!`๗ึ็K()ไปฌฑ‰@q`‰ห/ฟ–๘ฐœ†ภr‰.ว8ชํีซ‡akํฺ๒!*ิœ`ใ—uึY'8่อEใy#”Lœ81ฌ๑”PR{ท?$8?โƒ“%?ฦฯNž๘ฃ’ํCeb#ฑ฿๒WG|ฬฺI>”%&๘ฑว^ฆฆฃฤฏ†๛ึ๐ใ8ฆพ๘œcึํ๒๑c)๋yž๏yœณฆาฯ๑ลแeˆ9ฯ–็ๅผŒ—#๖ืe;๖6ษใุ๋๐c๚ซ " " 5%€Œโ@ำwqฉi*/" ๙D€-”/ป์ฒะ%|UฐcP,ˆ|๘แ‡แ๛6˜ฐK พ}pฬwm…†KกŸP๘3อEศก„-ชPˆ๐่|ํตื†-ดr >ฺ`ฝฏฟผeณ-2^ณ‰๙เ‰i|ุ๒Šsb?vัƒุ?ˆ .nธ๘มyUม'ใ๓ฤ…า<Vั‡2qYI(OHŸ“๎i้8.S..S.โ๘˜rœ{š_็็ุ้หงcC\>>๖zk#ŽนS_|ฮฑง๙=๐|ฮุหyฑ—cOงผgห๗ผ๔๓Bบ >้8็๙๎่•|Ž=&Ÿงล็คe๛เD–๋™,ืคqK™Šถ› @๕CD@ €Bษเมƒmภ€vาI'ภˆ4b'ภnBO>๙d; }๑ว๖ศ#”sไJ!ๆO1s‘$,ˆpีม๊“\„ผJุluื Bษuื]gO?t.ฦŸ๓66๐ุ;;!L~#\$“าdย็“ฺFIภ๐I๒sžL9“ฬ7ำย4ฟถขcฏr”แ<ดŸšH{z:Žหz[Œ=]Žs‚—๗ุหeห๓2ฤq๐tฟฦc/็q๚šสฮAาืน0_็iฤฑMlใyžว.n‘ๆา˜ถ˜8ฮ๓z=๖6)็i~m|ฮฑŸWวmวๅz๒ำ้žๆeˆำi~2’^ฆฒt/;;1๗“XD@D P ๘าœj;๔Bฝห—wy','ฬถ=3ห ๕ทฎpŸ6~aw3ด‚\„ผJฎฟz{๊ฉงr1œทแNk{ํีV]ฏฝ5oัn=ลr1ทชโ8^>ฦฑ—๓xฤˆ†ƒ/ฑUB%เBษvmgงžzjกSใ(2ฌD8๔ำƒ฿‘x่๗฿ฦWIœฎใย €5 7pCN”7BษO?d์ฯา›Tๅ„DŽqห™ฝฯฺหึฺฌcŽZU3๕EQ%ฑ“ ?=ฦ’k ฯ)]็œsฺงŸ~าฑยๅ‹q.ƒo0@›์ย˜๋๖s9ึŠฺ‚>š7onG์HูคI[jฉฅยฝม/ฤškฎi˜ยณQ฿mนŸq@4ูc=‚8ฐภ ฤY99พ๕ึ[ร’~ฃ/oผ๑FCNฏ ท '{ัE5,MD@ชG€_^xแเkจzWฬ^ฉผJ๘ใŠ)%%uๅPi๖pอีฌ“D=pไvถษ๖›ฬ~…ชAD ฦŽ๋uผM๚๙ืฐEp/ึ" "ะ@ผ๚๊ซแ:V˜็Sธ๘โ‹ํย /ด\ะZทnm_~๙ฅฅlา_๒™L6mฺ4g'ณ8Dฌ)ฆ€/v-ˆ K,ฑ„๛๏ๅD็๑ภq๋ท฿~ณkฎน&|ฒวุAdํฺต๓K๋`ใM3fLNบ'ก$'˜g6‚zซ๕=pk๋1จ๛ฬ ‰€ไŒภa›iOฦ5g ซ!ศ!qใฦ…—3Lฯ9็œถ\ySlฯบ๒ส+W^จ4wษ%—ด;๏ผ3ˆ)ีบ  ๙ห;ชย‡ํ• 3fฬ(Šญ]5xฑWUภJใชซฎ2x˜6mš=บŒ๓RฯฃมฤŠ\ _,๚์ณฯผ vโ‰'+ซLBŽ&Ož\ ธ˜TฌK9ฦฎๆ „ฟเ ้{๏อษˆ๒F(๙๚๋ฏญkืฎมDOถ<๒HNไบŠ์ฝ๗ึkฏ-mหม=sผฺHฐAแห๎;๏ผ#" "Pฐ^ucางO;๗s๓jœ๘gx๙ๅ— !„ษ#oึ ฝ{๗}f๛ิ๙ๆ›ฯ[lฑœ๗๛ƒ>ฐ^ฝz…vy{ษา–Mš4)คaร2!|^bภ็ใciH‹-ยvบŒsฅ•Vฒ#<2LTH็e<ธ–็ทฟ๛ํท_๐'@๐‚#ำบพทl|ิQGyณ!Fฌy๛ํทหคๅ๒ซ฿ฑƒ็่๙็Ÿห›rูต% •B ฟ7๗฿N†7BษW_}ex€ฦG k ~๘แœศu#8ฉEM๏พKwj๏’„sต'EMเ?ณ=ืฺ;|ฏฮณขfฅม‹€4h๘dุnปํ‚Pry็ๅํX˜ธnณอ6ก์|ศป.ึX‹0นg{ใฦC3oพ๙fุH`โฤ‰ม๚ ํk#[_ุ•‹!ฐ'แ€ฐC9คส!#‚`มฤ„†ๅ_6m8ใŒ3์ก‡ ็,ีYkญตยy]ˆ—ธxดKr๐๕ากC‡ฬ3เ๎ป๏พน๎†ฺK€_ๆ™gžŒx[ืษก„ตฉlำ…Pย–?‡ดฎไบ~ฦuฤGุฆ;mj}๗๏“๋ๆีž=)ฟOฑƒบˆ๑6SAD@ •หFุm๏‚ .ศaฒ,yะ Aก/ผ๐Bญ๚ฑ˜0aB๐{ว๗ฏุА€ส†ท”?๐C…|–Yf™0กgนะ*ซฌvM™{๎น+,ŸหŒ/พ๘ยpฌŠ“ี๊๎0รฒ1Xtdณ‰๛/“บ่ข‹ฌgฯชญกฏพ๚๊ฐหR6gฅcวŽตฃ>:ร›.qะ˜Qผ5ฦอฌŠ๘Dy๐มำU฿+>t๋ึญ\^]%pุข;ช˜<๘๐,!ญบ๊ชuีผ๊‚ ฐแ††฿฿\TไPย๚M74%ท฿~{ึ?l…p‡1=ฤ์ฎKฟ.ึ’ท'…0.A ฿'n‡u;"˜Rณ6XAD@ •€[jฐœeุฐay;L&ฤnฉ๐ษ'ŸTุฯ?๘รุว'๗์˜x๙็gฃ๛๏ฟx[๏S'สพควำ=f‰›oณs‹/ซมโ€%!}๔Q(Jฟฐคจnภj+i๊cฆM›*uึd\๚Žpแ7่7kฏฝผHน˜e๎พพŸkฐŠ9ๆ˜c งญูB์ุ–ฺ๋ทoŸญX™4ท(ษ&”P‹ถษ%ฆ,ทวยวKฑ:v์Noนๅ–2>PผLub๎bณร๗”e.*๊›็ืfŒ0ลFใวฏดZvฦdษ™‚ˆ@vl2วsไlำ—ผJPQvฑ()dก„๕’งœrŠmะg}๖๐็`ูฅŠ€ิI?Nฒฃถ8ฦ–_~๙‚ต\ซ nชSD แ๐]?ฐ`Rฏ‡ 8MลZ#๖e๗!=z๔~1˜Xณ0–2พL† ๗Obฐฤycm„ุr‰็%WพJโv+ฯ`uWV๒D P เฯ”%“O>๙dN†˜7Bษ็Ÿn›mถYม %ผ2dˆญืk]p๔๖9นษjค๚>น๖หo๖ี‡_—~e฿}-ผ๔ยถฺซZวnญๅ<-*ฌ์งo~ฒง๏xึZท›ืบํXœs๚๔6fฤ{‚#฿n;nZa]สจ;?๓ณปีq•~!ฏปึUณˆ€ไŽภ{๏ฝฤถทe›| ๎เฒฒ%B,›aน /ษ8ƒM[๒ฒYถ`แท ผ‰ฌnภสk็=๖ุ#X\TuพUN=๕ิ2ลpvJ|ลเฃ#j2.ฎๅ>>บ_ฟณw&€6U]_ๆฑQŠขP’("4‘"ee.$Sศ)•!IdˆTคค2ฅา<)๕!‰TJBฆ™ยw~๛YทŽ{๏ป๏y๏พ๛๎๋๛ฎsฮžฮ>sป๏์Y๋ฟ™}๛ž[๑ช GzุํูGŸฏ,œ‡Mเ„่0†G a3… Jตดึx๚ Yขุ4mฺิ„ย˜ฆ๑?่ก!ชฌ†7ก8xฉ'ฺ hถdษ’E›นญCภ!เC™ด~ฟพfฉv3D l>)ผ๘#7sๆL!/{<Œ}ฯž=ๅส:Wส๛ัŒวkอhื4๏ูทๅ‰o†œvฎ<นฅี-คrญJA<าlฐฌ_ฝ^Š–,*พ๚@ข6$/<~ำ0ด4ฆM›ๆฏzl%ซVญ ซข„พMia,ฌ `<ึ2 ๏ ยขขaถm3Z$œ+Xศ๕Qูฒe‹ฦt9ˆHฯฯ?<*ื3D‰บฦ;Q2|๓G๓ŠZUคลƒอฃr“Iย#‰1m่4๙b๎ฑซ๔8ตเฉrfั‚ฒqอ&ูณsO`+๊\!ญถ”์9ฒส6ฎู(5yุ_๎yž=ฟaฦŸ๒ะY๘๎ข@๛bŸ'ฝžํ%นr็ ”น่ ฐa๕๒pณGค๊ตUeส๓SขsRw‡€Cภ!่ณYYควชA€@@ๆ„ุDkฤNร›y๐‚ <8ฟมx˜ž={ถ ฑ…Z!Vz๔่ Baขs‚Hภ{%”)ฦิฎC๊WUลkโƒฌATึ^'็บO"L ;vฌิฎ]์๓็€ิ Cฆ6ฆ/<ิภˆPL5Zุ‡ ๑ื>u๊Tฬ‚lˆฤ&L˜`+ฺ†kีq๐tแํฐญฃuฉฑ…$ธา”ผEฏฟz ์*5ฮษxJ๎ฅf8Q$็vm๑‚๖๏฿/ˆBGรb’(™5kVข๏hญsงx็wส5ซHซGฃunwžเ|สว๒๊3U6่R_nju“๗0“ี”/›ฟLฆ>๚R€0ฉคบ4๏—๐†?-๙Yž่0าดญูข†4้‘ ?ร่)ƒฆสW๓พ2uำr@ ฉฺเ็^@$บ;kWญ•ม-†Jฺ5dยุ ั=น;›Cภ!เˆ"ึŒืฑj—^zฉY่ฃใฦ~0#Lฤ๖xภ+"„๐ ย;/ย:ˆบB,h˜ํ 5บvํ๐ศ ฬ6%J์์8ิCl ฟม‹=„M!wHฝŒGฤ๓Rร{C3๋h™?ฤ%9ืล๕*ฬ+Aวททxึเ}ƒ1/›0ฒ… Cุ้ฑฃ|๔ัG&ˆ0คH ญM{ห3/!็~ƒศ‚ผร#๔ฏตE‹OBฉŠ-ชลษBิ  จฦw!-S๋y[ฒ<๔ะCฆXCฤm์ใ#GŽาWๅn฿!™@ฆ}*ฒฃEรb†(ั?rx๐‡—ธxด%K–ฅ๏+k^)ญ;ข$ฝ๏๑๖Mฅ฿-?ทินrmใชRญaตใฆถ}ใvy๒žQฒeรVSืๆกึruซฬา—ส„>ฯ˜–š๚ฯ=[>x้ƒภXฦt5z'ทu~]พF†฿๙ธาเ๕x์fˆ:0๎„‡@!€`&ฎสd6Aท# แS !<ฏ‹`ๆืฑ…/YT^xแ…ฆ[(ฯๆลBrุbซ่V๕ลฏ กแ@~oœN:แS๕ฐP}•ส•+ ZิTCu aA๖(MฮušFXฐ0=‡n—.]jดQ8ฦ“ฏศBnv๏mศข† š%๕๋๐ยcวึูะ๚`[4P0tวhFZb<€ภส&n๐๒PO๛;แ๏(ย;๕๓ AƒŽ๓J 5 แ0MR~#›ž)zต|7mฺdพร~<๙๒YฉFจœ‚฿ {[ตj%ฝz๕ ึฤ•92%ศtNˆWV4,fˆ’ีซWยx'JTด๋๊›ฎ–6C[Eใปs„A`\๑๒็หM‹›Zี”F]J–ฌก…ด6โ…m4}ฤดฯj~๑ใ^šยl๒๙œ๒าiฆผ฿”>rฅ็ห‡/(3žœ8{ป!wI•Z•วn'}ภ๛ยซAำ2‘แ้3 wV‡€Cภ!tม™–๚)ฝ Žh€ฆก๊ภ"•E4คฤ:!C† x@l๘ฝH7‹a5่‚@ฐ0ๆ คz›0Wฮ Q๑ิSOฺำฯ6ผ ศยศT”E0 wฤ$ญ[ท6ž*Œ…q\ฌX1มฃB฿xฒ(†ภsฏŒล7„คPrฎ‹บ}๚๔1c๐„[ฬSo“0฿~๛ญษ๖Cy$F6Jศ(ฝ6ฮก^)๊™ƒื แ@ม O๎-}š4i"<็sฟUV๛0.แAJฌP‰…Hjk๎“ํกฤ๙5ณŽ<ฤ?6ษe7 ไ๐R๏,›ฌB‹…๏$฿[ยป ƒ,!4‹yล5!์Š…๒žโ๛Iึธqใ๘š๎‡@&C€฿r>่Gi}๙1C”จ˜๑ฐสšใ=ญˆ๖๘*ฌvๅWสรD๛๔๎|[=ฯ๕DWหUปTบŒ๊lี†}q๐Kฒเ๕/Lƒว฿yLN;หsท}ฮ‚ ;๖‹1๒ำ7?สธฅ๎ปฝO3นพ้uกu5QCเ‡ฏWษ˜{วสm-›ศฃGํผ๎D‡€C ฺlผูx“TฉREpc! ม2)ำl1บ่gaM(ˆ๊€hM™‹Wฯ‘vJVผ"X๐ฒ€UBNิปฤŸ…ฬ2š)$Bh8 aผ XฬŸrส)ๆุ^ไ๋๘lัม „9Š{๗›1จc Ž๑Zภ[#’๋ยAZ eฮรตA4A $›'Oในม9ฐ`ไ’ฉ๐CrpQ2ฤW่9 ๔๗฿›k ก_ฮœ9 .‰๛˜3กO่ฉ๘ษ‹eห–’€.s็ฮ5)}#>ไ 4ื„A2u่ะ!ษพ FC๎“ฆึgxข%Œ๏—~“ั‡๓B๔3พฯxz๙ทๅ+V4ล‘ฮื?†;vฤ+่2mบ5s%(๚ฤห ืxแสืU–๖O/—•!ฏcั{฿ศณDัœ€-Y ์ซ#^“_Dศ‚3๎‹„ทHำ†M—ฯf}&g)(]Ÿ๊โi` “๛๖\lอ’ TœM๚๛/พ—๑ฝ&สํn—‡๎KˆŽณKt—ใp8 )j‡6„DFXฌษน.ผ&…ศฑฏAฯก[๔LZถliยšƒpbน{๖์‘ 6—Pขญผ`ุ^vูeๆC๘บw฿}ทž:่b„>ๅส•3d๗ะฦ๎t่ะ!ใ„h#DŒŸHฑ&ตg!,j@4h„2›(แz5ษ`\„b1 ษา19/^Dvšjญ ฒ{ ฝม๓ ›Hณ4ุ้n๋ˆg '7n(ฉัฐ˜๑(Q––gHศ’x4uƒญTญ’tี./1ร\ำฬQณไƒi&"<"™<ฉeI1[ฒา็๙ฆห“Gษ*ฯ‹;ฃpูๆiŸ`ฅ+]$ฦu3แ9ฆภ“๎|๛้2™tณาฒS ะ5มฃ('ๅ&เp8า;vฺˆXฦŠกSAุ^!ล‹้ <[๙ไ“ƒิ&ฏ}ศ ฉŸ &Kh แRh„ฉ ๗p.ศปaร†O#ฦลรฏ&ผkภ‚ผ–ว!ไGP)ผ‚๐P fšŽ™:ๆ]ฒdษ`อ\™C S"@บ{~gิห+ญAˆข„๏pล$&Rู๖ด ฺใWE๚ตŠWU”Žc“v‹๖2ำ๙žŽฬ†นไI‹''ไ ‹๏ฟ\!cบ%ฤ“ูoฌwญพฒs๋ฮD] +$&๗•|งไMT๎าo>X,“ฝtอwvo+}:๔M๕ษ๐@•/_>๓ อ:โwแ˜S}n@‡€Cภ!p m,่x“OุFf5t1ˆiวซ๒่ค“N’SO=ีx6เ๊7‚~๔N œ๘mUC‚๋$„Œ๊ีซH๔0lm“pืะฝ{wใ ฎMFฌCO&›ดHŽ@mJฏ™๏พcฃคผcะสั„่Bๅฬ!เH@€็j~็ xฃa1C” ‚„`D ๚$แุh“V็เ-,ๅซ”—ฮO฿“VงqใF€ภข๗ฝะ› ก7ฝ:PŠ”,ถDศ๐ถoยn†ฝ๕จœtฺษr๘๐้X๙๘{yูu—I‡aํ${Ž์aวu•ัE`ษGKไูž—๖}Kฏ6ฉฏ&.ตผ1ไbnˆู๑อ›$\เ9h ภoip %`ฑ์,๓"I4y๒ไ !Xxำ ใiTชTฉธ ดk๐ยม[†ฐ).œ—ฦ9ช srspฤ ๗๖ฯุัฐ˜!J4๎/=Jˆท$.ณ\ฅrาebpงhxw‘฿V&C[%จตCj๓๘!3ฌ]ตN&๕›H ขrmฃk Œ;6๏พuฤาธV๖ฒด๗ฒ8‹–yก7๚>#๎$›uOำ‰j‡`nอค้$>ทIฤ<ใ๖‹ t0๎4”!เศ4่3ฯ๑๚*ำฬTบPผคE฿ไ๔ำO—3ฯ<3"ฺT:ฝ& TๅDำ"'qWํศิญ[W๋เ ‹ขdๅส•&;D j่๑๚ๆ6ืr—{Dษ3Ž(‰ฦ—<ิ9xXt#ฒqอFำฒไไำ‹‡ฯ~y๏…ไํ็฿ Sฝqui~ํใU‹~4้fพฆ๗&7qƒฏิฆหฝtะใ๏› ]†u‘nบEudj $ยฤ†cˆ’ฅา„ทy(ฮ‡@j €(&bจฒ๑šM05prc8b%JะวiำฆMฌLหอร!ิซWOˆB![n4,&‰ึgฯž๋O—s@””ฝฌฌtY:ฺt™d&9ฉญ9ข— aR่ผณdฯ๋eลVjฑูึ๏TOnn[;‘็ษ™๓ๅๅว^ ด+Uฑ”œW๚\#ซ…ํ‡ด“สต\ศ…โ‘ž[๎)้ป=Uบึ.Qb_7ฎƒ(โ“B|Bt๐8A<!=uƒ.\ธฐอํ;ˆเ7…P ><[9s8b4Jศ"„+แ7ฮ@P็ R‘GรQ ”}็เอฮE—\ไˆ.้uธl2ใa๎คm7๔.)^ฆ๘qอๆ=๗ถผ1แMS~ๅ-Wสท1๛sฦพ.๏พ๐^ }™+หHง‘๗Hฮ\9en'๚ฐp•Œ๎”t้%uำ(ฑฏœทพŸ~๚ฉy0๚โ‹/ŒK4qำ(์ฃศ_ญZ5ใm‚ว‰jารํ;`5ƒฤฌ3‡€C ถ@๐•g'โ๗ษอ.}hุฐกษxC่M$รNt–1C” ^ Kt๗›ล้ฬโีส”)#^\Rบ=—8UYผ^oFธฎฟK–|ผT~แwAไฏ?w ไศู–KฏนTสU/'นr็ z)+ฟ๚AFwyสิuัQ.ป2ณศ๋ฤฯศฒฯ–๚=๎crฺ™งŽN๔๘i๑O2าK็mt้Tง‹d๓k†f้฿}ฃ์+W.3ER0BดโqB๖,ถฑ&DkXบ๙82;x“+Vฬždv,๕;‡@ฦE@‰ยo’›r<%W3D )ฐ4h`ˆ\ัใ9๑‡็—*แˆ’”|ccดฯ/ห~‘\yrIัREอ๐เƒ๒๊ศฒ`ฮ!$งืคž‰๊A๔๘ๅ_dxปr๏˜ฎาพึ’;k๎่O"gตk—ƒ๓ฯ y‚ถ i-๗๎kR ^~๙ๅRฅJCœ@ž8s86ซgŸ}ถ ‘ไฬ!เp8Fษw฿}'ัJ3Dษ๒ๅห–ข"xฏFชพโ็“n“GIผcw]ฑ‹ภšๅkdXแาcฝาฆF[ษ—5์N6ศฬ–,YbˆBt๘Ci‚วษ–-[$w๎qaยง\นrAFpE‡@fB€Œ7d6๙ไ“O2ำeปku88C I“&&ฝ7dIพ|๙า๊b†(แ‚7n,}๛๖•>๘ ฎ‰’Š+สyลฯ•ฎฯwI๓์Nเp$F€๐ช!-‡Iฯ ๅ๖๋šหiู3n(ิฆM›คษ—_~)๛๖ํ3oŽpธqฃ†ญTฉ’๑8A฿!ig‡@ๆB/VDข ็sๆp8Œ่-]@IDATŠภmทf2G๒า0š}1C”,[ถLธ๘ฝ{๗ะื^{-ฃร$็อ฿s‹A”ธฌ7I‚ๅ8Ru?ญ—G๏์%=ไถ๊ทษ9 ฆ๒าo8ศCx›Iw๛“O>Yv๏-๑‡9&Lาไ๊ซฏ–ณฮ:+&๋ฮ์pD *H๙…๐=gฬŒBฉ„๗ใ‰yอ5ืdf(ต;2$M›6H’… Jาb†(๙๖oฅYณfr฿}๗๗ะW_}5อ/>ฝNภข็uDIzwLภฟ!ƒš>bฤ\›ิl*…sฦg๚฿=เm๒ฟฯจƒŸ๙F o“?ำค %Dา„Šฦf๊/ˆปx‡@œ!ภหย๒ P92+G•ž={ส[oฝ%•+W– ย้Yฒd1"้ˆณ๏ฬ!เˆ]”(แน–าดถ˜!J–.]*wq‡๙#Mๆ+ฏผ’ึืžnใ๓F๗œข็8ข$๎€;qfF`ำo›ไมฦƒ„ EM๊4•ข9 ๐ฦ#6„โฬŸ?฿x›เuฒvํZนเ‚ ค`ม‚B&าฌ๓ฯ?ๆแQ‰B;s82>ณ˜!Jfiัข…{๏ฝฦf๚๔้i~๑้uะฒ้๔์=rTŽคื4y™ฤ;\Qvm m:ด‘‹๓”ษ”8„บhR#๚ˆž +b@/ป์2#~๗๗฿-R—)Sฦx›(q’={๖PCบr‡€C ธ๎บ๋Œ ๓โล‹ำqวŸš@ผ๘อa‹^ศไ1๋š`ย„ RฃFไt™ถoผ๑†ั้cBx5œwyfnGŽq%ึ]‚H#LƒเภS ‡ำ<๐Tวk„ฟoถ&\ถm…F๐ฌฤ๓ฤy๔X?˜Bฎ"™๐ป%า#บ'ฯ@gตk—๑๐ƒ8แ ๏ถmL8i†!FึฌYc\ yรห๏r'ๅส•ห@W้ฆ๊ˆonธแมƒRฑ`ธMฯ˜1ร<่FJАก า๖ค“NJ$ธ ูRฒdIy้ฅ——†gก„อ^|๑Eyไ‘Gฬด!ขฑ฿~๛-@Aœฬ™3'*)1อษc๔ŸQnนๅ3;พ„เ๙ˆ็๒ฬ3ฯผ‹๐>ชXฑขมฑcวŽFง$XZQศ%]ƒโ{ๅฬ!เˆ-๐ $dwžEำฺb†(แอe›6mคK—.†้gข๚าฅKKว๑ไเัƒi}๘‡€ŽU:ษตชIว๛๏– ๙/๗ีบรPเพฌ้‡ฟ๛๎;“nƒB… —xo6yPลsŽ๕ัp 5gW๎ศ์tำM‚Zp้m„9.ใ7โ๒ภ›~Hฌw๏r๗w๛›':f!bล œมŸะ |๙๒ฆ5w๎\CDSทbลŠ!hเ#42[HS ยลโโQ’”ฝ๐ย ๐[ฤ•ิภผจ e|!๏† "x*9s8b œ*&๛ํทMๆฦดž]ฬ%ผaภํญs็ฮๆอe<%ธฑ—/_^:<ีN๖Ÿึ๗ุ๏p๘่tUฉxcE้:ธ‹T9้ _ญ;Œ๕ๆ{™t๐ฤ„7ึx”œลoBdหโาo>)ฮ่ €‹Kศอ๔6๔Žjืฎ˜ฯ|„Qฐ@ี๐=ฤxจaฯ?| ฬ"ะ)ฬค„BŽ9ยดJy^ {๗๎•p"‚7xแแ•ฑฌžœU๎ํ๐‘Pณแ9‘็Eผcxนฦ?gฮœกšวt9d๚+็๓ไ}Hgสpฟืxโ๐–9ๆ}๛๖5ู„h‡ป~8kะ  kบตIฎญซs8ขm๒ฬ™้J”D+<.fzไˆตฯqB™ฉ;šP—Pๆ•{}ฺ;๖vฬพ7T Œบ„rl๊มฺR`JšQIตู&4f˜%~žัาD,โ5โYฒ๛x๛ฆ์ุqVถYฒ™6์gอ๎ต๗๚dอ–UฒyรVขIe ƒม-†ส฿–ว฿}L*zYoNฮvJš}|M•7ัใo&ผ!ภ0ฒ;บร‡E 1๗* K}4&ฤฺ๎j2#,^y๕ร?dˆหๅ—_คVญZfฎ‘j”๐ฬHhก{xK`J”ฆ‡…ํํW/Z"~S๑ุ#x„=mr‰ฑ!n!s๑‚V#›i‹1ฤซ๑b!Tฤ6<,๐––Vฺู,0u๊ิัชใถ„ท ๕‚ก‹‚‡…ฺคI“ไ๑วืC3๕ะัยมฦOีซWO๐ผมHำ Y…‘r"-Œ๋แžโแร}e6๙ฤฃWฏ^A›Bv=๔ะCฆŽP,Z;s8bd:๐Pฮ”D Bฎ๏D สๅ0เๅ–“-C+y๓๕<|๘ˆัฯฟ‡Žx[o?P๎1แ‰ฺkCN›ใ๋ผr๏!เธroภ˜พzศปN๗๒แฐ๗ก์(็>ถฯ๖่a สถด=rฌ,ะ–vว๊ฉ3mฌ๖Zgถ:kLฏ,กโุxฆmย~์ง~Œไ`b‰0CžŽย์paชำจ ขาฤ')†DtHษ&ูฒ{Ho›ี์S–p(ฃWgฺสฒyorŽ๕?ึ6Gฎ์’#gvษž3‡—อเุ6—ทฏe6‡wlู๊๗ฺeg›;งูgNถผ๛IูฐzƒŒ๚ไIน4oy)ฃ€]ํ๖ำ \ฉ๙จไ$ฎา'|ึฏ_o๊xวCฒfำม„.Vาi๚๎ด˜D€็* m‹ษ ๚&eง๖“พฆCผบu๋fŽ!„ศฃd@ QฤdY$Cœ@ค๐l†—ฤ’๊Yะ&˜รA@๘ าฒรŸe…ล:‹๐`!…Žช€๋๐แร‡ˆŽKบ[~Ÿ|๒Iษ;ทษ‚Cืฌือ1ฤค‰ŠŸR†ฬวœศCโDฐ๑1J.q.ฌ2cฦ ใ™Ž™‚ะฤใฅE‹ฆ์DQข2ห๖ ‚ภ‚จBcELuGธ;E3๕ถm3:2ยซ๘๛โoC;žeU_†cg‡@๔Pขไร?”โ^dZ[ฬ„๐G๗D€ภฮ๓G!?ๅส• ผล็ Vฝฦ3แXa`?@ฏoQ+๚0‹'T™pœฐ87๛"7ัึ๖,๐๖๑8ศzlซ‹bใ…เ…งA–ฌBึlY,[<›:ผะYtหbฺ|hG_ฺ$”e9ถMXp'”eฃŸท่NX|{ํฝ}=‡๖Kุ&ดK8฿ฑ6,ฐอ|ุr+‹Yภ็I˜๕œ7ก฿๓ัr@ฦ ฬู;๔ฺ‚)cSงXณMp๔Hุr(วYs›:-Kม-5]<สArdตาz ษ#0&ๆวถOดถหŒทŒ๗‡2‹>^›lGณKึฃY ‰นdˆ-๚xuัBยํฐwLฤ˜ู?t8ก!ฺAฐyc<,ฝcฺ:pะด;xะ;๖ฦ8ไ…Wะ๏Wฯ8zez)ถดIh๗๏ฟ‡ผฑŽšrฦ๗ุxฺ๐aฏฏwnฮกsd์'๕฿ ๗Pฟ๓ฬ [ดj‘ไห–ฯi”4b๏H๕6!ญ($ณz›ฐฏฉ‰y8faPฑbล@˜N,dสˆ=DŒ2#„5ฯŸ?฿xle„๋ทล\RmาคI’ำถรdXคยโ' 4ิ ƒY–BX Q–.]jBภั-A—„0 ผภPB˜ d๙ญ!ฌ&ฉ฿40็0๕ว๚xsฆŒvฟ f9”ะ5แ\Zฦฑ)Lุ"แXs-o8ำXr ฑlๆฺ‚Lะ_ฮฑ^Kธ CP‘ž3 ๆ๛ฎUgฯ*Žh—พา"ฤ>)ฺฮTU‡rโ†ูฯ‘#G Œท‡ฦฃลj ํ๔”k_&ศ>„%ใ๐ๆ‹-cัŽPgฑ‰o™ีb๏ดj—TซVMv๎iธRว[LRdฺูt๐>qๆศŒ ›ม7ผ2‚mฺดษ„1W<Yศ&evศ‡†ญุ dผ +l1OดL4L„๐ ยwจG#ฯฤั๘ฐษ•คๆh):Lxฅจึ }๐–CE Hผ<^ต !Zˆ"๔2ะ\ม‹ีฬ.„๑[ฆญ์ณp ๓ึ๐"žฅ๙@ฉw ฿V๙z"ุ@๐;kโฎœ M%( „ิฃ„๋ัิสฉ!ยจ^+Wึ฿๎'@ฬr†แ}h‡แ)„W ๗wิจQฆ ดlู2~(๔vxฃูุ์๛bทq๛‡@tเท฿D~?ฃ๑\3D o‰แไ‡ํป๏พ3ขYั<}ฮขž%แฮฮ3],าŽ…ว๖ยE =สุ๊พ๖ณk}๔c—้ธv๛œ”๓๑ สํ-mtqฮ6ม[มฃGย์"่XฝฝO_‡zปฬฌuZnŸืฎฃ\๋ื•œc๐dถŠ“ฝe,ลฮj๊้o}๛'ื_-ิพึณี6บี2๛Xห์-๛˜ถณท์sv™ึฟฯq4อึ-š็v็Jxšจท ยถถ ๎๋พƒ5ouฉG฿Dรt๒ไษ“ผบึ Š@=„ะ”ŒB”ุ%dชม##)cqŒืฦ;Gs‚ฐŒ๐ผ0๐4ก-ฯš,ฆี†P/[dฮœ9ฑต}จญfƒapgaญ!<{Lž<9@€๘ฝFS=[่IDชuผ30ๆŽท .e1=ยซxQ(0xฆค%=ฎ๗า๓bS‰sB๋ˆ!ีšดม3‡>„๎œจ=ฺOŒรฝ$คgึฌY&D ์8—ญƒ bผก qุ'žxย1ฒ™ฅตล QยL7Œ.ชำ1‰gำ6žธWฅหหxZ๛ผลcฯ;ไ)เ…8ภb^่[Byแ ”:tะk›Cิ›rย๐J๑ฦวฯ์B $,`แ&$ร+๔ฬx’˜๖ mŒ‡ rณŸฐเgฑ›•žฌวศ๏X๗Mจๅ^ฯฌ–O6ฺA“@๔xอ=rวซg\@Cย71ไŒ9๖สt?ฑ6”'|Žiaxๅ„ฮะฮ่Z?;c ม๖X_๊9f ๕ cฐฯนณ3ฮฑ6ฆ>Qฏ๏!s>SE›c็ฬ๎ฏsฟt1๏>=ฒ?]N๑I๒พBษŸ#฿Q๏๋i‘l ฿K๕~J๘N๛ฎ๛^ฃ•รืTฟซl{ฤwrุ ้9Dศ~ฬcฑท{o>ู้wœ ^kMฌcเษˆ’% Q)ล†ฟ‘ŒูณgOใ!}๗ฤmม อเร<˜{฿พ} มI(•ฮ=ิte‚„G๚๕U๑<=t่ะใ2j‚+z0แ2 A้œ#ีฬItrwเpค๚;WIัขESmPล Qย›A๒‡ •qุxถอ›7xQ๏ 9zhs<_ฎป6‡@L#ฐe็ฉRํฆ&•?ฝcLOM.(๊mย‚‡…O‰%ฺ&„้ E€ว ฤ ม+Bฌ๐!›ฮูgŸt\W่ศˆฆ0sๆLA็'ฃฤahN@2Dbค<[ู๒’‰ะJศาค bยฯ\ ฯ 4Lิqแ7‚pฤ]!Sะร`žฯฐxr^C๚`ศˆPF6"คz.mwเภCโ(ฉ๑ภ"ฝmถว…้ะ๏dBN๓มซ"”ั-'ศMqœRlิฃฤ๖ฎ€‚เb6eฯ‡ค"EŠุE'ด๏ืJ!uจŠธœฑ„ ˆ‹ถ ^H์‡3[ผ๖w฿ Uแ๚ธ:‡€C mPข’ิ= 5˜"J`งQ‚)~๎น็Bอ9.สUีkพปE (ูืๅ.ย!Xg.ฉQ๗ม$S fฤkห์s&•งญmยโ@ Hbyว 2๋”*UสhPฑโฬ!‘ะ<)œEŽ@(/„P#ฺมoF_ศX0็y๒า’…p"ฟ6‰=&„โด„โ•แ'S์ถ้ฑฏD ž$d H/ƒุ‚ฌฺฝ{ท!=‚eชIนA€iบgˆถ™จบ1)Cqr๔IxฎSา7e#Eึ+fˆ.˜˜PD–ˆฉŒwข„ทœu๊ิ1d๚tพฬ%‘}_]+‡@š ฐzํฟr๋mรฅz๕๊q“&f AYผเqย–Lฤธ~!ยb…: ใแา Vะ<`„ึ‰3‡@FB@…JQ’ฒปJfžSmƒ๘Pอ#~Cl๑Vป]ผํ๓B"ง{๗๎’<0ั/แo‹2w ๎ญป‡@ฌ# D ฯhั๘อข‰}„Dฐำ}ล๚MKษˆ“mิจ‘qฑ|lเQฒ1%รธ>‡@* ๐ปฅI๋1ฦ“€ิ…ฮ2ธฦ๓เ 1B๎้*๘ i‚›:ค 'ิ๓ท •u2cจทIRn™Iw•ฑŒโผ|rDษ‰%ผD๘อ@„t[,๔ฤFฮXฝ!HศพCจ<:+๑nšš™Œ:dJrๆpคJ”เM฿เ˜!Je!(โhSC;ncาgFPแ0ธŸิ%ICๆZ8า Eห”ปบL5)eัตp–9เCŠ@œ •E+ฟั&#ฤแCœ@šะQn%Vจ'•จ3‡@ฌ!0rไH™0a‚yถŠDซ#ึๆ๏ๆ[hฦ~๓ยe’‰ญYง|6J” ‰าฦKภเฬ!เH?4=0ฯh‘๊Wศlc’(แญสา๑l๚ศฤ<ึฏ__ึฎ]k„วข@zฌM›6ษŠ…cQ’^7ยื!เ!๐๒ฌล2{๏ฒuyไ‘GคF‡@Šุณg‰Ÿ…8A๔uฃ็ฅTถlYCŠ@Œ@Š๐fŸzยt๖ฮ™3งั6กฺkฏ5™uRtrืษ!ฉSง )‚GIp\‘Cภ!เpdZดh!+Vฌ0dI4&3Dษ‡~(>๘ ิซWOึญ['O?t4ฎ?ฮมžYณfqตUK&J–]่Mบ wโLภ”—ฟ–)w์–ฎ]ป „ญ3‡@j ๐ร?Rาไ๋ฏฟ6q๎พช7 โ€„่(ฑB่้\`Dc๙ธp‰ิธ™wŒ้ำง›็ซUซVIŽ92/๎ส‡€C C#@ZrHาGรb†(Atะ Ar๋ญทส๚๕๋ใž(!ดˆk^พ|น,bœไอฑ)๗ร!เ‚ภ„ษ›eปไ๏ฅqใฦาชUซ ญ\‘Cเฤ8x๐`@๐โdอš5Rฒdษ@˜คศ† m V่cง .Uชิ‰Mย๕ฮtฬœ9Sะ€ƒดร{ษ™Cภ!เp82"„๚‘๔’hXL%?ฐิฉSGˆ฿Fฅ=žmฬ˜1F8ฯ/?)Nฯ—๋ฎ-|๑๕ฏฒg๏ฉuรล)่ํบ$Qๆหฟ}ฒM‰Ž;&งปk๋H%ชm)BfH๕6!ฆถม#เsฯ5๕hŸฆใพ)‚>Suš;wฎ๔๊ีหˆ฿ๅส•+S]ปปุ๔Gเ่ัฃrไศak๏eZฎel1๛X๛๋V๋ด/ํƒีi™ฝต๛†๋gืูu?ฉzปฟญ}l๏gษ’%€“]ฎ๛แถิaมฮ›P“๐/๕jก๖ต>ฉ-๓ต-าcฺูmํใP๛vzsmฃcุวฺŽ2๖ต.\นถัญOวกLหu_ษ(ฆeกฺk๊u_ท๔u–4ทv›๛๏ฒhัขคงB‹˜!J}ฃ p๓อ7„Nใูq๓ะยC๐g๏ސณN฿ฯ—๋ฎ-r๛$๙eอV™>ฉฅT(wn Fp]"EเฑัษฦญYไภก\RฆL“๒0าพฎC ต๐“"E‹ x›@Œ์ฺตห่Ÿ m‚Gส?cˆๅ,ฬBีk;{K{qธv{mg—ูc้พฟžcปฬื‡:mซ[moืimด]จญฟŸวฎใฦ๊ธZฎc๊ฑฟ ๅv™Žญ[Ouซๅv_ื6lu|s’๙Gยl1๛ุ.ำpฐ6v;ฎำ?†ุƒ}Lุ๛:ฎ–้Vหํญฝฏํt.๛MkyRวฺฮฟ๕๗ฃž๓ฺ๎ุฎำ๙ฒี๒`๛:ๆI;mร๗P๗ƒmตžkถOปพึิฺ็š”4ฑ๗ตŒ๏ฃฝoๅ„๊Rง[๊tŸ-ว‘|ด-แšดททŒoำึL™=†ถั-ํู‡ผgห‡๓$edวE๛Œƒัฐ˜!J{๏=แศ*„’Fรb†(y๗weศ!RซV-๙๓ฯ?e์ุฑัธt;วภeถm‚ˆํWŸ<%งๅ’nsq'N{๖๏?dHาฅ E|ฒš Ÿ–u%รี•zต/‰ธŸk˜|๚?๚–dหqบ์ฺ›Sx‹O<ฟ3‡@,!€p™ พ.]บTฮ8ใŒ@ฆž}ž`‹ƒ`ใ๋xบคถMญmฐน๚วีF็ช^ว๑ืŸศq$}u^œ฿nl?XYจ~v[ฝ6]$jnํ1ดLทvŽฃu)๊8บM๎8ฺmr๛๚๋XZžา1๕>๊8กถ๖๘๖พถื2ฦ๓—i[ฬฎO( ^–ถ:VZm+ฦท๗วIี)Flร}ภ)\ฝ}^%Vุ๊~$ฺF๛ ฯqึYgIด"ObŠ(:tจิฌYSถn*hxฤณ๕ํW๖ํ'๏ผ๓Ž|๓๙x9)ืฦ]๎๚ ษ๗ซ6J๊ฅผท‡ูS4†๋”๖s฿ ๙๔‹ี2โแzrkญฒP‰’!"n-Qื(e๔zpฎœ|ส™ฒsO)Xฐ @d:sฤ*„เ@š๐ม7TBฦะ6มฃ„ฤ„ๆจท ๑็wžฉSmศ8s8‡€Cภ!เŽ@L%ร† “5jd ขคGๆŽผ๕ึ[^ึ›‰^ึ›ไง^ท~‡ิl<มŒSผrUฅbrอ%ไœยงส๙ล D๋kแJS ีGศ?๛J5คUณส Cq๒วฆ]2๒ั๚Rงf™ˆ๚ธF)Cเ๛็HกBgหŽyๅ”SN‘A^.gŒ‚a7*๘บpแB#๐j‹ยูgŸ™By8`ผQT„tฤฮ‡€Cภ!เp8C fˆ<+{์ฑLC”t๋ึอฤฟ๑ฦ๒ืฯJฎ,ฟwW"{๓ฝ๏ฅฯCom7ONiRฏผ4ผฅœ”*yfะ6ฎ0:๛๏a){๕cๆdษ๑(น๒ฆQ๒ืฮdยMไบชi#าธฮ๓HZฝf‹l๚sทไส™MŠŸ[ภŽ-pวŽB้–ฮฝgJฑb็ส๖ฟ๓K๎น^R๚ฯสอภ!|มฑฝMHฃWผx๑€(,ไa<๊m๒ำO?y฿}d๗|๏ใค{ื“lXถ๔ูr[๒R๏ๆฒbุ‰๛% X*7ุตkŸTฉ๙ค๕๙1อไ๊*็Gt๕B™๚tsฉRฑXD}’jt๐เ!๙q๕y๗ฃU๒๖+eหถ=วuฉyE2ๆฑFว•วsA๛๎ฏJู2%d๓๖†ภ$ ะ™C Xทn!Eล!๑๎ปฅJ•*0ำN;-เmB„าฎผ๒JQoฤ9‡€Cภ!เศlฤ Q2o<1b„\๕F๔่ัq}/ฺตk' ูณgห฿N9๘sฒฎw้w๋คฝฏ™p4,ฎผผ˜:๋$๙๛๏ฒfญ';g™๛ฮ๗ฦ#A.W๖๋-€ฯ,x’นmุเ ฒ่ ณboMo/%ฯฬร็ข*CLŸ“ศฅeฮ1๛ษ๑#ยJพ\๘›œqz>#ษ?.IณธiำฆหหRนBIYป9ฏไอ›W}๔ัธน6w!Bs๐8Yพ|นEณรt~๙gCœขƒท (hŸEoๅดวt๛‡€Cภ!เp8โ ˜"Jžxโ น๎บ๋d็ฮ2jิจxร:ั๕ดnZฮ9็™5k–ธ์E9ฒoUข๚คฦN๚\ฦ?ฟภ4๋ะ๚*ู้้บใบ๒๑ฮG?ศธI  ไำNอ+oLk็ศ’ใะJป‚๏ุ(MฺN1'X๘AOO#OD'Sข$9ไŠเC‡•Kฎ๎/4mnฝฉŒ\~ูนr๎9งIžูๅ/ฯ๓ฅ฿ร๓ไ็_ทศา๙ฝ๋ฯ-๎~Iฎฝๆ"๙ym.งQฯ7ฺ]["๐$ต0ผMHI\ถlู€ทI‘"E&ˆฦ:t(เm‚ว‰๓6Iง;p8‡€C ŽˆขQำ‘#GJ๕๊ีEx'Jš7onิแQฒrษ”d%|๚ฃt๋7|›5จ ƒ๚ี๙ต„0้๙ภ\กŠX 9@”+๙็€|ต๘wฉxiQ9ี#v2บ}บเgนงืLsซพ๎\สฎ`ืGสญาW$„|4ง“๑ศŒ”˜ญBJ1าซห๕‚wQ0ำ”hค๛สLึ๔ฮคv2ฒ็l^ึ›3]ึ›ฬt๓ตXนre@๐ฯD`๑6!‹ฤDŠj›เyQขฺ&xœ8s8‡€Cภ!/ฤ Q๒ๆ›orืฟ;๎‰’ฆM›ส…^(sๆฬ‘๏ฟy>ูD‰ํฅpW‹+คอํ•e๚ฌฅRขXนล๓ฐบ„_†ำัyๆ{ขษๅ๒@ฏ›‚~‡๑@ุ์ {žvjษŸ?wะ6vแฝdรฦ]ฆ}j…๔๑๕7ฟ›EK[ฺงKด?๛ญ๏ไ‰qŸH{ช{,—%ชใ าkY๋eZดtญไiw`็>Eช]u—9่ s|ข0ฯƒ็yๅ•ฏOศv”ิ˜๛ผ 9—y™rฐฏ๋!งš0J๊:ป๗Ÿ#๏}ผJ.*y–ฬ๕ผ‰Rj‘โ„&ห ืxZ(zค็~Aƒ๗ŠฝL๋y$g†ญž7)˜}Xฮ>ปจ นB’ƒ•k›9PQXผM๐&A๔ศ๖!Sจ'L'kึฌB…xฃ8s8‡€Cภ!Qˆข„์/ธ๒ถgฯy๒ษ๑หŒ lR๓nะ \z้ฅFฬu™—๕ๆศพ’๊’จ~๑ท๋คEว—LY๗Žีๅ๗๕e๎฿›cผช]yพเฐ๋๏}๒ู—ฟBoh0sJ[นไโณM[gฯž2๙ๅ…๒๔ไ/ดH*–+*๗yต—r๘x1ฟฟ๚G†ŽPzoE =‹a๔Rฮ-rผ๗รŸ[–ื^V.Y+;ผL.่e”-]ุdๅ)y~มภ์hถ๖—~ฺหำŒศลn"ƒ ฉZgŒัhฉze yv๔ํ๚ไ\หŠU›คี=ำฬ8Žํ@(ื๙:ษใeฒ c;eฏ็๙r๊)yอตœtRhRiโ”/d๔ฤฯไ‚e+์กB๎oพGฎน๙)Sฟ์ณ>^&–ใEx#ฝฮแO}$Sฆ/4ฉฃŸ{๊?œœk๙้—-ๆC*โC‡{ ž,&SRZ—ๆ)N$อฝ๏ๅ/kถ๚๊N•Š็ษฐทสูฅฦธณX&+~,๛๒Bย๒Kี*% ูW๐Œใตt"‡Ž้ถ^๓gๅ๖ฦๅหล๛ไผbHฟ~"ํฺ๊92๋ืฏh›ฆCˆlๅส• 9‚† ž š‚๘ท฿~“‹.บ(  นโฬ!เp8‡@FB fˆ’นs็สุฑcMl๔ฝ{MNF2นsญ[ทฎTจPA ˆ–|๙ŒG”ฌLึ_}๓›ดํ2๔้w๏๒Gœ|yxAX<%F<์ทน‰ฮ๕ฺํrG‡ ฟฺ ฆy^xจพnปีํaaํ7ผ&›qทง๓เท‹๔'Ÿž๏o8._ถˆŒR_ JX@7๗ๆฒไป๕ฆ~ึ wB%ะ๘ุฮ๓/}%#ฦ}bŽ๗ฎI๕ษน–ป๗หตทŽ J’่๙ะ๒˜8๒69ฏ่้‚gฮคฉ_yŸืgาจฆฦ E๛ู^ฮ•y๏ฏL–G75ž`† &ฌšœ๋2๒yiฦ7&ฆk๛ช ฤีง_"๓D^Cู#๗฿l}’ำตud:/^lผI…]บtฉ'‡!Lo’UซV™0ผQศ๐ฆแ;x›œyfd‚ึ™Twม‡€Cภ!เpฤ 1C”@Œ3ฦม#J๓ฬˆไ๑๙~‘=^3M๛tฝA*U8WZwz๙ธ< ำ ฝ,+uj––ฦuห็ฑ~ร_r]/HผBnญUVV{‚ž/อXlฦฏ_็y์มบf๓ŸหmwN ค•e๚7_"‹<ขFฝ†ช+๕j'x#ิo๑œ มฐฏฉžื>gŽl๒ฟEฟศ–gG73คศฒ๏7HณvSM{,oฒศๅyฆ๚xฦไึฦํ;นื2mๆbฤ๛fXผRzs9%e๎;เyฬ7uคห๙h=้๗ศ<“RW็มตใ=Cˆ ๖h›ฅIฝหด:ฐ%ฌใ‡Ÿ6›cผ}6mภ๋.๏•5ฎWNnจV*ะ็วŸ”๚-ŸฮแVM๎uถ๎4อx๒ฒร๘c๙โฃ1Q’6้5๔ูOาฅฯ,ำœ๐๖ญฎ2 ๐ฮ^™.สY|NŸิJ.บ๐ฌรถ๔ย$๐Fมzuพ^ฺตJp‘พcr๛ณ†Œ€bตฉพฝa#ˆ‹ ืp๙๕# ๛ฯ็u;.ฃ^‹=vฐ}ดV๎nsตฉRฒยแ๓ท๏Mิ<นืYำ#•ึy)ŠvEฅbย=ผ๎๊’‰ยahวฝFŠำ|ฯCๅ O ๏g›๘ก์ภมCฒp๑Z๙z๑๏&ฬ‹2 ฒ‹๏…j๐]zyๆyb|‚ว๓|a\s‰t ไOไ•p–๐ึl๔ดtnWU^w\yีuานs็๐\ญCภ!๔L F๘ฆร๏$a:„่œ}๖ูฒvํZCš,ZดศO.„ล๏gฉ‹ภŒ3คA๕ท๗oตฮ_ฮqจ2สัชัพบี>ิ้>uzฌํ์พ:–ฝ ึ7’>:พ๖ืญฮAทZฮ6\m็oฃว๖–}ฬฟxJ๊X๛่\๔˜ญš=FฐHส_ศ6ิ8:ฆฮ”‡ซฃฝึmํ2ำ฿6ิฑ๖ี~กŽต<ุึ_fฅuกฮฏmƒีk]$ch๚วำ๏Œ]n|pmƒgปฐพZฆ[{^๖~ฐqดLฏIuฌ`วZ็;ฉrญw”#๊>ูๅ)พŸ9rไ0^ซ)+9b†(Aิ๔้งŸ>8p ๎‰’ฺตkK๙๒ๅ…ล฿žlขไํVส}็š{}๏ืzZ"ื˜๛ษภa๏$า ถhฅ๑วŸ${'-Cd\zqaณ`}๛ƒ‹ฮwU•ฎชy1่๛คJอโใโR…ไ•็Zย"่ลืฟส—^(Gป–WHำ๓S$ฑ)/-รว|lฺ{๐/ฅœ!ฺ๛ชœ๋ฅภKฌ–๋$ีr…๋ผณ^‡\qyq*ขmrpาlE9๛ODvกz-ž5ลy฿ฝ๏o0ณฝฆ๘่w/ฉ๛lฌคสชื+}ป ฯO^๊7h&mฺดIช‹ซw8R€ภ–-[‰ย๙็ŸFุoRผKถo฿nผMพ{9๗sท !:ี=o–œ%ฒ5o\>๘เ)QขD๒ˆรบะะE๋์.dดLkŽชN้lตnตฮฌๅ๖–6v;ฑ=พ๖ำ๖-ทิnฏc๙…*ท๛k/ุดืv-๕๖1๛๖ุก๊)วhฏฆ}ต\๋ๅ๖มฺ้๖ึ๎ง๛ฉQษดQโ},-u์`[สๅ:XฑลX(Y–ฌiฑqง.€!x มฬ๐ย่า๗? ฃฑร&<ัDฎซzaฐ๎‰ส`๔kxzšํฯ‡๚$h˜ไฬy|๚Z:๗{ไอ@ฺbB„๊ิ,#g™_sท|ฑhผ๔ฺb!ƒ ๆC%#Š–byhxŽงไZHญ{๙ #อชกใ๙ทถ&ยนGŽ•sฟ ่~FyœG๕๘บAฅ5W”ง<ˆ$;,ˆE_๔!ัMtZิ}ุSN>9งฒึค-ฆหw๏5กL)นฮoผqZz้Sbxฟœvjžˆqฒ=gVฏ_ศทฟผeซูh‚๙๗๏ะI๙sษ๏๋vศ' Vห๓ำพ6๕ำži้yึœ๑E<ร#€p™ค โNOธี6ิ<ฏŠฯผ,(jˆ"zj[Jฎลึ[a1๎ฯ,cฏv™๎฿PํByาKmœห#Šฏmๅeา,8I:ส‘ƒ็#ํ๋฿ฺ&ถ'ˆฆ้Mษuฺ$|c4j {Yo œžื่ง๔ํvฃ!…T—&)œธฯš๙(”ž3 ฆ๕l9฿3Oๆet:/‘>NR๓ฐวˆtjฯ[ๅ‘๛kห##>–>*ตj%e‹tœpํ.ผ๐B๓๛๖๊ซฏ†kๆ๊c=าoฒ้๐b๔‹.บศฑkึฌ1ๅ๙๓็7&่šเmrฦgฤ†hฏแษ‘ถ~zน๎บ๋d๊ิฉง๔ž;ฟCภ!เp8R‚ภ 7`ึฮŸ|๒IJบ'ปOฬ%จฒOž<ูค $๐ฑวK๖ลdคhโฏQ๘=ฮd%\๋=๗อ0™Xž\_nฎŠป<อ LฝOT๏‚ฒ๖^ถ›๎ฏ ๊@xฬ†?vัฬˆฑพnปŒ๛I ๛ฉ๐รข๛อ—มPศ•g^๐ช—ฌMDฐเUQืKEฬ@=๋ฬ“}#$B๒t0Gึพ]ฺ6ฟ"h˜-“{-xว๔x`ฎYุ'ๅQย๘บ๕Q`\_็ปฎ1sท5Kv์ุkH)%KTsา็้็ฟ”)ำฦ`\Œtษํ[^)„ูึผร‹F์ี[J๎un๓2๗ุแWŒัp]ี’Rฑ|Qน ๘Rฌ่้†!fัoเTท๙sแDชeR๘b฿ฮ๏ู๒ฉวoพ๗ฝษnฃ™‡ดกเ๊_ๆ}7สD^“3'9k<ขไa(0ไ=OHzดYl%ง$m๑’ใ7Žะ‚Aƒ9ฏ•H@sm*๚ i‚gษ)งœbยu (เีหฒeหdำฆM†ิB\ำห G๙?`ภ€t%Lะ}A<๗™gžž=œ9‡€C #"ภหtT2%Q‚’mนrๅฬ}ห DIกB…ไœsฮ‘วn๎%K“}…PBC"ท๐ฤh๘๐‘€vฦ๊_ทxZ ขš๔gฺำ‹(Yโ ฃมฑzอ6#Tj‡†ฌ๘ฒ_ ?_}๓›|ทrฃ'พบ!’ฃsAWB=K(ƒ,ุบmฏป`ม‰2ๆhŸ”nSr-„–ฐฐo\ทœงwrf’งฦ‹็MK|9รfŒAฟ„”ห๙ฝฐ›K.>;ัธคพ]ํแถ#ฎ yЇฯ)!q€๚๓ฆน Kแ`)นฮ…๔0?*ซV)E Ÿ*… ‘๗Nœ๐ญฉฏ.J'ตI/|%ฅKๅ้”า๎In๙๏๘๋oNโแš?๐๒wŒt~‘+Qr฿ภ7=ฯถษF#!’~ษmƒpๅํท฿nด‰จ|๙็“;„k๏pxฃŒท‰†้เ]Rผxq’้‹ฺdุ!D‡๐ชศ™3ฒฟ—ฉ๒O?d2hmธัผ:tจ”,Y25†Nึ`u้ฅ—ส˜1cไๆ›oNV฿p๑๐ผฺผyณนพ‹/พ8Qsy!ต๎ผ๓N๏w={ขบด:เ9ัฺ}๛๖92:ญ@2nz๋ ำpE‡@œ#ภ฿sŽg:ข„ุู^xม1‡)6,!#Iผ๏5j˜ทa่”<ิฏ‘G”,I—K]ฑj“2รˆฆ&5-มvcg ึฎ]k๔MX˜ฃoฒkื.“YŽ0œ={๖ศ?x)๏=ยเชซฎ2ฉ‡y+UฌXฑจ`๓ภˆ†‘ฆท{๗๎ Žˆผ,ธ_“&M๒71วO?ดูr=#-ZดHิŽgึ›nบษxหœtาIRฎ\9๑ Oฯ=๗˜~„ แน้†็.ไฬ!˜z๋ญฦ“Lต /ู‚‰แ’zoŒE„ d# EAฮแร‚คJ•*ฦ›‘๔๕G๔{๗Sร|Oไ^:2hน—xŽCภ!HeˆhเG}"๎„‡@P›ะ0<ะ–เฟW๎hฎUซ–๑6ม‹!œ‘ึ๖น็ž3M๐>Um‹p}’ชC๏„]˜Bf@VฐะVซWฏž 6์8ส๐$แฺ“รƒ r2/ 'Q{l^เiธ,Nฬำึ$A๏šP6pเ@ใ5ํฏวkƒ๏ล7hฦF8ัวWS5ฒ’=‡kฦ3„gKดd่ฃž(๋d๛ผร๐Œย+ƒดP‘_2J@TูกSฦร{‡๑้๋ทไk_w์p8"A€xด!ๆบ`ม‚Hบœp›˜!JpEฤีขล๙ไธ‡ž0 ้0‚jฤŠโJZ๑’“=ขไหt˜…;ฅCภ!ทท›๊ฝ ฮๅน’i/Ž—ฌนKว$0?๔“‰;็M๑ๅ<0๛]ัcrโnRLˆ‹๊ฏXฑย,๚Yิฒ่ฤKกN:ฦใ$˜@*แ$x—ฐpFฯ๏ำ`ํ"…ฏŽฺตk็!i;< TH5X˜ !ิxi$E”€ $5,่!aะQ#ŽPฬฃBฒEKƒˆ€pa่Œ<๐ภฆ+ฯ J"่Xxฒ€‚พ่ิ@0฿ูณg›4พz๔มใฏGวCD„M.AZu์ุั„›S‰Aะ๐๒“EคๆƒแนBนސ๗ฏฬึPมฃฎหŸฆš๛มตฆƒafถEzฏํ>n฿!เp$B\ั4BฟhXฬ%ผ1เวfทสAžบz<ืว'ฎ๙า‹๒zDษ๑|น๎ฺ1ภ]ฆหพส)'ๅ–g&<&Y๓”‹้๙Bด"่วo%B{h"8s8bผK๐6แm?.ร,ฐuั~^,pyRCเm"ฤ?O?t™0aBะL&ฺ>ขAะคย?ƒpHYHร…”lบีx ำ!ัล3 Fj\;ู~ม3/•nปอT๋ข]ฺuZ,ซŒึฑUขฤ฿}ศ0มฑ^”PM”(ยEHฉ‡ฦ๏DพำVL…๐eฒ๎บ๋J1w$ไฐlฆกํย8ลไ„aฟ2แn…๘tˆจQฃFนนฒc‰y Zิ|็+f๔ฏ™S๛u3‡ฒ‡iด๎ฉ+ฤ8วุhซ-^ผุํ"ŠณยY‡ฆ”,:Yฌณ %d0ป,FYฒpๅ่“!ญf*๘“ าZิ#Š า ค)? Jบ:นศ๗M2hr-ฬVข H_ด‹›4iUฤฅ๙ Œ!ขขแฐGซ"#G}tแJ;r๊ซฏœึJ”Œ”มฏ‰„9†๔‚‚`ภ_พ ฿Y-c‚€เมŸษผy๓œ๙ฆ^˜>!Q&5.ร๛‡y@ะ๑ K6๗šฟ?ข\ช(Š€" hขฝศw(š…ุ%ฐฐ;Q๎%์€๐ฃํˆ’๖ฬโ/โ~kŠ€"ฺ$ƒฏ|ฺ\4p7ณ฿>[ขค* bDั’Hโ%ค“Nr 5v*QE๗ีทKb:HE Dภ!(ค$ˆ/,๘๑7ย‡<ดุใร"า8ส5็h#`‹อ‡%ŸTQh~ร็„ฦฤ3–B 1จLcณฺjซค{ˆ$|เOš(2%A[y1ด}ะถแ~‰ฉSก‹~3mƒh>hๅd"hห๐ปQ)ฦฝฎฯxตฎ" ”hๅa^ษŒฆc!$6D >;ฐ]E“R‰m_Šั‡x$gฮืnn‰’ฟงc<ฺง"PษL~๕3sš๋.๏ev้พนiด|UจสRวฤที็e'*Š€"[N=๕TทHฦtbฒC‡ฮ\?๙Z g;ƒ-ถุยเP”๐ป*•…$šD๗w_ญ‰cƒ‰Ž˜ี*  Š€" ฤ’`ถ‰ฐ9Q‰ Qย—8ๆ($%„n+g๙๔ำO ไ<`6฿l“๘๓ศ้ฒ+b–_džKL$ฯK,&ฯึ’%ุึ&Q๗]ฒศช๕UซiK์|Vrษ’„ฉ:ทGknอ5sญ‘.ื^žƒรตQ]฿•ฑณไJOH@h;ฉ*Cูช๒\W•๑ฎซ๓\[Rฮ๕_]ฦ"เ๊IˆะŽ\sไฟ๊kเทป:ีE9„ฎซสป๔ชLW‡ำlฅฌjvีัžzื6™Lฒ ยอiƒ†Ui๎ฺฆูK.ฐ๊๚๏s—niHŽ๖C9JoิจกidUtฑ‘U7$-(S}^Vศธ;ห๔:โ6s๋u™ฎ]ึ1W<ช ค2๘žBTีูๅฤw š{*Š€"P9เว*•‰๏.˜แฟGฑho๓ฎข(Š@) €’มฟogvส:บ฿_ฑ#J็ฦฎLน%,Zบu๋ๆิแQฏ•Eaีโด๊‡K€๐ั˜๙แ๓ฅj_•&็R{fฮ…4เš๓๐ติ“|ฉSUฎšไXbฒยโ๊#ไ@U[๖Œ6Uๅ๖ธxq5I#R`แlซp{ัย‚5ฆถr๎ฐnpd4๕ุ|H'๖่าไ(eช๓];ีmรBT%Wีก>mV๏Ž.Ešv\‰๊<ฒ”jbฆฦ=๎บ*ั]ๆไyเัq็ีGjHšฝต.ฏ๊Yp•\žYBJU=๛jขŠ~ซฯซศฏ,ว๏หF–4แ5ฒค „Š#e์ฑ ไJc{ดงฺ๎ŽU„ e dวปฟU๗คใ๊พภeัขฟฬำfš‘ื`vฺ่ม4nuจฝษํใฝa–ฬ)฿ฉณจฺ๒€สCkฆdn€T("˜ŸฌตึZ๎; ˆระฎE@P:!€9ๅ!‡โใT:฿~ždlˆ’nปอ๙๋ภ‘+]๑~^๎Bฬ{์Y‘ช) ีชiB`Hšซ‰์H!Xt qเ ึ~Zาไš…gธ #้็ไห‘tฉ#i๙Hบ”๗๓Iรv[๊๛yR—<œ๒ิ๓๋ศy8Oฎ)ฯ'ŒคIพแ-ชไ๖ฤ‘,ฅํน%6Lธฃค“ึภ+UGสร0poจรง๚<๖Nี5ไ‘;าจS๏๒$฿iz^พฅ$ชำชŽ KV-ฐฒu!ฉถฌ{v‚๓*‚ฌŠดฒy6ฟJซgฑ%ฑชIศ .{\์ฮ%]ีy^ู๒k~6r’nฏZbkฑ๙๋ฯลๆKB๙็’๊ใb{^๕Yd๓ๅœใ_๖z‘ญทุฅ'\}ฺ$/[ฟชฎซ>ฎ}๒—Mใ๏#™8m—jาE4_ะคแœ{ษ? nฆM>ห๚hbฏ`I„†-“5Wฒ้8๎;๓ฬ3#?Tฎั.Qgz%{;uเŠ@ฦเจณ}๛๖†ˆ{*Š€" (Š@ฉ!@TGBย9 วฎu๕ู•อผcE”ท›^ผK๗l&Sie๑>Žึ‡„”sฎผlฎy๘h‡# gi“si“4I'-*Oสศั/รน|คMฎ)+Gœ4ม~[\KYษ๓หฅZ4็๛9B†~8๑ฯŸํŸ‡ว.ืsiทGฦืธ1คฺ-eีm\:’‘ีฤ\h~@–ูzMš4ถ็ถ ˆ/›ืฤฆA€5ถš Uๅhฎช,G๒จgOm๙Dีตหodต"›ฆถฆM™frือHณŸชฃMwืถL3;;ฆlคัr=MƒฦซfSฅdสฦŸ ฯ=๗œ#j‡ โB5–ฬt Š€"5D›มฌ๙‘GษบฎVPE@PŠบŽ<๒H็4ฝ๗+ˆฐุ%ทzซ‹aฟโŠ+บ]%JŠ8–v +!Pไ#ืBฤศตŸ•คหGHฎ%ฯO๓ำ]๊๚œC:$หยDŽR>|”|Žแฏ)ใ็…ำน†๐MัฬกŽŸ.๙Œกไdษ‚คCฎ๒แƒVNmiะx%{ฃšึฮ(ฃยZโ4›Pฅ{๎นงน๖ฺkkwe4UŠ"P๑lปํถTแl+$@PE ถผ๚๋ฆOŸ>† ?ปŠUF>ขd๔่ัn‡kฎนฆ8p`>็ญm+Š€"P๑ฬš5ห9zลAฺ|C‡5]ปvญx\E เ๏šจว{ฌฆฆ๓QE@จ^{ํ5sฬ1วธ >ดKpJo‰Q2iา$~-๋p์์ณฯฮ๗ต}E@P‹ภwi.ป์2ง้„Zcน‡gื›ฎT๘$โฅR‰’Jป๓:_E@PสW_}ีwqๆท฿~3h—ฐม—o‰ Qrห-ท˜็Ÿ,ทrfuึ1 ศ๗‹ฺ…^hฦŽ›v จ1ย`_œJžyๆ็ืeม‚ไฆRมƒ–หควw฿|๑ว5๒‰Hฤ',์Dใ(.•`^…_„LงŸ~zฺข0‹™ฬ™†2#8ฒhฬDN9ๅ”ด๗e๚๔้ฮaf&cjซญLำv=lุ0๓ฦoค-วณ3hะ ด๗%›1ฒˆ๎ัฃGฺพนwDvJ'Œ๑๊ซฏv๗ฉสf๓์์ป๏พAœ๕dm2็K/ฝิL:5(‚๙ ุVชเAœ๛๖ล_8‡ฺื\sูd“M*ท"PV@” ฑ๛๘ใ—ีผt2Š€" (•ภ+ฏผbN8แ๓๗fส”)fตีVห๛ฤcC”|๓อๆ…^pึ]w]%Jชo=ฮืฎผ๒สด r๘˜+๚๋ฏišL‰’ž={šO>๙$m{Œา'ขไŠ+ฎH2]ด๒๒๗๗฿gิ&ถู:uJY? 7tSส2’ษk:2‡pฌ™†บว—_~YšOztำM3บฯ4p๗wง}v !2ฝ/oฟฝก|*๙ๅ—_ฬๆ›ožชHผL๎K฿พ} [2‘Lžoˆ’C=ดŽDกz๊ฉง2้ขฌห\uีU†๏c„9ฐ๗*Š€"Pฺt๋ึอาO<๑DiODGฏ(Š€"P‘ฐF:๙ไ“ป๛ไษ“อ๊ซฏžwbC” QQยs‡ฬYg•๗ษkŠ€" ฑนฑฅb v |๔ำOfƒ 60h— ้งข(ฅ‰D กภŸ|๒ษาœ€ŽZPE ขx้ฅ—œ_ฝ๙๓็;+”t๔น+6D ;˜์+Q’‹ชm(Š@ฆ`๓H\๖L4Q2mณ\สa9n8 ฟ%‡vXนLM็กT%ผ_M˜0กdๆ๓ฯ?Mใtzณอ63nธaฑ๐มŽิ=๚่ฃm๘x_พBฤบ็?fแย…fŸ}๖)@๑๋‚ˆ—oพ๙ฦฌฒส*MSขๅ‰pฟ0๑ฺc="Mตฅ\.z_r‰ฆถฅฤx4็อ›g&Nœh๐išo‰ Q2jิ(SิฒeKำฑcGDพ'ฏํ+Š€"€ฺูI'ไ์ำ™RU"Zเs๎น็:Uวญทฺ`šรหฑŠ" ”ฅB”๕ื_;tด๛ $| ซZ๏ดำNๆ๋ฏฟv~ฎ EZ eว๗ ‚tปvํ!–๕๙‡~hz่!๓ศ#8gŠ2YL–๗ฺk/น4โƒฏw๏›๕•๋xR*๗ ึ3f˜™3gบ#˜๙็Ÿ†๐ป๎บkZฟ`l\เ[ “ุจtฺc!‰๖ุuื]gV]uี:"ชี๘!ภw.ฺฮ%ผ›โช#฿;ขdฉฅ–2๋ฏฟพ%๙พ๓ฺพ" 8ฤ/อ7˜‘ฃฺJ„—ป3ฮ8รฐPiัข…น๘โ‹+v7ต๏ฟฮน๔๘ืฟๅ6ขโ๊‡ 'า,ภ|๐Aƒ&I”„_Œ…(A#๐‚ .ˆช’๓4ด%$„z%fp/ˆ”ฤ}Iๆณว่tP€5Nไ๏ป๏>ณ๖ฺkื"ป‚B9>)…๛‚ฮQGๅศฝdำ฿a‡ฬ!C"ฃyด_ฟ~ฎ*Z๘<พ a…f,A๛฿ๆ’K.๑‹่น"Pา@” ้ฬ๗ฺ‘(Vไ[bC”Œ9าyฐๅ%›x^สUE@ศ7B”dโ๘6฿c‰{๛ผ1‹]_ขbแhบy๓ๆqถŽOจx Jุˆz๚้งc…‹วnธม<๚่ฃตฦuฤGธx“&Mฬโล‹k๙IbN๛฿iK๔4 ฤ7q 9๚‡่ม :Zศ’%KLร† y9Cค>"Ž=:Xxหผบw๏๎๘ญโaๅใ"ฤ Q–z๋-ฉ–WŒโ~_ย$†€‚s฿uN*ะนsgIrวำN;-๐1ฤ฿1E}็ ^Hารš>RVŠ@ฉ"เ›`6วฬวผbC”๐ฅ€บ%/mดQฺh"๙ฃPmJ8ึLยขjLฺ"Pฉ(Q’๊ซฏ‘๚0๊ฝ,vqว์ัาŠ€"PPโฆQ‚‰ภ9็œใฬ| X$โsไภ4ญZต๒ณjœcฎฐอ6ธE œ˜แฐ`FHร”’๖นด๘@0kภ๔ๆ๓ฯ?ด`?ป็?sูmมฺB{ี๖็ŸพVŸ|ฐผJๅุย่ิSO 9๎ฺh ‰`b2bฤนฬษ1ฮ๗…Pฆป์ฒ‹๙แ‡‚นขmC‹5ื\ำฅอž=m<aศ๓หBP๒)oพ๙ฆ+๎ป๏:ŸC\๐ท„F$- ํTˆะฉn0๚"P |ข„ฟ•ใy๏9vDIณfอฤ๛๗๏Ÿ๗ษซ]˜ yํWจ฿5„ฬT’ฺุคJมฏ”์โj๙ข‹.JU\๓E ˆฤMฃญaL:DXPc–ฐvE:fe!‰ฯ!ษฬ@ค=Ž„‘dั^™6mšน็ž{ฬนsb_ˆ˜Tmข‰!ๆ9ฉสe“‡}ใดถu๋ึyำ^ม –ศkฌaŽ9ๆำณgOGŒKบค๗ใป๏พ3hNค“-ถุย้Šฅฬห}a<“fh?…๓—ป๎บ+Hฦ$ฆOŸ>5Hษ„<:tจป„L?~ผ#H€lp๒5uะู่oฟขŽฟ#ด€XKฉ(ๅ†ๆ฿v๕ญ5Hม|Klˆพh IูดiS%J๒}ืต}E@`็๒ํท฿.Xจฑ ใ28aW {Q^เู]ลgห-ท,ƒ™้๒B€ศ$h์โ็#‚Ÿ#ศi‘}๗ื‘ญ8๔’š‡~8*หฅฑxฤษjงNœ๙6ถ๋นp:“M_ <ณ,1Gzฝ๕ึ3K/ฝtธXฎัรก-f>V8ีห?่Bg2ๆO<1œั5ฯฮอE๐)ถm[Iชqd!๓ะd‚fฤๆ›o๎œ”าœึืLฉ˜๗ญ๎ XaZ$š< ธแพqฟ~#!Lา9 ๔IDใJด9Lq๐อ™xวwศCH!๏ุ]3fŒ๓E$๋Q('๚ยๆๆฏฟ๊ศVฬ๒-ฑ!JP{ใ7[พษ&›ธ/๛|OพXํหยŒ~ิUE xศ฿ใgŸ}VผA”xฯ—_~นน๖,rฑ‹[โp่๐ุ!Qย.๓ณฯ>‹ฑฑเc่๛f`Qทo_gbฐาJ+ีงฟx$BBดJบt้โˆ5*คน`q ฑ&ห/ฟผ[ฤ6jิจV-Yœ’ม๘ ค_|F๘คBญส6~Xะ2^UVาž|๒Iทx๕ื%ฉฦฒ2aม ๒ึ[oud๕ฝ๗ฮฮ่_0gŸ}ถำd๐+pภNใว๗‹A>ั‰ฮ;๏ผ ((D ๒€๛›M่ๆBZŒ๐ข+ฎธb0T'๏ฝ๗ž๓‚j2ม4ฦ7รŒIฬiˆXณ๑ฦ'ซค๗Ž !Aฒขนร}G มx๎pJ˜fั๒๛v๚"PFผ๒หNKฟ>ํิ๙–ุ%PมีW]2฿ภีง}]˜ี=ญซไTWฑ๑ํัฃGnฎฐึ๐FŽส6*‘์˜ก]ย.ซŠ" ˆ4vร!w‹9ฒ?๘รํฐc*qโ D|•ฐEXุฒ‹ฮ5;๊ห-ทœ ้ฮ|0+บํถ๊Iฯ!9ˆCˆU_xแ;vฌ “%˜:ฐ0FลœC@(`–’L˜D e๑ใ„YE”เฃ9แ„ ไฆŒพ@ะเืƒตe–YฦigD๙ a –‹(@hK\๕)$ใk"ฏˆๆ ฮsม !5ฺ"hMHด•L7 y_๋ฑว๋ดHม3ž( —็ž{ฮEzใ>s/‰H#m เมsม๓ศทฺjซชŒ๊ษ‡มlF๎s-ˆ#W4ฏ๐Mฉ‡Y ‚ ฯ ฮีๆ€ึั๊ซฏ๎ฎ๕E \€(9ๅ”SฬขE‹๏|ๅsพฑ!J๐zŽ _V8มˆr%Jส๕ฮ๊ผสF€—Iศœะ!์4โw@EPŠ‹D &NœXD๔ฮK/ =ดาpํ ›f์ž๛QU$ยอ L^|'’>ฒ๛ŽsWฑ‹9ณ8ลtแN๋_„Eo*‘ฐฤhฟ`”Lะ@ภ4มTฤ๗S!u๐ซฏพj฿Lธ]ฺ,ฐ3๑9vx\dEๅB%„9ใ†4๐โg๘๐แ ?9ศ;<$D:SคB฿ฮขแ#๒๑วื"ศ˜;ไD„NU๗ฺk/ฉโ4ะเhำฆM> ็Ÿพ{๖ยeขฎ!ปฤt S4ฆภญํ‹เCฒFE(wฆL™โ|Oก๙†ำ์‚<๗๖ห bฟˆ–wห–ฦbL๙„ฒKุ€|5ฏํ*Š€"PTฌชqย.:ึO@ยชื'ฌ“ฟขŽG;W*K”$์?๖0XQ kพ็‘xOโcฃื$, [k์ึไฯๅE{ญผp‚ˆ ฺด;๓ ี%a#็ธb–๒h3ุะ่ฎผ%jRต„Aะฎ%;"หZงฆA๋๓)aUส๛์ณOฦwy็„%*"๋*ั.ฬ`ร๗บpฐf"ต†ภXฅŒ%‚jๅ๛ ลธ/ŒIฦว๏S”X‚$(cdฎˆี๎าจVห)๒ูค‚5— ส[mขจnjฅY'ธด/ฯ(ฟฉ2fh‰”Zmh‚"PฎXข$as$ฌ [‚๓B1็c!#|aA–”;Qbฝ‡ป/ผXฏƒˆ-ึiQ‚-E €แ๛ฒ„>^๔TE 8@”dB(gtต{ตฺ  YF-4eแšn^,6ญYˆk‹๏ข™3gึ่ะj™ะ฿ท฿~[#?|ฑnปน๒VK œUใฺšFํZm‘y\@0v๚ดฆ?มข˜๑B ๘๓งฬ๛๏ŸˆjงVรyLฐGึ,*˜—5ชี›ีˆ๒mD˜Z๙’Pฌ๛bอ‚๑YญNฃuP”กผ๘[-ก ๛ย}ฒฺ%ม“ฒๅZณ*?9้9ค m๒6lXPฮผา%Ÿ#ฤขŠ"P)ผ๒ส+Ž$ฑs ึH…X%ผTC– ]Rฮ"_rๅ3ฃตฅฎcฺ‚"P$ฌ:}๐‚gฝ•ปำ" EปU*ˆ๋c!๓ทQdK.ฺฉ„ˆ ™ขไB”ฐP๕…ล9๏“6JŽKf1)๏]6บข_ิ-4%OŽ,’S‰%แrด ‰`อ‡\uฯา&ฤOXxื•|฿aHAEสqค์‹/พ.žฐฆ‰‘#G&ฌ)FญผLธด›N ‚าFฦn๚ ๒ฌฐ ชห'ภl๐เม.ญX๗ลF ฦgใใ“knไ3ว… JVpD#I4‹žCk๚”ฐฆ\A9kžดe#เ้แ๊@ŒH[{ึD,(v๎น็yRFŽ๒ผ…“œ€ฟŠ"Pส@”๐›`#i%ฌ_ผ‚L%VDษGQ1D ๆ7*Š@*Pทๅ‡ะฺ”ง*ฆyŠ@์ฐฮr{์ฑGย:wMXgwNํ=๖ƒึ*e„€๕u๋งอถฑไล—…w”ฐ”ล ฤGXw?ฯ๚q๕ 4!&hว_|ฺจ'ตH้/ีNฝh ฐ๖ๅ๘ใwX#.ูFr ๚ตJ‚yฒ`ฝ๖ฺkƒ<๚ ฬ.ข| }D+Fฦˆ)Œ_ ษcnู ฺR–๛ฟ‹lbฮœ9 !‹(‰‰/˜I;>9ภ๏€คฯ›7ฏh๗BHฦ ๅkฝ๘$” k ๙srLสr„,[ฐ`+ๆkืฐภณพx๊๎œgอว“rพ …ไoฦ๏Gฮy.ๆฮ[ซ]I€bš๒;E T@ฃ‹ฟn!+ !ฑqๆjฟ r58hมktบkฅ์ฐ†ˆฤ•ว๑–Je `˜Sฐ 70ใ [•MCD–ซฏพฺX›ๅŒ๋iAE ฎเP๐HŸ>}œใืธŽUวฅ”8sลYพ}น,๚ดˆcwƒqฌฐย ฆkืฎฆeห–ฦ’.ยอ๔้ำ]ด)„ใฬฐƒRธ6™ฺตk็3ž Ÿ กพ/„&D0ํัฎˆ6˜44tฌ๏ษvG!ะhŸนช(ฅŠmึ_•๛a=• …ƒtXฤ†(ฑNŒœf?|0๛|ษชคFภW; —ไ‹›๋๔+ๅ—oธž^็7 ’ฮ;ป^v†xกห‡๐า๖้งŸTe๙ก‡pร,,ผC”พใาฆตy4ผจณ;ฆRXx?็œsœ 2/,ึ\sอยB{S*ธ%น‚<ฤ† ์๔Gษ์ูณอ๙๓5ผs๏—็7B ็(s^าY<‹ฐณฯ ผhRHz]ึฏ„3SD+!™ ้`กดiDlฤงฉ'ืล:~๙็f฿}๗ ศ-Xฤ๓iฺดiญa•ส}4B;"฿ฦŸ๏฿hอ !’+แ™…ภB )<ขฤ๓h#926ูD๗Oˆ81ม‘|=*ฅ„Dใ‘GiV\qEงอฑ™o‰ QยตHTืุ!ฐNฑ๒=๗’o฿:…2ุNฆl!M๘ั๒m*ำีำ ภnไbฬน็;“–E eฬ˜1ฆK—.™TI[ีQHv$ฐลeท(,0ดโG"œWŽืm๐"๊หๅ8ว8ฯษFjpv๎ฯ<๓ŒS9f๛oE@ศ%ปฺๅ&|w๑ล†฿ฬีV[ญ ำอ ฮQ‹ื\ ‚อ ๙ฮ|๙ๅ—ฦ:์tฺ6ห/ฟผ›+$Nœ75xฟ@sข}๛๖ฐ+ิ}แฝŽM!H54Žธ/kญต–ำ๔๖5r๕,ิฅ.ฤ< hLƒTRE€wuั2D ฏ|K์ˆ†หฑใJ”คพ๕<,จำมhฃfษ. ชช|y๓ลˆ-่ธqใjจnบ้ฆวfุ_ช๋1ุฐŒฎC_3DuฺM6ู$]๑ศ|TFูู˜2eŠYiฅ•œsุศ‚กฤJ" ”( "]bใ9d/h—ˆ‘†ค*eƒD ‹H|-จ(Š@e €ฉ>l4š+eฉ!€h6าX๏bฆๅป*ืsŠ Qrอ5ืธn๘ูP{๕ิทฏุxiGภ f-,จM˜0มyะฦ้+‚M$6ŠJ–„ัส฿๕๛๏ฟoz๕๊ๅ:€เสt๑'DI6ไJx8Gถ!Yรษฮฤงฒ˜๗ฐƒช(ปUุkใ์‹1WŠQ"Žื*eqœ';sgu–AลA"Ž aƒG,tLŠ@.u|%Jr‰ชถฅฤใ แ?•”xฯDGง-‹wvเŒYa็›X%„C ›~๚ๅs%฿6ก฿$2์š|FM ยๆ ีv$ฑUทieจ4bฎฑS๊B8FฑUล๕า ;:tpลุภแW]ฤทOฅ>*ย!hE "™Œ1ช~)ฆ Qr๗w;อฌRœCน๙Ž;๎p$ ๓ย‰^๛UE ๎@”๐ŽcRE@จ xฏมน+›a์ฦk‡สธ๏ๅ:Kขใโ{“ Š#J๐ฮN6๖žจ]+Q’๚1๗ตPซร ‡ฤ^วfห_่b~๑๎กโ%h เ…ผUซV.ไ]T?8๐˜–@hไJK…๑แœŠE=็“ษC=ไB‹Ož8๕aษt.8Mร“2DSษKฅht„อ๖šqโฐŒpD”‰`‚†oฯ๓d’nž|™ •R_็™โ„๙‘๐…2o<ง"วฝD{ล.“อ']zฆใHืŽไฃŽzำM7%J‘x๙{ไopข^F8Wพzโ1C…"P8”()ึฺ“"๘%j"aฌ —a้8:!@่rmveัึษH€@IDATฏScVŠF ๖่์ถ Q";๐ฮฃโŠฑเ‡‡8gยัืฃ>๊p@[@^ŠXจโผMLo(i‚ำ3_ะไน๕ึ[k8๑$ข๏Q]๊`ฆท๕ว\’ฑฟเฐฬš5หyˆ'Œu๑—3(แำคŽD{แB&<,482S-‰Oนlๆย!‡้ฝยํ‹ฐS.H ๐d 8๏"\แ “ ‹pใhˆเ€7ม{9๓C%ืผy๓Zี2'๗ํGv๊}a.๒!$!ค ฮแ U|ฟLq‚$ดโo9,[mต•[์โฉ_„v ศqไฬ‚ำ;ศพจ™ŽCฺฯไจDI&(ฏŒofˆฟดใTE ;ไ@5JฒรMK+ฅŽ๏ชผG็bฃชิฑะ๑—6}amBtD|™ฒ†ฬทฤŠ(ม$ -Bก–3Qยข0U๙Ln:ฆ)‡~ธ+z๎น็:ญƒ็ž{.eUจ, %‹ฦ๙+ๆแ๐’฿}๗9mน†”!< ๋ฐ 5ม8ฤ o้h %“อ6ฬ๙Qiำฆ+ยB/๏ไhVธ„๊Fmฎผ๒Jw…Yิg3H9BQCถ$Bฺž—?J4sFๅ>แ:ฬ‘ั(้฿ฟฟ‹0“FZปwwอE9Vอfž˜eaง v๊ฉงบ๙ข5„Iฯ+ฏผ5d—ฦฝศ'4•Rตษ5 _œำrpT›Lz๗๎mDjสfฏLE‰’L‘*^9ดช๐]๒ร?8ญ9๎YวŽ‹7 ํY(1  %JJ์ฦ้pE@P„lวฟ"๏๘ธ‘`o‰Qย.4D D๑าœo >šA๕ ำ…Cถ>}๚ธแcRƒi!“ย xฆ,(ˆ5 ึŽ`<0rB’ะแ'Ÿ|โL่5'4~ุ”—ฐฒดO> ั"€;จกญเ yM›6u j![ Xะ มŽr๗wUถค ุqุ0fสณุF "นˆํ&ํ๒‰C\ˆc8มe1†เLrุฐaNป„บ"ฬ;9™Ž'ม8,เษ7YรJมyCแ‡Aˆสaถ‚V}„ซf;O4f0-J%Œณ- ๖™โDไ%<mศ!ข˜@สเ|˜๛v ๗หV™'*thก%yเu๓อ7ป˜้™Ž#๐ฦJ”คz2โ•wy็™xภํŒqaซข(้Pข$=FZBPE พเขƒ๕,aธQจตb^Gl{ลB์๎rยN:a'ฐ;๘ฑS>awvAšฐZ๕j†uํะ–ีrpmูEhย.ฎƒtK"$์=e?ึ|'(oคAYk๚‘ฐฆ7.2"ึwLPช=%ฌiหฒ  ผ5๏pi–๔ ส2NฺณQ_คฉฤโล‹ึ%จวxฅ=™วW\”—ซตดk๛Hr"นXย'hว’A;r–0IX’!a‰ป ฌต๓L€5ย7๓ใcMŒคzp”นH™dGkขิy็w\{ึ&H““l็i}ใ๓๛ถฤZย’‰oฟVšŽV{&8ฯ'๋O"่gโฤ‰A}9ฑฆ5 K‚$ฌ)PPŽ๑Xโฌn*Š@ฅ#`7oึZbฤˆ cํๆeย: ฯ,V ;1rไศ„ีถv๏Œy๋HVสป‰๏ืํฦrยnšdถxA…๘D‰5ซˆล˜๒1ˆ\%Vณ!XHxใมPญฯ‰„5๕๒XF-Zฉ@บ,F9BdX-•„u$†”g๑ฯยืซา๋~l D|มjœHrฃต9 ฺตŽO]žีเpi–9ฌQึ:y ส^tัEA^ถsกขŒอj’ํDAŸแS!4H”ฐ๘D }Z †„๕ี’เว“๙J]Žค!V3รฅ๏ผ๓ฮ๎Zฉฯู9Š๑;๑๏ทีHX !?;8ฟ๓ฮ;lพ๚๋Œ๏Wะ@†'J”dTŒŠY< ซv้žžOkขฃั้P๘!ะตkW%Jโw[tDD€Mฏณฯ>;x—๐฿ฝย๏Zน–ฟัfต ~ฉ(Š@๖XWมฺˆตY!$6D šh+X{ฃ„u*Zˆนฅ\%6ิoฐˆผเ‚ jอญGภื‘ย์ฦRFย~y9‡จ…์ดiำ‚6ว/อคH{,ฐ!…Dฒ š า๙็Ÿ/อDญ/Wอ๋sฅF~๔ค9Z!5ส๘D ฐ๐ผK‡~ุeC:‘†6ˆ/ูฮ“{'mCพd+ูเ>Qc๗iอŠ‚13&œ\๛ZSณ—๎~ dxbฤ:‚0๊dุ„+ฝlธแ†๎yฒั๑G‘Fข*๑Fภ๚ใRข$ทHG—'l๐ƒDิป๏+ึ >ม๛์๙๓๓ิ{"แoถั'š๓๒^ทNตaE  `}ล฿ฤฆ๕ŸYฦฦG Žq`Iดv-๐ฟ‘Wปฃ"4.NX๋๋ฃฤj28ฟLc?๊‹L‹3ุp‰ฟขธXRลู๗ใ7ย.0\Qซ™แฆ฿'Dจฑขฑข ;,~Mฤo•ˆ`‚“ำ–-[Jw‘Gข๋ะ.ป์โBฐ† ู… [,พ?์ยว๙๑๘๋ฏฟผ๐ๅAดึ๒Œˆ?ยJดœบฬ…+โPg@–จ -ธฦง ~Ap„j —ฮ๘ˆ&ƒ“ิฐเ?งฏ7vYโฬ•‹(งฏD-’่Aฬ0ฯ?ผปwพ’บฬGฐ๘์@๐ๅ‚$๎๓ว๗ฺพ ธ4๏โ?„(>lฐ๓ื’ Nเh ็ŸD|•ธŽCเฆgฯž.•็Qœ๛ล๐c_lœ฿0ภว ฯ’๎~๙ํ่y๙#€ฯย๓H*ย'sฌ\h่ hp\จQ#uๆ ฆึปZ1=๖˜๓%F๗&MšิฃตVลมุฑck4ส๏พ๕xทใขยป5๏wผ vฬฝCk$šB ฏ}” vCำ์ดำNnzิQGน€๙ž[lˆชQย"๊่ฃฮ๗‹า~ฎˆซ]aX#8ผ„`ˆœgBIœ‰ฒะgม/žƒฉแมF:!๊ _๎ด‰เศ๔โ‹/vŽdqฮ%Dชฐล8w]mตีฺˆ:‡ฑDpAยฮP™ŽjรยณยbYค.s!ด.ธ!„แฝ็ž{คนZGซลแœี’มxภม๎!— ฃL`pตฆAฎ>กxญI”#’ˆ„wf„ekฺdฺถm๋ศ ฐฑš.X์-ป์ฒฮ๙*NX/ย)ืež8ูeuศšVญZeŒ“๏ด‡Kผ”G‰ีRqฯฯxXs&U‰y[ำ#3iา$CT#๒‰บDศ้L๏WTŸšVXS-๗ยK๛Gaฌ\๙OZgจdˆฮถ!๏5๊Mzภ๘แwูjญŽ้ำืช$ีฟูlŒแpัš{•4แษjบ7ๆŸง!šŸlฒ:ฑZ$๎}Œง ญฯน๕ฎ(ฅภฬ™3:”ภ๐Dๆฬทฤ†(awุIf1 STŽ"D $‡5นจ๓}ํ"ี{๏ฝIโห™…ƒฟ๏‡Ÿe,,L3aถ‰HC[ขฅ"ฒ[…†Š5qŸvํฺน,"แ !”N ๚๖ํ[ฃ jkŽๅข Hค KZ]ๆBt% “ฬ{8ฒŒดอQด;49'R ั]š5kๆ43 %D๋"‰๚ฑvฑa$uรG_ฤื‘0ฝu™งOา„๛ _๙†จ72ซฎบชำโส'๎ณD>ฒฆafuื w\'#ม‚๖„๛ย฿ฯw6๗หoCฯ+ :4ด>sGFZJๆXe!กณUj"ภ†;q"J หดiใ=xO!ยQ๚ะlไo˜w4"ๅ}ขๆŒ๒wล†x!h3บอ,๓–ม`นๅ–s !Žะže๓ญT๎ ๏ D์๋นณ‹”‡&ฌlขI/†๓^ว{๏…6ดฌฉฎ๋–ฑ๐šlงPcC‹ Y}๕ีwก๚ึ~RG€๏4ยX_ฐ-ั+ข- ยฯZŸeO”ฐ๘$ฬe}ณ๑,ิa๏S GV‡าํ?l,„ Œจฬc ฑNv!X„'„ุ%L,?NึใทำŒ๐ ~$ฬƒŽ–I”๐๒„ ?ฬ„CŽ2ำ ^ถs@„…}:ฺ็^ก๑"ใg~'t’๋WLl(7gฮ๗ว+d !L! }ะ0 ‘6(€๘cbไ L้ิฉSk˜-e;OB๚ๆWดฯ ชk<ƒ๔ษ‹/1Q๗œxถ2มi๐เมfŽ๕๛Q+ต?7ฮู…B“ฯ7ๆ.Œษf~[z^™Xฝ๎;‡ูCR–kธ๙สผป:๋บ €้"„~\ˆยล๓๎)ฯ๏)ๆญแ฿FๆI>f ๏l]ๆŸM1ห๏ถ˜ฏfำF)—E—๗~ู๐Yฐ`A-Dๆว{ไ&ผ˜€๓‰บฆ[?R๎P๊ๆ๛8}๚๔Ahฒธ*ถ๐.ห3ˆฦpฑวค+ฅ€๛ฌEYึUc>›นฦ†(Aฆ{๓ฝ๗;Xิg3™R(+%น J`๙๑!!>DาอŸ๒,ุๅ…ร๗A]จ๘1A-ไ๓ƒ้›†@H}ฯึ9ญฑ!zษHx7!ผC฿๘กm^ฺr%u™ $ uโpgขŠษ dาK/๒วž๙a๒B9|ด๘‚*/cๅลrˆชd8@H๑cสŽอFmไšฉห<ญc\ำฐaCgบƒษ์เ๙ใJuฮ}ลฌ!Nj๘fแ9ยฟMฆย3 มฤ๎!ฯ…<_แ๚™Ž#\Oฏ+๋ภฯiŸกฅˆฆ‹2ศYE ˆQ‚?,`e"˜]ฒน™R(แทF๙ฆพ๖––ปศ&MบyBคˆึง”ๅhl……๒lPAV$๛ืฉ๏5f@bM[ษขีทŸL๋ฃหBOศค๐{rฆํh9E ` ‰)›ผ˜ี‰‹‚|bข„z˜"~ ส™(‚\%นx0ุ๙G›‡/ y๚eฒๆฦBž{ˆ-(;…”\ฮฅใฮถฏJ™gถธhyE 4Jxq‡ฤง*โ*Š@ฅ!แฮBUvฒ‹=3ุpญฮ๏์ฌ#hณPวQ<ฮ™!๗ -laŽ ัย†Zญ?ณKƒดมLˆ๗œrด=™ฤ2q8ฯGึ_}ƒ฿นW\ัฅCbEิฝ๊ชซ‚†ภ=๔ำ ฌุ˜ย7^พ๏ํธqใฬ€ค[wไo •ฉuยyธ@ซฟkฯ›ษ|ๅก{mR(iุT…๔‡($๑}ๅkbJ”ไ ูํข2ฤหภฐaรR”*\/)x'๊ผH๏์ฤU$;QๆR6วršK*<+ežฉ0ะQDฦoฒไฺkฏ58ใ/”pะœ๗CJ™ฯฯWงN 5ํG(I๐…„&ไ-ฺ$ฅQQย7ฝ๘‹ƒรฅ’|ŠtะŠ€"58}Cฝ/*ๅุ๊จ?ใS็ภt/ฏๅ=c"`ห%฿o…qฤขฉ@ฤทd‚Sz"โศโŸv8nฦ็ื‰'ž่v๋ฅ.m๕DLz$]Ž˜‘Pม,IดiYDC `FŒ0.4)2ดVุ๐ฃ=ภญZตJ๑%›yษ8;ฤ…๘฿`Œ็ํษk?ธ+Bดbˆ:˜ฬTฺwlK=|ฅั(‰"Jจ‹ฦN92†gŸ}ึi๘Hปl@์!Dtdน.ย}€ฐ!๗3‘dc“\!ฆZ a“ตฟ?ดพTE | •U‘D ๖ช„#ƒGS‰’่‡DSE ท@ฮ๎ธใŽ[j"?ฉ”?hอฑศ‹)ฮYp„/—? :รJB`ำM7ušTq$JpŠำTด5๐%๘ูuื]Oึผ0๏ตื^™ nL์V^yeGŽ„wษง>ป๖hึ๐ฒฝฮ:๋ธฎ žxโ Fh7@ฤpฮ7›จY'N4l๚…MwR™ฌd3/มฒใฆ›n’หG|ˆเw.,ฯ<๓LRย ;ดn8†ล7‹สt!ฯ๗)฿๔&.ฟป๘cLผ๑c"˜๏#?6๘Dษ…๘šK<…๒Uโ๗›j<ƒ™:9NีŽๆ)ๅŠ฿ผซ๑Mิ›Šrๆ*D j’ฝ{๗Nถ\oพฮKPŠƒ€Dขย ƒv•สA€๛Mจslว!N๘จ(ๅˆฤ NขฝลMฤม%ฤ$@”`6ƒถ1ยxg “>็Ÿพ3ฦlยB„6 ู๘%ฺiงฦ]฿พ}ฦ…ด•์ˆoœE๛‚ณS68ภ๙่๐๓9ฯf^”วฟา๐แร9uย–]vYG๔€๓Y_s‚4p๒Cคƒ3ๆF˜ฅˆi ฿ƒQŽฎE'้AพเŸญ$•†O D พ‹‰ ศธr!h๚เณDฐ)ค6แิฉSƒb™ฺL˜โ u$šLDยมg ัTE 4!ิ1‡DกขD /ˆฑ๛“8๙ไ“ึษiยเฤbL:E@(์‹Sยฒำ ๛"[“ีึBภ๎^&lษ„u–ฐ ˆ„UOฏUFRGภ๎ฺ'vุa‡XNร๚คs฿ม7pCา๑Y๓ W†๏jN9๒ฑa๋ฬsซ่๊๓ ๋๋.(Cž YŸx๎น็’ถฮุ}๗]}N6œUฺ๋.pƒพ์™‹sฮ9'“ /šฐั3๊ำdVuญถ|ะท ŽPซ.๙–ศฉ•ฎ Š€"P๋3ษ-YB‰1cฦิฬฬำUlขภฤ๖H˜wq์อ)iช" (นA@Loโฒ;7ณาVฒE€hvข ีxัEน฿กlะ๒Š@\ฐ‹d็$๓”ธIฯž=OQฃF%uฐ‰ฏ‘ฐ9 ;๓<๐€3เ๏ ™„วD‡2o๖๏฿?าจ‹Œ ฿hฏ$1!sBฟŠSUดpา‰บ8ย.(Ne่ูฬ ๓$ัzดค’ูmท\ปChq`ป/กI'า š "`ฤณ€ˆฮํขร9ๅๆ~ื]w™ฃŽ:สœwy~Vา๓‘#G:฿1HๆฌU*ฃ้‚ฦ‹๏3F๒rqดk'cษฎ $/&7>๚h`v•‹>2im๑Q’KsขL๚ึ2Š@น ฐx๑bำฑcG็ผ๚่ฃvพŽ๒>ท<0Y7;x๐เ„H€ลท_ฌYืื Š€" ิv็Tฃคฎ่•O=ส2aUาŽ…ตM,\ธฐ|&ง3ฉhฌฮปpq4๘ถ>0’oย„ มฎGCŸ/฿๑ลvฟewqGฺ!ุaฺ2Z@จD๘;BอF*ศ๔cczcw๐ขคP๊4AX;Qุ#ภฏ%ฑฟM tแ^j7lณ„ํ,Xฟฺ‘"/ J0?‰›`๊& Hซ‘tx,.ฅว?0(หขR๒ 2ข„…9$$ƒ”ๅh5.3ฟž˜Y%~rโ๘ใw๕ญ‹Kท~Q5ไ‰/ึ1g~คOžูณgEณ™—๔M[Qfษๅ?rkาฆOVAษs NโฃโศšF%๐_#u“iO1F)“ ฿LๆกerDภš$l๐…D6ไm}pˆlย๑tM์zผุcฝ\…(vg#ฉw๗rทฮKˆ+ุuซ’ธโห๎๚นP›|gทnฺEœ zˆŠ"Pjเbญตึr>2Š=v|cXsภwGช๑เณ?๘ยษ๊ซฏnฌSึภˆิ•นv๏|P๘!Y‰ sโ‰':$Rj="ŸH(฿pt"หa!บยาK/ํ๐w‚Ÿ‹—_~ู,ทrฮ dข Dรaฬ๖EX๒ลตAYฺเš(™ฮ‹บ„+‡Pฆ|ฏ ‚ะ™„˜mัข…๓Bศภ |า ~มEขฑค*ฯผˆšcI7kๅ๊แ็ษ๗ ีcถœ? ,ๅฌๆ‹‹~ษ๕๘๑ใ]Hgษห๖hu;฿‡ิ0`€9๖ุcำ6†โWฦ#l๏๋ จ|เ <_„ญ!ขXZ"P’jyžปvํZ# ึAผ‹ ™Žืึ A€๏9ยภ[ ;๗]•๏iว†(น๐ย —-D ปp Uฎ‚#1โฅ๓j่rฆฮK(”()™[U”>๘เƒฦ๚ัr‹šLร…e ฺฉ"๕ึ[ฯ9๚$$lฑE„†วมขTฦ ฑcต1ข_œŸ๒ฮ!ะฉSงpUทภด>Xœ“Vฏ 8;•ฏT ฬ-โคแTU๚!฿jซยi-ฑฺฦFี า฿y็sึYgก€ษภ๙้I'ไศ)ˆ#B œ‰"Vรย9`อf^VSม9&…ศ๑็ }ศ‘๐บE€$ R9หตพ]ŒีN1Vำ!ฉำV๎ i9Zm;๗iผนs k}™Hื‘Gˆ๊@4CDp}ผJVซย๔่ัรX+Žˆ )~ูt็ึ฿TP ‚†ะรษฤ'J˜ฏ๕นโІŸ ฺลQ,!"ๅธฆ_ึ มยึ7ปฐผ๛๎ปฦjคธdqศฆZEPF€๏ŽVญZน๏Wˆ๔|K์ˆ[พ|:่ |ฯฝhํหฮ‡%Eปฺฑ"P%Jjภกฐ}qวนศ,ๆx‰mถmDIMRโ‡ฯฌตํv ดb๎ว4ึ|ฦi… ๅย"ํ v่ฃ™Ž—(3h3ˆ|๕ีWN+ญ„d‚V‹ูํถฎV๋ฤA:ไ‘ฌฟ— MN 0ฌiŽำกอ† JVญ# nข<ฒQ–Œ,๐+…็EฺnึdลฐฐFร†๚๕ซ8อlศ]ด—!gDภ‰ลบ lฆOŸn^|๑ล V[mๅฦล๘ฌ ˆa^hรP‡](A+ขhๆฬ™๎;‘฿ำ6mฺธsŽ|$PTจ4ž ๚^vูeฃฒณJ#าไˆ/Tƒ 2ํฺต๓“๙mทfฌ†6;๗ํwดh ์† โ4ศCรˆw{ดkภข‡฿ ˆu‚ž"NุF+ ฅ(!rัะกC]ใๆoVEPF"s๙ๅ—7มฝ{๗;#Ogฑ!J`e๙bไ ผœ5J”(ษำำฌอ*uD€—dBŽI่ล:6ฃี*vซ อษ‡ˆu๚Xณึ)–:,^ั๐Cย–๚œ2ื_mฆNjฌ฿ 3w๎\ณฬ2หธm^ธทz๋คคuˆj,X`ถrKำฒeหLป,x9ย!3OLˆะภฐ6 3n8gฦ‘ษ ฌOทS›IูR*CH^4™|า‚,฿›ฒi5@ ฏXศe"้ˆฺแูม›|&BุปtZ*พว๗tmfbบ&ฤ‹฿V˜„โ%ำฟ?ฟ-=Wย`BzิQG™ทzหฌฝ๖ฺ†๏๋dค_ธฎ^+๙@€M ดIฐํพ๏พ๛๒ั…ถฉ(Š€" ไ6h๑iJิชLึ)๕Plˆึุัพ๗{A” –อฎฃ/™์@ฒุอิyM๋ึญ]lwฟจ๓จล)ฮ ฃผŸใฐ0ค‹ƒt‹bฦฒห.ปค%^(วผฃศ!๒|iถmฺ๑๙ๅ๕<~คบื˜"ษs@๔tฯ"D „J๘o-jึD…x๊ฉงขฒ4Mศ;๏ผำ :ิ,^ผุr๓๘ใฯบ ญ ไัbําฅ‹ำ์หE›ฺ†" (Š€"Phˆะล;!C2฿วŠ(A “ย."6rพมMี>‘oย'2Y๘ัfช…ค๔ษ.yฆ~+คށrG๏oฟญ1อื_]gชESฃฒ^() บฮษ1ใƒฟ๛๎ป5Œp ผ4+?ฬ™3ว ษธํถšป๎บ+?hซŠ€" (Š@žุqว]ิฎซฏพฺ…๘ฮsw&6Dษน็žkฐอ{็wp!b#็\m_PE@@ณd๔่ัฮ๎’K.)ˆงvE]~๚้'ƒš;๘ƒ๙ใ?œwmLžธๆศวO๗๓H—rดํฝ!\้tฮIK$๎่Ÿƒฏ\K>iœ๓I&ษ๒4h`ไC]9็่_๛็ฤใ–ๅ8—c๘ฟnิจ‘แCYŽา†œKrM>็๒iธฑซ#ื’/วจ|Iใ(ํJZ“&Mjฅ‘งข(๑Aเฬ3ฯ4ใว7ญZตra„ทุb‹๘ NGR–@ฮกMยNจQฃสrŽ:)E@P๒G`ทvs&๔7t“ูnปํ๒>แุ%DAˆพrส)งT$Qษ€'_B๙-\ธะ}ธ–iœKž\“Fค…จ#ไํ ั‘NX\๓aแอฑiำฆมQฮ%OศŽ”•ล;Gฎ|ฮ…<#c‘2แด๐8รไˆ\s”.r$]ฮ#mหต9\‡?ิ'?Ž_ฮฯ—tฉวติฅOฟ/าฃสIบิฃ๚ˆเ.๘r”sฺ•|9FฅI๕ฉ/้น็~คษ‡<ษ—:\s๕œ๘yดI!‚ไู“#y<—ด%ฯ'วfอšนๅš7o๎ฮI—sŽ|H“yนษ้?Š@žเwŽฐใ?ณำžฤ4GEศB”์บ๋ฎfฤˆ๙๊Fญผฯ=๒ศ#f๕ื7Jž&’๗"ข๗Wฆ hhญืYgไkŽ" ฤw฿|๕ีWN;r›mถษ๛xcG”Rฑา4J๘q<๛์ณ“์`gืจrฮขะ^๐ฟฑVŸฃ aฏ๘ุึ6ด W[ฮ•‘cUำจModฐB้Dซฝa—๖๙1rB๙ UI’แ๔’d๓(ƒธbีe];มyUaiซ๊hษ‚%ถฎ-ท„s๛Ÿ;J}๔B X๐ihqrG0#อโ+‹}Ž m:ธL—ฮณษี๕ชq๗โ๏6P?Tื๕็•“นปC๕|9O&Bฒธ{ๅภpบปOถ9J~๘(๙า๙œ๛G9OVFฺ—“๒rdNr.GI‹:’Vแู๊gŸญOZWศ Lq&Ož์ยใ่UรgŸฮยฬฃขฬ ๆuื]—a--VHž~๚i๗๎K˜๚^xมฝKฒR้Kํ0^pสไ;๓๑ว7งŸ~บYa…\ุ๖R™ซŽSPj#ฐว{˜/พ๘ย๙"’[พ%6D D ฬ7xรœz๊ฉๅ์Ž/๛cŽ9ฦเะvูVห™ฏ–|QฅอัิšMฐถ E๛#z—s๗!?๊œดชzUuซฯ]cงC‚ธ>l3ม‚%UฅGๅWญหYฌ๓xสั5Pี”W?:฿ึฬฉ^์‡ฯ! \ž”‘#z็~=Gฅจ็สฺบฎœฑ„$„\ำf5)คUทล KI7ฐZ@ ี{ศMX KเิWš7ln›pJฝšjฐ™}h“ท้ฒdqตษื_Uว%˜†Ymช฿ท&f‹ฌy™ีฎ2Vกส™“ฑศš‘affMฮaฎพ่ณCฬC™ึMิkฌZYศqใฦ™‹.บศ™<๒;€iŽŠ"K„(ูsฯ=อฐaรrูtNโ]…ฑพ๒ส+f๎นฎmดฎXฯ›7ฯiˆ†,ƒ˜vุafาคIฆM›6ๆŸgNวSศฦž|๒IFœ>‰ฤถาJ+ฒ๛’้ อฎ]ปบ๑xใฆG)วN€ˆ8ภ•Qข$%Tšฉ”{๏ฝท‹$xฯ=๗˜ฮ;็}ฬฑ"JPทํตืLอ^{ํ•๗ษวฅƒ)Sฆ˜#<า๐Cน๒:+™๗{/.Cำq(ภ๑]N4]v฿สwa?ำe™ซ๒Uจ:ษŒ€ผ๛๗ฟmฆM›f6ุ`s๗›–-[f\_ *ฉ $๚๖o๏Lฉม •ฐู|๐;~๘แ‡†&ฤูศhxเWeไศ‘f็wฮฆzlส>๖ุcๆŒ3ฮpใ๘Yc59›l"ชT! คWW\q…้ปทหˆย้วtZTmˆ%G(i๖w_3cฦ ๗žTr<6Dษ€œ‚J$J^|๑EงQ;ถึๆk™›^าฑ^(5Ž๊ำญW7ำ๏cอK็Ÿก.5|tผ…AG›˜Fฐ0Bห๒๐ร/LวฺKY# ‹ห๖ฯ\yๅ•E+y|๐A็g"SRdีUW5ซฌฒŠYf™eึ|ตณ€l้ะกƒแI„ '|”š`zw๑ลปaoดัF๎๘ๅ—_ฤฤ ฺgห-ท\ฉM-งใ๏kPฝGx.0ฝ๙๓ฯฟ'า Cnพ๙fณูf›น Hด“D”($๔จ”.Žฝ๗{๎๛pใ7ฮ๛DbC”œuึYฮฉ"_jฐ๊จˆVŠ<๓ฬ3ฮˆไ์ุษ|ฒ๐ใJ™บฮSˆวv>ฮ์vไnฆฯฉG™MZn‹1้ *9sๆ˜C9ฤ|๖ูgfซญถ2cวŽญL tึ9C@ˆL.ฟ๒œต›mC8เร\&,K-ต”แ…2“H„๗ย~๚…‹ืธFkฬ˜1ๆพ๛๎sv๋˜nใ็..๒ห/ฟ40 ๒ตฤˆ|ล&yำงO‘dใฃ็ŸพโLrะฒƒร ฟ<ห้ไฮ;๏tds˜hVข$ršฏฤ๗฿฿ผ๛๎ป฿Cnธa;ข3~…1ฮ;1่gฎ็Ÿพน๔าKM็=ท0Ÿ/,ฃา!(•ƒภ1›๗3๛๗๏m9๒ำฉๅ?*gโ:ำุ"pษ%—ธป่Dลูiงb;VXผำ›ƒ>8ะZ(ฦˆ?๔SChG"?แd’„่e โ-ทา฿vm.฿]d๐ค„‘ฮ๒!˜p9ฅmถI›‡ธy้ฅ— ฮYqิ,fT˜0a‚ุ้ฑฃ[์3๏Tฒ้ฆ›:ญดc0ว[wufbช:qอƒ :ํดำฬถn๋ข}e3N๊๐รIซฌฝ๖ฺ.Jก‰ณz๋™ฅ—^ฺ๙๐›:uชำ@z๊ฉง๙ฆDIR5C( ๑=T(ํมุ%8ฐ#T็ห/ฟ\qD ป!C† q/0›๎พฉ๙ๆฏJๆี*ฅŽถอ:oŽพ่HณŸตw๎ุผ๔ิถK่๘ฃ@ฅU฿ฝ[`pร ั5UH€%์ฐ_pม)Jๆ? _8gEkำ‰ฐ๘D พzโ*—70ะn@Xp๗์ูำ 8ะดhัยฅA`๒ม.งOŽธฬ๊Fmvุaงฑห.ปYดม#ฺhวdใคฬอoู๒ห/๏pE3'Ÿย!ฒี ๘ภ9่ ƒL๋ึญku vทzซ#ภ๎ฝ๗Z๙ฉภA๐#HชO>๙ฤU|9้ค“RUwyJภK‰’ดPiE ๖๐=รw2ึศ๙–X%|ฑC”`›MปJ~@†nl:๕์dพ[๔mฅL]็ฉนณๆšณw?วœzษfทw7๋6ฯoั'ญ()Xฐ{ฒฺjซนG)๚`()ภหlฐ3gฮt ๔ฃŽ:สœwyฑž˜ 1HฬS:u๊”“๑๚๋ฏฮิ๓ศ „:เAŸผ">,lbAD ฺwu—หB[+พใ0;๎ธฃYyๅ•o‘]w5pฬŠถ 6ถzkC9ฮลไ-ใM6ูฤo*๒|๙nƒ œ|xโ‰'๗…Ÿž์<[l0กย<0Jำำ๙ใ?พFWh=๛์ณฮ็RถDๆ6ฬ ฐB๓ˆsฐV RX:9ๅ”S Z%„^wE@(]p|ึ[o™‰'šตึZ+๏‰Q‚F *‹ฐ๔ฐ๕•"์rห-.Dไ=ื7?,šU)Sืy*EGเ‹๗ฟ4CŽบย\p๏๙ๆ_›์`ึhVm ่ำ(ผเณaqฤ‹ ;E „(aQษโ2ฮ‚ถ€ผeJ”๐าฬ{#‹p1iXผ๚๋ฑุพ}{ƒ‹n"sฬผ…dุf›m฿(‚ฯ5ื\cˆคƒ อภ฿/ๆท฿~{ะึ /ผเเ<ิwN‹ฆp—.]คฉดG4R"š'ฉ*Qm3ัฎ , ค iœ3NH˜ฐิูั ท+ื๘ˆมWŒQ‰ะ$น่ข‹œ9‘คื๕ˆโื_m๚๖ํ๋๎{บv๚๔้ใfๆฎข(ฅ‹€%๘lโป=฿+ข๕=^+(มœี /ผะt่ฑฎ™๓ื์|฿wm_Pชx๗๙wอMg2W=sฅูฒ}ณzำีE ถqฤง็ุๆ?๚่ฃ5Dฦvะ:ฐข"๐อ7฿8อv๚%mQ”ขs?ชIฆD Zน˜w ฑ1bฤื:ค ‹s'ื\sMsqวฝxใnก}ีUWiœเ#ญ-ํดDึ๎ธใง‘ภ5›[8฿GpถŒำeิภรf ˜:pย 9`…•P—ด๏๛rqyเ๐นWฏ^ฉฮ Aƒ ‘ ๐อแใ‡ฯ0lะ W8Bฉฎุ|๔ัGๆ‹4Jดดt๘n2 …ไC๐aศ<ัjษ„0m๐ลGEPJ๙{†/@K,฿ข„o{ผ€cO˜๊G"฿ บ}พ่ ๛ฦq›yUล|/๔8ด?E x๑แษf์{อu/7[ฌาูฌฺดถ|%โขsŽ/,r0 ภt€ลชํ*Š@2„( ๏๔'+_ฬtข=๕่ัร !S%˜ฟเุืข3 4,|mฝ๖ฺห๙ ฯSœวโ๋c฿}๗53fฬŠะ6Z(`๙๚๋ฏ้D_ภแ2B8_ดX0๑ัHฺื๗อ “สœ๗e|ฝ ๘E๑=ฃฬๆ›ใ Iซ6aBh๏ฝ๗6h ๘T‚ฌBˆnDธ๓|๓แžฒณฬ}O'Œ‘{้›Jฅซฃ๙Š€"O H฿xใ ทaๅ็*ืฃŽ Qr๚้ง;65FlFๅ‡2ืŽc{็œsŽSdwcลmW0ฟ.๙5Žริ1)e‰ภท๘ภ๙3ภœ@EˆB@ˆ’๛วžTร…„“Qs# ํP ~๘ก‹#d€KL๒/ูh„@œ@คฐYลK8ฆ<,ยสD๙โ ‚€ExX>๘cงq‚ฃS_ะjมOฬŠ+ฎ่'ปs–Šื+ฏผาiˆH!ยขEvํตืบ DxA˜ณฬ›kดR Mฤ๙)i์ธNš4)ˆ*DZ}ฐ 1B.ั.ๅ8•HA„๘EใๅะCญ*X…(แ๛ฯื ‚ภ‚"Šค6Tฬฎ0ห ๛›kุฐa=FฃUE QY๕]š๋ฑฤŽ(มๆขค’4JP euะ[43 —,ฬ๕}ึ๖E ^๛™8๖9sหิQf‹eถ4ห6Z6IIMVโ‡ปฯ๘Qภ:*๘ฝmไ&EภG, ๑ษัฏ_??+v็พ3Wดฆ๖฿ดc๔อd0ญภฤ"L@hˆ ขมŒY f5nlภˆฟ'H|`Mgดธˆzƒ๖ศๆ›o๎“ฆ‹ศƒ†ษM7ไLไdดIT›pด†D"a:t่เŠ๑ ก"‚& D๘A3aLJ’ไุcuั คž เ๒ไบ>ุ@B ้#v—_~น\บ๏ ๆพ๏ฟพK็{‰4DB$ป‹:6ฬ}๐็"‚™ไ๙`("!†qฌ ั#๙„‰‘7UE Qโk๓ๅsิฑ!Jุ้Xvูe๓อq%i”เ\pl`ฺ่O๓Wโฯ|sm[P<๎พtŒy๙ั—อ่ทo6[.ณตiูp)/WO๘#ภ2 โnบ9'Ž๑ตŽฐPQยnัG]จn๋ิกฐทn;W7SŸ*พษ‡˜ญ๘dZ!๘๓gฉ4Ž/1ม|๓q่Šๆวsฯ=g๐๑แ“+้&„ำRB1๓"/พNจl„1-ฏ๚‚ฦDห๘\Aะฒ–ศ.8"]c5ญœใะ”:w฿}w`^QภrHดK0ัรม*J๊ƒ คยซฏพ๊…ฆ/“A!„fย|$ด2ัoขข ีh0อ…hญp_ัดAxnธŸJ3๘K‘รlภJˆuฬ%z˜ทิัฃ" ฤดาะC›Vยณ็sคฑ$J๘’“ฐ|N>.m‹็๕zภฬ_kžIุTE 0Œ>๗V๓ๆณo9ขค๋ฒL“M ำฑ๖ขไ)์จณH6lXฐ๓œใnดนC@ฬYย ศ8Nรื(มdŒtยโญ -ฎ]ป:็๘˜ี ˜[ U€ฆ eYDƒ…*ขแ๛มœด-ๅ“% ํฐ๙ว\—`โA!@ยZ#ด)š-ิ‡$๚๎ป๏M ฿iชลhFˆใZฏxเ๔fJ]ฑาํ vt…ˆ c1$žขึ่ืษ๔z๘๐แŽxข<๗“ž‡~ุ™Hฺ&โfัขEแ—๙^D~๙ๅงฤyXใ†4E@ˆ'B”๐ึคI฿ืcE”๐ลF\dุ๎J"J๐ฯ๒๘ใ›GŸxิฬn๓c<Ÿฬ ี—3พ4๓็ฬ73?ึ|๓๑L๓—฿›ึkต6ุถ“ูผ๛ๆfฉeZ$Eๆงd^|่%ณย*ห™๎wฏUn๑โ%ๆั5ฏ<ชูฝOO[fงZe4!pฺ๓ม”ฬญSG›nหห4ฐฉ(ฅŠป,˜>”]^qดXช๓ัqื!JˆN"‘\๊฿j~ZXธpa 1“b‡LณLทY$ทnฺ™x Aแk ผ๗{gฑ๘ถ๐R,^ผุ-ธ๑-๒ฺkฏ™ท฿~'๔ ้๙HXเ(๙้งŸ|ดY C|aแŽY\˜P(~YHžK/ฝิOr็ด"1อ๙๗฿ษˆ฿ฺlบIxdiMด@ ˆศจบbD›ผทB<เcOœ‚&^>;"Œอ้LMฉค^ฒ#~h๐+%W_}ตูgŸ}‚,๎ญ„n๖ฟB๒ˆYWฆพp‚F๕DPІภa‡ๆพง?๔ำZฝ๒1จX%ห/ฟผA-X๋์$TŠเ้งŸ6ž›`พ[แJ™v์็๙ไ่ ๆฑQ'gณออแ็jถ์ั9ฒฬล]jf~:ำด๋ะฮ\p๙5ส@’9๘.๓๚„ฟฝ็_9aˆiตš:ญT.ฎ>๖๓ษปŸšปพรlณLื๔จ](๙G@์๕ดiใยฯทo฿>jฑD_;๏ผณ๓%ม"6๎‚น f<ร ™ณfอ2<๏"hฐใ+๙!,ช7n์’ัฬภ‡‰&.[oฝต3—มน+d 0$.„š˜ื`‘L pB*}Iน?๘ร‘8DtA Xฬฃ‘6ำ!'ฉ˜œ`ๆƒVE2กddŠ„ำฌ+6ขQโka@Ap1Ÿ€๒วƒIRถmคz‡}ฅ@Ž`Vๆ;q•ˆิƒฉ๙โืwJห๛ทPRGŠ€"O Jะ”๏ษ|26Dษiงๆ~ J`ฺ๙Qฏ{ุIฏ>gพh๖yฅL;ถ๓„ฤs๙3e+5ฦธสห›Uฺญlพ๛โ{๓๋ผฟ#uูฝ‹9bะaฆq“ช,*}๗ลwๆยป๚[Xอ“~WดE๛w\x‡yใ้7ƒด57\รœ9๚Lำฌyำ MO ƒภG]aพœต๓๖ึGI—ยtชฝ(@€๖,”PQ็\ฅ๒ข$Y”–สC$Œ๑a“R|d"๘˜฿*ิลwฺ+h๓@@z@vฐ EzH8งล๖ญŒ0™"ๅŠuขM’>}๚kb ฒjม‚ฮกmห–-ณ ฤ–„q.”ฏƒฌจ…E ˆ๗ฟฬฯublˆิ ๓ณ‹zh%%์TเUๅi/›.0ื๗XหI๗M2๗_`Z๛žดู๕๐]MฃFUaไฆฝ8อuษ=aฒ›CV…คโวobะT@v9tgณชHธ฿qั]ๆต'_sysุy‡šํ๖ํšัฎWPIOr†ภฅ‡^nf~2ำ๗๖ฝf๓ฅทศYปฺ"ฤK|วŽ™gฃFโ24GขD หฒ้M "ซLž<นฦœ >๐…ย฿พ๓ึห์ำ-ˆ67q[ชฒว{ธ…6แ{[ชsาq+•€DษิฉS >J !ฑ#Jžz๊)gฃูฝ{๗Bฬ?}ฐำ‡]์+3^1ำซ ง‹Uเ ๆ|?ว ใ๏]ื๖›๕ฮt๋ีญsพ›cฎ=~˜๙๑Ÿ\‘aถkwฮคwฬศ7ป๓รฮ;$จะ๐Gฬ๎๙Oะึ)ืŸ์ zRp.:เb3๋๋Yๆกท4ทคเk‡Š@!ภ๊‹‰คQˆพตโ"€yˆ8Fญ$ณๆ\ขŽ–ๆ4๘gกน์ฃฺโปƒ่;ฏh—ชHศe!IEPJˆ’wyวฬ˜1ฃ Ž Qrส)ง8uDbฌ_vูeฮ!TAˆA'เเXjาด็ฬ†!‹มดc9„๛0๏ฝTEVํz๘.ฮ่0%NIDATfฟ“{™ $๋ทŸฯ >๐b—ฟ๔๒K›ซžjUe™—ฦฝl๎นlŒKxวณฮฦ๋˜‰c'šฏ}8hซ๏e}ฬV=ถ ฎ๕ค8 ๊u๙ษ’^พ๓ˆูฐลFล„๖ชูIb‹-ฬ๗฿_ ^ต›b" D ~ˆ<ขขิ‰ธƒ™ๆFฅ*B”เ๋ไศ#,ีi่ธŠC€จ78”ž>}zAๆ;ขฆปPsI()บีึŽ,ยดหErrมหชซฎZ’3มG ^1๗ท%9ด"Pa \€_ก๗฿/ŒF์ˆœ+็ฝ’v=z๕๊eพ๚k๓๐ซ›ฏ~ขย๙๘L๗อg2ฃฯปี ่‚{ฯ7ํ:ถหhp๗_๕€™t๓†(87Nนฮี3ไ^3๙แษf•ถ+›“ฏ;ษ\z่๓วย฿]ž๏ณ$ฃดP^ฐ@๓๋/ฟš oO0k7_;'}ญทz†๛{๏ฝ7'ํi#Š@ฎ Bแ2gฮœ้~oั6P)O„(3fŒ้าEV—็].ฬฌ;พอ6U&ฦ„&2Q) ฆT๙งsš[Šใื1+•ŠD ฺ$„{/„ฤŠ(Ye•UœฃนJ#J๖{oโํ—ฦš™|Sˆ๛ฎ}D ๐ะฐ‡อฦLฌAxDซ•4hฟ อฌฏf™›ฎkv–หฟ๖ธaๆ#ซE‚ฌิzE3๚>A6่ผพ9ๅฦSœyŽKะŠŽภ™ป0ฟ-Xhž}็ำพYnBจ^yๅ•†[<๑s^Iฮฉ‹~CuY!@˜OBšโL[อ7฿<ซ๚Z8Fฑgฯžๆพ๛๎3;G‡ณ,t„qAเ ƒrฮ! ฿TE@(8”ฦ‘+.+ !ฑ!JN>๙dงย๗ุc™กC‡švจณ„=๗ำฬ™3ว>้6๓ข๏ q฿ต&”?โ1—sหิQEก๙เ•้ๆ๚SnpuˆlƒถrVณอผŸๆนs๙gต5W3o?ด\n)Iาc เ^กQ๒ยดL๋ฆญs6ขoพ๙ฦ`K๙w฿™vอpCีs’ณด!E Gjs็ฮ5h8B๎ฉ”ผT๒ž๑ะC™อ6ฌ|&ฆ3) |_HิดาTE@(%ธซ mฃn`ฯฝ๏พ๛š๑ใว›N:ีญญฅ(Š€" <ะ`NJˆเBHlˆvณx)ใ‡ผา4J J~๕WsSรอฟๆโพk|9ใKs๙แWธHใ‡๖K๑ๆ๋พ1ท ผ% |่น›ํ๗/Ww๎ฌนๆ์ฯ‰่ม˜-m”›clด•๘ €œนพ9ใMณB“๒20Ÿgžyฆ#D mvมไฅmTจ/๘ 4h ƒz๔ัGLsTJB)โ4žจ‚;v,ํษ่่E@P*ˆ"นกูV‰Q‚FษีW_mถ฿~๛Bฬ?}๔่ัร,Zดศ }Jณ`๑XŒฉ‘H$ฬE\lพ๛ขส ฒdูVหp๏ๆ™;c&6!Hพ๗๖ๆsV?่อškไ‡O<ใำเส‰๊žฎฯ๎9ะฬแg3ํ“if้†K็ux8กzใ7ฬบ๋ฎ๋|˜ดiำ&ฏiใŠ@]เeีVึใฦ3อš5ซkSZฏศผ๙ๆ›uๅgŸ}ึฌณฮ:Evฏ(Š€" ิ ๗฿฿`ฺฮปt!$6Dษ‰'ž่Bt๑Bvอ5ื˜ซjwพ ป]vูลšk,6—ฟิ,\๒[ฑ‡Sั๛>G“ีึXีฬdฆ™๊ Ivว}Nุ๔๔ข{ล}AนŽ›w4klะ9Š•ฤc.๋kตKิฉžเQฬ#ฺ?hฝ๗ั{ฆe“–y ๆ7hอAฬกeาทo฿ผ๗ฉ(uA`๔่ัf๘๐แฎ๊YgeŽ<๒ศบ4ฃuŠŒภซฏพj?p๓๓ฯ›๖ํsใฐบศSา๎E@P*๖ฯ๏3ฏฟzAfฏDIA`N 1–,Yb.?ุฑไิ…57๏L{qšqฦศ”๖ท๏ๅ}ฬZญUซ“ทN0|ฅoฝวึๆ่มGบ๓q7OWNฦ.'ื~{RVานHž”s)/ืแc8_ฺฅฮ—4—Y>งŽส฿€)"Gษ‘kŽyบฒเ›ฌ|8oK๒4‹คIฟษ“ฒRฦOJ“จผp๛าถิ‘๋จบ’ว‘๏Pฟฌ฿๗฿๏Šฬ˜QSร_๊ๅ๚;ข„๐uื]wูnปํr=ืุถทำNึ_…ป;‘sc;FXv|6ํ3ำฌE3ำฎcปพศอƒๆๅq/Lrฮผๅ๔๙zQx๕บภฬ๚๚3mš๕Qฒt~}”Dอ„G'D8ค้7h7ึศHQXiZqภ.gฤจฝ๒ฌŽ5ชธา3F`ร 7tฺ$ผpส‡Q9็ˆศQฮๅZŽ’>J~ฒ#ๅ}IVNา)+็r”๑๚yาฆ”‘๋จ2~žœ‡๋…ฏ“•“๔จc6mdS6ช/MSา! N9R^ฮๅoสฟ็๛ํง*วณ์็๛็ษฺคLธž”ช๏ง๙u%]๊†้๒๒๕9—ฟgฟ?ฺ K8?|ํ—O•็—หๅนฬCฺ _“•–*=Y[แvไZŽแ6็ฮ๋65Ÿฝ+ทฉj๏+‰PขL™UศL Dž =†LIฅ”™Bธ”>}E†2•9C•(!‰F} R†ะฟ™<๘เญ2ฌฑcˆ’|ส•+G+Vฌข$ฌ—\” ‚€‰ภธ.ใ้๖ฤŽ+‹-jVE,7€๘ฤ›฿bลŠลษ_Z: ๐ญƒ๊J”(A3gฮคบu๋†Dฏ(๏่Eƒท )oๅZ“ฎC>ุดnc.ึLบฑึz”{+ำ๒ˆ๑ฮ`พฉ๖ื9O-g-ณๆ!g-ร|ญeพ๒fนN[cณิi<ญr:oส#-A๒†€ใˆ’ๅห—ำดiำจYณfy›Qถjูฒฅฒ7J ัbQ…WO†ํL์๙ดฺbuˆCaแWaีชU|4+Nม๊ึญeffไpคoAภ'pคKจcวŽผะckŽA@A@bว%๛๗ง *ฐฃธ3fPำฆMcใ€๓hัข…:5…h๔๊QeE@B‹ภณ}C๛ทŸC•*U*ดส๓ ํะกC4pเ@ฺณg•.]šญK4hMาD?p gก8Mvส”)NฅA@A@ยŒ€%aุŽzX”ไœฯกฑฏฑ#.2‚€ B^xh ํ่[ว_MฐฎCภ๑้ƒ แฌE• :ฐ gฬ˜1t๚๔i>๎G KA@A šp Q์•*Uขล‹SVV5iา$šq j์pŠ๗ฯ™ำ”นnlPํDX๒ภLu๔.u$๔ๆอ›๙Tˆk †ํทำะกCy{CลŠ๙dœZตj…ฎั$„๘่าฅ ํฺต‹ชUซFห–-+็ศ!šŽจA@8GภqDษขE‹hึฌYิธqใธน4ญ[ทฆใงง฿œ7s–‰ NA`่๙ดใญดqใFแด€ท๔ร‡งu๋ึ๑ะ๐ถฤฒAภ‰เ๗{ส”)|ฬ๎ี>}๚8q˜2&A@A@"เขไ๛๏งส•+ˆ9ODIถm้ฃะณฤž฿ปU*0 ฐxาRฺ๒ฺz๓อ7ฉjีชa่!4*๑†~์ุฑผญSง?žญ๐Bฃ]ดกCว๗u๏๖ํG๕๋ืg฿cกำ.šA@A@?Ž!J๔ึ›xด(i฿พ=๋ฯ4๙gรลฅA@ศ…ภ๊้ฏำ๚๙๋iํฺตTณfอ\uNห`แ9bฤv๔z๖์Y9r$๕๊ีหiร”๑Œภ„ ่•W^กŒŒ >งM›6‚Œ ‚€ Q€cˆmQ‚‡ชูณgว•EIวŽ้‡C?ะ๓๏=7 Rˆ%~eญšบšVฎ\IตkืŽŠฉ=๗sly—””Dp Gš8!G‚ เ4~๘แ๊ป7๓ฯิชU+Z๋ด1สxA@A@ฐ"เHขdฮœ9ิจQ#๋Xc6ื]wั๗๛พง)[žู9สฤง"ฐmอ6zuโbZฒd op๊8ญใ‚๓ูัฃGำ?Cููู4jิ(๊นณUL๒‚€#+M เ2H—‚€ ‚€ `ว%๓็ฯงy๓ๆลQ‚mGl€f|8อฦ%A@%฿์MS~‘^~๙ejผy(UGLถ,ยDฑbล(99™ญKฤDฤเ—Ž‚Dเ{๏ฅญ[ทRูฒeiแย…Tฎ\น 5ˆธ ‚€ แEภ1DIฟ~จz๕๊L’€,iะ Axg๎ ํƒ ข๕oฏงฌ34*Š }˜2{Nคฌฌ,บๅ–[ขvาปw๏ฆงžzŠ8@วงnบฑuIbbbิฮIปฌ^ฝšOqยึ1'ร† ‹ษ:hfำฆMฃ5jPBBŸ …๏3กขLPง?(;<ฯฦŒuZOy]fฦพาะoง ๔›rีฌ๗ฬนXวeŽ้ฮO๋ื๓ Uฌ็*}Z่u!กฏฝฦ1๎3X๓vdผตฑ๊4ฏ7ykY~๒f[ถฮ]—ุ๋:O;ๅ๘ฑ;ํษxซ7ว๏ญn™9Oด1ฏ‹u.:o๊ึe:ิ[[=VวZง›ํอvz์:6 mีฉๅtl•7๓f?fนN›๕ะฟgุ…ฉเHขopค`ผ๘Xพ|9อ๚$+^ฆ,๓ƒภ๑_NะvO๐ฉ๐ํแ้งŸfยนdษ’TดhQšำดiำhŸ–Œ?ภษM8Fxืฎ]ผ๕๖ีW_ฅโล‹วเL1ฅ้ำงำ”)S"2<ะ๚ ๊ฌeึผ~Xึ:อz3zk>PSiะo-๗งว—ฌตM^tC‡ฉ_๋tzฌ็šืq๊๖ๆ5๑งKห๛“A]0rpทซว:k;kฝษx“ณ๖eๆญ:ฌyฒม๖ฅu๙๊รWy^๛ ิŸฎFฟฟ1š๚ฬt^ฺ˜ํ%m;๏ผ“pจA$‚cˆผQยัœ0‡)n<%“'Oๆ“~f๚R$ฎน๔&ฮซทL็ิห6|Q๒—eฎ4สTวจSBHปพPu๚œz๒ฦ–๋มๆ~่t=ƒช7}‰ฦGr^ล‰(G%จ•H์คำIิทI?~ฃI–ฺหPBVดaรถ&ม6œ6าฟ2dHศ๔‹"A ”ฬš5‹๐๘พzโ‰'่ž{๎ ฅzัๅF ๑๗ฦo0!หmaฆsrrธ\—i”ใw ySF—้r3oถEฺ๒fวฐu{k93ึ๒ฆŒ.ƒ6c-๋ซ^หขykl–Yำธ—Mบž•๚tŒMY3 klŠดฏg†`หอฑXšyFฌ็f–i=ึ2krft™ykฝต,ไอั”ำi36ำึนZ๋t[ŸบฮnlgฬtแปUใYSฏซฤeน่ญ\—!ึAฯ ฟ;Mš4‰่‹MG%ุo_ฏ^=OฬวY/eัŸ๛/อ๙lVิฮ7tvvๅœล'›Oแศ>“M9ช,eจS's žๅด,ส ร๕๊แ ฑ๚Cpษ#Vd\็Šฯqzุrว9็tUฆไฮๅ ฮมC™J็ไสปsิรžตว฿&?Dะเ;<ฤ)]ช‚IU~Žษe~หiW์ฤ‹งฟ`/(สค: Ÿ fืฎ|“,œ†ูต’มัณIษ*NNRyคี'ลuฎ๒dJNIฆ๕INuฅ“R“\eœOแ4๊RำR(E}'งฆzา(KIS๙Bฎ:๋mธ๐ฝ8ฉ(uญำเ+‹ดX GŽแcƒแ "##ƒ*Tจภ๙Zตjลสe1„๎ืž={าฝ{๙๗๑โลCS,๐ฉผ๛ิทo_ฺถm›'^เWC ‚€  'Nœ บu๋า๓ฯ?ฯ‡ำ6ฏฒŽ!J๐ใ}อ5ืฐeลขE‹่๚๋ฏฯ๋œขฎŽ%3f อV[oผ์มร„ฐp?ซˆ‡์ำู*>C !ฒ!2&&T|ล™ณžrิปศ —๒LTp9 —WนN+r‚ห]๕ 7LขCงน›ะค†เyฎr๋8/ฒฑวยฑ^”ป๓ž:ืa๏’Mฤ^ฅmu9ฺC่ใEฟ—uนdA๒สฬ7ศCžญ4,ฑฎื1/๎™้vฟ…pณ*r3ฌ`ม/ฐแHs<&R1ฃห„ปJีhยฦMเh"ฑ™fRว%รคH&•<„’‡@บ@X้๋~NW”ฃ7ศ+M‹Y{๊>„ ๎!›0ญwฅฯช4dp๏บbศŸ9}Fฯ๐_qZZš"MRฉ"OR ข4งJฃB*OZบ+ž‘N้้…(ฝp†Šำ™(Rธe่|aUฆา…T]แย…ฉpzaบ("O๊ŠPํต n233=ๅฑ’€•คI“จ|๙๒t๐เม˜ฒœ‰•k$๓ธ€ภฤ‰ oA๎!ฎ]ป •’สทoงฝ{,Kฎผ๒ส|้’ฦ‚€ ‚@$๘ๅ—_่†n 3fะmท‘ฎG”ภo’โŠ(yM%#ฦจล`ชZเโบ{_๘๚ป#.,๊] z,Mซ สŠ ‰ห5)เ"˜ pLT0)Bฤลƒๅษ‘ฌญ tZๅQ‹‚$wYrJ [ภย ‰ห]$ˆ/b ‘+Œ‚@P‹Xwยป—ตGฬ€œ'้ึโษ{”\ธ็ค‹ะ@ษyฆ.…ŠWฑบ ญJ+~‚็i–=ฏL๔P„”‰–r้b}๊ศ)ศชZขœ๕จ MฐŒู‡*€ ดข๔ธ{เ~U๋เ๖ฟ›lqงนZฅตนฒŽ!ด5o–ฃญ)c•ัrF(ฐ$B,:mูโศีํtน5ึa:เZใFŒฟ•ำงOS•*U่ญทา"1รฤุฑc้่ัฃFฮฒแ๘UK1u™cf2๛๗๏็ํ7ุ6vำM7๑–˜™\Nd็ฮิฃGฺดi“œ4T€ืAบA@<€ ม @<D"8†(มžไ๋ฎปŽ^z้%‚…Lkโ%}๎oบ้ฦๆTแšŠซตlV~+\&\ y,9pxมฎ–ปX'๓b‹[,ZU ซฤzซาผ`ไุฝึmtlถQz\J Cฐศv-Š=บUืขซoี๋p•กoUg h็/ -‚็_โZŽตNkžu่Sท Uฌโˆ๋5ฏหญฑ–ำ1ู๊‚ล‡.orf™U?๒v๊™|KผpB‚ฉวNky่ึi=vณฬWZห๊~Lf๎ฯZ†rญ๗>[ท(‚คŒ&_tzฯž=ิซW/ฺ๊ต+ท‰ี@–ภbฏRฅJfษ'Ÿค.]บฤ๊te^QŽถยญYณ†ฝฦคx: /—๎“O>แำฐเร฿A@hAเ๋ฏฟ&8r…‹๘*‰Dp$Qฒt้RชSงN$ๆ๏ˆ>ฒฯgำแำ‡Ž%=ฑ฿๚ิ„Bl้เK(51๖พช)%!•’’|ึวj…Iฆ๘Jc๎บ‹qถ–#ฏ๕:F™AภIฌ[ทŽฝ–(Q‚๖ํว๛<วGEŠqา0e,‚#€ล€่ฯ?ไคHyบE๘?๛์3&Fืฏ_O•+WŽล)สœA@b?˜Oสร y7Žศ,C”๔้ำ‡ษ‘™3gˆ’xฒ(‰ศ•–NA@p#€- ๐‹„…SฉRฅ่ไษ“|Œpค๖|ส…‚Eฮ–฿{๏=บโŠ+ุ‡IลŠƒU๗๒ุ‚_L8๕ฆZตjq‡ ‚€ =lูฒ…Onร้ธqgQb%ห–-‹+‹’่นEeค‚€ K€˜†๗p8า๊ซฏ๘ิ๘.‘ 8,๐ฑ]์ิฉS„gค%ุGเห/ฟคŽ;ฌสชWฏnฟกH ‚€ ŒภoฟMค๙๓็SำฆM#2วX”ภ;ธNŸ>VฌXAตkืŽา‰ ๑ŒภG}ฤŽ^แรพ\pขฌM5jฯฐศŠ ม!้งŸ~สGฐWนdษ’ญณ†2ดC‡ดvํZชYณฆณ'ฃA@ ฐjี*1bอ›7š5kๆG2tUŽ#JฆM›Fฏฝ๖Z\%x“‹`ZŒฟ0jิ(ชUซ–?:|๘0แฆฒ๐vฉu๋ึE?๐CยยJ‡5jะล_ฌณนb;๛วŽ?Nปw๏ฮีฮW}-ZิWตง๓้งŸ๐ร๔ุcEแldศ๑€(ม_ ศ=ง<๐@X.ภi\ Œ2vถุqK;c (ภาภฎีหญทpkนs็๊–๋๑ฐiืาวu๑ถ}ย†่ืฺN€ w ๋ =˜๗7฿|Cv๏5;}‡RFแoะฮ|Bูท“tŽ=สฯฐŠลvHXฝยสฏpแย๙Qัถqญ#:A้L ฉSงฒี๗ฌYณจy๓ๆƒcˆ’^ฝz๑ˆ’ีซWำตื^œิ‰^จ…’(qาd,‚€“; R๑‹/พp๒0#6ถ)Sฆฐฯ(8ฬยi ฐ}*ะถภˆ P: ฐ™ซB์]^ฐ`Q+I ๐๗฿ำํท฿žoขไภB ไ`Iโ-เƒiEจฯxึ™‰๋ฝ๏์ผtˆฤธฬ>ฐu ๗๎ป๏พหพcผmO-Wฎ?G _ืฺฤTา‚€ ›<๓ฬ3ซol‘ว.ƒHG%kึฌแS"€“๚ขฤIWCฦoเก๎6ขxม๑@Žเmfzz:มสึ%:uŠdžQ†ภศ‘#ู!%—\ยํ"ต9`ย฿o›6mุ฿uมP๐ใ„g4k€Cฎ]ปRJJ ม็QฅJ•r‰เํฌ$`M lAHHHเ8ิ ?ึ]ตฅศ‰ฤฤฤPwg[†ฮ˜1ƒƒ$ฑ@Jีญ[ืŽhหฤต.๐IหA ์ภ!Œ)@|ทhั"์กว%ุg\ฟ~}‚E‰%fDไ๎N8AŒ๐ฆำŽ/“8ฤ3M์๏‡ฃW)Š7…pŒลฮ๘๑ใ)##ร#' Aภ)เ\8wลึ l5นฎ"lซป๙ๆ›ูi|ร† mC‚ญง8i['อPฌX1๖9‚—<ล‹7ซrฅฑ…[>a}‚๏ œj‚@;]Gœmใศ็PXgดkืŽU^vูeผ๕f+ŒคEค J8ตษ  พWaนWฅJv’๐LผdษยัุีชU3›82]Pืฺ‘`ศ A ค 2„ึฏ_/D‰GŽ!E!สฤขฤ!B†whขฤŽ3ธว=a8สฬฬฬไ=๐7ƒฝ๔0กy"Ap"   6ะๅ—_ฮ~กชVญš็a‚t%Žึลข6ร?ศoแ.\HุRg7 <˜็ญๅAz`›ฌuผ9f=rไ“Sุ๚2[~…Gy„}๔ั@b~๋ฑmง"ภษ/ถi"ฦ_#lัาsษS฿-ุ่ภQพีzคผ๖?.ร† #๘7๓†%๚……NRR’gภค,7|ต๑‡9QPื:ฬำ๕‚€ เ@๐›W ƒ9ธ#?SqŒEI=o8๐ๆ"poAˆ’xปโ2_ง  Oˆขฤ3Hœ‚ƒu/ foaq"Ap"›6mขกC‡ฒ3้๎ปณ%T^ฦyๆฬถ<ภ6ดฅK—RลŠ๓ขฆ@hŸ8๚=˜`=†}แ:t่ะมณ%O—™๑๐แร ง๚ š7nฬŽฯqขฌRฅJ๙ท]๒็ท฿~๓)kวจ่ฯ˜ฐธ่ข‹|สSk8ดลw"N}ัXMžูs8M@เ/๙Kx๑วรL3อ.นไ’0tำuนท฿~{ุmทยไ“Oฮ>๛์^wฟ=:,ถุb๚์.ทr™๛Ÿ'€฿ซฏพšœ3แ„†mท6lบ้ฆกI:;๛์ณŽใ,qะ Aแ๕ื_ืŸิูe—ูกL๛฿แำO? ใ?~˜lฒษยิSOฦ{์N็<8ะV„๖ 0 ฉwฯ=๗ ป๎บkงsโ๊#ฺทo฿๘Pล[nน%\uีUa๘๐แe๓ฬ>๛์<ฑaปํถำค๔x๏—_~ oฝ๕–bฮ;๏„๏ฟ^๓M3อ4aใ7ฃF +ญด’ฆอ3ฯ<แฦoŒ‹N๖Ÿ{๎นฐม่๏8 ฉ„?0๐อป้ฆ›๔8X-นไ’แภ 3ฬ0ƒฆ๑๏ว ฟ๖[‚ลO?N>๙dฃฎถฺja๕ื๏๑ต๊ซฏยB -คu^qลa‘EI๊๗Gภpb6lณ๐โ‹/๊๛k…Vˆ5lฟOQˆ:ฟ๘โ‹‡SO=U_sฮ9gร:]ิ‚t<๕ิSœ‹#เไ‡€%L –Xb‰*๎ล5{๏ฝแ๐ร SN9eธ๕ึ[ร{์กษ^-oz #ภ„๖˜cŽ ?sุa‡ย^{ํีๅ2้|ไ‘G๔<สใ๏-b“RHžW\ฑKอfา|๑ล‡๓ฮ;/!#ฌ€M6ู$lฝ๕ึแ๗ฟฝ&}๓อ7แข‹.า฿K-ตT๘๏~vy็pื]w…?้Oแ‚ .ฐSซn!W=๔Pล!d/ฟ๒Ndษoฟnพ๙ๆ0๓๋xrœqฦั๏พ๛.คษ‚ธ<๖้D y!‘ ‚ห „:B GXไ‹าaๅ•Wsฯ=w˜d’Iย|๓อf™e–8Kธ๛๎ปรN;ํคi—^zi๘๚๋ฏร˜1cยฃ>xฏา†rฒๆšk๊;L-ฯoผ๚๔้ำ)๛6l|๐AMฟ๏พ๛ไŽ;๎จHArุBฐx .ื^{ญ’GMwygRื?๑ลท'ื๒ ยyโ‰'Bฟ~’๒}วpศb็N:้ค.รโrบฒ๏DIWะส!/.Ž€#F”๓Ÿิn~5๗๎šx_฿Ÿ๎ืYgภ€|ๆ™gึมฌณฮฺป;็ญoI~๘แ‡ภฤžU)dXลžxโ‰3๗•I-a4ะpธ๎บ๋:Mุ3–sฦoฟV'๎=ัœCซอš /ผ0Œ9ฒC J™L—›ธCx€5ฺยh ื’gžy&lนๅ– !@~4Iจญด)˜จื/-ฟ๒แฝ๗Sํ4&*ษ๓ฯ?ฏใจคP:/Z-Fค?๖ุcแถn G}t’ "…๛ขšœyๆ™แ”SNฉ–E5b žะ๐๘๕ื_•œƒP:tจ’8h๕!!ำO?}‡ฒ^xแ…ฐz๋i pึ๏X“…ƒkญต–๖•~ฉr๑ว+(›;œ๏ใG}ค““ธขJ„RWฎ5฿w฿= 1C.Ž€#เTB-9ด๐x™f]ฅผuKGฃค"๊›ฅ3ฮ8ฃ$ฬ{I>พEh’ทมpฺ/ฟฒ$ซymา๚wSV๕-ฅ’L”Jณอ6[I&1๕ฏศKt๊„€LVKbQฒคห๗ช˜;่.ๆ%™ไีฉE/FHmทh]ิฅ21.‰)’–ษุฟฝ๗ป$Zส— พ—ษuงc้„#F$e 1Qถ$Z@šMดZ’c”YKV_}uอ/“๗ชY…,Hสฒฃl^ั J๒<๛์ณ%!JB'i๔_4uJ๗sOู๓-๑C้pŽaท๊ชซ–ฤ\วภขัaู;m๙^ู9<๐@‡ใเd}อ›’h๗่qฮrIฯc+DOr“O>™”G&–ŸvY}\๚ศoส/']นึๅฮ๗4Gภpส!ฐ๖ฺk—Dcฐ$šqๅ7$ญP%ุฎโฃีษ9ๆ˜ฃndไ8Ž€#ะXXกg%‘U๋ฅ—^ZWYอ=\ฬs\บฑุ{้C˜NฐB…o4ฒ >/>๘เƒ€&+๎ฌฮ]ะ†Y`ิฯ„ 8๋ึ\40%๙ไ“Oดฬrf.Gu”jiฬ8ใŒชVฉr|t๐ภ_f,h;เkฤdซญถ ?ฐ,ซQ‘”|i`ยƒmจ$˜Q ก‡1‡ม<4Y„0PํLS๐wƒiํฝ๚๋ร้งŸž๔Ÿ๓\pA5ํJ—ร14(่— &5;๎ธc‚ู’jnQAวT›ฟ๕ฏI~ฺม‚ๆ ฺOš(h™pะสAb*๘a,Nฟ๐ฏ ืƒพbŽƒ!˜^ฦ’๕Zว็๘พ#เ8ต@ซํ6gน๙lาBๅ#V’—ปฒิbิGภpf#pไ‘G๊{\œป–ฤ๗TI%Vk]ข" ๆ%13(‰?‰’๘ฺษิL!tE]œœ–ฤfIยL็53“˜9่ณ)ๆB™›A?z่!ีžจv’˜ฅ$ โฏคSV{/ ‘หว\ฺ|๓อKึ&ดTL{A&แqึR|ฬ๒์ป๏พ๒ค˜6D:e3๎4 f๑ร‘ิ+ไWบ˜d|JฝโฤดำqดhะvAหยฺfyำZฆ…">๙:•“5aุฐaZZโฏDOC๓ฦ๊๒$) อKOo:่ ไฎ{๚ธiก ํbไHKึkm็‰o’็ผ๛–ไ[Gภp:! ไHIH่’˜v:ึจ„ะจ‚ปZฎ%]Eฬ๓;Ž€#PL˜lส }i‹-ถ(ษ๊ขธ!N\ข"๐๎ป๏–ฤIฆซoฟ}ฆfbยยdRVํK๑$3ำษMศdDษีW_นv‰ฦง}-15O4˜t6ฑ†๘Hห9็œ“aขวyˆh7$๙Œ ]œ~&“sซวถ(•DœhyโซฃCั€ัtH2„ษบ•มk %ัJŽ‘,*™ฦpคyฌ<ถ˜ฃุ9fาr๙็ซi ค๗Ÿhๆ”ฤ™j ฬ!CD ค$Z%๑ู’œO{%2NR>&˜๛Xน˜7ลุล“hื”$`@‰s M8ฒs2kๅวื“๖_sอ5$'žควฆ:v0๋ต&ฟDเI๚!rญ฿:Ž€#ะ ‰tS’(Yน.พฦ๔ตHyiซ้ ับข‚XKUว;Ž€#เไ‹€ ีG์฿ีผh8yยฤC@ๆ{)ผถ. šงฮ˜‹‰฿ดš๗*๗ณฌชซa–]vู.ิ–oVgŠำฦ\Y„0ถ85ม์„PฒM4‘F"ยอK/ฝคฆ2–‡()˜๘ฤ‚Wย#ๆ€๓Ž 7P๋b"‚ฉ๏ B#8G%:‘qškยu!ข ฮ^Mdrฎ&;๖ถB`™ไซ#Xขส „ุฅ>"วเŒZ]๒‚๙”…@ฦ‹>ษะ)๊e˜yๆL˜าฮXœพ~srฬˆ]vูEฃ‚ฅMZ๔`†804'ญdท{5}*f=„86ม้ญ9฿*ŠซดโEอ8ฮuHG*2Ÿrแžณ^kสฦŒ s*คZNn5ฃsถD€๏+๏\ั@Sณส<@(Q‚งqย;Q’วฅ๗:ฒ"€5ถ์/ฟฒaฯ‡?Aุ?3`ซ$ุฐฦo6ˆ๓โอž0W Dลฟ8Ÿ๏;ฝยl2ภ—•i‚ขcˆศฺ%ow‹# ฮD5zห็ŸฎพxGW์ฆe้K'D„)ช-†ธL์ำam+ต„o็ึ|X@ย”๓‚/ ั\ะ"oหยพ1DsAำŒxG_XzบNB3VD๐—?ัd #๘1aLI”B„G|o!ri/u‹œรทŸFlXl!N(|s๐>#ิt/พใ๘'1ำ"}๗Y™>„/ฮ"ด,๛๗SL1…†ดŽ๗1.k๚bRŽ0‚ธ2?&Dภ!N-ม็ิบ๋ฎซู ,ฺ#N!DถW่S9*ฦคฺตฆ@ฮ%’โQ็็8ภ๗฿ฏ฿0qZ]!W}“ C”เ˜ŠU >ji6ผพ]๖า์0ภโžฌ$ dp*ฤ@นœฮ +Hฑร4๒B’0ศcp`ย mฺiงตŸพuZVeq๔Šฐ๊Šร@ด™ฐNุล(";์ฐƒ:nบ้ย%—\fšiฆฒอไfโŒSK45pึYD๘YtัEีiฉMrณด็hอˆYHr:1' aก€oฤไหTSMUถH๒3ฦ+Gธ้`'ข๑);m%ํ๛๏ฏ‹–-ฤซฝ[ะvก}๛๖MฒฐภQษั.˜vZ7b๒ข}%ฌ0!(Yแฝs๗w‡Oล๛ำ'คœIk[๚1ึXc้Ÿฅูถ+ืrFฃ„I'ิN๗ญ#เ8@ณn้˜๊ๅ!…!Jb’v%Jฤมšฎึฐส๊า\b›^k ๖ภุk=๖ุš„ /๊ฌถbฤjZ|ํb[๋8„ชลฌŒ‰๓4+ZPฌช๑pqZ&ุ—Jิ O‰ฟT(Iซfฦึส˜x฿Š€8๘ โ๐SM๐yaๆqห1i \0vิ˜›MŒ(แ๛#k›า<~๛ํ0๏ผ๓†iฆ™&—6๐อE๋vฺๅศ”z4 B๖พ๓ฮ;แ‹/พะ๗ูd“Mฆ}…ฤThฆpร :๖ศาดevuื,Y+ๆiฦตฎุ?เ8ฝ|lฑ อโE%MมzwฒDษwัIฝฒ/byL”๙˜๓qqiฌNagยช+ๅVฝQปeELยฺi๖ใŽ;.ฑทลฎ{e$vžG๑vฏ้รIjฑ.อC@ยชชuLt5ฏ5ญ_3ชฌฬใ€ ชMLธ฿๓ฒณณ:}{๖ *หญw>รS๊ฺ$D…ภ #ซผgŸ}ถ:ด็ฆuxŽ@=ภ็“|˜KโP4>เว‡฿,๚I r0qฦ‡JQจ ฏVn Z6hฤโ(ณbืhmๅ+๎}sz?sอ5—๚Ob^–๖/ีจ9Qา(dปQฎMึ\ฃคเี้4Cp‡ฐ%bGA ulo๐จ๊ะB9g๘๐แิqFฤัฅ๙ุณ‡รF์ๆ]๒Cmœโ›‡( 8z…4!์j:ฤh~ญ๒š๊เ่›w<ค8ฆ,ั…ณะ Dฃdฏฝ๖*”ๆ>1XBำ‘ถน8Ž€#เ8ฝcเ4ญศถ#J6ฺh#5wp7ฝiๆKdls‘›oพ9ฤก๘ชต‹1a ‰‚)‚@„เ‘†fPSj๓:๛,ฉVฎห& \o'J๒ม;] ซ๔8˜ดpŸ๘0@ ฟ@;๎ธc:ปv๊‚+YQG‹ ‡กDAdะ A๚W)‚‹UŽฯ‹ 7Pอe‰&C(xLศ0อ$rKฟ~,นฉ[3+ล—J์ุณฉ๒สGภp ๐}&สc๖๕ึ[/ร=ฯR’˜(AuตCFฺชถk”๔ฦ๎n DฎมgHLxd)‹‚L๎pP‰ษ ย ใใ?ฎ๛xผgะŒ`{ัE5หฝVๆ2!๐ทฟM#V8Q’ ฎ†eยก5‘!ฐ“g qŽำG4N˜ศบ8๕D€ะฆ8`ลwัศะf"ผ้O?คšƒึ{MณJ๗เ1วฃ$+็rbЉv"d ค $l„oฯึV[mฅฤdฺไmpGภpj!ภ๗™ล Bง๏ฑวa๕ืฏuJ]Ž;QR๋SNเˆ[๏DI}๐์N)๘H8๙ไ“๕TBgฑู}๐ม"QplŸ5ฮ๓bdฅ`ฤจ4฿‰’ๆ_kaƒ1ปaโŠณLmฟ%ฌป8B3ฐG}4ฐ}๑ล๕=MศRBล„0ฎDMฤƒ‰Cน๑SJศ3ด๏ ŽSQnถเDy™e– ้mอn—ื๏8Ž€#เTCเ‡~sฯ=w`แ™ฑ!พย๒ย% €๙€ใำแ๎ป๏ฟ๏๓่ก๊@ฅqขคy—ๅึ[oUฆ’ฐ{YM Bธwฃ…r๗ซšต1Ÿ้sั<มy%แญ\Šƒ€%ลนึป&ุค- &„Ž'จ–฿ทŽ@= ”.t#FŒx„zEkdฬ˜1Jž0fแฝŽCL's„ภๆ๗้งŸN:้$%]z่!u˜Yฯ6vต,๓มต๑ฦซๆKWฯ๗Ž€#เ8ๅ€Pว“๛—ฯไฉFเ๛๏ฟW๊ P?[y-œ9QาํKV(ฉ?ฆ]-"f๗ฦเ‡}qDƒธผ‘#G*ซษเaท้ฆ›๊พ9อำฉkฎนfโไ5uศ6 ›”ป้M“.@…jัึย์†Aซเ˜IเS‚0ยห.ปl…ณ<ูจ?แ8ไ†8y๊ฉงิดmHqศhš บส*ซ„w฿}WrŸน†0d๑’…๛น™BปVXaฦpย อlŠืํ8Ž@K!ภ{ํA"‹1Vqฉ/1Qฒ๋ฎปถŸF *4ฌฮ`“~ฯ=๗จŠk}!.~iN”42๛rฬnศ˜fPL4"˜lถูf:กณ฿ฌDฦQ,ถ˜lนๅ–๖ำทMFภˆˆ1&:.ลAศ…z) fzƒFI%ฌbzs๏ฝ๗†gœ1ง]v JkีŽ}ŽXk\b๖ส+ฏTจcู{๏ฝ52GฌyBˆำร?<ษFDl๋pk)ธฦkุO฿6#Jvy็ภ๕t)จด] "kๅ•WฌˆM„็Œgหลh&๋'wyงšฺX„34Iุ‡@ˆ5๓nฏ%8˜€บ8Ž€#เ”G?iY} ~๛ํชe>๕ิSซฏซ๒ฅzjwpขD4Jฺ(a•!tŸKs@ซฉVXRยZTŽtkั6๔C๐ซpโ‰'๊>sฮ9G๗๙ทิRK…aร†…๑ว?I๓`EGŒN”ไ}Wjฤู5Ž^1m#œ0า๐;Q๎Jyžืh/ฟฒ›<๐@@๛ยฦcช“ทเ ขฑูš-y๗๋sŠ‚„)ๆ{Lภ็œsฮข4ห‘Bภฬ๐Yดg>%ฐƒ๙8œ|๒ษU›0Uค์!mO”ๆงhL.‰rภ$ิลh&q@•ŽๆK/ฝ๘อ}‰ึ๗๊๒ห/_ัฉไ#<’˜ึœuึYช๎L_,๏ฒห.๚โตพeฺฅyเg†wฑูำผ๋ตfดI0a‡T๛ฌ„FปdฺiงอZŒ็srCMYˆuด'™d’๐์ณฯๆVทU๔๚๋ฏซi)fฮถ0cวŠพล7ั3ฯ<ฃ฿แX ำ$“(Eh๔lฝ๕ึaœqฦษฅ;hAึb;ฟฮ:๋ไRgั*!”6ื…o่TSMฅ&๔๑ค’qำM7คฺณ„๕ฬCŠ|]=๔ะQŠเ/ˆ๏ึ<๓ฬฃ฿14$]Ёภ?๑ฤแuึ็h$Cฎ๐พwฉ/F”ดmิ›˜(!rศภ๋‹ฐ—ๆไŒภำO?ญ‘pๆ˜cŽ5๓ฐcBp๕ีWLr0)pqฎ!ภ@Gฏุซโ@ํย /T“˜ด๋คฅkz๎vCเีW_ี koq6๘ห/ฟจ ;฿J‰X0‘eภlยยš;Dส๋๙์ณฯtขKฺmŠฦิตื^ฎฟz5-ณ๋€+>pLะdŒƒB"—ๅ!Eพ.๚ำŸ4Jb9^xแฐัF…UW]ตโ"\น๓<ญœqฦjžศ;&ซ๎๋ฎป.xเa๖ูgWŸj๕oUผ!ผqฬMิMดWจฏV„ฮFด%๏2!e็škฎ๖ Lค>tฌ๊ถ'๏›อ๋sG  L+ฤชฑDย๙๊ซฏtขฤ`2r์ฑวn…nzบ ภไ–Ilั z|ฉ0ฟๆšk4สUนฮฃํi๐9nD &”ฌฺ็!hK,นไ’ZU;8Gซ็_๚—^&kๅํ>ยO›๐^พ๒ส+รฬ3ฯ‰์ฒ<๕๙บเ๏Ž๛ปšL8แ„-‹ L‚]๒G`่ะกบ๘2๓,‚ฆ๏ฏซฎบ*ห)™๒@‚HkhฌYว_ล'CHV ็ํญ๛1Qฒ๛๎ป,๒ย„މlzY%tqGภpj!@(>ˆV’Yน<๖ุcš[˜โ ฺ์โ8!า~ํตื -ดj4 ฬ7Xษฝ๑ฦ;5m‹-ถะ 8‘…0ae–Y:ไฑ•zh• ˜` ฑ)ˆ&ิ้!ฃฉA[‚w๒oฟ…ุนป&๖โ_uภแผ๓ฮ๋4Iร|dซญถา๋ม๕ร,*ฦ๛ ƒRb%ํทก‘๑บp/b–q๓อ7&฿|›€บ>๘ <๓z฿cŠKšxŠ๙~ใ ขd-Q0O?๔L™น๏„8pCฆ“ฃLD๖CK–ํxใ>๙ไ“่h๙%–X"\rษ%ๅถHj%8ผไ…‹F‰%-rW{7Gภศ &ฌๆ|๙ๅ—j’ƒf" +น8ํŽ~<kอ;๏ผแ†n( hบเ™g8&ื๘๙๓Ÿฌฮ/ใc๑>2™( ๑ภj<Qฬp˜0#ค1Irห-๕wฝ™)ๅแg “๑ทz+ั‚ก8o_pม๋Ueฎๅ กท฿~๛ฉ฿ภtล›nบi€ผJVq>ศ=๖ุ# แกํkTม ็๗๕”"^L&bํLณหESlโžมฬ wm7๛ุ้f›mิไว๑Y"๑๘ใ๏นRฎ\|-•ำแ๙ažฬ๛@L0šแ@ชฐ ”•ะ)WgoHsข$"JาถงฝแzGภpšภ1ว.บ่ขฐ๋ฎป๊ภ?&จ่ณEลhWXตF]ฟYฌlE๖ูg5้ฐ๖0!`‚BTธrŽYGญ˜tC†T2ฑ๒ุ2ัdยูy๎น็ยฅ—^พ๘โ ์SญLV™อ<งZพฎcาM`ƒ๓๊Fiฏเƒห'•mทN'tRKNถด าƒ๋มj8ฤ\-ฉ‡™BQฎ }ๅžฤ4า ํงXbณ›ZNq‹ ฉ ฯ๎DMd? ทลI5šGอˆๆี0ะผƒธ…(ฤi|9๛์ณรษ'Ÿฌ๏X“๎ f6ฑ๙๗ใ™Jฮัฐk3c'Jœ(้๎3ๅ็9Ž€#เDเฟเศ#T‚„HFD๘€€วŸI<‰N๑]G ๅ าฺhุ*:อณซฃ๕‚iBฅ‰!ซ๙ @“ƒึน็ž[I!ฒSม n55xˆX&Q8$BฤOำj๕|œ7โะ–๋`uโ‰'vชG{๎นg อDฺ๋Ž๐e‚f‚Fฤฐaร*šฦช}฿}๗ต์ถh๖`๖5฿|๓)‰MyD™๋)ัำฬ๋‚ึ ืฌFŒ‘˜&q/เฯฅo฿พ ฆฅ@ฤ฿$ด_6ูd“Nัฺ(—t#‡๚๗๏Ÿ”๏@ฬpฝqYPŽXŒ๓ฒถีO?fšiฆNdN:o–฿๑ฤพZ่sขC๑eb cc๕d้ „ร?ะDƒ0B-/ป์ฒjสde๕d;x๐`ี รŒwร 7ฬT&<hZแ›งš †๏‘rn&่๏/๒ Q‡๙Zwค+8๑~!l๕kฏฝฆUแฤ–่hี4ฦฒถฉ+ํจV&๗,ื™ถตฅ’ุ๔ฦ5Jช*~ฬpG ฌ:cŠCจn-฿|๓M@ุ}ฃถ๊โดฌR3๙bp^ค๐•LP5gาhยคzmท ˜xค'ˆi  ›P.ถุbแฒห.ณb2m™l1ัฤ_ฤd“Mฆf4ๅVhm๒Dกดญ^H‰˜T(W1๕๐^ขฝๅ&‰ๅฮนๅ–[ิ1$ๅrู@žดเ3‚˜~ G›ฮS๋7Z|5@€ฤย 7?ณฮ:kœฌๆ"ฑ™(D 1็“\฿,y+4ฏ๋ยทถแ3$kˆ^ˆด…ชif=๙ไ“Lฦp4ุci๗ Wะ01แuC&`~smทู!อwึYg%ฟm็ร? Dยษ'ย=‰๖D"TZธO0ฯ0ำ'๒sฯnฟ๖้ฌ๊฿็พ๛๎ำkฮ;๏จฦTLฅhw|โธ”EdวwฌH–{๎นแ„Nะ|๘€03ษฺฬนะ๒€„J ํƒฌเ9MKึ{‰๓ธ๏-Š ธวื)]nญU4ฮvyg5๕‹ู>คฯ&ZPค.~Pธf1ฆkฌฑ†“๛๏ฟง๋ƒF๗+คฯDใ™ฅ—^Z‰Zสํ N/ฝ๔’พgํ9ๅ|๎K๐ถถqbถษKC)Œซpž&=ปาซณาึˆ4kะl;gฎ1Q๒ะCUT1ช`+คร #ๅ์[กGภp๒F€ษ‚9Zdาล๊53ผฤ3ฐpqฺ้C† Qํ ฦYEิช๑)„?ฯg,;ฌฌ2‘E˜ุb^วoฬs319a๐GАฉเ Z!„ดM“%L0อ'+พL๚๑‡ยBณ”JB˜ภ‘wนๅ– Lห‰Mˆ้ไื+&&LVั–™d’ItฒYnี-’;๏ผ3ิ# ฺLฐฒ๖€5f fnรRpCxท2Y7Gคฝ๙ๆ›ljJžื…ฦ@@ €-ุ๔d๑9Lพyุš@จุฝeiถM›—0 ็นฐถZ>‚S์๓'๖ฉ.<รia‚ `F๛์๙๊J_ะุ0gอ้:์7Zค&ฌาา่;ไD„&+1ษม}ƒ)I%VŽ๙ฝเ7“NดสExข<&็DQ‚ˆK ŽสcRŽถpO5d‚ [q't5ืว„๛3ฆ C}mr-mชลD™s บ˜Ÿ™ฐ๐ภsaˆ†วโฒ,[[ฐ`?&บา—ุi3ๅะ'&ๅ˜่a๖„\qX@จv็ “Z*๔/ึŒโ~แน'Oฌํfd-˜@@ฤ‚๏|˜ Mฟฝผ็Lร,๐mƒ†H์๘7.'งm‹SL1Eภt“<ฎcX#F8Wร Gฐึ.ฎ1dื2ไึ[oUโƒ:ฉ‡:bแžรฯllh๗^WฏWฦ๕ุ~ณˆิซ !๒)‰จ’0ใ%qUˆ6ๅ๚.Œsีz}Ž€# ๐์ษ๊คcัยศคAฟ12ุ-}๗%QS.‰อtIว-k๏š#๐_dๅท$3Jข1ั+ ‘ศ %qยชฯ,ใ#d%ป$ซซฺ?t่P=.“๖Nวา 2ฉJส” EIด J2จืlB$ว(ณ–ฌพ๚๊š_&GUณสฤ-)WศŽฒyล„!ษ#dJB์–d1Iฃฒ Xขข์๙y%Š‹ุ™”ด Fีฉ ดีฎAŽว อธ.ดษฺ'ๆ_qs’}™ศ&yd2ฎ้ข™˜คq>Xˆ–Sู{ำ ZuีU“s,sฌ~ถโ<ท$e;i+QฉSต$IYงvšฆ‹๖A’F๙ฒHไ—Iบฃ{ŽฌMขAS’ ชึk,~h’2…„ัcใq_ฌOๅถข5ีaพ*คŒถO'ลM*‰๏ค<ฟbf”g,be ฉ้โ8Iณcถฒธ$WI๕’2lGH?๛^ 'ฑๆH๊*7๗‚จฤป‹๗ชตญฐVญn…() 1—ไแY๎J;ฤ_K‡๒สเ>คnฦ้bบU.KCา C”#š%ๅ^ถ ้}ม ๅpขค`ล›ำ6๐์๑ บด6bงญE5โ ฎ$ซ%ฑG.‰mqkw{ื๖ศJiIœแ•ฤ7@ฏยBด1JLvx?๓'jเฺoืZD „สa‚ศ$.›์X]๑ค&ฮg๛6๙ –Tv{ๅ•W&ํ'ท–๒ว&#YFฐ…@‰๛Oฤมd‡Iฒ•“็–I”ฌŒ'๓จNีห wrœ `%iึu-‰ค}ฒ๒^ถy11@~ฎc<9ไบp˜จ๕ณผlํ๚’O`$‡ 0นํžƒLH“ –Yl%๙ศO™Lž๙ณ๓ูR&"ๆI:X˜œŠฟNผ-=&n I*‰hOhน๔อฌคˆH1ัc้็ญซ}ณฎคศบJาำ{)M”@ ANˆIR โIดE’vpo˜ˆฃlM8Kา๋ฬ6พ6Šb†‹3fŒž'ฺFI~0ใ}ภ;ŒณHVœ(ห๎ปธๅ๊อ“คM•H ๎'{OQ^WฺQฎฮtš%r#มLrร8Q’พ=ท#เ4'Jpqสgภ.ชห%Qk.‰๊sI"n”Dํณ$vฏ% qXœ†zK:" ŽKโBษ’:ฃขDลป$RT{ขZAฌ พ„ˆ›ธYY<๋Lll•—g›˜ุdา๒ฦว,Oญ „%้|” ‰ภฤ a๒leBค%^Yf๒ˆด]˜4Y9lษk ุyLดEฅพ0ฺ,”[K „I)คตษ๊ทญ๘ขHމ“RKึ $˜‰LM‹ฑฯ๓บˆ9Aา>1 Iฺg;ฌ๒[฿ุŠฏ ;”l™X›f‘ๅๅ>dี=ึฦฐ{…vŒพuU0ฐ๓Yอฎค๙็Ÿ'“#๒งอF0!ฒrPฯ7A›ฯา1มhึu‰'์\x“<ึึ4yaakไ˜ๅe Yfไป ค‹ฟ–๘T‡„มดฬฮง=1YโุSห@“„ 8ฯ5š๑}`๗!eฦš*_š•V+ฏผR6[|McR$6ใy4ำสฃ_ฑtง/โ็#i[5MฏžKฑฉไG๚žๆy2Œbขฤ4Gะส1มฬŽผ\Kฎ/ฺ&\'ฎ็bZˆ™J,lV>คŒDนQs๎ด˜ UธNhึ3 =\[#฿ฒโD{ฌžjฺCดM|C%ˆษฟธ๖ฎฅLHวฌํฐ2ภ \$น%uุฑร๛™=๓็:ฏญQเˆ ็k2ธ „๗“ีu Wห9cฃฺใๅ:B€H7202้ีะ’iง•ชทZน8ฅฤ‰ก Žf qŠƒF!ิ!#แ+ ๏i‚ใฬดƒRธโˆมก%Že‚DA โŒSV8ีู#N(‘?‰๓B‚เdTศMใ฿gœกe„IาdBข“„ํศ๊}ธๆšk:8ฑญhu‰ฃXB“ใ๔‘๗ ใ\™d้™DŠก|sาQwศ@˜Q"จศ$;ˆo%m'cd๚Fไ!4lpยIฤG ๔ มมฃL^t?๋?œ]ฅ#1๓SN9ฅ†Žฅo8๗ดgถผ7cฟIt1ข•ธฑ 8ถ”‰ทโะŒ๋B[/“4v5"ห +ฌ แขอูฉ๘฿?ž!'๔—S๊ภวœฑƒ]Šรฎ๋‚ .จใz1ทH๎3œโโ ณœvุœ๘๒<ศฤ_๏ฏ8ฬˆzTKๅŠำX˜ำ^žr"&-ษ}ŽSOฐฟF2Wˆu๐)fdz*ฮ7ู7‡ว“89ŸU2R!ฆนึ&้ NBq‹๐ฬk9žKž—๒ูขU๛๙ย /tˆฬ…si"ฐ ิIBˆ้˜‚4๐ฦ๙qV'ำœร๛‡็บซbŽtณโฤwภB4 i„pฉX%แœ‰๘„๐.ฅ฿8ฃs!uๆสผUˆx=ฮ3Nh!<2]/Nโ1ถผปˆTXNˆ่3อ4ำ่ป%ๅ๒ี3อ‰’zขูรฒœ(้!€~บ#ะŒ(แcมGรฅฝ€,!J“-†&xดg+~ฺ ๏mK" ศDšษ7ไC:ไh3:M;ˆ˜aชต‰ึQGˆ’YอฒRซษฒโจ๏p&˜ข‰ขiF<ศ*คNึ-=]N<'ไc1B "JU!ช ค Q#h/“›HB,lณอ6&’œ qBู6๘็{ฤ$5๎ฤdHœผุชIต๘๒้๓x†ฏ]Mธ&ฦดืZเ8+@6ศซT.mdฅกœ‚.ždฒ_ซผrๅไ‘v˜„ๅƒ๎DIhณ“ ,X้e J(NาD]' ลlตทสศ†š 0๙d]‘ฮVrฯr1G…I%฿HาพCำN;ญ~ฯ‡ าibf5“M”r„‹‘–H‰xb กภqX,งจ ฺiJา )RNb ;๖ร† ำพ2้Xiฅ•t‚ถ“ ฦ8ฌฤ2)aฅ„ี์๔„ถ qI#„/šBF๒ นVMw„ '/ด rCT๛“ฑ“Cฦ้Œฤlต๊Xฦยฆฆภคอำ4hๆuต~ีโ\CA|†่ตW(ำย‹L‚ายไ-^Ha/พ:,คฯ้สoq8ชZ+,ฎT&oผง˜P›0แ0`€lฺ๖ญท |ซm‚“*ฦoผNํ๊-ื…1Š๘แPRม๚–๎ ไ“^[!‡ะƒหj๖†FˆiฉP6ฺJ๘&jiLคyฎ32N†ุB[lฑpูe—้พ๘คโะY'ฅ–Gส?&๔้ฑ=ฆ๔“๋T๏์๎๔…๛B“–,R{‰็R‚”1{ต๙)๏ p฿&ษ;…I}์2—แ]ž#‘ฤFJก™ยธ" "Bฑ)R ˆา,81๙‡˜zAvbึ’U(›{™ลP*Iึv ™ƒน"~\*ถขˆ๚ ตหiVjGOา C”0yใgฒาฮD ำT'ซ]ุฎY&ง6IฌVงหBBืH&นฑV•c[>๐ผj “J๊ฒv.ƒ‚Zไƒๅ๕m}(w]๘ธ–#๏ฐ=ฌu}ฤ3~@๕“3Lw5aล"^ฌ”ทigซ †๙sขคŠํ•iฦ;Œม#*๕'๏ผ๓Ž๚ˆ}ด*Œถ๒จ๎ณศ{“๗gซ ใ'&จธ—[ษnDM๓‚o&4ๅศ”zิหd UCโเQะ ฏLผาf/๕จณ^e ยไœ๏ฟ๙"จWู•สษ๋บ0bBˆ1jฎ š๘์ˆ5*ตต+้iฟ#ีฮE#%ญ`๙!aธงxf c–Yf™ฬŽ•ัำmฝ๚าำv4๒|pฦŸM- kƒiู๏vุšู}ลฏา3#‘ Uณ ย฿‰ฑ o7(โC›eโ‡vCฺ eบ้ฆ ฌŒคUฟ,l$/zีฆ,๙ำ๕๘oG /Œœษzฏiทฏ“ล$*.ว๗[VPฝe๕Oย!ชm: Npา่โ๔&Xตไพ•H%๊@ตxก7๕ว๊ด+ehณ˜cีดŠ0ัQRหq>>wƒ>X)็ัายh”ฤD ๊ฮ๎0/ห๏u8Ž€#เdE‡ภh—เGฏ|ุq ˆŠ3ฺ%„BtqŠŠN๒ูHHY‹สPิถzปGภpฺ|”เlœoๆ7•ำ$4r T๐—™‡8Q’ส^‡#เ8Ž@ห pฦg„ำN;M#jlนๅ–Jš@ž i‚ญญ‹#PD GŽ?xu8Itฬศ\Gภpf"๙๑๓ฯ?Wtโjm#D2&KyŽต I”Œ1Bใ$0พuGภpŠ„ภใ?ฎZ$ใ?พn ปx๊ฉง– ฑXคv{[ฺ›oพ9œtาIjใ7B-บ8Ž€#เ8ฝ"3}๛ํทบ8•ืขT!‰bJท›s›84แtซyช&ึtญซฤRG%<‹ฐ"š%ๅ{๏ญ+Qตส$๚พfj ฮฌe‘w฿=,ฑฤUณาgVy‰fRKVXa…@ˆๅZ’ตฯ\3ผYื’z_—ฎ”Gฮ9็œšฯืŽะจต„>ใŸกVhgฺHˆjยๆีB๕^uีUตฒ…ํถNฃ6ิสศฝH_ๆž{๎ชYฑGKเ์ณฯฎ๙lU-ศถฌ‚`Šsํตื๊ณภฤยtฒลCป‹#Pnบ้&u˜#Aพฟ„MwqGภpzห-ทœฮ๑pJŽหŽ<ค0D กqa‡˜คต#QB_๕šื|โ‰'ึ‰_-า€Aฮnฒ แ†ซษ๛๏ฟธAณส}๗Wsยษ›kE˜hCZT๚pqวUห’›vฺi3…a&f๗7฿|“œWi‡๋ย ดล„ผRL๛tูุ’ื"!้ 6YฺHŸoนๅ–บ%๔™]ตฺQฒำN;…QฃFฅปุ้w–{‘“bbฑS!Q}†จE”9Dœ๛ZฯVTผ๏:Šภuื]งŽ^ฑŸ… มั+„฿พ๛๎vqGGษ(„>็ไ]|้ฅ—ˆiG @‰'ž/ผ๐B`ฌ๒ฺkฏา4B}๗ภ8pึYg ห.ปฌ’๊จวหtZ•VZ)|๑ล:ฮj;ข$vๆ๚ฬ3ฯ„I'ดฏqล>i๐ๆ›oVฬำ์_}๕U9rdอf`๗œU#ˆ‰~-แ^จ5ัญU†wช!เDI5tX{๏=ต›e ฃืQ#Œ,ธเ‚Jข@ฺน8อDขอ9ข\pมมฉ™ํ๑บf!@ะ"™vm๊”;nวฬ3ฯ๎บ๋ฎ8ฉn๛oฟ}`!Yjฉฅย฿w 5_ท ผ G …XuีU5ผ=Q0ศC ฉQาŽD f <๐@๐ํ}:ดอ8Ž@GึZk-uFŽNดK๒ยh”ะab"3ay๎น็ฺIlข–ล/E;แโ}u๒@ภž?ื่สํ๖จ๗C9$ฐŠะA…9็œSษ‹’ƒ#G Oฎนๆšpแ…†ฯ?<œxโ‰ŸP.ี`โฦ๗฿ึYg๊™จ’$๛์ณ"๑€†ซภK.นdSI“แร‡‡!C†$WM&[ƒ Jา๒!rวฆ›nš˜ณuิQa“M6ษณ ^—#ะ๋Xoฝ๕~~†š)I=:่DI=PฌCๆไ3‹ำา:T็E8Ž@„€%พ[W˜œ2f๕ะCี•|ขไเ,p›mถฉk]^˜#P ิ/พ๘bu†ว$ง•E"๑ฅŒUu&‘Dh#๚฿Lz๋-M':฿ภsm๒gŸ}_|qญ๓๛๏ฯฝ\;[ก20ภ๏xใ Žธ‡ฦ{์0ำL3้ต๙้งŸ4‚าเมƒU[i๕ืืU฿ธ8HLฬ!๚๗๏สe็ฺืmAs>4S>๘c%hร๔ำOะ4qqสเฯM,ˆ’ถึ(y๙็ฮนชฺ›oพนF0ฉฅ๒-ไGG ;˜3eื(้z~N-y็5นyใ7tKsศVY1อiฦฤกV›x๋!ภd‘w˜1ctา๑Pมม์iงฆžz๊0๙ไ“ข์}๗wšฦq&“ใŒ3NงcJˆ'ณ8, f๊oบ\ฬทฺj+%ˆ๊วป Rซœz๋ญJnqกนฤ_น๋ธ๑ฦ‡w฿ Iธ@IDAT=L5ีTๅŠiHmb ยบใGชูYn Z/-h๖๑๚‹Œภf›mฆZXD8อ๋]\:Œํ+ปํL”`~tส)ง๙>๕ถ9-‡€%D…๐K-wy ำ!&ƒL  ฃŽอ<‘ฮุโHะลh$W^yeธ์ฒหtฒ{เๆ5 ZŸ0Q›cŽ9ชeIŽอ8ใŒ?+)y ค~,็lฐ๎๖omฺRจต-๓ฯ??,ฒศ"Iึ_~๙EM>๘เ$อvศฟว{่ป0/โ 3 ท฿~š ~,P6Kˆ$Iไ#“ฺUcฉY๘{ฝฝฦNธ็8แ„r39QR๛„ๆB -ค~Zœ()ศE๑fด F”9f: /ผpอ๒บ›!6qฑ2จ—6@ๅ-๘z™oพ๙mเ๎ดำNy7ร๋sz;๎ธc`ฑ้ไ“O+ฎธb.mwข$˜ฝGภ(2ผx_~๙eu6WไvzZ ุั+ฮ]O=๕T]m…Dูrห-[ซณ›ฆ#@hTVฐ!J˜่ฦ>šธ5เ๑ว„ัFx/ืำัˆ`รไ๘ล__Aรรข๕€๑ Ÿ|๒Ir,ฝ3๓ฬ3๋„sกนๆšKฃฆ%Jใ{๏ฝpฌŠ“ีฌayั.๚๔ำOUฃฃœFHุL๊๔ำOฯdบuม„c=ถฌณาGy$pภ Tๆ87ฎ"๊–[nQ?6%5๐‰rmทลล๊>d &y:6ๆแ2UL(eธ— Œธำฅ๒G ์ถnแะgถํˆl๙h๓ยโ†*Ÿ‹#เ8Ž€#ะสคฝ~๑ล๊่•o"‘I&™d’V๎พ๗-G๐OBไ&ว 8‹H”0!6M…jฆ฿|๓FฤฑษG}คซŒ8e—]tต ฅLูšIฅ3๒ Dn1ณ&ั˜„eก]LYญ•>๘@หc<ลSิtึู•~Y;h;ฤ…๙฿ ดs๛ํทท,ถ~๘กŽทoบ้&=ฦ9hลเปงญๅ$vlหyY4฿LฃคRT4vˆ„ร–6y็ชแc๕›Y:ฟั†Š} Xž,[ฎ„อkฏฝฆื3“Jmณใ๕๒์xไศ‘U‹mG_U๑ƒŽ€ €ษ่=๗ฃพ<๓"7 ฃQ%˜ ฮลpGภhbGฏ˜‚แว„ษรแ‡–[nนv€ภ๛ุ` Jะb"nQ‰‚โ4mุ—E >B0ืฦ/k๚C03“aย}๏ฝ๗†)งœRษ'วยqฮgี"ˆYf™Eณ@6|๓อa๙็Wํˆ๖™เขฐvลEUฟ๛๎ป•่ด6Yฦj&+]้—•gกํํwผล‡ศ;์'้wQ‘๐มDญถi‰อขฒNไ!p๘‹Moาๅๅ?0`<ฯ<๓จ#ภb1๘ฑ้ืฏ_๚๔nŽ5—ธ๒๒Uื[ญแƒYW+ว9ญ„๏44/-ฟ๒นtอ‰’\`๖JGภp๊ฐส 1bŽ^™โ ‘ษG '`ฺ€3อ"%ๆเาข –๋/Zว๋ฎปฎบ๏พ๛T‹ˆ!ฑrศ!jพ†ูšY&Dฐ9๋ฌณย๘ใoI5ท ศ1kม‘ ต฿*๘ŠR‡26ฺH}tฤวู๏Jฟศhฬ๕L่ค“NชDi8Ÿ5'Hง˜์gฬ0Kฑ0ตว|X๕ษALง้ัแ๙ดJjB1yƒ|"h”`63อ4ำฺUAำŸ%† ฤ4ฆ0y„pPl‚6ฆ8h1™&‘p๐ูางOหๆ[Gภ๐้N๔ภฤกP!DThJ๒า/ ซ_๛ูBดษแ8Ž€#เไ‰€ šKBŠ่ทP์๛Kฒ2^’sIื%1ศณ)^W‹!p๑ล—db\ZvูeK ฝฝ฿šW|ิTหึฃc\ ๑•ดIข๑”>๓•ู•“?๛์ณค๎ฅ—^บำฉ"งSบ'8Ž@ฉ$DzILJๅŸย'4ชเฎ– Qrๆ™g๊ ฤ‰’ฎข็๙…€จ—๊D…A›x$ื[ฑw.3ฆjตขNZ›ุƒ–rยวPTŒKโธซtัE•หโiŽ€#ะฆˆ/‰’˜”˜\‰“’ฌช–d๕ฑ$๏vO€(‘•๚าoผฑงล5ไUW]UวbบRฑ|1_H&›F@fˆ–’FMฤ ฉ~ณ™[~ถ+1Y`๙ำ[k“hฉคu๘-I๙ข‘QЉ1!)จฒ&=!๎Jฟ[X_DคC;Dcจtส)ง”ฤ|ฃCบhM$็p.ํฑว๚geฑฅๅDดd๔|ัะ)wธlšh๏$uึยZ4v4/ืฒIย5ดพBqอ๒–˜=ztี{}Ž@ฏE€wP%ขฺ˜h”๐Aqqšไˆ}Pหm๙ศฆ"q›mชGŸ’„ƒ๋Pพ8ฃ‹O๗}Gภhsฤ_B‰ีU‰†Pป\JxN}w|๗mŽŽwฟซˆJแ‰พซ|oYคจ$ทzk‡o'ˆ„œี์oผ๑Fr โ$ฦ–E,Nฤ฿tHX##>‡}#J๖w฿‡ ฤ1งjpเ์ณฯึr)_Ÿvศ;lุฐuRuื]ื!OW๚ต๕ึ[kyๅด:๚ฟ,@ZŸำ„‘ฅณี๖rงkš˜j็w^ล<้โ๏$ฉขฆœ@dล„ ZEฑˆo’$Ÿz"b•ด…พJธโžืํsลWPาŽ,‹dฟ๚kท๋๒VB`่ะก%๑ำž%%ฆQณ๐ญtฝ/ฝH ฑCN>d6ˆฐu:(Jฒ <า๗l1f€ค0โ“tศ#…บา/ฺmๅฒe"]i2OโqM-ณa๒ว‚้_7ฺŒู[0เO"ลงtุ?้ค“ดญเว๛ ยฒ.nฟaม{.ศ`ห'แ™ใC]ฺ‡ธฐrุrํณHLrล๗„c;+3&ซ ๎์พ'฿Aœ@ฑ(†;ท’๖mด<ี๐อาฯใดผ;1AฎฆX๏~&๊ ^ลื[o=L80 ึNn~-ฬำๅ%N]/L_e๐ไใŸดGlแ4ๆ=q๏ำBุ?B!„4`ƒ tŸhป์ฒ‹๎uิQZ†ๅ!ก‰8k xชwi.ฒ๒ฆŸ~๚0ร 34ท!^ป#P8ขyศ$)ศไ- 0 qฤฺT&fแ๗ฟ}•ณPป#@"ID|S$‘Eš‰ ‘Tˆd@hุZbัb่‡ ๚ฮงฌaqวํpชฅd„ ผ฿๙V#|o๙6/ธเ‚ษ9ข๕ˆ|bก|eB›c‡ศ2D˜Aถุb J%)A4"กe~๘แ๐ป฿NAฆœ๕†ฑ฿ศ๋๓Ke๐<‹iPๆ~ฝˆpล้สิC฿ฏ<๏ผ๓jˆูพ}๛jด#๊@ˆCŸZBจdpฑh,ี๒ำ/ขๆ ฃ}ญZ=oผ๑ฦS\ชK› WMˆเ๔ุ_4_’q•8 ึฮีสชvlฅ•V ๔ ูร๖o_-ปCป7ใ0ยโx7ˆYurjซญฆaIเb hBD๊‚ศ’:lนŸ—\rษiเ9]hก…4=k{;โ Ž@ ! –'๑†HZ๑\ญ‘],QB82>pผ€ฦ{์F๖ปeว‰’ๆ]>œฒ2  „!9วkฌŠ ’ีกภ!d2>๔โ์U'4ค3 Y`4›ฌ@คยเ‹Ks€่’ีญฐๆšk*QึxํŽ@mxง@ภ2ธ3>ฝoe%6ZUV0kเ9ฺ&d7tS่'…!JธลoHง๋มคtะ AA|๒BจŠ6†N๚mlศ8 B@w:— ฆh_1—ีษ+ˆ๘I&ผv฿l$&H>|x‡1จhัnฑำ:lE["ˆ–N’๖ฬ3ฯ่ธมBs`ซญถ ป๎บซ’)–Q4”ฐ€ศA๘1๘๏JฟDS!ˆFช9qฌ^ข’ศ&โ3E1ฒ<๑V|ปัN ข้>๘เ๘Pฒฯ5™yๆ™๕ฺ0พแo‚ &ฅKร™'ห์@Œพ๙ๆS2‡khื5rx•UV โcE‰˜4‘’ฮ_ํท8“ ›oพy’‚†ะร•$&J่ฏ๘\ัฌ้{‚r%*’ƒฑ|$P/แ—!๗าโ›FฑK{๖ูg“๗9aโYPvqฺ‘„Mย๖#J๘H@”ˆZ^pื(iฦ‹ภ&ฬิmƒ–,ํ`5์škฎัฌLV๘่ยzr/#ขjฉฏx๕‚jมึŒฏ)ุเi™e– ฑถOSใ•:x๗wรa‡ฆ lั†“H:ฐf๒ู“ Eฦ&xถ^†D‰˜„/พ๘"ˆC!4J>๔S๔ข‚F“tด3X€`โ]ฟamžดBะJจ$hE0™•pฒ ษลˆ ไˆ8T hฆƒ็อสฌถุย„[ยำชq%ฒ .?/މ‹ภุƒ‰5๊7>%H8_ี๑ง่'&Dฆ, sร 7จูI–ยก ำj">ไT#/&- ศ6xใ†v•{ˆ?๎1ฎQ-2mAฦขˆ๘๐ ˜Pน8ํŒw=+@`–3Wk6N”4ีn–้ฆ7ฎNงฑ"ภรYŠ6ปWTƒmล 5WฬpV”ฬ๖™ƒีZศ,๕zž๚ เDI}p๔Rš‡๏ˆาlY5ว—j–cพ’šื:ฏน(ฐ‡ Lย*™“ฅฝŽฦ Iฤฝ€ูNZXฅลD‡ฑสlณอ–>2ฟัPแฝ‰ฺ2˜ตฤHE่(ฆู9ๆฅm๒68อD€wc_•Aีป}…!Jbำ>Tb๕๋ @‘สsขคนWC"จํญภYŸ>}j6็ehˆ 8Jณ}œ๑ขR ๖ญ๘@ญุฅ88QRœkแ-้>ฌPข>nNงvZUทวก%Zo ถ]ฺ—จ๐KธSีžsขคฝ๏ดpH‹“)ฆ˜"L5ีT™ฦ=ํZ~ฝ7(+ฏผฒšs็Wณืไฬqwภ‚s[%Y'ฉลผŒo•%วฎgโP‹H๛ตVS BpœˆถZ(ื;๔๋ื/เคญนhžœvฺi]ถฯญG฿ผŒส8QR?า๛ "p0ปมQ!๏Lbธ๖ฺk๗พy‹๋†€i”Œ=ฺ‰’บก๊9Aภˆใlนๅ–ฉฤKuzD๙ย๏ถ๒Š[’e—]VC€แำ‰๗QาŒ็งซ๘ษA 5pVIณiไศ‘: ฑะภLL6tS=wิจQ yd…จPœ()ิๅ๐ฦิK#8Šฤg މฮaN๋P…ั 0%˜เษ5JzแE๔&ท ˜วE-0ืl›ห๎ญ‚ฆฃ๘N"RๆyH!‰’t ๛<€(BฎQาซ€*^เ!๊ศ๛' ๛๖o5„QmLา“์^๑QRI|u 2อIwขค9ธ{ญGฒ—0ไC† ัwค v๘ผือ้า^Xิฬ-๘รลpЉๆ”„Gv'ฎลผ>ชธ๛๎ป JฺZฃฤ‰ื(ษ๑๛oฑฯk„ a _yๅ•๐ะCYฒnY•qว;hžเDgC&„ุ›{๎นีQฌฅ1yมQ—K๓0‚าฃ4Zx ๊ภ๐แรีW !9ั2ม4?&ุ๙ิฅ}€(น้ฆ›ิ\”ศ+ฌฐB๛t{๊8Ž€#ะซภลม๖oˆ~ำv%„/ร฿H[ั๏ีWณฟใŽ;ิA ฑำแg7ฌำ)๗s’ีŠ#์/๗*6คiA2duื 'žxข๎ณ=็œstŸx—6lX๑“4฿ษ#J<๐ภฐํถๆ฿ฏัh0Dxภั๋ีW_ญกA ‡ŠV &ฏ„ล๔๏Mƒ/@AЇ(มฦำ,{D7qqGภpz<๒Hุjซญยฅ—^ช~ุ๒hsaLoŒ(ม๑Qo\f"๐๑วˆ+–ผ๔าK฿#ƒ Dh"”\%uHdsผuึYgฉ }มษ+ก:!bL}๔ั0๕ิSO฿63ฝ!ค*š?.Ž@ซ"ภ=~ฤG„มƒ+)ศ๗–I3pผำ\Z#Jz๋-%ํ๓Z‘kmTฝwŽ€#เ8y ๐ฤOจฏตห/ฟ< ญŸ‡†(aecฃ6RN”ไq้ฝŽF"๐๔ำOk$œ9ๆ˜ฃC5?๐ƒ†๊de—‡œ‡ลpผ๘๐รีŸ%ฏฝ๖šjถํฐร๊M>ฏvx=๙#€]๗7จืœน…^8FxŽ€#เ8Ž@7 ‚\A%˜œqฦ๚๏~~Š#เ8Ž€#เd@m7ฬ/6ูdี’ƒ40`€นณฬ2K†c~๛ํaึYg-|›ฑ฿ฝ’–ณฯ>ป›GUนJฅRธ๋ฎปxญณฮ:Ur๚!GภhˆŠKX{m-นไ’นtฉPDษŸg5ฝqข$—k๏•8Ž€#เ8ŠDย!’ืฆ›nˆลGฏ‹-ถ˜ฃิบB ฟ48Ÿiฆ™Z WญืHฌv-L?๔p˜c5V๋uฒ=๚์ณฯ’กเ4pเภ.•๚sฯ…ว<Œ=Z฿uSM5U`ัvม์R9žูp๒Aเw฿ีฐ๖\pAnQœ(ษ็ฺz-Ž€#เ8Ž@ก5j”:xล$-์ัB@ำd็w.tฝqตภฎ›?ๆ?๘เƒ:ฏ}Vsr -๐๏;๎‹/พะF็? LŽฟ๒Kุ๒ห/แ็Ÿใ?พž๒—ฟLวฆ›nบ^=ูฝๅ–[ยž{๎ฉ}>|x่฿ฟs.Bมk%กญ*ฃฮJsแ<๐}๊ฉงสf_a…ยI'&žxโฒว=ัpšƒ฿‚ฟœsฮ9นE๊+Q‚VฑฐArqGภp`rโ‰'ช9,ันŽ:๊จฐภ ่všiฆษฟA^c]ธโŠ+~JP_f%}ส)งฌKน=-ไื_U-ˆ9ด]^~๙e๛๎ป๏บT4Zษ˜!gŸ}vXqลปt~Q2๋_ ๛์ณ6โgฦgิ฿~๛อตKข‹d“&’Ž;๎ธฐมิฤ้ƒ>๋ญท^€tซ&๘A8ๅ”Sชe๑cŽ€#3FŽ6Lษ๑<ชwข$”3ึ๑ีW_…฿๎ws{6GภpG 1†ณ›Ÿ~๚)์บ๋ฎV–ยGqDXmตีSฉ—ฺP0ปน่ข‹ยoฟa฿์๑ฦ“O>ฎนๆ๕3‘•™z๊ฉ&“L2I่ำงO‚d >Wะ€2A3?ฝM ณ0ƒCๆšk.พ๓ฮ;ม0‚8!zQณฏŸ6ฌ‰0ำ_c5ด˜ผ๕ึ[ 2๙ไ“๋สslJsภจNโ"mbnˆpฟ์ป๏พบฯฟ"<#Ic|วpิLS`”*V^yๅ\) QฒิRK้๊ซฌ&ดฃฐb7hะ dEค1๐>;Ž€#เˆ&Ÿป๏พปNLO;ํดฐล[จiNqZ้-ษ‚D ถุy?๓aข‰&สrZC๒˜ญyบpœ 3q… ภคาูoฟย;์ฮแ7f8ๆ‡2h=๖P_25๑‹aŸ~๚ฉšลุ๓Ÿ <๐€{้ฅ—BคRSม่พ๛๎k;“|Š๐.ย‹๋‹FI-I;}<๘เƒ“1v9?'ผใJดียฤ;ฝ4มบbjืำพŠ(Am๒ฌณฮj[ขไ๘CXhก…’—xO/ฎŸ๏8ต``Šm; ๕K,Q๛ฯแดทv›ฎpCไ]‚๏๔d“Mฆibถ๗ W]uU8๏ผ๓ย{๏ฝง&ฮใŽ;nำฦo„UW]5ฉ—]vQsH’qฦGำ™/ฒศ"บ_nR›œ\fRBกQ}dภํท฿†”ฉฟI7=๔Fย'Ll๎q๋ญท†ูf›M'๛ุW“๙็Ÿ_M฿ะŽ™cŽ9cล๑ฦฏฺ)…=Q„?๑kแœO>๙คโ)3ฯ<ณF #4qx_ฅŒp๏ฃ)วตDฑ{อ …$,A์ู1฿:Ž@sเ;฿|๓…SO=5ั&kt‹ E”เฃปฃ‘#G6บ฿…+ŸษP'J wiผA-Žภc=6฿|suV‰ำJGภ่ŒN4;์ฐ๐ศ#ิืŸ}๖ู@คœพB4บˆ’sฯ=7ผ๛๊งคู-ฦ๗ 0ƒHKL”ะ๖…^8%๗฿8ลฺ ๆ˜ขxเกo฿พš€Ÿž˜ัƒ๛aต์ฒหชfฤJ+ญ”ข<ำ–@ ˆิฌf}๔QภŸ d&ธข™ำHกY„๊ƒe–Y&lผ๑ฦaฺiงํT-ุ๙J€แ3ง+†'ARแ˜|มDฐงฒ๒ห+‘H9อึบ๊i_|G ี๘แ‡ยsฯ๖ทฟ…ตึZ+—๎†(มs5%ํJ”๘d-—๛+q:!เฯ^'H<มจˆภ…^†ชYต=๖ุcร๊ซฏŽ9ๆ˜0มT<ฯ4bฬช|opš;๋ฤ<…r=ไ›oพQSฬ_ +"่`–A˜›อ2ห,ชโ^‡('h;\|๑ลzˆ๐ฺ๘_‰ežyๆ ห-ทœ:ะลท๖๕๖mm,พ๘โ|์C!ื_ฝฎ ฦe•3fŒjxS,/7฿|sศ๊„นซุ`Bตูf›•ี๔ภ!ํN;ํ7GตH๎ผ๓N]œ8๔ะC;ซ๕s๚‚† Xก ย>พ[ oทnปZET=Ž#ae~M๐Ÿใโ8ลA€๗4šu'œp‚ŽAri™„`+„ศGฆt๚้ง—Dทํษปฏ$ๆาษ'Ÿœwี^Ÿ#ะึุณ'ƒถถฦม;๏dE@VZK๋ฎปnIV_Kโข$ั&J2 ,‰ถIึ"<_ขค$เJ2oBํ]ฏR&ฎ:.bl$q2 …‹โ๓#ษ/“๋’Dภ)‰ู…ฆฑO™‰fHIด/J2ฉOาDC*9ืv$\lr„,,‰ถ‡–ke‰ฆNI๒Šฏฅฑ•CVLฆญYI]โ‹คๆ9ไ3ฆไ๊ํ›$}qฤ\ถœžb# œ๊๛อพจศwจW4ƒJฒ\gัาป๛ƒ๗๕‰ี"’๓„์M๚"ฆธIบ๏8Ž@1ง๚Œ^wuน5(ไVSŠฺ(5Lฝ๘N”ิธQฐ#Pg<3ะำฟ:—์ล9ญภัGญฯŽจม–$„ฐ๎‹kwบ๗Žม%c-&ฮฝAD๋E๏)ฯY‰Kํผ๓ฮIลjิจไ'žx"9ษ๒แ‡&วXเ#?ร‡ืtสด4Š–JIฬŒ’๓ชํˆ•ไ|๑T-ki๔่ัฅฅ—^:ษ/~7J_ตžใ9!”–ž`#’zญŸ—_~yIL:H^ัั6๔tกCดU’พ@„q \G x๐ฎmฏV8ำ์:๑ืัn‚ฝ๒๐๐๎%ํ๊{›€;Rn๖๐๚{+๘% ”)QJVXa5ํภDBˆ“0๔ำ๗ึnตdป1หภG>+0๗(บผ๙ๆ›a•UVัff๕Q‚๙ ๗ู๊D-A0๑ภf๘ดฐ0ปรฮ_"i1็ฑ๘๚ํฉพ๓(งณ๘zr$9ฟ=„-F็+$ŠšŠ$dgทv [nนeีะพฑoœ‹š9H\Žํc‚ฏ„๑3>6L๐GƒŠบ ํI‡๖๎ 6wqGฟ kฏฝvล>ญŽ0ฝพ“๗f๕๚ร5d“M๔บgฉณ3!ณิ— ๗aฆ™w˜_˜r&CYส๕<Ž€#ะxฏห"๚Aj|m!Ž(แล.+y๔ฝPu์ตื^๚Auข$ฟหย ว>Œีjeฐ?ร 3Tหขว๘ะสสSภVธšL:้คATีซ”8Ÿ๒d๕ซZQษฑ้ฆ›N}$ vฐQวั[-กlณMญl:Pฤ†:ข`p~ZHว6ปˆยšม]Gภ่8Xฤั๋ฝ๗ซa„qxษณDš๙Z่Z‰žปเ฿กHFE_0ษFา$@ฅถำ/BY#ข๑ ัaŒ จt้8=m%N˜<ใง฿#FŒะIธๅฉu‚ข -๘ฝ€์€PŒeวw [mตU่ืฏ_œฌ๛[ฟ๙อ8าฤœŸ’ฦX†g4Ž๔าlาDŒ‘Kิ…tะA๊็?)เˆต‚ฟDฃ2dˆฆ๕ไŸ%Y'žxbRฤะ!‡โศ\เว$ซ–P.แฅe๕บlV4๓1S6ƒ':Ž@C€(แ;9š‡8Q’ส๊ภ‘ํำO?ญอ˜L2)uอš-อJเซ ๑ม$“u&๘hำิผค฿sฯ=šv2๘จ$8ฯjb<ซๅ‰ฑฒUKX`LRNBฬดŒjีหqผห?๐ร5ณŠ}z•โš๙ศภX๋^์JE:ิŠ*ร}H๘^d…Ž0Šiaฝํถฆ“;6BŒr*9ด็/หu๎T'8Ž€"ภ$Gฏkฌฑ†’ห๛฿ปๅดัแl D)"Œ๊ตื^˜J๊X*c ‹#ี 7ฐf้8Qล™*ย8งœi2Bรด0ศGดmภ…่‹โ?#์ฐรaฟ๖S )H&๛|cล๗‰jง๕†o ‘ ‰šV+"&h ฿xใTฉB™Dตaเ‹่”‡YgU“p0 กb‚& D8~ล‰,‚ฦŒ…R†$ู~๛ํ„eZ๖฿=f้=มMฐใ๙7แ^ฃเ+>R4ูา๘Q๐ป`รuม)/‘„Lo@Nq ฎ+m4?คฺโ,doี ์น้Wšฒr}๋8C€๗ฅูซๅ—\ข„—=“&ฤ๖BอlฝฎLิxqณ๒‘EฒLศั2ฐIญ2ณ†/N๘ซ•›erส}สp94hPข๎สq>Œฆฎ[.?iLžQ'ไ6์t ฺY&ไ/ฑฎน”.7ซyefขOิ"5(G์n;จW*›>W"โsภQ์ตuๅฎ–& Z4ต4sาืB /ๅ$+9Tภ‚€aฐK= Yž—rm๑4Gภ๘/จต~๘แƒ๏CVy฿fyง8ŽCS ยุฮ7฿|I„–ฦีึ๓’!๕!๗ขง`QKb“3[‰ษ4Gธ'ใoฐ8๎LฬDXฉฤ|‡ใ|ะ`‘†olLฎิjใ*พhฅฤgฤ'V€@4ย-)งœฒC‘DE|7m์s๗'‘]0+ยอ&๛์3Nแฺอ„a<ฤไi—Fm ด({‚ QzŒBX`๊"B+c๚cก•‰~SIcฃU~˜ึ ืM„๛ณ0€˜ูb‹-4]O๋ป‰ไ็žโ1\ำLHe4ƒนN&๔œฦxฆ #~ร:๋ฌcู|๋89 ภ๒pcุsุ่*(i4ยหGอ‰Zญ3ำฑขำDฅณE1หไTœผลงUฯ2ูๅd4jMœษ—u‚O^G ;@ฒกลDศลXส‘0๕ Aืๅ๛Ž@ป!€oT๓1แร็รxาาnxกฟ˜rB6@>@]b&ฑhdิ&วh] h8-นไ’jf‹Khฐ0‡ฆ y™Ds_š0I†0-ˆุศ 7”m๙+m! ะ่ ฦlŒ ๅฬ6ณmHZk„<ฆูย๙L่1™E‹‰CืV Yผ๏พ๛*ัร9˜—F €๕ฃ™า]lŒ๔ ์1ฆvF8P_,Cถxiร8—sx?๔T$ชŽO”รต„”e<‹‰ุQ—-"IดฎfLqŒEัŽ้ท/A.ิ4ษ˜๕ษด_ ตะ6Bะสb!ฦลp๒Cขโ3ษอmlŠ„ฝื๐ภ๒ซ‘ำ;Ž€#เ8Ž@ั๐’ฌŒkD)"บ‰ฬาž{๎Y-ฑข7ฝ%'š%™–d+๚'“๚$‰˜yfn๓vmง็}ํ }ภ$e˜(@„›Œ…๐พB”hd ŸY#ูXDขฅ’|๚้ง‡๛;5k็M…2์ทm ฑ–‹.บจS>๒S†8/Mฒ๗๊"Lู2 ™ั!t1ฟ{‚๘Nั6JWดA7๋o1แต๊u ๆไฉWิŠ‘#G–ล‰:„œํP7?ภEฃ็U’…ฝNy‰|dแ‡ฉ_9ษนงdžเ4žm!ม^UPิqฬ‚a;šไยŠy%Ž€#เ8Ž@Žเผ‘{‰š฿Vv๙ึ›YEŽอi๋ช0ุe—]Tณ ˜ป`ฦฯ ข๕d46>๘ใ€9ญษO?ฦw\57ฑดJ[ !Pงงhf mh‚‰หโ‹/ฎๆ2h.เฯ ดAƒ“ดจฮ8ใŒŠฺศ‹ณc4cซค๘ใm‡ˆ.ๆ+๘hA##mฆรqž3LN0๓Aซข’๓"๗`Œtำ(‰ž !ไถฃ’ณSL’ Pฉ‰]NO๛Jมf๋ญท๎เฤ5]่? fฝ`…SJ‚6ํ5-%ำˆ1ฃJ็yบ#เ44J๒ิN-Q‚š<ƒ(GภpGภh 0 ฺ‘8๐€๓ษtคŽึ่iq{๑ะC)YลDŸษฟK6DหD”โ๛#‹ˆ6HBr.พ3๐ลFศHศฬ‰ส‘V„ฮi1ม&MฆXพfm(๙๋_š)J^ฃฺ ฑY…๙:m'šhขFUฅัˆ ƒˆ”—ีdฝa๑‚6D ญ‰l:ฑuขค ๏|๏ฒ#เ8Ž@K#€ฃMl‹™0ฒ’ฮŠ;พp iซ- @“;ว„Ÿ1b”๘ฎhr“zU๕hb  ๕เƒvh7ฤพP๘ร๗G์ผตCฦ๛At!ˆ๎'ฤถบ@ฤ˜Oฝaัลp๒Eข-ฒ-ท2—Š ฃQ‚#ฆ78ธ2ุน เ•8Ž€#เ8Ž@n˜FVŽ=Zรvโ8‘ฐย.Cเ๑วW‡— 2ss„ืธ๎4ญdดDp4‹๙คˆ9 mZƒšT1 ัwp~KธฮVโB๐"น:“lu`ฝŽ@pขฤ‰’..žีpGภ่} 9‚šdศ‚ตดw7‡E("ง\|๑ล๊Kฃw๗ฦ[฿l$r b%ฒ๗{kdขfทฉั๕cn…Sข9ึmtฟฝ|G (ด=Q"ฑ‘ี^น(ฤแ8Ž€#เ8Eเ๗฿Wrdไศ‘Gฏ๘ภabึฐฐma๏/…^P“ˆ)ขvธ8=E ฅงžz*ฐุyูe—๕ด8?฿pช@”ดex`ำ(aฅ๕PGภpGภh/ฮ<๓ฬpส)ง„UW]5|๔ัGaฬ˜1jŠƒรw—ž!ภ„–‰ํญทf›mถžๆg;‚ภˆ#’จ7dpqG ‘ด-Qฒ่ข‹jิ›K/ฝิ‰’Fa^ถ#เ8Ž€#P`p:jQ4fžyๆp๛ํท‡ฝ๖ฺ+์ฒห.nu๑›† ๆaเภลoฐทะpGภˆ€(ษ3๊TaœนB”เฃข„UGภpGภh_Pฏ%ฮjซญ{์ฑฐภ „ฃ>บๅF6๊Šฉ_L0AkฌฑBŸ>}๔/งnKทm|าุ’ฮb๛–ฮฑ฿VFต–—mผŸ๏ว๙จ‹cvฮ็ท#อpVส็็<+งา6‡|HŽ๘\;–ฎง\~หห–2โฟt~ห“>'ฎงT*qXฆ;ัพ•M:๛&qบ•็‰9๑qKฃ๎ธ\K/—7>ึ“}๋oWสจิฮreYšmฉ‡}๛]i[._œ7ฝn้ดZepแผ๔น๖๛ท฿~ำkby*m)็ื_ี๛†-ยนถฅ}๑oKทญ•ซ'ศ?๛อึ๒ุถVšหจ”็ก|~ำฮ8ฝ\šตลถไAา็๑๚^๎X:ญRqพ8Oผouลyหํงฯ‰๓p ‰ำโ๘Xผoy,อถค~z›>‡฿vyzฒK็ตฒ,_ผฅŒ๏พ๛.์ดำNaŸ}๖ฑ"บ-Q‚ฺ6ŽN”4๔š{แŽ€#เ8Ž@ฏ@เๆ›oVำ›Aƒ้€๊อ7฿ิ฿ซฌฒJฏhัน๔าK‡น็ž['> @™๘ุไ!Oใ7๙์฿้4๚jeู1าุGโcvพm9n๙,-ฝ%็‹๋มว9ื์–?]†•_้xœ๎๛Ž€#<ปีค๑ฌiVnœฟา~:oน|–f๏ฮฑดZ[+?๋9qy์๏๔๙–nylk๙์ทm-=ฝตใlดต<๑ฑx?Mดฺฑ8สฒc๑ึŽแว์ บ\ค0D ๎ั(qข$—๋๎•8Ž€#เ8ฝO>๙DUm‡๐Urฯ=๗„ญท:tะAฝขศึC€ษ?๔Ž฿้ฟJว--๘ผธฌxŸ<&–?>๏[J[ห[mkวฌŒ๔oKทถO^„฿qš๕๕ฟG๛฿Ž6>f๛ีŽYžฎliGZ*ฅฅ๋Ž'uœcV^สด4สŠำ8ว~ว๛–fJวฌm–ฏาถา๙ค#œgmc฿์X๚wœn๛6‰%ฏฅล๛qZบผ๘w:Ÿๆ&"P8ขไ๒ห/W็PMฤฤซvGภp‚!p๙็‡ใŽ;.,นไ’แฝ๗ SM5•j—ธcา‚](oŽ#เ8Ž€#ะ8Qาัปเ8Ž€#เด„ธ=์ฐรยW_}ฆ›n:uฮoขนธ8Ž€#เ8Ž€#P/ C” <8 2DMo7ๆโ8Ž€#เ8Ž@9Ž9ๆ˜pัEฉvษ#<ึ_0t่ะฤYgนs<อpGภpฌŠ(ูlณอ‚›dฝtžฯpGภh_๎บ๋.5ฝ้ืฏ_๘้งŸิถศ# /ผp๛‚โ=wGภpบ P8ขไŠ+ฎO>๙d]:็…8Ž€#เ8Ž@๋"€ ฮก‡๎ผ๓N ŒF๊๛๏ถ฿~๛ึํด๗ฬpGภpŽ@aˆV€0ฝน๒ส+รO<ั๐Ž{Ž€#เ8Ž€#ะ\rษ%jzC่ื_=,ติRแ่ฃ“O>yktะ{แ8Ž€#เ8น"Pข%˜8Q’๋๕๗สGภp–@เตื^ ‡~ธFฤ 3fL8โˆ#ยrห-ื๓N8Ž€#เ8Ž@~Ž(น๊ชซย๐แร๓CภkrGภp–Aเค“N ร† ๓ฮ;o JฮN;ํ๖ูgŸ–้ŸwฤpGภp@aˆLoะ(น๚๊ซ(iu๗Gภp–Eเก‡Rm’>}๚จfษ์ณฯŽ:๊จ0ใŒ3ถlŸฝcŽ€#เ8Ž€#P? G”\sอ5แ๑วฏ_ฝ$GภpGภh;~๑วpศ!‡„oผ1 4(Œ5*vุaauึi;,ผรŽ€#เ8Ž€#ะ5œ(้^žpGภpz,ภsฬ1a๚้งWGฏ8Žว—‰‹#เ8Ž€#เ8•(Qrํตื†ว{ฌR{=pGภp.!๐{๏ฉ6 >K&œpย0ๅ”Sช)Qr\GภpGภH#P8ขไบ๋ฎ >๚hบpGภp!pๆ™g†SN9%ฬ<๓ฬแw ๗6฿|๓•้';Ž€#เ8Ž@๋!เDI๋]S๏‘#เ8Ž€#เT@`ฤˆjz๓ๅ—_†ัฃG‡5ึXCMs&˜`‚ gดf๒ศ‘#{ghีิล๑ฅ$)„คR†dJTข4H๓<(๙RiาคDQ‰R)2–!$DQ™2„ RH(ณˆPdL†rฟฯ>ฮฝ๏7ิ;๗w๏Z฿๗9g๏}๖๐?ื๋๎Y๋ฟคu๋ึโพ๕›:๖<‰ˆ+๓9ธsŽYปzŽ๔[จP!_{๎๚wm9ฦ–ล–k™ฟ}lyNฎใตก,Q9ในzwŒ-skrss}q๙ฏ]~น๋DGฺลซ+\ธpฆ็ฏ]ข๛]œิว›ผ๛}eužU]lฟฎญ;RŸนm`~นพฒปว๕็Žดgอ๎ฺž˜_ฎw[ŸUนฟEปD}ฤ+7msz?๓rๆฮ‘rฮฯ?ใ๏นำžSฦฟญk็ฏ‹m๏๊่_็หตqวxu‹น6;v์ˆš—๋฿แ๚เฺรัตใ่สนปื•ปclน๋ำ?ืฏร{M;7žkฏฬ฿ท๋ร็?บsฺปsŽ๎ุr๊โีป2ฝป7ั_ฦ฿จ?ขภ-4DI5lึ›… ส๒ๅห_ธ (Š€" (้‹ยฎ<๐€”-[VŠ-*;w–^ฝzฅ „!ตkืฮฎนt้า๖Kผ๛Bฮ1ัน๛ฒํoC™kฯ_w๏่o๋๊้sื๎‹tVืิน{\Ÿ๎h+ํฯ๕•ี‘๖๑๊]?ษ<๚7ฅ๎<โ]3x6^›”%‡๒xcลkŸ“ฒxmr3Omซไ๑;๐—%:gพฎŽฃ;wๅ๎ฺtํGทnWๆศIwtๅ๎่/็]๛๎ย"ถปๆHฝk{ค~ฯ=๗ฬิฦ_ๆ๎/Rคˆ‡:ฒใ"ฬฮ;๏ธฅz Q‚ภฺ‚ ”( ๔‘k็Š€" (Š€"‹/ถi„๑&ูดi“\z้ฅาฏ_ฟดgอš5ากCyโ‰'ไ๘ใO‹5๏ฮ"ูฌCศธฃŸธq็๑ศ"={™‹ฟŽ๓xeใ~8๎ฺt}Q†q๔—นถฎฮ]ปฃkK=็‰ฺั™ปื•นkฝ๎ใŽ๎}veฑ๗ฦŽ็ู๊น>1ซ๑ํ]ปุ2ฎ]=‰๓‹ฑ}๎H3w๎?๚oงœŸุถ๎ฺีนต๘วถqm]9Gฬ;็ฏOW๏๎‹=R๏สุ๘บuป๛‘ ฏ;ฯษ‘พh็Ž{bหธๆsใธฒุฃ๋3ถKนห๎สh็๚pe๎ฺีนrฎี๒ฝ{หoผ‘žDษ๙็Ÿ/๊Q’๗*ํQPE@Pโ#ฐeหน๊ชซไ•W^ฑ_ดkีชeCqJ•*†)}๓อ7ฅSงN๒ไ“Oสqว—"ซาe(Š€" ค* eห– ‘ษฐะx”œ|๒ษ‚GษขE‹,ษXผŽก(Š€" (Šw฿}– 9ไC์๕kฎนFฮ9็œ”G‰’”}ดบ0E@PR!C†ศ๓ฯ?/๏ฝ๗^RึงDIR`ึAE@PE ์๐ๅkฬ˜1ฒaรA์ตo฿พ2lุฐฐO{—ๆ‡๛r—.]ิฃd—ะำ›E@P’?๕ิS‚y2,TD ก7=๖˜uMฦโu E@PE@Pb˜4i’LŸ>]J”(!'œp‚๕49โˆ#b›ๅ่๚๛๏—‰'สC=$ีซWฯั=ษh๔ฺkฏIืฎ]ํ๗.ึจฆ(Š€" „QฃFY™Ž๕๋ื'ešก!J๘๒ภ?ุ>๚จ%Iy๔:ˆ" (Š€" $B`้าฅึปd๛๖ํ๒วศธqใคM›6‰šgYŽ๎ }ผ๖YถKfๅŠ+ค[ทn๖K็I'”ฬกu,E@PE ืKถบดK Q‚F‰z”ไ๚3ฃ7(Š€" (Š@lถMFm3รัฯืฑcวๆzคอ›7K๚๕m*bโซร`/ฝ๔’M <|A'NMPE@3x{ข'ฆDI˜Ÿ’ฮMPE@Pา|ะz”-ZTส—/oCiชTฉ’ซ๕“†๗’K.‘ฺตk แ8๙mฯ=๗œ๔๏฿_ๆฮ+5kึฬ๏้่๘Š€" (Š@–tำM2mฺ4๙่ฃฒl—W•ก ฝมฃไ๑ว——_~9ฏึง(Š€" (Š€"ฐ|๚้งr๕ีWห;๏ผ#„ใR๘‚ .ศUฟ„๏ฬœ9Sz๖์)#FŒศีฝyAผมƒห์ูณๅ๔ำOฯ๋๎m?๘ฃผ๕ึ[๒ํท฿Z}–ส•+G๓๎ป๏ Z)^xก์น็žQuA]เดdษ๛ w5”*จนฅrฟ๙๑ฌSO]›"Žvmr๋ญทสวœ”ๅ‡†(ฉVญšี(Qข$)ฯ]ษ๙G๘Bฬ[รbลŠeัRซE@Pา )Sฆ?… ’–-[Z๏’ฝ๖ฺ+ว0พณjี*ฮs์ฑวๆ๘พผnˆ&๐แรญ๓™gž™g๏ุฑCะ?™7ož%$๓"์ะC๕Šฮ>๛l๙โ‹/ไ†nุeฏณžlูฒEะŒม^|๑EฉPกB๏ฬฟf?๐ƒฌ[ทNพ๚k๙๛๏ฟๅฐร“SN9EŠ/ž“สๅศ๙๑ฌs9Emฎ(!Gเž{๎‘๋ฎปN>๙ไ“คฬ4TD %O>๙ค7ซฆไ?ณuE^นrฅpภ๖‹l™2e๒c*:ฆ" (Š@Hภ ๕๏ฟ^J–,)ื_}ฎผ2ุไBฤ/[ถ,฿V๘๐รห•W^)w฿}ทิญ[wท็๑ูgŸษ‚ อ๘เƒL๗~๘แVˆw๗ฯTฦ‚xึaฤA็ค(ปŽภฌYณAWฒ)Rdื;Lั€@IDATสแJ”ไ(m–เ‚์๊ใœทjŠ€" (Š€;wฺPาb—]v™\tัE& ฯูำ–ะผ)๒ระ&แ฿8โฝšU๛๒ห/e๊ิฉฒhัขL]Uงs็ฮ๖ -xuิQQm h๐’๐ใ@h ถว{Dตอซ ฦsฤย€:tฐ]CNเ%”_vื]wษํท฿.|ฐ%Ir2‚$ฤ›ฯ:'jE@(8๐๏-?!ฐษ๐จ QRตjUzณx๑b๋ Yp™ฮ4•@`o๘๑’๘าาธqc๏ZOE@P?„ฐ ]๒็ŸZฏˆRฅJ๙›ฤ=๏ืฏŸ จŠPl~ˆฉ๒๏.ฬ„sฮ9q็˜U!ก ่ฌผ๛Qอ๐ฦDsคSงNrเFี๙/!9ใŒ3ฌ๗ษ>๛์#„`ใE‘Q6t่P้ฝปฝฮซ_xgดhัยvwศ!‡ุะยm ๓‡ดHv& ฅีซWG-“น@"ก!sฬ1วศ~๛ํgCoxf]xawqQ๗„๑"ฟžuฑะ9)Šภฎ#€D.ผ๑ฦY๛ฒ๋#D฿ฉDI4z•ๆ๐flฬ˜1ึอตcวŽ2dศภjฅ9ิบ|E@PRM›6ษๅ—_nตGxหัฐaรlืwฺiงY/By’mำงO2๐ณ+แ'—^zฉ q๓†๔่ัฃ‡ิฉS'ฎ0+aJˆ๐๚’“ฌƒ ฒ‚ณnŒ]9ฎYณฦ ึnบUrDLV}A"น๐œฌฺๅฆํฦFดถlูฒ™ผW?z๕ีWm—่ธ๐yjิจQ\,i„‡Nแย…ฝ)€+คžษฦ๕9ษฏg3 ฝTC€๐อZ,ˆ๎ -TD %O?ด,]บ4่ukŠ€" (Š€" ไ)NhŽN{๗๎m7ปY €แอš5ณžYตอ๋:ดI .๐€iฺดiฎป'Nœxqgmถต/นC_qล๒ศ#ธๆ™ŽxO ฒJฺๅใ?^บ-]บtฆvน-@จ๖ป๏พKx[ลŠญ0*cžpย ึsฃD‰ ็ฆbร† Vะ–๏ถd}qV“'Ov—๖๘ภXฯ$.|๓Mษ๖ศถm,vฟป%– ˜ูศ‘#mvI>ซฑYˆธ‡>6olํw•pษ‹g Y…ว ŸQฟpขuiน" ค>่˜๖๊ีห๊™’t#h QrาI'ู4{คซSข$่วฎ+Š€" (Š@;ทลW_}%G}ด Ex3‘ฑฉe#Kqผkข๛vทœ๐B8๐~qก(น้“P•ฎ]ปF .ร—ุ.]บd ?Š๕@!”ฤy•Z2gฮœ oฝ3ุะ-Zิ ๊๒vั๏aแ:#ฌษ…ี0?พ\ปq๑ๅํdV†ฬ7ง™๐ุเK๚๋ฏวํšpฺ๘ <kXlFผQ"l่๓ฯ?ทฉi‡ุก์ฤOŒซC5N“7u|^๑.โsˆ^5dูqFˆz.‹ฟ๚Knผ๑F;gฟ๖ํฯ?"ดฮr๛ฌึฏQฃ†ฝฃSO=ีuฅGE@Hc–/_nร1Ÿ}๖ูLšWAภ*ข„pqฉyแ…‚Xซ๖ฉ(Š€" (Š@R ‹ ›<6๒ื^{ญดn:แธl ๗w฿คfCฤ•ฌ/&Lศrn 'm*ุ4ฯœ9S๐Npd„ky็Yญ’#<า๖o61ื„็เ1ัฟ๋qAธศฝ๗๋nอ๒ษถฑzdย+#–,!ๆ‰'žฐ(xฌเ% žฑdA์ภฌข…ถ 4ฐ‚bp}วwุbึ9‚‡ด฿ ะ;ร[†็Œ._ฌฐ-z5่ึ`ห๚๋ฏ๒ห/ฟXsพ3‡xFŠ๊1&dL]›?8nุpฯž=ญ7 ๐Rา ฮ=^x๚,Yฒฤf„ !\ \ศšัฤฆลž เ{฿}๗ษฎ>kฟŽ ^Wt๋^Š€"ฦ๐wr8Y๚Lก"JˆฯT’4๔๋าE@PB€์6ร‡ท^6ด7฿|sี’ย›๛พ}๛สฐaรโถษ๋B6๗wyงอ|ำฎ]ป๊ฏผbfฬ˜‘Iu๐เมv3/‹#“y๑{ $šฬ[oฝe฿&:B€vx’0>D lิณ [qฉj๑~๗D†w!<Bฑ†W ๚,#|๕‹ยC5„YV†x|ขฯ‡ปย๒‚ฎโ G(iชฑ—_~9Sธสฺตkล=gบž,ชU+ปVึA?^Gเ@F"ผค0ผOะๆ‰อฺ”ˆPสอณฦฃไโ‹/ถ3Œญฆ(ŠยH่"ฉ่!œ7๓G/fBo"&^3bภ†b>: E@PE@Pvใ1ใA9๋ฌณ"Fp3n—f1:‘ํทวญฯ๋BใM1ฤBฤxไiืF_#bย‰์zY3?&KAฤx!dวl๐m}Nพ๛ญZตส๋ำใ1ูTlŸ†ภ๐๊่3;kผนmo6๏Y65dืฏ!;โถ5!6^›ท฿~;๒วDLฆฏŒ๕›ฌBCšลฝ฿š”—Q๗8์Œ~Lฤ่tุฯ๑่pอ3๚้'๏~วUNnอฦ๓&bผ{l=๗๐`,ކ่๑๎3Y%ผ฿™kฯผyฌ‘k๚gนyึ๑๎ื2E@P๘๗“ฟ3ฦs/)`„ฮฃ„7z8?ฆ(Š€" (Š@@๘”0ย๙เญพ฿M!|„ทd๓ๆอ๓WrNุ ^ฃFฒฉ|๓z<%qBช๑ย\ฦgฝ4ะpษ๊ปx ‚W~!?ฒํ,[ถฬ[B< ฏาœ ฅAแAฬ!‘ก3b [M8 ก;~ร“!\าขB๖"B{˜/o<ั€q๋็>R_rษ%™๚ก ึๅ ค‹.บศŠฺบฒ์Ž.ล0!6คnvฦ<๘ม๐\! ร/ g<C„ุKฟ† ๚1่ศฐฎุtฤ<ึJ8ฉŒ1p8๘เƒํน๛•ำgํฺ๋QPX\Xก}„nIกcr0 ตqŒ˜sะZ›(Š€" (Š€"|๐0ฉ#fรYผxฑ็ี“™‘N{/oฤLถ›ˆูxFfˆ๛ถฬhjD•qa6ฮึ‹ภ่จไบ{ณ๙ผ๒ส+ึ{"ซ›MXŠ็ฑpแ…fjj2็ุ๕โ‘เ7“๊6bยฑ#&$ษใฅโผฬ&฿4โฏsm.ป์ฒจ6ฑฮ"ถ}๒ฤ๓๚มฦ๕iยpbป‰€กซ7ก)™๊๑ขม/ ืŽ#mcฝ>œส-ท’ฉŸœ;฿ฉMx’ฝ ฯ7ถ!Oผฎ๐|qๅเ๏ฮc&KŽwฯ=ถyกเํโึษg#ึr๚ฌ}F›$ย=_~๙ฅ+าฃ" ค9†เถƒ๘ป– •G bฎF!hฅฆ(Š€" (Š@ุ˜4i’ฎb6๓Vƒ๙ํท฿~rฤGXO4#H5›•‘ขu๙ึ QU—แƒ{LxŽอjbBMฒ๊bท๋ฆN*ำงOทš(ฑโฃูu๎<H:qโD›•$^*ูu๋ึYอ ๚‹ง๑แืี๐gzA ฤB๑ฒ0„”M{K?ฤจปŒ+~๘กN’ฅ๘โมฯœJ๚๕ญญkใฤeฉวำฦ„Ÿุ >ิใQ ๋ฤ+ˆดตxg8 C~ฤQล ผ:๐Šq†็)่ทํwษา/š&ˆปฯ“y๖;vด}๐‹,:hžเร฿r๚ฌนŒะvม๐~๑ใl ๕—" ค%dโoบO๎o]@„†(มี1W%J‚|ฺท" (Š€" ไ„\ฐ&ิ€L#F๓มvอf” 'Fย’'ๆ-|ฆ!น‡ิภQAๆฬxHุPยb…2mƒ<๚ลFŸฑัฑ฿ฟrำญป{;!•l๑โลล่aaD๏ฝ๗^)@–”๊ีซป[์์HŒนpH6฿"n“์',ุ@= ›๊\g?d”้ฝป+R ฒkŽจBvลŠถšปŒa0z๔h้ึญ›%D7ล#M-kเลfก…็@4๐<™g“&MจฒฦฺHฟ ๖Ž00`€ฤ†ดธ{ฒ;"เ๊DZikผdไัGอt„ฤ“3H':kดU,vฎ.ัqbย0žClฆ"ˆ ~โฅ{ฮ้ณฆoยจ ซฐฌDmฅ(iƒภ† ฤxtฺฟ3„Pmก#J๐&,QSE@PE  !ฐeหป&-›k<๘H@฿‚7`lž]๊๐ฆ%๊ฑว+hbฐูวำ€อ"?lๆƒ0โa๕AศJใ'r2$ูxžฑ๗ฃawHผ๔ศEฌ#„€Xฏ#ุgห๑`\ฌญ…+ท•พ_x เฑ‚ก—Š3^ยAŒ๘=^X;-„H‰%า=ๆ ๎.sž.<Glธ~9Bœะทำๆ่ิฉ“ีก๑ฏ B2ฤ๏‚‡m]Ÿkึฌฑพ3?๔YJ•*%x อ”ไ๗`๚๛๏-ึ~m”x„ฤ•ำ1มซ%V3'๘.ใuคŽ%ษยใ>Kฌ \๙1ษ๊Yำž{;t่`o…๔tTSEภ„โูTํd‚ฤฺBE”๐%lต%A?vํ_PE@P‚D€อ=ฅ„อ!ๅi‘"E,qยwD@y3ฦ†๗ž{๎‘oผัnๆ๑D`“H(bฟภg^ฮ—Tดˆtฒ‰7๚!น๎šึลwถ๕๋ื[’2 ฒงlูฒ–๘ภ[ฆt้าq๛ง=ž(๑G:ธ๑๘€”€ฤpF*Zา/WชTษูฃั]าัbTฬำ…œPBB™3ผx๑แสxv„HฑVผˆ ผx›‰ท /๙LๆF[6dศK€๐|๑N๑sม๋ฅ pฟA(@ฐAขfSฎ\น(ยว฿ึŽP-žBqcวŽ•š5k๚ซํ9s€ฤqsd}|ใB_}๕•”,YRw",(ั\H%HB>๛{๏ฝทื]nž5^I`ktTฌง‘Ÿไ๒:ิE@H;\XžKY4ก!J`‹a๕!J`ฉีE@PE@HaC ๑ม~ผJุ<’ๅ†M'›Y6ูผ1cรŠaปBdd‡oไ ฅศ‰7Avํjฝ?$ƒ>๐*แลž7๑  “rY*Tจ`‰งxm(ดi“%D  Š5ฒูเมใ rœ+Wฎ์Šv๋ˆ‹8^+๑ย`\ว่š!BX„ „š7AxัเMโŒฯ!z&„„แ9„๎ Ÿ],^HปืYGกB…์+sว๒๗’ r้A[จˆ#a •( ๚ฑkŠ€" (Š€"_:ืy›ฐกvค zmlŽัŒ(SฆŒ-'œ‡๖ymxฐ<๘เƒางO๛“ื็ฆ?ย["ล‹†u'ร๐๘Ak=Bhโ‘)y1— ัีพไ ๐๗฿ห๑ว/]บt‘kฎน&๐ACG”ฌXฑBž|๒ษภฎ(‰๘็ŸไำO?•๒ๅหKฑbล5ำrE@PE ภ"pื]wษ=๗c‰’+ฎธขภฌcวŽยwลy๓ๆYBย?๑—_~Y=๔Pฏ่์ณฯ–/พ๘Bnธแ†ค‘[ถl‘Zตjู9ผ๘โ‹RกBo>ฉ~ฒn:y๘แ‡eม‚‚่ขณ›nบIZตjๅ.ํ›เxภ~๖&Mšไ•yRPžหฯ?,๏ฟพlธัม”อแ™gž)7–ชUซf ำย… e๕๊ีrัEษa‡–ฉ-กIด฿~๛YA็C9$S-PยŠภฮ;ๅุc•ฮ;ห๘๑ใŸฆ%Cฌ$๘ชฒrๅJ9เ€ไ‰'ž2eสค%่\E@Plธ๛๎ป-Qาฎ];I†(^ถสฆมgŸ}f7เ๓็ฯ๚(๎|ุะฐฑq†ถภƒ>(+VฬDvน6y},ฯœ=zXr/ั๚๋ืฏ/'N”RฅJej๒ย /H฿พ}m9D(ŸฟแaE:pGb‘๑jธq&zฎ„G”t๊ิI&L˜๘\CE” Q๒๊ซฏชGIเ]H„ฦŽ๋Usฮ?*jŠ€" (Š@*!0}๚t™6mš@”Œ92ดKc๓ˆ๐์ขE‹2อA?6เEŠพ@uิQQm๊ึญ+_ต๕&มซ#๓‡‚ุ‚<๚ลxŒ‹แ-Ah†ทjกB…์y*๚๕ื_ญฦ ^InใํึีฐaCปแ็y๐ชWฏ…7Ÿ7ˆ^HญZตส(Fa.ฑ$†ฅZตj‚€ๅ|เŠ,nwq‡ิฌYำ+ใdศ!๊้งŸ–ฃ>ฺซ_ปvญฐฯ๒?ซXOฏฑž(!E€ฟฃวsŒอึvํตื>หะ%ฤ’๒_Mศถ๓ปr!v‡ซฃš" (Š€"J{๏ฝ‚NIถmeิจQก[!xบ†เ76ืhŽ๐F๑ภ๔WEฎpฦgX๏“}๖ูGุp†ร†ฃl่ะกาฝ{w{Wฟุะขฝึ@่ แผฮ †๙๓ถไ“Oฮซ!“ฺžทร† “ฅK—fศซXยส฿ฮเมƒ…<ฦ3ย!g|๏โ๛W^Z˜ŸหถmคQฃF๒w฿yKฦฏฏ#Ž8ย–}๗ruืy„!Ÿ_t^\=ภ7ฐํ฿~๛mูw฿}ํ9-A(:’„๐vRi *`เ5Hถ6<ซ‚ถะ%ณ `ซDIะ\๛ฯ |Œ3ฦ2๗G;ิ[งฌๆกuŠ€" (Š@w฿}v3VขไาK/ต!6ิ„%ิฉS'ฎ0+ษ[oฝีnบ!C…ธ84ศnฺeน=_ณfเบu๋VปูwDLV๐Rฦ…็dี.7uhท06ขตeห– ฬ{ จึแ‡.ฝ{๗–fอšY‹ุ93/HžวฆM›ฯ‰์์”SN‘‡z(ปfYึ‡ๅน0Iˆ H H3ผŸb๐—™3gzล„ฤ๔์ู3Šq•'ื_ฝฝ„Ly๔ัG-้Gd „“฿S‡๏ตํท๗ˆ:;ย จhัขฎK=* ˆ>ำ‡A[จˆ\ยะ†€!USE@PE@6๋ผU&3ห•W^ฬ ปั+ fอšๅ๕กร‹Œโล‹{eiyไQิ9›GDVซTฉbณ& HF–5D6žฑฑ™eใฯ มN8มบ—(Q"ถู.]oุฐมj|เแ' ภj๒ไษ™๚ผyณ}ฤœ ฉ>'่ภ 8ะkzqวู.๐ใyฤCž5jิฐ"ฅ๔ล"คปฆ”Ÿฯฏ2กEฮ“ƒฯz.D<7ž†„‰_g'n~‘ฉผhฦลมs 2"๒ ฅ#๏N<๑D™3gNย†โฅeŠ@ุPขD‰’ฐ}&u>Š€" (Š€"Bฐ!C๛ฃu๋ึ‚ธfุŒ @ฟ6›๊^ฝzูƒX1Kๆ‘ตว๎ผJN?tปAฬอู\B,๐ๆฝdษ’v[ธpแL]ธอ)ฬยภ‹WชŸTศtณ)`6ดฬืฟŽืึ•‘‹ื_E!โeD3mšSO=UๆฮuON/ะ‚!4ˆ฿ฮ=๗\๋๑ใืล ž์Dะ.lั*a#‹ฑฑๅ-:ืผQ฿m;์#ฎŠ&KN ’ƒ 9คX๕^!คด%Ku`cŒ๎+l๚9‡€P ,%‘ฑ>ˆฺ6hะภjRฤk‹p'FV>ศ<ฐAƒฎ2่RB6žN่gŸ}V๒" SฆL๑H!7ฐ&๓ d †x.ธagu–๕คsูV>๙ไ[—ฏd>ๆางOซรถ„๑ฤ๓py๙็…”ิ๕ิSQข๓lดู`็Ds๏๐ „‰L4ปk lศ™7ค฿ ~ โุควkธ๘โ‹m1$DvกHษ~..ณ†›๗‡~˜‰ cํSeFˆชถjีสb=๐เ(WฎœW{นฉ†ฦg/'ูๅBงฅมc Œ๐๊ม๐Aธุค(dš" @”เ ้2™บ&๓z(ฬฤŠF ป1 ล|tŠ€" (Š€" ค*ๆmsฤlา"cวŽ-PK|๓อ7#F„5b<&ผ“ฝ&b่gZ‡Ii˜M{ฆบุฃ%แ๕gฬGLV—ˆษœc›"ภซฃฯ์ฌy๓ๆถฝ!jฒljฏ_CvฤmkBlผ6&“IฤคŠrห+‡sฮ9'bˆŠธ๗'ซะlฬ#`cศ$onเ`ยD2Mนบ็gˆ L๕‚x.ฬษอฯผฤ๕Oว;7‰ืฦd1ฒๅฦปร+ใ~ฐ0^Nq?›`ยeผ๖Fคี๋;ซCโxฯŸgิ„๏x}นนs4DJVi"Pเ0ก7j™”yใ Sข$A'ก(Š€" (i€ภ๙๓#&Dฃภ%๎ัoŒ„†ฦhบkvD ›Mb๛b๓นqใF7Œ=š78Œ๗ีW_Eีว^4mฺิถ7^ฑUQืUnฦ[$ชŽ ศๆN๚ใmŠ™/Šด1ู๚"๑๚ษิq€F$bยขผu™๐จLฃฏd„ษT๏ ๒๋น˜p o~ฦ+ฦM'๊hjฝ6ดwฦKศซใน๐œŒw‰๗\[Ž๎๙šฐ*qยsH๗™น๙ๆ›ฝv&ณW๎๊9B,ช)ฉ„D ไx2,TDษ๘๑ใ-KšŒ…๋Š€" (Š€" ค+ผ6ย‘ก$JL™ศ+ฏผbฝ'ฒz>ผ๙w ๑6ไŽ(aฃ๊76็Fง#bฒไุb6“ns๙ฺkฏ๙›ฺฆซsG6ษY™#Jbั7$ย๛๏ฟoog๓์๚„๘‰5าแีณ๙Ž5ˆผ] Q\?i๛าK/ล6˜Pศw1ก™๊rR€7 f็มiใๆทั๑๊L๚ZฏฺลFภฬy9ๅืs1ู„ผ๙}o~๎ฤ„y๕ฌq๛๖ํฎส;โ‘ไ<‹|M่Sฤ„ryํLx–ื—ษ€ใ•วžpฤˆ๋ bฯ„ˆyอFŽ้ีน6๎่>o^ใ'เฏฆ„ด&J4๔&์OŸ" (Š€" tŒfGh‰’N:ูM›ม+Vฤ}lfโ#ึo฿uFgฤก™ 1^?องษศ’‰„pใe๕ฆy ฐ ๖[ฟ~์8ผฤVฎ\้k2”x๋dรzำM7yuŒ „]ฤ3ˆ H็ใๆH(Œ<\\kหญ‘P๏~[ทnอิฏ+€"ฤˆ๖<;5E ฬ$“( ˜+๙์s5 ผ4YŠณh็Š€" (Š€" ค)‹/–#FH‡B'ๆJฆ˜_|ั{2p€ิฎ][Š/.†ฐn{๏=›-ฤ5B83V Wาcd'!๋iTทƒ˜ บใ4! 6‘™C0ฤQๆ‡อtbศ[ฦ/R)“Qฦ/ธiˆAธ5ึฬ}1กMVะำ=ถš”ฎˆ"K–กnบ ขก€บศdŠa |ŽอบC'N”ำlฒญ +๓lาค‰7๙d›:ูlHฅs็ฮ^_๚จXฑขิซWO eลrยฌ$ฟ ซM์ณ#ญ0๘;ใsฯ็ืkศ›"›†b 1Z~0๗฿IlฝVย‚bฎ-[ถด==งะ%‡Oบ3%J‚~ไฺฟ" (Š€" ค;คw6l˜% ย–๕คG™Rว{flชI5K„X3o๓ํK8สIlBฤxx™s๑ภf•์?ฦC%ถ {MVฒา` ,ฐ้`ํ…๙Eช]ˆา;#หmทf/!Dศ๊ยฆี„Y`ูฒe^ๆˆ…ž={F‘>ฎˆ๚fn˜๑ฐxบ v Cุx;3ถญ#KSฦ†0š.ฎyŽ?ณ%Š ™rbฌ‹ินฑฉuษ"Tนre$„หzI*gŒ,FC† ฑไK~=ศ(2๓€Wฌ‘ ’ r"‚มฟ.ศ*ศ,๗ู0ž*bดฤญ๓ัGต)!8x†๑ฦ๒Mสb๚,Rคˆฟุ’์ฃœฝ๐ย –แ๙ƒŸKญอ+คT…ฐ๓ไฅฐx~m๕\ศoาš(!ฝีย… ๓๛่๘Š€" (Š€" ค,lึุtฑ๙Q่FCŒN‰Tฎ_ฟ’ ”axv”-[ึผd+]บด-E{๑*มƒ7๑์๛๏ฟ—_~๙ลnPc฿๛>!RซV-ไฏใ่ุอณ+็อพœ๕<)\๙ฎฎ„๕Zม+!‘แ้`๔Pฌ7kc2๖H๙๒ๅeพ?๔SiถญG๖เม&žŸฝ๖ฺ+ำผ สs4ย;ƒ"(ŒA'xอเ!’Wฦg R%6ผ$>&#‘ !ร ษแZŽ€ˆs!8ฎ^Š@ุHKขฤi”(QถฃฮGPE@PR ^๓V}็‘jkt๋แอgŸ}&่8”)Sฦztžlœใm^๓jp๚่#›bฑGชQ’ฎ]woผ๑†,\ธPžz๊)๙๗฿ฃ๊*Vฌ(K–,‰*หซ‹>}๚ศาฅKmwu๊ิ‘nปMŠ/žWk?Š@J!Qาฎ];น๚๋_—%Cฌ(Š€" (Š€".>๔Siธฑ(Qฎ็ขณI>ซWฏ–oฟ]–-[–ipiิจ‘4hะ@๖w฿L๕yQ€ไ€_P๙ไ“O–๛๏ฟ฿ ฌๆEฺ‡"*D"๋yีกC™4iRเห Q‚{ƒ>๘ยuE@PE@Pาฯ?\ฮ9็›๕Fำง๋ง 9๋fs๓ุcษA$งŸ~บ)R$9็`”ซฏพZxเจ–u๋ึตฎ#๛์ณOT]P/ฟฒ\wu‚งFฮw฿-š‰&(ฤต฿‚ˆภ?#$€ุ้ฑฃLœ81๐%„Š(!=๐๚๕๋5๔&๐วฎ(Š€" (Š@:#ฐqใFป#=ฐ%น๛$ฐ๑' c๛๖ํVT0wwง_kH’K/ฝิ.โๆอ›Kํฺต๓•4y๕ื…ฝ‡3<9ฦo7bฎ,™Gา๔v้าEHl7Nฮ;๏ผdNAวRB€#J:u๊$&L|ฎก!Jˆ7ฺ๊ตซี(Q’ภŸปGˆKr๙๒ๅฅXฑbYดิ*E@PE `"๐๕ื_ oฮรzรห•+g฿ชณ‰ผ๋ฎปไุc•ฝ๗;อ๖&MšH… ’๚ถlู"ตjีฒcพ๘โ‹I?ฉ‹M0์ฟฒื^{ ฤัฬ™3ฅpแยrฤGุg๓ื_I๕๊ีฅfอš๒๗฿Tิแ…™o™”ฎKษฦ]ว+8Bิฎนๆšภ'ญDIเ๋ Tฦ‰Ou† :Š็jŠ€" (Š@*!ฐu๋Vป k่ o Wฎ\)!lyณŽตlูาz>ตdษ’6L6ูฯๅƒ>-Zุa๑h!๔‡ั–แC˜šฉhhŽฐ>BCQ&.ฦ›aร†YัVสyv๑๎ฺ†8|๒ษ'™าt ‚๖ฏ(Š€" (Š@:!€8*›ฒ0†ฤ>‡ื^{อ S๊ซฏๆฉŽล† l6ว๏พ๛ฎ7tถmญืgžyฆ|๗w^]์IลŠํ†žpกN8มfM)QขDlณ|นโ‹/aUDVsš–—ฐอ›7[Žx!…ธ eSฆL‘fอš๙ซใž฿{๏ฝ6ตg<ฑาๅห—หๅ—_๎แ Aๅ„sAD=๙ไ“VวfWI 4Qœ7Œฟoศ’›nบI6l่/๔œgDชbBใ๘แณaTฅJ•@็ +aG€N*Wฎlรใ“ ฺ”( aํ_PE@P!๐วุWA Jุใแ‰๑B-‘๖o6#ŽoฺดInผ๑F+6:`ภK น{้“ฌ'.คว•ป#a$ดมศโยjุD‚ฆฦผ๐คศฉแตBjf๚c|เf+ึ™›uนy0wˆ งฟมผ™gŸ>}\“Lวฏพ๚ส?ธญใผbฎธโ +ฺš้Sเถๅ>61ู™๓(‰G”p/;hpdฯ>๛ฌ๕๐qŠUฃF {‰ฎก_ลตษษ‘็0qโD›H‚gJ˜‹ณDss๕yy„˜" ฐK œจ๏wyG9SSาด&J๘ฃHŒงŸMMื‚ฎ[PE@P pž!๔APDS๑ึ@#ž๑M1t1ุXใ1ำชU+/L† ๗ /ผ |ฐ%Gp๖๕ฯ[๛}๗ื’*Gu”mู@ผjีชY๏ˆฮูเโะปwoW ฯŸ{๎9ซƒบ“UศJnึๅฦโŽ;๎p—QG4D๚๖ํUฦล3ฯ<“๐A+cษ’%qsaQ9ศCเ๐Cฟ.๔&vB„Bฃฦ'žxข cโ0ฟF :6tP์ํปtํ๗\โ๓,ญธYMœฯ`NEŽณ๊G๋‚ŠภŸiH‘*%J ๊วV็ญ(Š€" ( 2ด šYˆ'p ๑ ฯ›!\[บtฉ Kฦฟ]yๅ•6ิ(Vธฝnบ–X(Zดจฟy–็gŸ}ถึาซW/๋q‘ecS‰ถJl–H๚ภฮ=๗\ซัa/|ฟrณ.n#]๑-ทโ๕ภฺ๖o?K๔Pˆ๘ฌ฿s‚2p๒“=เLธa)ค^ฦฎป๎:i฿พฝ=๗r>Y‘๖œฃO‚W –•‡Ÿผม3จu๋ึ๖ž'.ŒมZ<๐L`ฃอ†›ท’lLš$่Œเ’ร~s’}แพ๛๎๓6hM[g›^B‚๐€ม๎น็ฉ_ฟ~ิ๐นYืบu๋ฌ๋-ˆฬอ!ึSยŸŽ–:2า8Mผ= ม &๘‰5Fƒ–FNฟฟ๛‰’๕๋ืgฉโ)2ไ@6ah%Ž5JๆฯŸoป‡Lย{ƒฐจd˜KีอX๑”SUธpแdLGวPB‹วO:้$B›ฑ*ˆI+Qชฺง" (Š€" (!G!}ˆ<-ยl ำฆMK(ฐ‰ึHl8 oๆ็อ›gร6ฦoรrฟม๐ Xฐ` ๑ ตBฌ\rษ%Y7'ˆผW™ กžpRฟ:QUผ N๘๒Aึ *๋฿็f]„'ฆ„M:Uš6mjฯ๙ลc.ต1ๅdšมSม^.„บ`Nฃ…sHศXcํ3gฮ”ค™พ๓ฮ;-aE_‰ฤZ8xบเ๑โืŒquyq„$ธr)y!‹-Z$.์*/ฦศIxŽหหpขœŒญm‚‚€!'Yก7๓"฿อธFฬคˆqญŒf>฿็ฃPE@PE ี0DIฤ„ƒ„~™fใnฟ' Œ„s]ผxฑmร๗I~ŒBฤคœตํ?๘cฏฮฃF๕aผK"fฃ1„…ื†๛M˜Iไฅ—^Šj๋ฟ0$„mูe—๙‹#Fo"bศ“ˆู๔ฺrC ุv๔o„Oฃฺโ'jLฦ}ไ‘Gขฺไf]^xกํ๏ฌณฮŠ๊#ั…๔๕ฦ/‡]์qไศ‘‰บˆฝ{Ÿ๑†Iุ&ถย่xc™L/ฑี๖ฺh่DŒฮŠืฮˆGต3d‚์-“จ๒^/o ึmผhrEžด7D”7ใ“mŸ;w๎ฬถ6PR _ีwbB0“ฒ4Iส(ู ย์q2o4"ๆm@6ญตZPE@PE`w(D‰ษฤโm wFย%ณน๔o๐MŠืึ}ฯค"#žฑ1‡ค€d๐๗c<."ผะ‹56๎ด3%QUๆMง-7,ถœ๏ถดƒ<๑› ํˆว aaB-ผฆนY—›พŒN‹ืGข“7฿|ำ›ƒ๑ุ‰ฌYณ&2x๐`K2ANuํฺ5bผ+โฎ฿๕้๐2ฎ(#„‘[oฃฺ๏žˆัYฑspm8aUฏ3{ฟื(‡'~‚ศxทไ๐ฎHdห–-ๆฯ oฯะต1oร#F“%.ž|Yวัh1ธ2๙L๐|&OžœฉN TFเ—_~ฑ;ŒSR–ฉDIR`ึAE@PE@a&Jุ8 ‘aทa6"ฃ~ๆ–#oโ1ˆ ื.žwD๕lย1พp:4bB]์ต๛ลธ&$'Š0‰๗๖า ฺ˜ƒ3“Žุn`วฦฺb“ล›;x0@@ธนฒ)†คเ‹ฟ+ƒ|pคPnึลผ]ูH'ฺฬ39? นฑฯ?<โ_s๎ุฑฃลM6ร eฮŒท„ดiำฦ]ส[oฝ%ร† ๓RS๘้ภ-™โ›j1QฬxXXึฌ‹—“Bไ๘ืเฦpG2ุ๐์!‰Y‰ๅm1)b<k<i9Vฏ^์ฝ๗‚€ฎั2qCว=BŒpOีชU-™ร3๔ใํฟษxUH“&Mฤhฌุ๔ลฑDŠฟmv็ฏพ๚ช% ];H R'2?QยzๆŠm๛™€„D(ƒqํธf\า/C‚ลXmปX{๛ํทลxคุb2ๅ4KSl?zญD~๘แ9ํดำ,!์OiิZBG”เQ‚zถš" (Š€" (Š@p„ีฃd๓ๆอ6U.ูaŽ<๒Ha“Žwo่ใmsŠYf๐fpถaร๋‚WB"ร+‚อl:u25![ะC=ไ•CŽAUฉ\นฒWๆN 0LhŽ๕กฯB… นชLG6lLจFBฒภS์บจ3bBV„5oผ๑†/ญ1,x“8c$6๋ฦอ]{๏=1ขถlR˜๓3! ยบ๐†แžƒ>ุuuฤ+ขhใฦRพ|yKt•+WฮžsไวeŠบ1‹ >Œฝ฿~๛eั*gUd‚๑$•I2!*T๐sา.ฯ;ืฆ์%kไฦs3fŒ%o ์&Nœh=จรรฏ&ผkภขฏ%ฃqcำLำใฅ1^Ax(ล3—Ž™:ๆMๆ*5E ]pฉด๑8ไomะ*ข„ะˆ*Q๔cืE@PE €(!l„/้lx3ฏ^ฝZŒ๎†lบU๖w_)Yฒค๕lจUซVBR‚ภขŠษฤ งžzช/^<ด0’™uB„Fฝz๕<fแย…6์$'“7š ึ&'m RR๒โษ๔มxำ† coค๑โโŒg”w ฉซFŠ’ั๐ฑ!TAฮO๛Vย„€#J ฉ vเS Q‹ช%?s@PE@PQขD?Hข3fุฐWๆŽxำขiฤg&U ดk๐ยม[†ฐฟRึขE Kๆ8—0ฬI็ $ ผ ๑hป๚๊ซm่`ะใ†‚(!&“?ผ๊Q๔ใึE@PE@ศ@€๏^ผ•s‚žŠ‹"€w‚ด่›xเRบtiูc=˜ เ๔Q7n,ท฿~{HfฅำP’ƒ›ว6ฤคK—.ชDIเ๋Š€" (Š€" „ˆDEแ›ฅฮHPŽ(IV่WŠ@๘ๆ›oฌ^T2ยโXo่ˆตI‰ฅฆ(Š€" (Š€"J”‡ญ๖ฌ%dBศ•๐5E FฉW`@IDAT@๛ฌณฮ’I“&y)ยƒ\ฟ%Aขซ}+Š€" (Š€"R”( ้ƒัi) @๐•๔ศลŠKะB‹ิE‡ „จoผ๑Fiบuเ QB๎r˜ข๛๎ป/๐…๋Š€" (Š€" ค3%คX$ฉš" (Š€"fQr๓อ7Kห–-Ÿช%Cฌ(Š€" (Š€">”( ฿3ั)Š€" ฤG`ใฦRฟ~}™2eŠ4kึ,~ฃ<, Q‚H ้ษิE@PE@P‚C@‰’เฐีžE@P๒/พ๘ยฆํพใŽ;คQฃFyyœBA”owqวษน็ž+฿~๛ญ%q”)Š€" (Š€"—sฬ1าซW/>|x^vซ})Š€" (yŽภ็Ÿ.็œsŽ}๗า Aƒ<๏?ถระ%ไGพ๗{c็ฉืŠ€" (Š€" (yˆ€%yฆvฅ(Š€"(Ÿ~๚ฉ4nุru๋ึ t,:QาฑcGูผyณ%?v@Hm~;็๋งHฮjKE@PR ฃ>Zz๗๎ญ%ฉ๔Pu-Š€" ค(Ž(™9sฆœyๆ™ฏ2TD ก7้เQ2t่PฉQฃ†.\8๊งPกB๖ฺ]{์aหัฉˆD"K{žจŒ๛–จฟ ็นmG{๗ใ๎wืฑว์๊i๓ฯ?^Ÿฑ}ธ6๑ส]kฯฎ]ขน๘วv็น#ั5ๅ5์'";vท3ฑŒพไ?่๓ำŽถฎํ\M=‹ท้Qv๎ฏฬ<นŒ{ฝv๓ฐs1๗์ไพ๋\[ކ?๗Yูร|&)Š˜2,ฃœzฮM]Fกส( …0JฦGอด3๗;mมQํ่‹้๒yทš8๒ฟB…97›๋B”ขm!ึส(ณๅํจง=}Qo๛เศ-7%9e…ฅt…#ฅRี3ฅํ๑ฎร.F)Š€">(QRpž๕๖ํeม‚6T”SN)8O๒L๙ฎดdษฏ6mฺไxtR๎๖oRฒdI๓!๚๛rŽ;ั†Š€"(ฑ4mฺTๆฮ+งžzj cัyจˆ=cฏo+G.ธ› 5เNํัึข่r*อฟตๆWพXพfA฿bอ๖฿ุฟธ‡ฟ+ท•mฬo}ฦmo1N46…คJF๑ฟd\EaไoC๋Œำำฟ๗pศธ/ฃซฯซ6 2ส์๏ฯอeขํฮตwำๅ˜qฏืภVA Ly๊izด%~ฌ๔\PาJ•*Iฟ~ไาK/MŸEะ•>๔ำ2hะ 9๔ะCๅล_ฬx1P@ืไดูGิชUหN*TH8/g'L˜ ฏฝ๖š๘ใถ>๛์cษจใ?^๊ิฉ#๕๊ี“=๗3aZก(ษC`๚๕6-๐ร?,ีซW|เP%;w๎”ืำ(qjฝทOŸ-Uชi<vสN#f๛Gƒรถ?vุ#็ุŸŒ๋vr๔Ÿ๏”?!;vd๑๕๓ืŸ้ื๔มฦ๑ฯf“hv‹l~ไ€ปฮุปบlkํmk7จฎŽ๎น9๒Qฅฑ1oSo6๔œk๏œท๙ฒฎ3ฺE_ว+3ฎ^q๋๕.pใd3๎17{o์5ๅfร์ีgพฮจใ><2๊3ผ๙ฟGๆ็๊cฮฝ๛งPa—฿ฟ๎> ค ปFu•MŸ c็ฎR’ภPึŽE ฬเํˆFษ€ไ’K. ๓Tฝน๑ฝใ๋ฏฟ–+Vศึญ[m9\6ว?๔“๕" AE‹•† Jืฎ]ๅ…^rๅสษษ'Ÿ์๕UะNž|๒I2dˆ๖๋ฏฟ.ฅJ•*hKHส|I Qปvm;ึmท&Mš4I8.|žฒฒC9ฤ w๎YŠ+–USญS€x๗wฅmถฒhั"9๑ฤอl อ?:ปภ‡J<€#J:t่ ?๐ƒsฯ=‰๐š๏ฟ^N?t}4ู๏๘|5:}E `"p็ˆ๓ๅ/>’ษฏ’ฦ•ิฃค`>Eต" ์.ใเภฝ ๘๎๔—ื๗๒๐ร?พs\ทn๙๗฿s5TงNdผy๖ž;๏ผำfLศU!iุcyž??‡~ธ„— ; ษ<๓{NไqาคIย‹‡Sณfอไฃ>’๚๕๋ห‘G)EŠ‘M›6ษฺตk…›~›6mš%ezฎ(ษEเํท฿ถŽO<๑„เ๕ด…‚(qXงQฒm6ฉZตช {ฃ|rห Ÿฏ๖ฏ(qธ}xgูผ๑นqมj9็(%Jโ@คEŠ€"โ๙็Ÿrย 'ุpŽมƒ‡fตoผ๑†ฬŸ?฿๊Lไ”แญ้าฅe฿}๗5žš6Hีฎฒ–ูณg{๋ร3ใธใŽ๓ฎ สษฌYณไškฎฑำๅนaคสtAœ,\ธP๖฿[—ฎฟ>๘เiัข…]>Ÿ Bo€tก5p€uื]ึป๏<(๓ค7(/ฟฒWฬ3ฯกjjŠ€"ฌZตJฮ;๏ป0C{า฿‚+ž9ADฉzAญWฏž ˆZถlูLร‚/!ภH๛™G6›'tG0ฤoัเษฮœทwผv|yƒ]…€ใญKห‚ˆ๚Lx’E6฿’ผ^Sจˆ4J๘cžสก7<@bชฮฝ —œาaX^?OํOPr€ภไ~Mไวอ_ห‹฿•zJ”ไ1mข(ฉ†โ๙งvZŽยWยดvฟทแ)„3็…แaCจ แ/^ภฃFฒลุฑcๅจฃŽส4ิฤ‰-!ฉยเํ0sๆL[ีฅKAลodmhะ |๐มV[คqใฦž็&่m๊–vœณiว,X`๕๎}ล;วS]p๒ฤ bˆeส”๑'<ฯ-6„P๙q==HEKฬแEBศ žW]uUยyฤซ€Tb-xุ€žGœZv๙ๅ—K๏ฝใ–ฉ์๚๋ฏฯrq๎น็ฺนํฝ๗™๎ีE@Hฏx@‚ร฿อ -tD ฌpช{”เ๖ื๚ษ็_๔๓ีE “zŸ-?n๙F๎yvิ=B=Jโ@คEŠ€"โเตมฦr๘๐แางOŸณZผ๐ึภrJ” ˆw›p—Qื)SฆXO†ร;ฬzpฐ้ฦ "๗Aล‘ gœq†งb™_~’Iร›‘Aฒงฬ˜1รz…Pโ‹/ฺิฤ„ษ8แUสัM! bN ๆ€9ฯ“ฌ๎ฅ}๗๎=๏ ฺBฐนCฮ™gผ›ป‹ ž#xู$24qยd%ย“dฬ˜16œ(ั}9-?๛์ณmึš^ฝzู็žำ๛ ฦพ๒K‹‚ฎxฝ๚๊ซํ|วK&oฒฝA๕DP<žz๊)น๘โ‹eๅส•rะAyๅA„‚(!^“ุAฤ’า!๔†?ดM[w”zŽ ๊นjฟŠ€"บื‘Ÿ~๘Nf<‘œฅDIHi•" ค*dจ]ปถŒ1Bz๖์Y`–้ฯj’Sข„ฐย;๐ุธ๖ํZ!MุœC  xัEyvmvฃ=y๒dฏŒ“ๅห—{^x‡เ%‚กƒq฿}๗ษก‡jฏงN*ทzซ=เฌ็Bกฑa xP๐vดTฉRถmVฟ:๔฿ดiำ„อ๑jืฎช3z๔h๛m?~hv€ก?S๎6๋ืฏ๗<_๑jมKง[ทnฤ†‡๏รAYoX'^-xํŽAœ๐9แ3„ก Cvก‚ชณ;X่ฝŠ@~#เาค#พผ฿~๛>ะ%ฤฬ’ซ<•šดh'๕{_›สหิต)กE`ฬN“m?(๗<๓ฎิฏT,ด๓ิ‰)Š€"hVœuึY2rไH+Žิ8y๏'Ÿ|"Mš4ฑๆTฃ„๐—qใฦูM.˜#ำภรย๏ํัชU+ซ%b๚~9๑Xด>ฺถm+๏ฟพWห/6ึฏฟบW๖oดลฮ/BE†‡Yฅ๖๕kณ@ย4o฿Eิ9แ-l(0ผด๑ฐpFx;a&ฮ˜๓ะqeปƒM,!ิบuk๋yC฿ค้…ฌย6lุ๗}ึร3ลร‡็ž†‡ "’|N็!ฌGMP’‹~ท๗ฮ;๏De jก"J`ฟaฬำ(iุดตœsัuA=WํWPฒ@เสsซหŸทษฏ–s*—ฬขฅV)Š€"š|๕ีWV`“ฌlา Š๙Sว’‰ึเตฉ'คoG$บ‡rDO๑8aƒŒw^ „๒ฐ wme]!4ข ึ>๐C๋qBผฝ฿๐j้ัฃG\—rBำ€+ฉj๑ยvFบ+VศM7$hhเฅแขฮ3พcCš8๑Sส๑‚A ัeขlwฐ‰%bนDฟฤ๙๓m่8bd š={ถอF๓ฟฯ–ํฮ/G”@f๙ฝ‚ ฐ †๘ฬWฎ\9ืC•ˆ!ยฌxฃํว ๒ฌP! ๅอ5จzƒ" ๘ม฿Rฆ'C/H‰’\<œผjŠGIร&-ไœ~7ไU—ฺ" ไหT–v๎ฉ VHำช™ณ*ไข+mช(Š@Dฯ„D QโsEHตcวŽูโ๏“แ‹6Lbษ ็…A‡l† K!ฌ!O6ฦd[@ท]Ht>ศพ€,แhZ์ป๏พ6›a5คฅอส๐0นใŽ;dัขE^3๚$ซ ‰Dl2ส˜…Pq†' D/ัADcN.•2$ Z4๑ดCbujv>Ox๚8ปkฏฯƒš0 ึพkืฎตอ\.EฒปWŽ`รs!=g„9ANQ†นตํท{š.<๒ˆฅˆ*H*ž๙e—]–nตฝ" ไฆ๑๗‰ะ:?Q™รs,TD ฬ/สฺN+ืซ) 7๕ฆ~ฃ&าt`Fj™ถNSH†ตฬˆ‹พi๎Riu๊a)ณ.]ˆ" (9EภyfฐIE;ข ุ7฿|#u๊ิฑำ%{ a&ู™?ไร…ญ๘ษ๕G๙์7ๅ#ภy๘๑ีๅะŠั.“?^+Ÿผ๓šœีๆB)ผg‘”ฤ@•7เI‚G vฬงฅ™G็Mวฺ‹" (6ญ5ฒ›b6ทล%ฬŒ์Œอ1^oฑฝ๚๊ซmX e„‡เ…ง m!ŽุL;#รไ†๓‚๐k€ ์้๚vํ]6๚นไ’K์ฦŒะ ฒะ8$ึk„6ฮณ…๛!‰ะ™ม;c๎xห`Yฅ,ฦใม ื"ผฺฉS'@ฦว3…#,ทุ8าo%๔Yc;๓‚rZ3ฮ„{ู]ปๅ–[,๑D?ิ+›ิปก๐ํ—าy่๕Rฃ~ฏ\OXvงŒhwข-๗"้ ใ<ถ^+Š€"ส8/ ƒฎ]ป˜ฅ๚ร ` ‡œLžฐ“ฅK—ฺM2้]„฿ @พ€๓}ิฏ7ฑs็NปแF[ไตื^“7฿|ำ'Œ‹giใm6่ิใอโ76็E‹อD(8=[Hž๑ใว๛‹์9}เ้€ว2๖วุPXx=6ไา#†ๆžeD„d%ป‚ d}:ิfฟ!ซ’ท+4R | vœ9ฦœ†Rน๛ักAW&žpร าฆMฦ๗Dผุ ฯIDๆฤปM<ƒœGd สฉfNผ~ตLPฒG€P:ฤจ๑(I†…Š(แจs๒v เ1†‹1=๓ฌzาfุ๎ณๆAฬ1ฟ๛๒๕gฒ๊๙…๒ฦsฬ$๑ๆsูํ‹ๅร2พP๏ˆ’3[Oฺ๔ฝ*-ก-๛ๅวอ๒แ๊Wไจ“N“ฉฺyฆสฤ๚ใwีฑš.ผง\5eŽœ฿8๋๒TYทฎCP?Ž(3fŒไ…€ฆฟ๏ ฯ wม#อ H†œคD.Wฎœืฏฟ’"EŠไศ…›๏o&.4ฯ 4LœโRซV-๋…1™‚๓ฤ๐ ม“ƒ๐า๛BF$ฒ–-[ZR7–k๗็ŸZ‡Œ.ฤ›t<2bรtจG$o6๕xU$2ฺAf@ฆธวปŠ๓(๑{W@D@p1?ๅŸ!Iๅห—๗ํึyฌV { ฒึฤŠธฒvดRภศ7 †˜ณ#Pแแ%'Lคe>๐ภฝน๙ลkŸ~๚iฌ๒่‰" ไศs คDIžAฎŽ๘‡‡?าต๊ิ•vร๏ ืไ๒y6?|๓…<ะํฒz้_<”jท์*ง5๎${ูหŠp–ฎ-r6ฑW}ู๚ืฦ›คต๑*™loใK Fผm˜mฺศฎ๒้ป+eฏฝ๗‘กS“ƒสๆ้๘น๑๛/2บำ)๏b2์ฺ;คGซŒX๗ฟ0]€" (น@ภฅู็น‹nาถ)ฺˆ”3Ÿรeiซp/ฺ<ดb  = ;ุŒว#=ˆำ+Vฬzeฤ’)ฎ]~Q‚'Iฯž=๓kยw@ศ*B๚ด-^ผxฎ็KŽล๋ฬฅ{~๗wํs‰ืNหE`๗€d&s•%ปe({ภอฏZตjRx”ดV๛Œพl<ศ•พใ๏—;–;ฏ8฿–๏w`iqฯ ึ ลyธธ๐"นpฬ=ฒvูำ๒๘๔kmqีฺMๅ—฿jฯง_ำ†้ดฝ่*9ฃ๙lูจŽี,1ใ-bŒฝ๗).›ฟ๚\ [ฦฬYiรทv]ฑ™ƒจ$“ฮฐ;Ÿ•ต†€ยN8ฝก.ผง=Oว_[พ๚Tฎ๏ืT*tบิ<ฅฆŒN‘฿t|6บfE@H๏ฟพ๐‚j๚๔้6$8y#๋HฉŽภชUซฤeฝ9๏< oM๕็ญ๋S’…ภจQฃdแย…้้QB่Mช%+Wฎ” .ธ@๊ŸPššฌฯUgใวkๅ๑ๅ—ญ›ํ:šw&๕ฺ๗ŽZำcwณGvD ฉˆoฦ 1่ฦGโฆโ๕#/ฏษ่Yหญžสmรฮตบ)4„”iู๓ 9าdฮ!ฬˆ0tM c0ฟ็‹-Hณ_[พ๚ฬ%M„ฐค๊ีชสตW^šf่rE@qDษ๗฿oSุ*&Š€" (Š@˜ธ๒หๅ‰'ž<"“aก ฝ(!ฮo๊ิิ%^yๅ้ืฏŸิ3% ’Œg๊1~6Hพ๐‘e6๕~=ุI๒ใfนฎO#๋aO‡ไ1ใํฑx}เq1zๆr๏v2œฬป๙ ฉVท…?fรrำ Vถพั ฉีฌ‹ืึ๒๋ฯ=’ถ่โ›ุ„YŸvTVž‰ฝ๊หึ๏พ–๊u[สyC'ห๐ึวนฆ™ยHi|mฯ๚ถ..tศyฐ€หx“™ลoxฐTชz† ห๕tซๅ้QขไAQไฯ€๋’ฝ‹๏็ฟU๎บฒ›|๒ฮkถฌ—๑l9ถFจ๚tบ jRŸs”(Iง‡ฎkULธะ%J2AฃŠ€" (!D`ุฐa๒ิSOYข?ำ Q‚๚:ขHฉL”,YฒD.ป์2ฉ[ฏพ4่ญ9‘Œถ1๎ธ<๙|›6Uk‡ใฅขษZ/,ไ๋O฿—[†dคq=ฆฺ™า{\tสนน —™ฤG2g#—”๑ฌ๘Hnุยึทํ;Zฮhัีk๋N W๎รfาม‹ใู๊ฏš{š["ฤต 9น~kw)“z74™mพดYpZ›~วw?หซใฤ๏QB˜Œซo{”ิnีMž{๐6Y2wŠฝgโย๗ไป/?๖ึKแน_+5ฯ้`๋๙5cloซงrฮyๅค3›xk"ๅํภษ๓e฿ถm™Yw^}jฎฝf=cๆผๆeาฑ…i๖๋วอ_ขชmยชN>นšLฅ%i๖ะๅ*Š€Aภiฆ‘A VญZЉ" (Š€"jˆ~๖ูg•( ๕Sฺษแ.4z๔hใQR_๊๖นq7zJ[†฿ญ ˆขfCฟs็๙cฏBธ ฮNžg„8ซปK{|๋ลวไม›†ู๓‘๗.•J—ท๗฿vY'๙๊“w-qมศๅŸ;gCคGVฉ)๛Œอ_.๋V.ตbจˆถR฿าR๖ˆใไ๒6วGวแ-พพ๗ฺsV…2ฎ?XX๙็#4`ึZ]ฯ•ฟข_ฑP๓+ลyšยิ*™[T6ญY นpปYŽฟ_ผมํฐˆ*ZLำ+J ”๘๛+๑ƒ€_กdษ’%TฑbEฟd€Aƒ€xž={าฦi๏ฝn้ดว %พพGษœ9shฦŒ๔XฝzTนmสqณnyฺ>ˆ๙๙ •?ญ`๑‚E‰ดฎ๘ุkt)ๆP^ตฌ(ฆPยงฮ[ผฌฎŽ?แ r๎"m˜B‰์—ยŸล๙;ๅน9uญJ9๎K์ตห^๑มuR@` Taส1รต›wR'๊ผb๋ใOฦk—/าึ•P๒(UR{”Œ„PโOcp8rไ5jิˆ–.]J*T๐hบuฃ-[ถะž=ฉะ]๖8กฤื?ฝy๋ญทˆw˜ฏ_ฟ>•v(%%gืฃ๕ฯzyิณjฏ‘{Š•ฆทสฆPาgโrบ็กา้ึk'”ค[ 3ฏ^๚‹^{ึZRซSฉTต๐llอ;ชๆ•=,=Xช2UฎPB‰w<6๔@ ‹ ศfฎIpนrฉ๗สโฆP€€k]ปvฅmถั๎ปu]ฉBIF(eกฯไษ“๕_o๘ฏ8ฅ[ คฤค,ฌUe ^น1 ูuผน๋TJทใ๛ถา[ญำtฦฌv๙bK+ไปiๅููํlา7ฉKWhฐณูธˆี&i%.eล&v3อq๎ซซอต,ง๙r๕ใt Z%ฬกไsZlvf)g๚๋Š๐|„@งNh็ฮดkื.ทŒศใ„›๗๐๐ีk์ุฑดjี*jฺด)=าฌลC(๑ŠG-Ÿฏดye2•ฉั0>Ÿ9yŒข{Z>CๆoT'žฎvf๎๖cz/๚EโSw†-šMyM|๒Ÿb๔€:ํจJลฒ4B‰ื<;t@ ๋o •ฎNmLต๛Vั~‹้•AU+A(๑ญ'‹ั€d”ภ๔m:w๎L… r <็ษฟเ Bƒโ'โ†kศ๙โ๋ZVาf๔โIOZ๘6'œ–‰…๘ธฆำ*ใZVสษไ…ำf[ๆ'-ป]Yำ—๓9-กิ้šถ๓aVโ/กk9Ng๖–ถธ~)+6 อ<๑แP์:ข~ˆอ5mฺ%.ก๘บ+ผ‘˜ย๙ฆคลf—ๆพง•/"—™/f]g_3ฯ,๋๊+i๑‘r’6๓%Oฺ`พ๙’ธไ™ๅ$ฯฮ๓คLz~fYณŒ)4Jy3฿ด™qื6%อ!ื)iฉ_สบฆล_ส˜๙vyv๕บ๚I[r~V^๒ฝkศ–๑O๒o˜ไfgcฑลฅnฅn3ไฒfžgฟดาb็oฎ‡/)รq๑แใ์ฯœ9ƒ% ลฏจจ(-”ดm–๎ข'ลA(๑Šวผh‹ดkวt{แ๛ฉ฿[Ÿ฿ฐฯรฺ<ชOšฉึ(‚šwzC๋ภาoSUWSธh)๊9fก: 'Œๆ๎E๛ิiBฺ๗ฃ:Ow๙ทอ๘Ly^QRคD9ฝขdไ>3. @2J@„’Œ๚gฤฑๅK~y6๑•_tๅ—_eุ๎—r.ไf๖ qึ)ush–—ดูŽซoZyโ'mši‰s[fyŽKฺ5Lซ อrฎiฉวดู$_BฉS|อดซMสศsr๕ๅ4_ฆ]สH่š๏š–ฒœ1œ6ฏy๘ˆแก 6๋0;j๎Eยํu }โฯ๛S๋fxCญ*ฉŸ]๐ชบ>Sš ?๘Uญ\N}zกฤซ:  -ไu%ฮซ=$nฺํl xF์๒หผิวฟ๗I;lใด™'๕Šำf,#uKื4—“๒ry๑“|ฑIZB๑“„ฤ9d?W_3อfฺ,c–ฑฅ•ๆ๚ผํbม„/N$-ใดk˜Vพิ%๙ryๆf^Rงi๛'qณ^ืvฬผดโฆไน†าถหm๚Kพ7…ฬˆoฺ์า’'!ใ’–0ญฒโห!_าž”3๓]๋p๕‘ฒJู›vmว5ž›Vฤn†vดณฅUF|™#๛pZlšv3_L_ฮ็Klโ/ก]W›ฎ ‡~@(q3๘กC‡าš5kจw๏Tจ๚stB‰›Ÿภ?kNNJแาแ}ฉ^๋^้Vtl๏w4sP;ํ“a%ส2˜นtR๚ซ•ถC@๙ a›็ฦa•5ฦRพ้?Kไƒ1ƒ€x>Zธง็ษตฤ9ไKlฎvIห„\B)#iืP๒อ๚ํ|ฤฯฬsตIš'G์'i3.6ปPP?ฤ_าโห๕š—Ÿ™ฃธYืeฆอ8ืcฆ%ž^ศyfœ–[๊“4‡r™63.e$ดห3mท›ฤJžLๆ%m†้•“พ"o"กฤอOk๐เม๔้งŸRฟ~จ@ล–t%อ@s˜ภ†U๓่›oSปAำ่b้o|ว†.™ิ8qŒบšOy๒๒อLม[ืาข๑/ ;r•ฉั€ฺผโป$ห83Ž๊P‹ีาฝบPŽm2Sพ     >Nภฃ„’'Ÿ|R+ง“&M๒Y์ผ™๋’%Kˆ?มษSฒ ]†Pโณฯ:งs๚dn4ํๆ#ตGY๊๘ฺL%ิศฉ๎xdปใบ…ำ•KQฏQฤ3=ฒ่€€€€€@ฮ€Pโf๎|๔๑ฌYณ(::šBŠืงKqn๎š๓,˜ไว็6ถฯ{R฿ฆt๖ิq?๙-j๔x-[A@@@@“„7?๗ูณgำฤ‰้อ7฿ค€๛๋RLฌ›;€ๆ@่อ~-้—รปi๎ขจfๅ๔?ฃ."เQBIฃF๔๎บพ้ ŸฬŸผ๓ฮ;w5๚๋šฝp-xท^ ใ๛ทำ‡ŸฌฃRลŠxB—ะ!กฤอbๅส•z#ืE‹ัๅT  JะอŽŽํ๙Žพฺ๘=[ศ=ํ‚;€€€€€€w€Pโๆ็ดvํZ๊ฝ;ญXฑ‚.ไ+I็ฏบนh@€f้@GwoขQพP%”4lุ‚ƒƒ๕)]๔ญุ† จC‡ดz๕j:›ง8K9ลีท๊!ฃแ๓่ีก๔๚\zัaŠ-ษฒ๋|+.็ื๓น๐H๊{็ุsาฐ9๓66บqณ_๋จ>ฝูF๗คผJn@ ู     เ_ ”ธ๙yoูฒ…ฺดiCŸ9|?้ก$!>Žใc)>.–T˜G๑ސำ‰ ๑สG *ไxbผ#ิie—tb‚ๅฃาI*ฮw"‡ Ž0)ัฒฉด•งาI*ฯ‘NJJRv$)™}ušใสฎnถ'%ฆค“ดŸ)f8‡๐กR–ขžกฝ๘ก๒|Y K)ฎ‹ถXข‹™งใฌษ๊y‚( (ศŠซ0@ฅ9/H‰6ทnํฏ”T>—ีกJ[6๑ ข ]W€สทl\ีŽสSโdPpˆพƒ‚ตXdฅYธไผ@G>๛‹/็9ุวีืJ‡ZuซzYT๒”‹…’Ÿํคํป๖าM!žา+๔@@@@@ภ@(q๓Sุนs'ตlู’>๚่#:Ewำฉ๓—)๎ฺŠUwUu_ปชำlณ์W•ภqM฿ ฑ*ไ›Eฦฉ›…Ž[!‹!WยG ,ฤY"Bใ อฅ&ปj๒ข&ฦzาฌ&ำjาโ˜ ๑D7u>๛๒„Z฿jยอๅ๕คูaS“qฑ๒dš'๐œ'“tž๘;&๓<ษWB€LฺS&๐,XฮUŽ•ฮด)8่ JŒ0B% Xย„k9Iซ๒์/ทิk้/,รคฌFa!F‹1l•ธ„ฎ6ฃœrถตอtXฤIฉ+9™E$KTาb•ˆM,V9D)ฮOะv XXQŠCK€ฒูวžุฮqงB”ุ’๕sZD/ซœWRชE-ซ.งะฅ๚ž‘ห๎ู๒{`ฝ+Z๏UP0ฟ/>Z๏“~7ƒC๕;’K…กขn~w๙ษ•[ูTจโกนยtšm:ž;ๅโธ ญ;Œrๅพ‰ๆŒ่F'ุK[ฟ฿Ey ”dไ๑ม@@@@†€G % 4P Ÿ๔fำฆMิฎ];LO๒y๒ศ“w%๐$^วีฤ‘ำผj@า,"่tฐฑzภ ดภ“LKl`กCDž„ฐxม65ๅvธNฅ(จะ!,8๎ฆ%$X!'-_ซฏœtฌœะeiŽ_wูฌ๎`"=?งa ฆกสฆฌ$แšDxเJ%ฮกใณฝjลJ[O๚นŽ|rRฅIฮ•.)q๖ๅ2ฉ๋Lษืeน]V <gœหZyฺๆ๔c›ๅห=ฯชหZฅยฯz—๔;คใ*ญ฿#yฯ8m๙ศปง฿ญ็๏|ฮ6ย็ฉaZL˜'ณำใVcW)ซ๚iๅณAณๅ<•PYN–Їๅวพึญ")ฬค3”|]ฏฎ”+ฮิลc{๐(…ฉล.ธ@@@@@@@xœPJ&L๙d๘๒ห/SฅJ•่ฤๅPบฏ’๎๘”Aฏ*ะiว_๔U๚๋ฝส_๔ๅณ+ไ•Žษทc๒hNZจ1}T\‹ภ!<)ลI•1lฎiฎSฤ#ฎWฝ8์:ฮuจดwM๋\ฦแ็Lkqส0ค^ษ3Cฮ“ดU‡”‘P๒yๅ ‰rฤUฺŸ.๋S/kUMR":fล๕J-ต:+>Vญิาซฐิ -็UX๎(L}ŸฉAน ”๘ำซ‚ฑ‚€€€€ภ @(น!ข์sˆK$JศุW ูื —šyAภี๘ด„g7&ฏ%จลึญDีŸXี/Oปbี{ฅถ‚๑จ+A=<~฿=ํชtw ๅ†Pโi%เBIผฺSใแ‡ฆ๚๕๋ซr๙Š’}โh@@@@@@@ MJาDƒ #เqBI๎นi๘๑๖0^ เQBIxx8………A(๑€]$กฤŸ:ฦ        `Kภฃ„ฬีŸ>ฝ™>}:=๔ะCคŽ{UGั๒ลวผ๒%G฿ŠรฤDวQภ๊^>8ญ4็I>๋š——ธฟ”“}ฅMถฅ•ๆsžšqฮ“qน๚Iฺี_Wฆ~Hพ„b—๚8-qื๐Fyฎuู•—:8ฯฬ—ด]่Zฦี็F๙าŽuฐีฎkฎi๑uญด›yb7๋‘|ืบnUฟฃ]๖a†–oJปฉส(5Jสจ๛้šวe๙bป„ฆM์lใ๗222’๖๏฿Oปw๏ึ๘     !”ฐPขD ๒งOo8@M›6ฅqใฦQ…วšำฮ฿ฎ_€ื@ { ฬูŽํูBำื์ก:๗ฅˆcู*j๐d'”๘หง7ทoงˆˆzแ…่‰Vi๏J<๙๔อ7 ผ;ชฺฑžf}บŸjC(๑อ‡ŒQ€€€€@& x”Pยว็ษ“ว/๖(Yฟ~=๕่ัƒZดhA}†ั3J2๙๎ย5cžง}›ฟ 9kPอ"XQ๒ฏข๐Jr่!~๖ูgิฟชWฏuyuBI= 4๋วIป7|B3V๏ z็๗c:€€€€€€€P"$._พœฦŒCๅห—ง>Q3้‡sJะะข๑/าฎ๕ำฤE_Q“ส๗‚€€€€€ว %7t“เิืŸอ๙๓iๆฬ™TคH๊?๑=๚้„_ๆŸ็X<แ%ฺ๙อj5k%ต๚_Iฯ๋ z     เv%”๐qน7฿|ณ_%,’,[ถŒX:cˆPโ๖ท ๚=๔f฿w_าซัณฉ}ใ~ฯ@@@@@ศ3V”$&&R๑โลษŸ„’7xƒ>sบz๕*ฝ>-๖7^Gw˜?บต‰zŽฆญร<ฺ๐@ฑขฤ…’qใฦัw฿}G็ฮฃฑ๏}Cง/yเ.€˜;ข+?ธƒz๖ขž||ด€€€€€@Fx„P’@%J”ะ+J๒ๆอKcวŽอH฿ฝฺgฤˆt๐เA:qโ]ผ‘ผโีรA็Aภ+ ฬ~ญ#zluŽL}ฺ5๗ส1 ำ     YKภฃ„’วœ๒ๅห็Bษภ้ื_ฅC‡ั๘๗ทา๙ซY๛`Q˜โ)I}โ’+ทi๖๛๘ฬAฯั้_ŽR๛^(ฒc ฟ็     ฒG‰ฌ(๑'กไล_คK—.ั๖ํ)๚ƒ๔w,^Gศ>s†wก๗oงึ/ŒฅRีฐ‡žสณt๎๗ิถkzกหณbF     เวฒ}EI๗๎iฦŒ้"ฮŒPย+1ยรรฉvํฺ้ึ้้™ฝ{๗ฆ€€๚ๆ›ohย‡{่rผง๗๓V‰‰ 4 ูu๗+ิmJญ_Œ๖ึกdyฟงพ๔ ลœ๛ƒฺt๊E/tฟ,ฏ‚€€€€xlJxƒVฌด}๛๖4lุ0jำฆMšt2#”<๐รTฟ~}š4iRš๕yCF็ฮ้–[nกO>๙„ฦฏOฑ‰ะ๋œ๏ใ•ฟ/ะ๑;่ขšyธ€%HฯNฐ—Žํ๙Žj5๋HAม!b๖๋๐์ฉใ4ฎ{}อ t๕pj;`ช_๓0?ๅ…ง้๏๓gจm—^ูB‰ษq๐Wู&”ƒ!ศIDATะ5jPPPญ_ฟ^Lื…r๊อ>ฝ๙๒ห/ฉGดt้RชPกยu๕x“…ฃ{๏ฝ—Vฎ\Iใ>O๑Iิ{๗๖•WDฝ‰ถ~พŒ๖}๗eชฦพ๓5ธnงmL—zt๎๔ ตjbUจฬi๗็ศมm_ั‘5‚โๅkR็แ๏๘3ŽTcŸูœ๋OzN %};C(I [III๔ใ?Rแย…),,ฬึF๏&ํBษœ9sh๔่ัดpแBชRฅŠ--S(ษŸ??3ฦึWalูฒ…๖๏฿o›๏Mฦึญ[Sฑbลh๙๒ๅ4๚ƒ”์MwS_y%ฤ๖ต+h—๏ำๅ˜ ถญพiเxDD„3€€op‹P2dศZผxฑๆ๎ปS>“„"”ิซWO๏aทขไ่ัฃิฐaCโอ\;v์(Eฝ6lธฑ^aณhั"Š‚PขŸใฉใ้7าฉฆzฎ7ๅ/@5ทฃ* ZำM๙ ฆส3 ๑qีกฆ^}š;[ผ WŸแฐpย๊ท้K5›v0‹๙|œOv๙้เ=ฮRUง็N๓๙1gt€z5ข+—bจkฏพิฝ]ซŒƒ€€€€Ÿ˜7oEEE9G?mฺ4}ะ„ำ€€€Op‹PKฅK—ฆZตjั์ูณฏ—ก„7„ๅฯwxƒุnปํบ:ผอะ Aช[ท.ฝ๛๎ปJo๑„—i็79eั2Uฉf“vฤ๛jุmฬ๚๗…ณ๔ๅขฉ๔ืŸฟำ…3ง่๔‰cฮฒiE๊ต๎Eแ}ำส๖I๛ไศfN๑‰Wไ4ํ:ฤ'ว๙O5พg}ตขไ"๕~ก?uŠx๊ŸT2   ~Dเฤ‰๚ Šร‡S‹-(22RŸd้G0T๐ nJ˜dถmiถm๔๗฿SผySมๅ ‘xฟŽ๔V”ฐศฏ…’T…ฝ4มcๅำ{ๆฬ™Kฃ>ภง7WฮA›>^่|ขืŒšuJนยnrฺฬศ๛S^ฅmk?0Mฉโผฅhฉ*ฤ๛rฅNว)t_1ส_๐ŽT>ˆปv….ช“Y QXmŒœ้.G๗ง3ฟคห=ำ{คt)ำ•๘hqร้ชZQ๒BมิฎU%†     nJxร#~7d0`@ช>H(aๅ๖๛5mฺ”&L˜ชฌท&jืฎMอš5SBษฑlท#K๛อGฮิŽ~๛้ฐณ^\ฆ๖Sจjƒg)๏-qฺ9โบฅะฝEซJ,๕(uฝ •Z‰“?์ฃํ_ผO' „ธซ”O‰)ลหื ฒuSพท;s๒ญ[6ƒ~9ผ›nนํNโOZ*?ั‚Brู๏|~d็๚๖ร9๊Dž“tืลฉ\&Tฒสใh[?ฯq’>[0™vญ_ญ}˜E๑rีฉQ‡t๋Elหล^ฝฌ๗0O’}[ธภw7่๑ู๖Cใุฎำีห1ิ๚พ๘้F~HCp%เ6ก„ฎZต*%$$ะ๖ํS๕C„’ว{L๏ํบGษฌYณ(::š8ไฯU|แช^ฝ:ตlู’ๆฬGร[๛G๘ยธํโbiรG๓hส9ืtSต~kชีผ็ฎ๛u3ื._Tพ๓้ถป๏ำยFุอทะัฝ๔ย9๗๒ล๓ดf๎8}ฒNZฎ\๏ijc‡ๆrบ์฿ฒ–ีำ™–ฏ`iีw =\)๕;๚ู‚‰ZT? ๏บฟต๐†ฯ}br†{7}F ฦ๔qฆอทำญฯ(ON3‹=ผ"็ฤKtcัจa๛~บ/รฺ<ชY๒ž-ฯ฿Yข1]ำ+JM-›ึ ท %cวŽี{”,S'ฝ๐ 6r™BIม‚้๕ื_—,†‡‡ำ้ำงiฯ฿Yyมข % ฿{/ุ–jผHล+มdŸ พ]5ืนฟ†pyโ๚๏5bwŠอ‡ำ‡าๆO๋ฯmา;—Oึ™ุง)๑g-r๑ŠŠ5Wขยy:๔zg †ฬ ›๓฿ช&ีฉ c๋8๓คฌvŽW…m?๎B3=gfงŠณ่9้Cต*ๅ.งเถฏh๎ศ๎ฮtนฺ้กฒีhฯ†OˆWฆ๐ีฒ๏๋TI‰8|ูฑžึEว]D-Eƒ[–ำๆj"จน๚” W ^mร{”ŒMอึKษ@ @@@@@ภo ธU(๙ๅ—_ˆW4iา„&Nœ่„ฮวท>๔ะC:ฯU(9sๆ UซVM๏็๑ๆ›o:หx{ไัGฅVญZั’ฅห่ีy›ฝ}8ฺูŸํ jๅˆqห•WŸฎ<๓( 1Vzฐใ9chฝ๚ฤๅึB๗า€ูkูd{นŠ…‹–Rbศt็g)๑ฑWiใ๊๔ษปใuyXถ[ิปดi๕|Z9+สY'‹+ขๆฉ•R๑๔ึ๋hธ|oงWgฏำซPd…‹เU$‡อฆฝ>ฅญอej4 6ฏLัqSˆแบ; žNEหTำy?ุNำm<ฯำฯ>O—bฮั๘^ ซo*? •จX›N?คWJฐธ๓ลข7ฎkG๐ƒFwฌญ„’7i*5zผ6ˆ€€€€€€€{W”0o^r๖์YฺนsงzBษoฟM)ŸYฮซ0|ๅชXฑ"ตnš–๐!ฝ2วZ%เ+cหฎqœa/อ‹๊ฉ76ๅ6ฉOK๊<z%ลชY#ตภq#ก„"žท™๎*ฆ๒„ๅ๚๘`ืพ›ย /฿ฎœK›ืผ็tk๑|”ฺ›คฅN๏๘z%-™ุ_ว›tจŽ!nOๆFชœัฦg๊Sกดนmไไี*˜Gh๕;ฏ๋6ดƒ๚มใธงX)ํ1S๗Q๓้มาUR 7f_ุ๑๏ฟTŸ–ิKต๚ๅ๕๛)8$ิYฟGขฺืิ{บL>›๊ีฑ)g‚๑ƒ€€€€€ฟp๋І-g/^ผ˜*Uชค๙ง'”ฐฐยซJvํฺๅSฯJ„’ซ>ข~ณพ๑ฉฑ“มฤœƒN|”,Y9ี~ ฎu]ผp†ฦv}BOํ๖!YฅV{lTซ>xUวw7:‹_T๕/4€สึ~Rฒ๒๛ฯ‡iโ๓ึ)'Oฉ=Hช6?งฏูฟๅKตI/m๊3๑๚|แd็็/lไO[ฬSydใT\ๆูฃฉำฮ๊๘๔๓s >าxt'k?9สืiJฏ>m‰">้ฦ๎zTmหซi๘š3ผ‹Lศ•ERb"-™ิOm๛qช*:ซี,ล+`ๅ„@๙\ โฝjfฯ[@ตชZIB$เvกไ๒ๅหTฆLzโ‰'h๚๔้N๊E‹ฝ๎ำ›“'O๊อ[]?ีq๒โ๏ัยŸฌไsziFฺŸˆx๑3ี๕้ฏห๙นL๔๊ฃฮกOมiช๊j_ห™วsEIฬนำฮฆ]Qแ‡Jาดฯj—˜โิ็?Vอฃใ๛ทำต+—ˆ๗Jแ=TXP‘Y„cญzR6‘บ,6ดp\$๖ตN๓็8งO 7zๅำyž8M๑ƒhไsี๕ส›๙‹—SีŠe€@@@@@้ 3gแƒ๗+17gตJ๘ค›™3gา๛๏ฟOๅสYR๚ส3+[ถฌฬ๕หฏฟฅ>o|โ+ร๚วใ•RorสBH.%P$&&ะตหซ}7ฆ)zG/ฅ"%Rฟ;ฟ^E‹'๖ำี |็+*p{a]อ—[ัฏว๖iƒ…^q1ถ[=]‹ ผขใ’•(ฯM๙่ฬฉŸ่เึฏ่›o๋•+œ฿sฬ{t็}%่•fKaใNดˆฑป/๕(œม+Jช5๚?ง๐!ฮ<ฎf]‡จc‡oฃฏ”จ#›ณr๛ฑWฏ8๗-ฑx;…œ_Šฅฒst๗&‰N๓CีI8๙้ƒiฏ97ภๅU,ฝฦ-ฅ]฿ฌข๗งึ๕ผ6ๅUํใฒ„’‹ฮาฒQ๙าศก„?ป2d-\ธชTฉขƒPRฃF Šงญ[ท๚ฃbแงYณfดqห๗ิsโ*Ÿ_fฤวพ3ผณsSา๔สณp๑tฯแdฎไc{6ำฬมํu’?G)ช๖๑ุฝaS8เWesิํk? eS^•ขถ!ทีi่,z@}ฤGหง1|l๐6U๎โ2/L๙P‹0ณ_๋จ]ช5xVŸฦc็/bฦ๎๕ซiูตห“๚Sํง:นงฒ๑fณผŠฦ๎2O๋แพ๏ีHฏvi๑uฬr'ป"~gใ%,”ฌZ๓)=R!ฟ?      p=ทzร]`๑ฃdษ’๚ณš3f่^๑ฉ7u๋ึฅ[oฝUฬซMž~๚ijถ- :๔๚ž{นฅB… ๚$Ÿ๛Pื1หผ|4Yำ}žฬ๙-P+3~๛้0๑พ%๑ฑฑบ๒ynVG่ฉษๅD๒ผรถQฎ#ชc-[มลC ๓ ”Mk๊ฯRฤฦ!‹Uย[i1†…พLกค‡Za’คNบy๊ ็*xตค๚ดฅ๚“mิJ–ป้่ฎ$BษธŽ่W?]0ษนนj‘eฉd๖oK!นrซME/ะจŽu๙ํี‰7๘cZทn)โ{ศ–…กCวORว‘)งจ˜๑Fภ†kเฃ}Yผ`Q"ญ+>๖š>j—๗ศซ6RตลJžฟL}nSVWว{]๗9‹)”ศ~)QฬŸฟS๕YMn๕™๋๕ฝZฅฒิXๅยG—ชNนณˆ>ๅืc่๐Ž๕z฿.๛ ฺหฅำะูt`:บr๑|ห่ž‡JiกฦตnNŸใ$ๅU>ฆ€b็็/6Jพๆ[บง๐]2lŒ@@@@@ 9&”ฬŸ?ŸFŒA_|๑=๐ภTฌX1ชSงŽsE o๘ZธpaZณfM:๗ฌส•+S๕๊ี้ง฿ฮSปasฝw ฺ๓?ิๆฅgี^#๗+M๙o-”%ฝ4…’>—+Aขtบ๕ฺ %้pd~ฟn-< #ฎั—๊ตถNๅษP8ฅ" Bษๆ๏พฃoรพ-ฉเ     ~J ว„ๆ]ผxqฝฒdธqฉ„’z๕๊Qทnh๘๑z_|6UซV%ๆtฬ5Šhฟว„/Ž›วฤซA4ณ6ไอ]๏คRบร‘O]ุiฬสƒถซTาชเฯ฿~ขo?œK฿}ถไ:{ฅx๙๚3คBEŠ_—Cฦ Dตซก>๑:ฃWถๅหw ŸŒืO_!ฃBIƒ (&&†6oฌE^QRฐ`Aฺปwฏ,‡C_ฝx5ษ#7ฎA-ส๊=Dฺผ2™สิh˜๎๘ฮœงZฃj๗Noบ!wฉŽJ~ง~๘มร{Š๎€€€€ธ‹@Ž %,Ž„„„hqคfอšด~z*Wฎ-]บิ] rคฦซ“R้ถ‡*RฃNƒrคh4๓๖n”Œํซ ๒ม`Ÿ’g งอk#>bx่‚อ:ฬ|ซ(‘]^๏\W}zs†Ž>”]M ^/#ใBษศ‘#‰Oภ าŸข๓ฯด|๙r*[ึ:zีหxfธปฯ<๓ ]พ|™Š”ญKแฯฝœแrpฬYqืฎ๏SยWFNœ9ถ๗;š9จ๖ฯˆฐข๑รmฦtyLํs†<เถ6ั€€€€€€gศqกไโล‹Tพ|yฝบ‚ล’นsำฎ]ป<›Z๔.""‚~wzธf3uผk๏,จUธ‹ภ†U๓่›oSปAำ่beาm6)1‘–L๊Gœ8FFองแƒ7t}็w<XVuฌkืฎjrv*5|Žj?ี9ซชE= ™ #\ %gi฿™(W_&เBษ่ัฃ๕fฎ|4๐ถm|™ทsl/พ๘"mธ‘jท์Mีตqฺp ฝ๊Oo๖๎้พFั€€€€€€G๐ก„ -Z”š5kFใว๗h`YีนกC‡าชUซ๔Fฎ๋=UีขL˜๘“jEษด{็ŽL”‚+€€€€€€/๐กฤ—!-::šๆอ{—ZFŽฅา5ุนภ อ&๕mBฯฆ;พฯๆ–P=€€€€€€ท€P’COjๆฬ™4i๒dj7p•จX'‡zfAภฟ L‰|Šbžbีฏใ‰ q” mqŽดสg[,ลวลQีหtํสeŠฝz‰โฎ]Qแeฦล]ฃ๘kW).N๙ล^Seญ2\6Qี@I‰ช„Dชxr%ซeณ ฃGfลP€€€€˜7oEEE9G9mฺ4 wฆ๐ Jr๐9ถh†๒๓_=ฑKเ‰OcyBซ&tqzbศษฤDk๒hM๔xยง&˜<ูKไIŸบ“ี”ฌ&~‰z๒—œœœ๎จxbh^7๒7}นฌˆ:–ฐฃาJะม‡รภ@%๎)กG >,ฑเฃ์,๚่€X๘ฑ •ๆธnุฦiKฤฑ์–c๚;๓bฃ^i“แ6uใs%O @–Mฦb Wl—[สHRNสš~RVBฮใธˆ"‚ฐ €€€€€๘*%พ๚d1.L€P’id(       เซ ”๘๊“ลธ@@@@@@@2MBIฆ‘ก€€€€€€€€ฏ€PโซOใศ4%™F†       พJB‰ฏ>YŒ @@@@@@@ ำ ”d €€€€€€€๘*%พ๚d1.L€P’id(       เซ ”๘๊“ลธ@@@@@@@2MBIฆ‘ก€€€€€€€€ฏ€PโซOใศ4%™F†       พJB‰ฏ>YŒ @@@@@@@ ำ ”d €€€€€€€๘*%พ๚d1.L€P’id(       เซ ”๘๊“ลธ@@@@@@@2MBIฆ‘ก€€€€€€€€ฏ€PโซOใศ4%™F†       พJB‰ฏ>YŒ @@@@@@@ ำ ”d €€€€€๘+คค$๚๑วฉpแยๆฏ0n๐iJ|๚๑bp     YE &&†z๖์I[ทnฅ ะ๊ีซฉPกBYU=๊๐J<ไA      žM`ม‚4|๘pg'9แL# เ ”๘ฦsฤ(@@@@@ฒ™ภผy๓(**สูสดiำ(<<™F@ภ7@(๑็ˆQ€€€€€d3'Nะฐaร่๐แริขE ŠŒŒค€€€lnีƒธ›„wG{       KB‰ว>t @@@@@@@ภ ”ธ›8ฺ๐XJ<๖ั c       ๎&กฤฤั€€€€€€€€ว€Pโฑp7%๎&Ž๖@@@@@@@<–„}4่€€€€€€€€ป @(q7qด       เฑ ”x์ฃAว@@@@@@@MB‰ป‰ฃ=%กฤc :       เnJMํ€€€€€€x,%๛hะ1w€Pโnโh@@@@@@@ภc @(๑ุGƒŽ€€€€€€ธ›„wG{       KB‰ว>t @@@@@@@ภ ”ธ›8ฺ๐XJ<๖ั c       ๎&กฤฤั€€€€€€€€ว€Pโฑp7%๎&Ž๖@@@@@@@<–ภIฆq่IENDฎB`‚opentelemetry-collector-0.141.0/docs/img/component-status-runtime-states.png000066400000000000000000001341021511331344600272560ustar00rootroot00000000000000‰PNG  IHDRึพท_CldiCCPICC ProfilehํšyTืวฟ“• ‹`(q‡ ’YดHิ b[ญB @…“ฐธq_๛*Z•WญV๋‚Z[ญ>๕นแŠฺVmีบพึฝOฉธa๒†พ๛"๑ฃ7zย@๖J๔A7ีo]ไฯส–Ubฃ๗qๆ‘–์›8†Pฯ'˜Œ’Pฑ\*W๔oศดพ[ร6ฟT=M์่ง“๔4– |ฉผO<u0žQภฎฦBK‘๖Kั฿ gปุค(Šลๆpธ<>฿Eเฺ๊ยอรณฅ—wซVB‘ฏ_๋6mƒฤํ‚‡tุ่ฉs—ฎBร$แR™\กŒˆTฉ5QZ]w}ุ่ธžฝ^‹๏๐zŸฤคไพ๚RRฆ‘ฟ5xศC‡ฅg3ณษฮywx^พฉภ<ยbต—Œ5zฬ{ฅcหฦŸ0qาไ)SงMŸ1๓ฟ|0ซ|๖œ็ฮ›_๑ื,xัขลŸ,Y๚้ฒๅ+VVฎZฝๆณตŸฑn—6nฆอ[พu๖;ซvํณw฿๊}๕๕7‡๖ปcวO|๒ิ้3gฯใ‡ฯ_ธx้๒•ซ?๓zอฯ7joบ}็nฟ๏๐Ÿ‡?i2~;o/B ฆ#ฟ… ๗…4ฐ๘ ์…k4šยฟ†๛๔๘๋ิฐง€N!รภž (8bpไเ˜ OQ4ฐh€ั@ƒมa็มaˆ0H™0P๊ฉะX>Ybวยpฑg‡Œ==ษ4ขqdใœฮ9แœฯฮ‰†g™ฎGI~žธ(หbอ-0u–Iคมโ,“ฑ 3ื”=8uภka๊เz]* Y,YF[Vฆ^gะGh$‘*L+WKJ…J+•ศ#er]ธAฏ‹ื+"%RตFชUซ$MคJ+#G52ฉ.<^ฏ‹ีหU’นTก•‘[I5JญLฉ"&Bญ ี๋า๔2™šœญ’ierนDฆVศตฒฉD#SE่ยำ๔บpวŽ0๋…zqษฦcฌ4XDI/๚Lงั฿ฎNBกiธฉ ุ$ถฺ,dไbลณํ<ฺณ์{๊™6,๛๖lŒ–ตXLžS,V’ั4ํGคLฉ"‰๕ผ~ส•R™T!ำ(ๅJๅ‹x/rŽใf ฆ๚)*`ทˆ๊Jr ธU  ถ่€๙c(ŒชZE“cX86˜ยDโ…#9ธสBqw`ๅZฮจุ0’xRบyใ9˜ึˆ]้†9-yX@V-ึ1-q๘^ไ>ฮ ๑]ญcb€“5ญqe 2c ึ ช๓€/นNษช(ฟโ…d_7"q>่Fโ7n)ฐm•ฆ‘๘ูตZv!ri"N\uม!Qบ]}sฎฎฎ-่*คปป‡‡']†ฃk‘ญ„>>"‘/S‹c*’Aโvt9ฎพ(ษิใส’uษ˜ฦส,SŒcJqt!n่ฐtcfVvN๎๐ผณลZXT2r๔˜าฑใฦO˜4e๊๔๏P>{ฮ๙ .Zผd้๒•ซ?[ปn†›ทlถณjฯ๊ƒ_}}ไ่ฑใ'O=๗ใ๙K—บV๓๓อ[w๋๎?x๘๘‰sฏ๖๘ฉ†ฃim๐‹~I5ูrmyY™ฐ9|ง๐ ‰ฎ‘ฦง็็ง‹ๅ’๛ใฌ—\O?Oำ4wWšEษข"\“Œยฅšy๘hxc฿๚ŠeXIfMM*>F(‡iN’†x ึ พASCIIScreenshot=_šุ pHYs%%IR$๐ึiTXtXML:com.adobe.xmp 446 726 Screenshot แdS/iDOT฿(฿฿Vน“S$;@IDATx์`G†ฟ(^ชXฉP)๎ดะโ$X xp—Bq-nม-P( ”Rฺฟ”Kย?฿อesw@d“พ^fvไ™g๖–w็F<^Šƒp€€€€€ฤˆ€„uŒ๘!3€€€€Hึธ@@@@@@ึ:@„ €ฐฦ=    :€ฐึ"L€€€€€„5๎ะ„ตa@@@@ ฌq€€€€€€ ฌu€     a{@@@@t aญD˜k      k ย€€€€@Xใ@X๋&@@@@@ย๗€€€€่@ยZˆ0    ึธ@@@@@@ึ:@„ €ฐฦ=    :€ฐึ"L€€€€€„5๎ะ„ตa@@@@ ฌq€€€€€€ ฌu€     a{@@@@t aญD˜k      k ย€€€€@Xใ@X๋&@@@@@ย๗€€€€่@ยZˆ0    ึธ@@@@@@ึ:@„ €ฐฦ=    :€ฐึ"L€€€€€„5๎ะ„ตa@@@@ ฌq€€€€€€ ฌu€     a{@@@@t aญD˜k      k ย€€€€@Xใ@X๋&@@@@@ย๗€€€€่@ยZˆ0    ึธ@@@@@@ึ:@„ €ฐฦ=    :€ฐึ"L€€€€€„5๎ะ„ตa@@@@ ฌq€€€€€€ ฌu€     a{@@@@t aญD˜k      k ย€€€€@Xใ@X๋&@@@@@ย๗€€€€่@ยZˆ0    ึธ@@@@@@ึ:@„ €ฐฦ=    :€ฐึ"L€€€€€„5๎H๘๗฿้๑ใวF!!!j๛๐น}ธ Sแ๊\›W๙9ฒว~g็/_พ$๐a๏ท“‰์าฑMm:;Z๛*-งS‡งง'ฉsv}8ญ W~ฮง*Nน2BแsNงฎกโตฎึฮซ์ฉ๔ฏ‹Wvดืา๚UY”-๛๔๖iต้U__๙•ซ์)Wฮ~UfmธJซ\mœ6———ปJหฎฒฉ\m˜ึ/Š?ฺ0ญ_ลวฤuvฑ=ฎ๕ซ0ๅ๒๛โล z๋ญทbRไeึฑ ๆA@ภ๗฿”+W.wจŠแ๊ ฤ\๙•ซ*ฃฮY„)ฟŠS๎ซยUผ3W‰:Žใ|ฎ ณฯฃโ์]๛tF>ืrิ๚นNชฺ๚9 ำฦGีฯ/Wฏ^j6ค#ึ4๗’<}๚”žg๓็ฯm~Sไ0ฐŸ?ฯ.๗บผ้ใฌ†ฏญย๙หงฮูฯแ์ฺTธบG8>:‡z ฐซํะ†ณ_}Tญ๋ฬฏ์qœŠW= ์ชpm˜ึฯ๑๖้ดa2žฏร้TZv9ฮYZฆโ•ซอฃยุU6U˜ดห็*Œmโณx๘๐!*TˆฺทkIy๒ไ฿ƒ๐๏ž๚ฮx[ฟ–sห๗ุหห๒}โ0๕,ฑw=ฝ,ฝภ–p‹€ำฆ๑ิ<‡o๛็ž๖Uู„6ŸJค ใงซ:&žว‘ฯeัซฎy>‡ูยลณ[.ำZใœ…;„){lƒŸ๛ู๊os9<4฿‰P๕o†ศ+ำห|ก–๒ŠฐPMZ› kZYNrL#ห'ำXํฐMป๋ช:„…๒ฏ‚ทˆgN*%—]–ลR.>ทิI•S0ถฆ‘yญืฌญ#ฤ[ms{Yฺ#—ฦื วถด‡:๙’ฏฯฝ้โEฤฟqฺDยฯ๗žณC‡"Š—๗(;gM๏!โุฯ๗ณง‡ๅž๖bฟ๕฿Boๅฎ‡ษ๏ O,็แ๏ป>์๚ุ‹๐ฉ3—ั๏ฟIงŽn ฿œa๑Lภpย๚มƒRุr๏ X ๓ฯ“์•ซS~%ข•0vึ๒ๆ‚สืื—XX๑‡แ8ญ฿๒…ฐˆ.NวยŒ?สฯฎwJดฉsๅr8Q•+ฟดโ\}‰นŒœVฎS m]ดaสฯฎ๚จด|ฎด*ฮU๑๒อAร1ข_ูาฆณ๗๓ งำบสžzนPqnฦ็*^๙ี5^ฎตฅŠAT]ีnส•ํสํฮWk๛{y๒}  แBฤ––จ2%N>`ลฝฯ๖Tœ‡ผ๏dz‘‡๏9u~๓น6Ž๓ฉ0Ž็8uŸชtร,6ุ&?ะUœr-ถ,i{}J่™ะษ?IQฅˆ๔F!p๏=*QขMS‡Jd2JฑQNp+Mฺ.ข+ืะ‰}ษ3Yiทช›ปTฦPยš{Šณgฯc๖Z1๑UU๓ๆ๊…๕อืึผ [ผv6,oึv8—&ภ=3็.ŸฃDž‰\บœ(œ~nธAๅห—‡ฐึ),@” ดYHWƒN์Nkฟ(็G†ุ'`(aอร3rไศA_5๙๙๙ั๕ะ๋๔ิใ‰ $ฤซๅํGRณ8*\E†4d‹WŒ-ูิ™0g ฐ ท%ฐ๗X…ธFš[R8tk ๛p๎™ึฺ”'–Wคg–รSk๓ZฒXา๑_ป๓yร##คำK;ฺ๓/%\[Yl’aึ(mŠpX์j๒ฉXMK MผสขumyN›'ฺ~mษลi2f)ฦซา8 ท–\ฦYDHฆ ท‹ฐ~Uค๕}เŸ[๙็โฐ๑a7L2 2Œฯลg๕„ี๔่ฯGt๒ไ)๒๖๐Ž6:d4K—.QีชU!ฌีl(ญ›hz!]ป๑;–ผ’•wณฺนGu )ฌL 4 ฃฆงaแc็ฃIP pmร›Ž ‡wคใวŽ aํใฺ…E้t#pๆฬช[ท.MY‹ส—ฮข›]ˆ<F_/ค๋7YXยบbไ3"eœ0”ฐVCAz๖์I-Zถ CP่หะ8ƒ…  i8T๔XC‡ขž €ฤ$Ž=J4zp5๚ฒBฬ‡ไ™ช บh๘๕บq๓O:บ{y%BW0ฆC kžh˜-[6j฿พ=ตjMGึ‡ฌ€Dšภ z฿า“วัƒ(กGยH็CBcุปw/ตi5 ๎S™j~™ุ•A้Aภ ดZ@7o aฝkจึ_ด๎]lC ๋6mฺPหN-้๔ใ“๎:จธ ตฟก็/h๗=”ุ3ฑ –EŠ [ทnฅ.]:Qฟฎจ^ผฑq ุx–๓้ึํฟ่ศฎo…ฐฎ๚†ิˆŽ†ึผ^tึฌYฉeห–ุ%ฮ๗C|0ร5Aภิ๚V๏Oผ*ศŽ;) „ตi๎…ีซWำ€จgPYjP+Ÿi๊Šบ6CวฎำใŸQฅฒู\ป :•ฎ~เ|๚๕ฮ_tx็ !ฌซ๋df๔$`(aอฐdษ’…š6mJ-zด หO.้ษถ@"A ๗—}ศ7‘/mูถ•’z&D$q‹/ฆร‡Qื๖ฅฉQ๎P%ิม |้?“ฎ€–ฬlLys์5z}ด\@ฟ“Ž์H^oื|}bฤฦ C ๋FQ๓>อ้๚“Ÿโ. f&ะใ‹^”4yฺฐy#%๓Lffฆช๛œ9shยwใ(่๋Pฟ ฉ๊Žสบ./๊Nงฟ<ค)ฃkSู’™]ท :•ฬถ*ศฮ~ไ๕N]ฌยŒž )ฌ๋ืฏOM๛5กฯn้ษถ@"A k๙๎๔Nสwhอบ5”+y$r ‰;˜:u*อš9ฺต(FMr‡*ก.Fเ้ำR$gอœ*า%ซPs*C#F~S•ช}‘3า๙ŒšPํผx|W!ฌ๋ตn]nC kช:sๆฬไ๏๏O}้๓{n8จธ"ฮ~](ลG)h๙ส๔Žฯ;ฎXD”)Œ7Ž/žOญ Q‹FEbแ ฑg๒๖ฏั๙๏Š๕ท3“65Š=า1ณฆ๋ ฺ{่'=จ}U)GคŒ)a=ด฿—T๋+๗_ญฆY‡%t๑๒otr7 kH1Bขธ%`Haอ=ึuzืฆ?Cฦ--\ @€‚Juข4้?ค%ห—ะป๏‚H,๘๛๏ฟ้๖ํrงูX0-“#FŒ Uซ–Q‹จe“ขัฒ™n‰๑จjO“—N๗ษ{TดภงTผ๐g๔a๊ท)}บ๗ศหห+>Š…k:!ท๔h๚๏ษs๊ำน|ค‡•ญ>™๎๛›ฦ~[ช˜`}๕ภ et๎โ!ฌ{“ืป PDP|0”ฐ-gส”‰๊ีซG5zWงBล7?\LG }๑ J—šทp>ฝ๏๓พหีย… ๔ัGQ๒ไฦฆยuจ^ฝ:ฅI“†จvํฺ๑.ฒGŽIซV.ฃf๙ฉUSใ๋ ฮSœง‰ล$:ี๒ศuน3gLแ4 ใ†@HH(ๅ(6B^,*=ึE*Žงฟ๗MS‡ส”ศ7…วซด๎ฒœNp›Nํ้A๏5‰ว’เาฏ"`(a๒ๅKส˜1ฃV๗ซ^U่้Klgช†E8ฤถESฆฯ3R๐ู๔ฯฑu™(ูฝu๋ํหญYณ†ฎ\นBฝz๕ขภภภ(ูpตฤ\งูณgำž={่ฝ{6‘]ฑbE*R$๎‡bŒ=š–/_LอEu+๕Xo}‰:๕Y๛ฦๆอ‘5 ีญž‡ชUฮA |}˜ ๔%๐๗฿OจP…qา่์‰๕ฉXก๔‘บ€๊ๅž?ต!ส๗iค๒9Q๛+้ศษ›tfow๒~ท)‘‡‡‘ซใ–e7”ฐVcฌ๋ิญC_๔ชˆํฬ๒–Dฅ\@๋ยํ([มฌ4}ึtJ้›2Šหร%VญZeำ\|๙๒QPP-jœีศถm๑–โJd'K–Œส”)C,ฒ .'ฝ๓,ฌ—-[LฤPc๐=s๖-—ร x n‘ŸRช”ษ่ัฃง๔๓/ะฮ}Wi–๓ฒวSตC๎าคต(ลX๑F1‰ —ืf.'&"๒ฑqIKส˜>rฟ d)4TๆY1ง)ๅสก๔ป๓Ÿ ซ้ภ‘๋๔~ัcnc!ฌ1gภีฺPยZmSท~]*฿ฝฌซฑDy@ภธว:k,4uึ4Jๅ๙ู๛zมYพ|9ํฺต‹x‹m>’&M*Ef็ฮ้ใ[๎ษฑc;vŒN:E?–“บห•+'Evl๕f3F๋EBXคภฦq฿c๛gาฬ4e๖A™•{ูปด-ใ`†‡ lูu‰&ฯ<(W—เ๏ผ˜ึ/ „ธv {็/ฅ:อๆส ฿ัEผ,&Šิล”ฐŽŠ”aMิฅ:ฺฝ*=ภยZŒฑ๖๐uั’šทX†ึOž<กœ9sRฝ†uฉ\kWปmo\ผA>ขW~ฅ[Wnำฝ๗(uบิ”ณXสW.%N๖๊ๅƒ;h฿ส๔NŠไTฎA9‡ช…††ัฺษk้๐†#TฅEe‘ํ๏)Žฺํ@Y dฆ)3งPj฿4qrUsฬ๋(ณ˜็Ÿไ5yพE“&MจRฅJqาc'ฦEŽ9Bทoท๕fณ‰๙๓S๙๒ๅๅGฏ— หช จUใ‚ิย ยzวหิฑืjIตพุ†›^_ผ’0 ์.ึ็แใUB•โ8โฟžััS7)_ฎ่m๑"`๔c๏มซิฆJY๕#<ฤ‡‡f-ส๘ Xึ/Bี๓องc›ูยGnN๏ฆzืvOh_ฌ#eยz๒ŒI”ฦ7๖~zUใฆ็ฯŸOw๏•ไ้jีชQ:uโ}2_•๘dๅส•D6/QZณfอ‹์๑ใวำย…๓จu“ยิผQแศ*Sj{A[ˆ27๕/HKVกฯ>}พฌ˜=‚xใษ๑<,คฯท›d‰ywษ~*:-‹!๔Dฯv"๑‹ษ›…อฟbหํ_๏-ำ๋5ฤคi๛ลtLŒต-๐๙วดpบ๐Šc๕ฦณ4f๒๊ฆดCนCชศึ…w๛;qๆบ๒ำ๏าฦ‡ฉ“Sษขฤส*๚L`ๆr๖ฒIZpt{g‡r: x"V๙\ฌ$ยวัm้w^‚ูz:ปŽ+…๕Œ6mป@็๕"o ฦ3‰+e %ฌyL%กฌืด>•๋เ๘“Z4๎ ฐ่]4lZw8ยล฿เmฑึ๑t๗็{๔๘mq…ซฆ&“ทf-ูป?฿ฅuษ4๙Eฯ๖ื#[ูาณน็า๑ญ'laŸf๛„บอ๊F ๚ฺยเ‰;ผ*Hๆ™hโŒ‰”ึ7ญ๎ถ๊ม(]บด\ƒ{งqDŽ‹l2ยรfฎ^ฝ*3ฑศๆ^~›ีUS&L˜@๓็ฯก6M Sณ†ฦึงพฟEZ/”u๏ิบ4ผึm>/ฯy,uษ"้‰{=~๔„๖พn ย VฮmF9ณEEๆ๑ใง4g๑qš:็ดม๒ๅˆฺ4/&–๐Ko Sžฟ๚†}ท“6 !คย<๛ใดŽฝซ๗Dหื~OวOBŠ•.7 ๅศšZฎZ’1}ฤ‰ยj5 ถ{fo7Jœ8บ„อeA_ขสD9ฦผD‘ฯhึwแ๋Gฅ.~ผGmI;6ใVฟ€tmW†‰Vด‹wGŠž๕ท“'–uI–์ี/!ำ็ข๏ฆ๏ง Ÿ}@›–† ตi๏ใแc*^y‚ AŒ9N˜ะqาiT๊io฿ฯ๛,_ฯ aํ๕v-๒๐zห‹i๊2JX?|๘ *D๕›ืฃฒํLpฎR๙Kwำฒ1+"งF๛๊T1 ขXึS†ฐ๏šํB›ภ.]ง45์€ฟr๚*i5Vฆญะจ<ี้\[๚๙ผน฿ฬงฃ›Žฺ์7๎ˆJิ(กงษ Oœ่P"ˆ2ๅห$Ž>N ฯ˜f5Q;อC=ธง•{งฃ*ใ„.ขVYฟ~ฝ“ญ&?6o<า='NคนsƒฉC`ฑHฏ1฿ˆŽžผAอฺ/‘ล่TŽN กฝ๛€ๅ%ใUeใžุัƒชR๏m6ปAซ&:jm,ฝฦ๙…hVวอ[ฉEวฅreฆ\รฝmลืโพถ๔ฐro๊%วiิ}*‰ƒ›'GZ?ด:ฅNeYFฒก(ห้ณทeบU๓D; nฬ^x”F‹j>F‰:Uญ”S๚ฃR—yJฅพšไTTKcโฏ>}l]๚ไฃw‰{gฮ?*>G๒ฬ_O๖rซ|Zท€uดi๛Eส’1%ญใ#sp/zE๋ๅ—๗uศ•z:dvั€A#ทัส ฿ำ…รb๋ทkaถ‹–ิผล2”ฐ๗฿ๅl๚-ฉฌ่}ภฟ{Hฝพ์c+ฤว™?ฆRตKPษš%maส๓๐๎Cืf<๋ิt`*Vตจ๔Ÿู}†ฆ๕˜!๛6ดๅ_๙jฺฑp‡2A'vใตm๐ฤ %…ฐฮ›‰ฦOOŸ$๘$Fe`มทz๕jZฐ`;ก1ยฉฬ‹/Mธo฿>™žW้฿ฟ'~Ja='˜‚Z— ๎ฅ4ยqเศ5jีyน,jeฉ@ฉIล‚ืณฮ$VกจR!+ีฎšวก๗•wnฌbžMTsฏ3๏ ๘ำ๕฿iแŠSา~๕*9iฤ€ชาGTท๙\๚หฏulฟzๅœtB๛k?[žฺ-ธซ7 ฆห?€ดšH๏๋ใEGNฐ‰sไณพซ/E๔็ฅ๚๓eญ-e„{ซy• ^ใ™—\1ง yzzRT๋ฒhๅ)2fป4หฝ]ฺ”‘Bš๋ถe็%๑‚ฝOฦU(“ElาRz D›w\Tล ฎ;๗ฮซ๚}งฒX;qHJอ€ูt้สo2šp๏ทฟmธyDXํjนฉlษฬ6—ฏง๊ƒๅ5ฮ์๋n gOT๋!ณ Ÿp[,]s†.aa]Mk ‰tตๆ2”ฐๆq–%K–$ึไืฒดซฑ4]y&wž"&Pœ“๕ฎPjuจIžฏžp๒๋ต;4จ`™>้Ii๔๖QไํํEึค…Cษ๐^s{P๚\้i็โดb*ำภก-จPฅ‚ถsxโ@G!ฌ3ŠuฌวNG้ฆ‹VAิdฤ ,ใ๒yจวG<๑๚ูณg๒๓๔้S›?$$D๖๐q/xIQฅ†]ฆ\N๛ช8Nรqส†สฃ\Žณ?๘W‚ห—/หฏ,๒{๏ัŠ+่“Oœฟ,Mž<™fอœAฺ—"Z๙์อนไ๙ฎWจ}หs„‡+๐2,ฺุ‰0%โX๘-™@Y2ฝz้ศฦb8 ๗v๓ัMZPD๚๙˜พ๔Ÿ%ลซvฌsป๎+m=ใผ๚>UD๏t"q<'ฟ๊Sd๚พ]สSใzลาOจ`yห๚อl”Eไิัต้s1)‘nร๛ฎะ7ขง’E2—w๏๚vฒท[‰Q?]ผ8hoGoฃลซNห ํฐ–จึฅžxก8{แŽดณoCฑ\aฤกฬเฤ™[rจ“แ-ษ๙๐ฏ™WNๅvฎC~ฟฑถš›::ฌธข๊"3ฟๆบi1™Bฝ\คx?)ุ!WT๋!ณ Ÿ ฟ“ญ8I—ŽŠ-อ“)V‹8Dศ…‹nšขJX๚๋ฏrฌฅป๚ไืผŒiษ+๚@๔<๗ฉf™d˜ปd.j?พ]คŠน`ศB:ธึ2>qิ–๔NสwhSฐ˜๘8อ"ฐ&šHWN^ฆษ-๋™ฒQขฝ๋กฝ#8u,D๒a=c,}–เณ(]‘ืcž7ož\&.u๊ิTฃF 9vZฏ•+^Uณ<๙™ฎบJ์><‚เๅsฦ—ำณ(VaZ?/สถตq*žฏ_G‚ d๏คทททฒ[นผ}7๛๙ฃXpธวCqx]lgว”)ShฦŒiิ+ศฯ้$8gyโ;Œ{NปŠๅษ๘๚บ” ]\๚Ÿ>}A‡o‰0๖yŠณฺP™Pู}เ ต๋’ฯย7WถิRnqษ&ต(AZ•$ํF'ู2งขฅม6œ9t์:>~C,YX˜{7ฉผŒฺไ„O6/๛ฺ้„ภEon ัซหวฐ_สqืg์—ใฝํ‡O?}S๖ฬsZํ$ฬจึ…๓ซฒi{ไ9Xน{๊?l‹ nึ ๕Coิกฐ:gั=ฐgฤZดยš_šิ/HE ~J)ลzโ<ไEM*eWต‘รNŽบAM-‘=่[WดVๆฃfถŒ๐Œœธ›ๆ‹aC—ฤส)^o}A๑ฐไฉ0ลk %ฌoผIผVkƒ *P:^ม™โ'ถคY}ƒ%†K๚ัG™-ฝ+oโฒl๔rฺฝl\%d๒!หค“Eร—ะU๛)Eฺจร„๖4คัpz๖ไฉ4ฅs&ˆRX็ฮHฃgŒฆ 3D๊ข<€{‚r•%“่Q‘สหH๓–ž Gฏำ฿ห๖ฝOๅJ‰๕ิ๋๗‰ฏLงฦ๒Iก|Ÿˆauฤ–@ฦฝ๊ึ์'ญูt6ย0 eS Q็ัฉ /U—ฟ์Xi‚{ข็Mnจฬ9ธฺ1อ ก๕b}qgฎŽ;ปะ[o%’๋j๓2€|$‡ึDงžสฎqS๗สWxฏd~bใE็s"ŒPw-ฃก„๕?Hำข]9ย]ฦี๋ubป าว2dเฒ”6ใ๋฿šY8l6J๖F๓f1ร7~KษyKLา ฃึ8T๗๓2ŸSซแึปvH„€x!ภย๚ณœŸัศY#)KขฌQ.‹พฃGส•)ิ–l„…ถŸŸ๑pฑ=ๆ:ส…6H๊มซฌจํนุั้vV]^นe๘๐a4fpUช่๕vwf3ถรดฝ—ฺษ…ฮฎหซh4หใ๑D=5Nปœ๗ฐNW/R<ฆธy‡ฅถ^puฝข…าQV1l„—ฦห)>jง@^)„‡oผ้`มjฟ9j+v,ไบ-;O๎ใI~ฺ#:uัŽื๖ kํ*ฟ๊=V็ZทlษL4N,˜@ผX๐dอฑ2‹Z%„_<๘% o๎ดฤ›Ÿจuฦต๙ต~mo๖๕P•๚–ฅ๗ฎ,วGงžZ๛ฎ๎?mอ˜w˜,ยบŒึŸบz‘MW>C ๋‹/ส]ืš  โี,ณ‚Mืb.Raพ|XภYมmF}สA~๙๑อ์5ำถิ^ฃ> จTญR2๏ŸฟI=ซ๔vZซ‚b–b5ฎE€—๛,G:<’ฒ&สใย9๋อๆ-นy ๋่ldใฬ€ณ5ภy์4oฃ็เห–-ฃoค รkPูR‘๛ฅยPถ้บBฎT1nHuช\๕=ํCBŒูๅC๕nซ๑บึRฌาฉu)9ั“ฯตื๘๕Žฅ—šw#ไuฌGOฺc[D›V๙y"ไ†ล๔ม๛ษˆล๘ŒyGไxnํXn๎ตญ*–๖ซ/&ฅLqEe‡_ :๕]C?฿|(7๏yีrˆQญ ๗พwผณ๐S5—…'0ฟห๖Bม๕kืขธ,ป๒ม้๓_๙ฃฤต3ฮ/ Sg–kzkp^~ฐeใ"r>W‡Zฯ[;Œ&ช๕d[zํ ฉส[./o8}๎a9ฦฺ;Y)๒H>ถ.ปั$`(a}yนŠ@๓มอจˆุมGเฑฒ฿ิ,vVผ+ มโš๓[๏†?๘Ÿ๗”ถอA›goถดtmฑ9Lo๙'.ห๕ญmvžz]๋Rน—‘ฒK‚ำ8&ภย๚“,ำจนฃ({โบ^{ณyrš5kไ‘่ldขk\ุฟ๐ุiตd!56—-ไž๐ฝ{ำด1ตฉ”kl”ƒŸU{๖,ีชUK๔bRมJโ‚ฎ๑ฺ1ำ* ์TŸคคWoำ…#UฐtซทญF•›‰ๅ4k]๏[นXjK—9_f๚$๋วrbค D{+ฎแฒฐN›!-Y8šr$ŽฝIl<้nๅส•ดgฯนšแ^ฺุตk›z'F^a…‡e\นbsส›๊ฤ๚ฒ…7nคฎ]ปŠ J๊QฑBQ[fั5๎่—‚ท๔nm…mร’ืYโž9ๅr‡ฮา๑๐ wฤzฺysฆuXยY=ร๔ฌ‹žๅา–ปึsโฬขW ุyฑ%x[์Bœ ‹่`/† %ฌฯœ9Cu๋ึฅฏGดขๅฑAA วๅณ๓vๅSบN{m9yฝภa-(]vวอDดkX๙ฒ5ิTฺZ3i-mทอf7{‘์ิvl๒Mเ|๒-!<ฑN€…uj1นt์’ฑ”+I,ปฦ"{๖์ูr์0ฏ*ยป๒0˜แฐ฿ก’๋ฬห๒p™z๕๊ล ฟกCš7ฅXํโำ8นฆ+]„1๏x7_,ัวตhูฐDแtTด`:9V˜ืwๅร๊๒:ฮ๎XOีc}ž…u๒ขไ™0ๆร๑^วqQ'`(a}๚๔i๙H›ัญ)ฏ฿็Qฏ-rฤ ฟ๎Eงลถไ7/$Oืษ5ฉำdHMนŠ็ขฅsS‚„–ฅจ์ p๑จุทVด๋็ึvๅŸbงwŸA?์ม–eิVฑกLŠwl็๐ฤึ)าฆ ๑+ฦS๎8ึฺšฒภใ!๛๖ํs๛ ๖;TFei-3=หAซVญh๑Œฦ”/ฯวz˜4ฌ lฟ‰ๅ๖%๔ฆ4b ด๖aฤ นS]^ว฿]๊ฉฦX_<ฺ›|’$ฯDฑ๗ซแ๋x"๎ี %ฌyฉ.j7ถ-ๅb ‡{ธ๖ร5ฑv‡Mfž?}Nหฦฎ ƒbหs"าmf๗จฐมkัก„XึJฌ7>a๕w”'iฝเr/.๗b๓๚ฬผ%wๆฬ™en๙๒ๅbU๎‰ๆฮำ<™ณE‹”#‡พcฺฃr+vW8ิส"j<6 Q^ลยศGppฐ^<>ลด–3ๆฑซ็7ง์YRkฃเˆ#cล@ณฤ1ผžgโBXปฦ38ŽชoˆหJX๓ƒฝI“๊8ฑ#ๅ(๚๚e“ A…`a์ํค4yหdส—4ฟหี€‡O๐าœq5๖ุๅฤRTวฦ๚ล-)s†7ฏKล€Y05Q“vo๏ฮ;/๒0ฯฤฎ๗ 6u‰สJX>|˜š6mB&Qถยฐo๖›๕<ฦ:qาD4e*ฌ`Ws'Nœ  ะฆฅญึŽ๓ยเ‚ `R#'์ขyKOศuฌ=eยฯ`Wป %ฌ๗ุObœa็ฉ)kA,1ใj7สcKuซณ๘า๔Sฉ@าBๆจ4jIjUฆ๕‹DuF๔Xใ–๘ 0|NZฐคEX'ฬBžIŠฤG1pอื0”ฐนw'ตmี†บN๏J™๓gzMต [‚Jwk๔zั๔}ำจp2<ิc‹ณซูUtญ^ะŠฒgภีЇ๒€€) ทƒ‹ {.ํ#–ฺห$„5vกvต†7”ฐผk3ตขม(ใ็ุmศีn&”ว‚สtฆ—a/iึมBX5GฅQK๚๑ว้ซฏพขๅs[R๎l่ฑฦ-๑A`๐จmด|บxD๋ศ3i‰๘(ฎ๙†ึ[๖mกށฉืœ”>w๚ืT Q ฑE “_z๑์™IE฿*[—]#pํฺ5ชTฉ-žี’๒ๅ‚ฐvฑๆAqLB`ภฐ-ดf๓Yฑ๓bo!ฌ?ยบ”IjnœjJXo=ผ…:4้Hฝ็๕คฯrškK]ใR(ฉป่Zพ;=๙๗ ›Iล’กทฤ[ี๏—_~กฒeหาi-จPT*.€@่๓ํ&ฺด;ิ‹<}?&ฯdeใ๐๊ธTdJXo9ถ™:6 ขพ zำงู?L@@g=พ่E~L3ฮ o•ิู:ฬน*;w๎PฉRฅ(xrs*^๋Xปj;ก\๎M ๛ภ๕ดc๏e:{ 'y๘ฆ%ฏdๅปยฌก„๕ๆ“›(ศฟ๕](„uถO ˆEใ่e๚฿รGBXOฃ’ษKฟBจAคปwJ”(Aม“ฉxม”‘สƒD ๚่w ํ=x~8ะƒ<|าื[๕ฝฌล˜€ก„๕ฆำ›จSฝN ใf‡ˆ>พี๛ำŸ๗ขวฆRฉทสD฿rŠภ๛๗ฉXฑb4sB •, a฿F/_พค01‘8Lธ<กX9†ฉ8v_r<—œ=๒Y ถ#C-Žˆ ”Qbำ ‘ภรรC|ควzn ใฬึ8™ฦr*V๒ฮใ!]๖{zY2ฬ“sโˆ=Wัแใ7่ฬพ๎BXงยบRr#i\0–ฐ>ป‘:ี๊L=ƒปS†ฯ3ฤ\@ภŽภ€ฺ฿ะƒ;h๚Q‹ฐๆ4qธ?P‘"Eh๚๘–Tบจ๋N^ ฅ/B้๙svร่yˆๅ\†‰๐/B่นt-แ!!a๔BคqpEฮ+โ#ธึpNFกโรฎ๔‹0>ื†…q\ศK[ZmผลR‹vUZk˜ฏ๙๚zS๑๑๕ต๘ูU็]•Ž]•Oธ ผEนผโผ ฺt]A'ฮขำ{ป aB๋*q^\๐๕ %ฌ7œ_G]jtฃn3ล:ึ๙ฐŽ๕๋›ฑ ;๛ก฿~นOSLขRษห่“Š มชKPยzฺwํศฏ๘‡ส๖์Y=+ลb J RZลจฅ์†๛E'2งใ0แสždNฏyถ๘Eณ†[–mธ์ ga/D=๛-=ๆWฦ‰^n)9Nผˆm/กœGพpผ/โaIม/ร^Z^d8ญ๕eGพคฐ_พ X_bฌ/5aถ–PหหŒh{๕R*า๐ฝภnˆxูโŽใ0yฯ๐ยqš{(ฤ&_ดฤ ปœ็U๗ศ๛๘X๏๋|ฑ+๎›Bx'L่C x‰%J$โ|๘ *$D BOซฐโแฏฒJฬqz>ุๅ0ๅjใ•_นœF›Žส†}ธ3›ฺ0•Oู–†4^WNฆโต.zU๋ยํใุฆึฎ:Wฎผˆ๘ฃฮ•koG Q๑สตOวแฺดฏฮUZ>W~•^๔j+m๑…q<‡s๙ะ2”๑๘‡หฅสฦ๎ีหงEiฤwย3I<– —vFภ0ยZผgา๚ซ๋จ{ๅิiRGส^4ปณ๚ @ – Œl>š๎|—&์Oลลช >>ฑ|E˜wีชUฃผy๓ŠžYั“ห=พโงp้ชsvY๘rธ\~ญXQ็๖a*œ]>ด๙-!แU^ข=g?็ฬ™t๖iTนTธr๙zส๏ฬ}Sวkำจ— ฆ}กPiUœ๖\›N•Iลวiฯ9:W๙ิน6ฟŠำฆW๑Zื>ฏŠำ†ณM๖ด๑ส†ึ•ฤำฆU~ร?|Oฉ{ฬฯ/"๊ๅ„ใ”Ÿ‡%i|n แ_YxธPธ๛฿‘๚}J์>{๖Œxqโฤ‰iศ!1ฌฒวร๋g/Ÿัๆk›จว=ฉรwํ)W‰œฑลD7ปr2 “?=ฑ_~ล่ฅ๕'/ห—ำ๚…ดฆ‘_B้ทไใs[~›Ÿfณ~y…ห?งI๛šxK‹m5NOูถนโ'ฎ—ถ๒Yฏ'*ณไณ”S]K”฿'ฎอyญื“e”ถT™T™…+๊jIงฑรM~Žืึว2วjƒf\^KZลำ๊Zz2ญ3ฟ•ๅe;ศน9ฒSย&ใ8P–v‘~R[&ๅ๐8ึษ9‡‹%Z“N†หPK.™Fฑ ผŠ'ห? ‘ัฯcE˜L#~Z?3FLc9nM/n?G๚๘๚๘Iา'ฏ๘ฟ<๗ใ}ศ[|ุๆ+ยDZ๑3$ว9;ฦดKฟ^ฟC฿ํGE“งž œ%C€€˜Ž€a„๕ฃะGด๗๖n๊Zฎปžž^Vกcm3‹^ฑชVวโใฟแฎ‚,I,มVQลAฌพคkอ!Neaq&b=~๑? B๑GxลยอCพญหqv–๑vBd๑8:"ใeฏ€&“'Dše|ป*rํ๓Xยฅ=mZ›,•m9ห;žๅ๚สฆE4พ๒šl‡ฮZ.•ฮReƒลชี/\N#?ฒŽ–ธˆ็แ๑–pKnK/‡๔„๛Y๖๒ํม๖ุร —?,ฒนmeซหๆตถ+฿าkqํำษsพ ]:uจp~)แฑ„rกี ฝ<>P๖nhใ9ฬnฯ/9œฦcy\ข็สป$>๖œž?eฟpล๘ื/Dป!๒๚\Tgทฅบษˆ๓2“'งQ‘ทŠQB„ฮฒ" @@LGภ0ย:ไe(=xqŸ๊UจOณeยU๔\Jัยฝค,nฤว๊สYวB„{9ญ็–Nใ๔ึp[>!plvXจึs;จผOh`›ฒท–{}ลนฝวRจฐR3ซ6,*Yเˆsžธย~Kœ:g—ตpฅฒ๔rJแ,ำZฤ‘—xฑๅv8- Oี#ส.•ข\cหึ›สย“๓7| _‹mˆ|ย ฟ~ฤ0ฦJr9”_›W^—6—ืแr[.cไpY'แ†Ÿณ_\KฦEL+Yสผถsแ‘ZภถY,ชa ฒญE{JQอ๗๛ลกu๙žP๗‡๓/|/Z๎?๖‹{ฤzoY~ใI;Bศ๒ฯƒโ~‰๐“ ‹jqฯX&์๐d-๋‡0 d!€e˜ศ/"œ'ึผx\Lุฒgvี‡…ด๔ณฐแ\๛ร[NฐI &ูX>Sํ๋+zซนW[ฤyy‰^m้Z&eY๎ O๚๋ฯฟ(qาฤ4aฦJ๎“ํมโ@@ภด #ฌฺBj”VD)กฃS~ๅrzญ_›ŸE’}<‡qz๛<,๘ดaœNๅg‘๕Kแ(า+WูQ๙ต็์ืฆใ๋๐นJรmฉ=W้UผŠำบ์W็๊^P็*Žร•-๖sธณร>\KแnํœO{.…ที˜ —/$โE€ๅ—/<ึ—NงยีK‹ŠWใP•ซ ็0Ÿสฎ๚hฯYชpลR ‹๔์ฺDฒ๐๓น๚pxขD‰ไ‡ว็ฑŸmเะ„ต~,a @@@@ภฤ ฌM๘จ:€€€€€~ ฌ๕c K    &&amโฦGีA@@@๔#aญKX01k7>ช     kXย€€€€€‰ @X›ธ๑Qu@X๋ว–@@@@LLยฺฤชƒ€€€่GยZ?–ฐ   ‘&๐w฿Qpp0]ธp!าyะต @Xปv๛ t   เŽ9"๋QดhQทจ•3f อœ9“ฎ^ฝช‡9ุpึ.ะ(€€ธ;qใฦัฅK—dญปื5ฒ๕›7o 2„._พL‘อ†t.Lยฺ…Ew!ภย๚๘๑ใด|๙rwฉRŒ๋ฑy๓f ขร‡Sส”)clโŸ„ตฮm1cFZฒd (P@gห0  ฦ%aํุvงNข๚๕๋ำ† ([ถlŽ b8ึ:6YHHeษ’…FŒAตkืึัฒ๙Lบu‹Ž=J๕๊ี3_ๅQcpCSทo_บvํšึ.zUบrๅ UฉREŽณ๖๓๓‹žไr)ึ:7G† จ_ฟ~ิดiS-›หOr ภุ\อŽฺ‚ธ1<ื—;‘XP<˜4hเ˜!†#aญs“๑P:PวŽuถl.sx›ซฝQ[๗'€็บc๛๏ฤซคดo฿ž:u๊ไ˜!†#aญs“eส”‰š4i"๎าูดฉฬแlชๆFeAL@@=ื,X ลค ชฦ*>~˜๒ไษ#‡=:๔้‘ภ๕ @X๋F<ฦบz๕๊rœตฮฆMenถm๒ `S5;*  เฦ ฌWออ*WฎMŸ>1B GยZ็&ใYฝ™8qขฮ–อeŽgO:• ฌอี๎จ-€€{เyHxฎGlcฅ;oผดlูฒˆ83$k›-GŽrฉฝนs็๊lู\ๆ ฌอีจ-€€9ฐฐ๎ีซšฃย‘จe๖์ู)mฺดด}๛๖HคFW'aญs ๅฮ›ฒfอŠ7ฯrUยšวœaษฝยDvp,ฌถmK]บtq‘ล1xŒuขD‰ไณ๑_” ฆ ฌcJะ.๙)u๊ิดqใFปœF…€ึxG…า‚€€k€ฐvlŸB… ัฟK.\pŒDˆแ@X๋dI–,ํฺตKgหๆ2amฎ๖FmAฬA€…uร† iะ Aๆจp$jYชT)บs็]บt‰|}}#‘I\™„ตฮญSผxq๒๐๐ ƒ๊lู\ๆ ฌอีจ-€€9ฐฐฮ—/๑.Œ8,x็E๑ภ”&M`18kฐL™2๔ฯ?ะฉSงtถl.sJX—.]š‚ƒƒอUyิ@”@‰%คx„ฐoเ:u๊ะ๗฿Okืฎฅœ9s†GภgHึ:7[ฅJ•ไO:็ฯŸืูฒนฬ)až sต;j  เิdt๋๐v 3gฮะไษ“‰;“p›„ตฮํWตjUบ|๙2]ฝzUgหๆ2amฎ๖FmAฬA€…5๛ศ=ด8,Zตj%…5/CXปvm`18kฟ?๐;wŽ'Nฌณu๓˜ƒฐ6O[ฃฆ ๆ!ภย๚๔้ำtํฺ5๓T๚ 5ํุฑฃdาคIb‘รุ ฌunฟฦหต(:DฉRฅาูบyฬ)aอ9xBใ€ฐvlร๎ปำษ“'ฉbลŠิปwoว1k›‹w“ฺทomบ•2fฬจณu๓˜SยškŒž ๓ด;j  เ ฌwภ€t๘๐aนk๓ˆ# ฤP ฌun.Igถmr็ลผy๓๊l<ๆ ฌอำึจ)€€y@X;ถ๕ฐaรh๗๎V‘ํ?yIDAT”%Kš2eŠc„Š„ตฮอีนsgฺฑcM:•xัwั#a=nศ ฎL@ ๋ PัขE]นจqVถ๑ใวำๆอ›ๅ๐ัE‹ลูuqกุ!aญ3ื=zะ๖ํi๘๐แTนreญ›ว ๋ใวc’‹yš50kวFž6mญZตŠ’&MJ๋ืฏwL€C€ฐึนน๚๖ํ+วW๗์ู“๘‚#zดย=ัcˆ\  เj ฌ[dผyฤฮ๑ฑgฯว1k›‹'!๐๋6mฺPณfอtถnsึๆikิ@ภ<H‹/–BCA,ํพt้Rš1c=~ป6ปมWยZ็Fๆ›oไPโ‰Œ8ขGย:z @\™?yาะกC๑ซฎตกx๘ว˜1c่มƒrƒ9Wn?”ํอ ฌ฿ฬ(J)พ๖[)ฌซTฉ‚๕(ฃD.bb๋ˆเ๕ฌทmฆ๓ฬcŽ'sพ}›๎ฝ amžfGMAœ„ตcณV2d)R„|||ˆW มaLึ:ท–-[hฤˆฤ๋W๓ธเ่|๓˜caอฝี| วฺ<ํŽš‚ธ7kว๖ๅกฃผIL•*U่ัฃGrHฉc*„„ตฮญดu๋V๙ฆษ๋P๖๊ี‹Nœ8ก๓ฬcยฺ<5nX~1ฺทoฏ๓UฬcŽ{6,X@?Fตyš5pcjW]ฎ"„uxC๓๘j๎ฅ^ผx1;–J•* Ÿa@X๋T'Nœ“.^ผ(E5๗Z๓บึ8ขG?Fr้C ,,Œ๘๓๒ๅKฺ้Ÿ‡††พ6^›WูPฎณ8ใCลฉด์ชŠSฎ}z•Nน๏ฬoฆ์จ๔์๒ม้œน๖a2๚cฮแ๖aฮฮ9ฬำำS™‘y8ฬูG%rงตร๖ินึี๚ี5ูีฆ็kจ0ๅช|๊ๅx^ƒุ>หหK–ƒ]3ึฮ[Ÿw่ฃhำฆMฤ+ƒ๐/8ŒGยZ็6ใaš4iB,ฌนง:u๊ิิทo_ฏbsึฑำึ+Vฌฐuor9อซ>JTธrตa‘๑sฝ๙P๖ไ‰๕ไƒำ(?ปฺsญ฿ž™นบ–ีผญMิ5์ร9ฝ๖๓บt*ฮYzu]g๎๋ยTybำ๕๑๑ก16/แrถ!ฌ7 }|๋ญทHญ.Vฝzu็ ๊า ฌunždว“๙Aษ ฝ๓๏ƒึ๙*ๆ1‡p์ด๕ม{จY‹V๔uใj”,ib #๎}}B!!์ZฮCDXจ8็8๖ฟ0‘V† 7์ฅ๐s<๗๊ &4šฅืฺร+…‘ลV˜ˆ ็าต๖ณจQโ‹ใ^Š4๒?แ‹จไ)ว๓Gž[z‘ezฦyUz้g+ึ๋ฝใk*;DaUK€ลท๊์j*ฮ>\ณหiT:ีหหแZฟนŠำบ* ป๖~uฮืแœOผ3๏AgฮœQAฆp๑\wฬฝ{๗–ฯCJ@๕๋ืwžก.MยZ็ๆแ%แๅvค๊K2rไHฏbsxวN[>ธ‡š6kEมC[Pแ<b็".hU+์ตBŸUนิๆVแฮ'.๎e˜ิ๏–ดแiTZซธืุb๒e€‰ร๖`Mฃฎk‰ๅgๅณw#Fศ3M 8>๘ฏอoMคlzx%q,eR๙‡ำzz AศOฤYฤ qธTvUผ•"ฮห'‰ŒS"“ใตย1J‘๔yz“‡W‚H&Žd2๏„"aธ˜dฎื&๓๐Iฺ๘ศFvํ3Œv๎;B็O์"ฯ$ฉ#›อ๐้.\ธ@ช7cฌร›sะ A๔ื_ัอ›7%ŸฆM›†Gยgึ:7 k~หผrๅŠ\ไ๏ฟฆ๑ใว๋|๓˜ำ k,˜ฏ_ป๏บ:t๊F฿tจI5ส็ำฯ0,Dšภจเ-ดhaบธ!yง.้|๎0Cห =„uxkr'7่๛๙๙๙ษ}0ยcแ3 k[Šืฏๆ ‹ผกษ๐แร้๖ํr๋V/csbย๒มซƒ-Zิ4uอŠฎ]ฝ‚๚HuKS›๚~ฑy)ุx๙kัจเอt~฿"J”ถ๐+Rนgฐึ่0 o฿ &ศะxx\ไ.ฮแฑ๐…„ตฮ-ล๋W๓"๏ฮหๅ\บtIฎGฉ๓eLeN=€!ฌ๕k๖ล‹าธฑฃจBฑœขืบ†~†a @ า6๏;K=F/ฃcๆะ๛JF:Ÿ;$ฤsฑgฬ˜A{๗๎%๊=sๆฬXQฬ‘!B ฌun&5v์งŸ~’=ีผa OPม}xGŸซrฮš5‹ๆฯ™A?IIำ5}U2„ƒฤ"'ฏP›oๆั ม๔aถาฑx%ื3็บc›ฬŸ?Ÿึญ[G~๘!Vsฤc˜k›Š{จyKาห—/ำผy๓hวŽฤK›แˆ>%Jะฝ{๗0$๚r๒OŽ[ึฏ /1mํ” ‡x€ฤ>~ผE ปMฃ ‹'QถB_ฤ]่ y๒ไ‘แ—ศ๐FYถl™w.K–,XQ,‹แ|ึ:7/ณ๗ีW_ษๅ๖–.]JซWฏฆ๕๋ื๋|s™ซWฏžา`ฺ}ุฐatๆุ^บq๛>Yึ_?รฐ iืoNU[งE3GQaฟš‘ฮ็ ๑\wlEึ ้Qฐ`Aฉถ}wL‰W&aญs๋๐j UชT‘ฤ๐O:kฝu๋Vฏb.sx๋฿ผiั[—h฿ั๓tj๕ J”ะW‹ภ"€ภk ๘ˆ†ำดqฉ|ีฦฏM๋n‘xฎ;ถ่๖ํๅพๅส•ฃGaE1GD†ฐึน™xl๕_|A<‰q็ฮ๒ํ“g=ใˆ>ภภ@ฺทo†‚DกCNแ+A่_ดjห!ฺ8ฃ }–๖‡4ˆ]ฟ‹*6Eใ†๕กชu›ว๎ล\ฬ:„ตcƒ์฿ฟ_n,WซV-บs็M™2ล1B\ž„ตฮM๔๓ฯ?S… ˆ—;x๐ 2DnOช๓eLeNmkซW/b‘#ๆZตjE้R& ๅ๋๗า๘ จhŒ17 Q"pํึ๏Tญอx;ฌUซ4Jyžยฺฑ?Nอ›7—V์˜!.OยZ็&โลห—//ืข}ค]ปvาญ[ท@Dเ๓>ืฌYSžL‘H.]พ$‹ๅ–f5Š๙ผH$5}GฮJ๓ทgสฤ๗†I…*uขฮ์ฒิ๗{O&Ož,๓ๆอ“"EŠธฌwฑ๋ฮท฿~+ฏฝ๖št๏]6o,๘วเ<๑(ฌ};h?๘ฃผ๒ส+ฒgฯ9sๆŒ4o\Ž?๎Jฌด;wJำฆM)ฌ}8๎5jิ*ฅ ศบ [ฅฤ Yฅe’>,?Š๚็ฦMy(q"h [Aุบ๏คด4W&Ž!ๅ+ีŠ ‡{ฃ(ฌ๏s็ฮI้าฅฅgฯžฒfอYฑbล™ใ๗(ฌ}2i…Lž”ญP9Žj๕jŒ‰฿;๏ผ#๕๊ี๓F=เV\ฝzU๒็ฯ/ึK–,‘/พ๘โทˆีว†…ulจEqฯล‹ฅhัขฒ}๛vนvํšTฌXQ>,?pw1้^2eสไXaพแศฤ‰ๅย… ๒ศ#g}ร›”Z•Kษž$uช๒VซJqVw\Tt๑ท+Rบ้poUO<๖ˆ\ช๗ฺœ$M’Xฺ5,# ซผ,‰๑ญ’แืวีษ[c< ตึจ๋gŸ~L7แ๖ํ;ฎžฝžธpƒฬZฒY&L˜ eส–k์ด> ๋ˆ๑gฮœY/^œ?พ์ุฑ#โLŒ๕kึ>ž฿~๛M^|๑Eูดi“$L˜PŠ+ฆqคNMฯ๛Am^บe•4ฉŒ;VžเอBกB…:`—owจRฅŠิฉชผื์.$K"ฺนฯพ3gฅiŒ˜h\{นq3X๖9#[ิ‚ฑํพ•/ๆล ;๓‰›ส#s๖ฺ %Oญ%๏L]ฅkฬž๑}แ็฿ไ๚ฟ7๔yบงS้1L‘์ก8l•U˜™|๔๙n™4y’z‹Uฦ จ ๋ˆ#Wฎ\ฺ›ุฌYณ๔ค\ฤน๋ฯ(ฌ}<:Wฎ\‘ ศ† $y๒ไRธpa-žาฅK็ใšซ8ท k3zฐว,๖นsฝ‹\1‹ล…ตjีฒmยบn๕ rx฿6I?HuชišไŠใ_ื‘"๕๋พ๔~ณฒ4ญ^๔ฎ~]ธ—LY๔ฅ,]ฟOงAะอูJ~(๑]yแ[ซ6xฤธ๛๙๚๔yฏ€ŽฌผYX3ณ‡<žา]&"}ว-•ฯถ’I“ฆh๓ฐศ๚—๑๘N๚เƒ${๖์ฺ”ัฎบพvฦ..˜`มฬ้ำงำUฏ]m.—ยฺว€๛oษ›7ฏฌ_ฟ^0K๓u๋ึIฦŒ}\S`ืฒeKมยทฬXG4z˜ลฦ,ลส•+ต}>๒ภdฃvํฺ>๗๓Zนreฉ_ซ’?ฐMn,รบนห‡๎c฿Iำำ5ๆ…ฃJพ์›ูภปืปษ:ตxกO›ชฺ,D_„๛q฿›ฺœ$M๊GีรHpฉžK”ทใภ)๙ๆ์9ฏQ>ฎLPฒฆJJฝ˜5ฆ&^ฝ.ืฎ฿ดjกalยฯ—๒อร.. _NžlฯJ>๕ษขุแ็๙ด+~ รgsuืแสŽv฿ -ฌa๊๖ ƒิ๐+,Y2™2eŠ`๖ิฮเ๔ต3vฐมญ† j฿tีka๛หคฐ๖1ใ๙Gr็ฮ-p“๓๓ฯ๋งUซV้ >ฎ* Šƒk&๘wณฐถ(๚‰แุ$มืf"•*U’uชษษCไฯ+ืet๏๚บทX้n:eฅ๎ฮญ$อSia ฑ๛ฯฟสw๊s๚‡_ไภ๑๏ย,rœ9๔ y9ๆ0เed๕zf ˜=-R “tใUe œส›๖ภ๓ฑ|บ๙๎ กเํbธzx๑ต+น?ฎ-?_SDํ๓•‘‡ดฝ|Tถโhใีฟ‘$๕ถฌถ๕ญคO๓ธt{ฝขฤWo0" xX={ญ9qN'งL‘T*ห#=Zผฦ_8„๗ฃ–๒๗Nๆฏฺ! •gคทTผMจjŒท ”ฆ?+ฮ๓ิ[_s๒Vๆg'ญ๛ฯ–}Š๋ไษSฅdษใK๔˜กฦ=5653oํฦEa}7a์ƒ7–X์NWฝw๓qB …ตGษฌ๊]ฝzตีXˆ๐ษ'Ÿ่™kWPลšฐ6ƒ‹?z๘Yพ|น๖(3‘fอš้Y์)R˜l1>BX7ชWSNู&.)ใnใ2๙†๏/๓šxDทSฝ.ล e “}๖cาu๘ย0qๆ‚๐ำiฝ"r๚G›ๅy๋Lr„วŽMสK๋zฅ$^ผPwr0IูถคไษšNฒexZ฿๗๛_K‡!๓$]๊วคฏฒo๛—ฏฐฯ]ต๑ซ0๕ MK'tV;y˜xsั[อฮC๘ํR[j”+( V๎”แำW›di]ฟt„ฎ฿๕นฬYถอ›ฯz‚< ภ}€๑หคV๙dp็šJ„( บO๖fฯซ,ีFv(!โ์/๒rพŒ’3s๙๖๛_คf‡๑:฿‡๏ต—Yำz๏q๓Iใ^ำไ๘ท?ษฬY๘ญิฝธ;vL jLA7ƒq(ฌ๏ฆ๊ซฏj—ฌึ'OžTบฟป๛Nฦ๘  kDppฐdห–M?็ฬ™SฯTใีfbO3ธเุทo_๛ื_ใยpฬI| rรฮรUl๋ญq๗#‚MYฐล†ศฦ,6\๖มe^lฝ‰`&๊ส๗Gทษ™/ษ$ตpฯMกvง ๒อ™๓‘v 3ศฯง}B๒fN๒gK'นฒคปKผn๓ด<ฯ[Fฅ’๙ิlv&Yปํˆ^ˆ#PaNSบูp๏์๗ปฝศ yžื๖ฺ˜้นd‹์WG„ืJๆ•+jึv|฿ฦj๖๖_yEนDภฌํถE}ดiNใžSๅฬนK:พSำ ZŒ๋ ๕ใ’ฒKnูg–7๑ิฅHฆใp>u`sีงปลis•m๓ ฉ]แฉZ:ฟื\ฦ”6์d@แผ๕2ฃM: า๋พVXž{ๆq™ทbป|๗ำeฟvVOIง ภ}ปณ>ำจŒn#u;Oผหห'ใ;j๓S'Ž่ำ+M<^\๐ปำ™@5;ŽWoN.สย…‹โ์oพGๆฬ™#๛๗๏ื‚ปฺถhัย'฿Q13ฬŒcฑทnbzซk๓cโล‹kSœ#GŽHาคกo—\i—uŒยฺ†ลS๘ฒeห$Ož<๚3mฺ4ํ‚ฯ†ชฆHฬฎเ แ้งŸึn๊bำ๙ฤๆถ๏ฐFภฆ@&`#ฬ2O&>1ƒ„28ยK/ฝคiาค‰p๑"l!a‹mfฑa‡ {H-ฌ7oีณตn 0wศ]ๅmowŠฬ"๐ [็,jF8ฺ&Qยจ]๋ม\กlณ‘zQฤไ„~ๅฅ|™t™V๛ํvสJ{ๅฎo‡๒2าJฝึGhZฝ˜๔~๓n๗…ฟA›กLpฃ๔ห๏๒ัุ๖สผไฐจ๚F๕cำI?ต  ^KL€GŒตjแfฒ๋wไ5›xปuฉZฆ€~(ภฌo๖๏๋|ฐK^๒~‡0 ˜}ว,|x๗ƒ/ๅอ$ปŸึ๗~>ฃ‡ฮ˜q4{หcซŽ‘้C๐nฎ3y๑F™ดภณลœแoช‰ ๒แgปeศd ๒แ1#„!kIอ๒a'0_ค>ๆญ†Rฑxn}๎๖฿-?žอ๛๗ยฎโ;ๅX$๏+|‡โอW:uˆ 6คฐ6$B`‚ฟ#XผˆฟWพ˜” -gqA€ยฺสYณf•?P๏ 5fฬ˜f?gC๗\Y$L.ฐฝ5D43;okภ)l๚Yภ๏D3f‡L0ข:|œ๕ฺไล๗ฃผ ม-D7fห1{}่ะ!Œr›7oญแค^:r๚ะ—ฺ3ร{Jฬธ%œฟ๔ง”k>RwgD๗zRฅtพwmิฬฯe๎๒Pำˆ[ˆs„5[{ห›=ฌฅฮ›1Œ „๗ ซํต7sศIล–JL)W%^ศฆgญ้•Kๅ‹ะF{๏'๕์ท1ๅภ=๚6‘า/{ฦpY๑ฑsึโT‡ัฝศซ%๒˜K}lขLพ:}˜80ชX"ท๒ข2D?Ha‹”บ]&†™๙ฯ๚ำšฺฟ๗่Yo9ป>๊/ษ•+<๘e†งkภ์8ผฮ`๖o๊Wz้.๗Žฐ/ึ`จพ ณฏ• nkyn:/ัh˜๖็U๙๔ำO๕ฟm_๗อj?ทuิqiC}ฏPX฿Mo๐=ปwธ$|๒ษ'๏ฮฤฟ&@amร๐ภMั‚ ๔S'f‡*eห–ตก&้o03~%7LP าญ!ผ@Gฺฮฆร3ๅAAAฺUถ Ž,ภ•_ๅส•ไฤ ‚Œ้Z;ฒฌŽ‹วฬ0L)bcฏ ืj๔ำ๗‡Ÿูี‘!?Œ`ฤๅ4e_=>ฤพzำทๅIๅ $ฒ`„ud้ˆว r็ฆๅฝ๖ษ+&wัณศ๙ซ{ฺefสM˜๑ญิzŒื๑0w๙lzwตh0ิF3|ํ—“v J๋bบฉ-ลแๅอบฅคKณ b™Šƒ๕แe๐ค•ฺ/ณi์ฏงjฆฝจ˜ูlใWไม ‹†ฬX๓“>ลNูy่”Œ์QW‹w๏†ใ ต๊‡x‘ส!ƒฯบsฅK—jWฏ(3 ;wŽs;nำ!ผq4fxึ ผuร›Hš‚R"ญZต’ดiำjำG์ผˆIg ฐถaผ`[๕เรฤ๔้ำGฐ bJ "กnสภl5fฬ1ำŽ‰ฬฬ๙C=ค๔E%ฌ4h wฒ<ถwƒZ|—D๚ถญjŠuโ"a๚เๆ3„˜ซ0‡ ๗฿dฎฒ'์ฌ}ฆ^dXญlฉ๒J>ฏฉล๘๙_ศ4eโฐ~v/en’2า*ร‹๐ณิ˜^8ฆฤSฌู_—Sฌž๑ฺcรำIกฯ๋4ˆ๊Cๆ฿5ฤฎสหGห:ก&ฬฆ9HซZบ€ ๏๊fq๎๒ํ2jๆgR gz™?ชตzXุคึk๛ํ ณ฿’-{Oศวk๖ส‘“?สรI้|*ฟฦƒ‡™•F๙0Y^;ฏํ๚ฑS?K=5Žp`ู`I’8ก>ว;สซIฎสo๋๋^-+IณลผiF|N่งf่_ ก๗fp๐ ”`Ÿ๏  ฑ๖ำ1ี3?๓]d#š$ˆhํJdo฿ฌB์ใmฬุŠ)bM ่๓N:้ท’‹/ึžกเ]ŒมY(ฌm/๘ฎ†P|YภuN—.]๔œ Uฑศ"€?œปw๏–]ปv้น`ห€? 0)Wฎœะ!:6yฐฏฤถ#{7Jฦดฉค[๓Šฎ!iฝ^#eสฐw `<˜ใให€๏#cบ†rฑ8มฌกˆึ8"ัฃGI \Sย&~อš5ฯb ฮ"@amรxๅฯŸ_&L˜ gซห—/ฏ_ํ`“ˆ)ผาลkbฬYยVฒt้าzQlลŠ1ลoพ๙ฆใwhฯ&)”๋Yiซฤ—[‚ี…\d๎ใข๊๋ฒ๕๛ฅ฿๛Ku–oผ&อk*ปN9ใ3๏"ฤํซK=%–# FXCD6ฃป\๚๕/ฉง$"ŒWvำe,vำ“”ฝ๒deท\A-ๆƒ|Tn๏:+๏!ญ”+?„“฿]ฦ=ฆy7L2๚ดญ"M”‰ฬ]ื6ฯ0eฑx*y9dทJฬ๔cwDใ“ -#๒2bฝ็ีฬ9ฤ8fแG๖ฌ>Y™ถLั~ฐน‰5CรSไ๐7็ดw”–uKส/ส แวk}Zฯ๘#ฟีct๎(ธรณถรoึy fh1YL฿oŸ0๛ ‘ S‚๐๔อZ ุ=฿๏[ฏ๛m'๏˜ภ๘๑ใต้Bฬ˜1รk›qnฦ๚# kFฅdษ’าณgOๅฮฌฒ6มu›6mlจ‰E:‘€ฑ›†˜† *,๖ม"Wฬ(ลฦ^:6 `ว‡Wวทn–ํซธฮBl˜Dtฯ็ีป [_kx)V ‹ัmf ึ~โ|๏แ32k้ึ0ื ณส0S)ขlธaฦูV๊ศห–ภy5ใ_๎๕‘ฺbุŽ€๏ณุณโึ€ ฎ ด๑ฝƒทbัY๔lฝŸ็๖ภฦ00ฤxฝ๛zF{jbฉv ฐถl™2eคcวŽฺ?'œฝใUฎ—fงแ๐~[ฑ๑Aˆi+}cวทyำFตัH#๏ฎ‚ึ<<%wp—”™ฬ@RชญรŸH™ฬ' ลBkpฦfฐฯ_๚K`ฮ๑ค2CIก6…aˆุฯ—n:\’?’Lพ:x(v…ฤเ.|Ahรณfศร m3›ทeพ4;‹A™Uภ๎˜๘;w‡0 มค ƒณPX0^˜hูฒฅ.& ๐kM๘6€v@‘๘c6hะ ฝบ๛A‹i+ฎ‘#Gสw฿}งfFพ”…๏ถ•<ูาY“yN$`3_ธ&%ฟ#ฅ|T๖๎ ™ีๆjร~๑G+พ'Nx7ฉ‚m6JSd‡ม'ุตโ;จืืฤIลฌฤg(ฌ}†2ด ซ'์ข”)S&M+CเภขฤYณfลฺ-ž]ฤฦŽซทB฿ฑc‡`ท›2ุล‘ๅ’@l ˜mŸ|"•์ๅq+ฒ|yฬR0ซ…ิุ๘ฎ`ˆ;ฐ‡ Hppฐ๔๎[ 'œE€ยฺ†๑ชZตชžญnาค‰ภญlูฐ๛" ๘ I“&้เ?w๋ย>’๊ัdา4ถƒ‚€๑ฬำOษึmขฯ์ไฝ `A๛เมjgRๅ~ั˜”๛.ๆ๐'ึ6Œ^กA\ฟ๚๋านsgI•*•๔๏๏ูšุ†๊X$ ฤ˜V›ฏXฑBนu:%GVฝใ๛y ภธv†ผXg คK›F6mr…๑nืภ๖๖ปwืบม˜”บฆsา kบnบฺ. (๐$iาค‚ลb $เ/`ร‡ฯ?_•อ๓hฆไ/ใยvิf?…j๖— ฯ?'๋ฟ๘2p:ฮžFIf8ะฯ=๗œ4jิH6le~&๚ kฦJ”(ก]์มถ~J‡nCM,’bG`๑โลsษ–ec[ฦฎE$kุˆ'๕~j NFๅญc]ฌหแ๎"p่ะ!มไ\Ž9ธนœC‡–ยฺ†ƒm5๐w่ะAV฿ธqCFmCM,’bG`้าฅ2bฤษ™-ณL๋[#v…๐. ๛"งJษจ„๕็Ÿฏนฏrxณ{ภ; ๖ภศ“'TฉREš7o๎žฮHO(ฌmhCศ›7ฏt้าE  Wฎ\แสj8ณศุ๘๔ำO๕C_ูาลeX›’ฑ/ˆw’ ฤš@กZ$mบ็dอ ๋XCtูpƒ 7‡๙๒ๅำ&ฅ๐,ฦเ,ึ6Œ!dฮœY๏พ8t่Pนt้’`›R๐๋ืฏ—ฎ]ปJฃuค{œา,ถƒŠภห๕ห“ฉำ่[ชใ์lค.\ธ w[,P €ฆmถ‘ๆe‚ ฐถa\`๒๔ำO๋AุVร—๑”)Slจ‰E’@์lผYฏ่ญ“4-๙D์ แ]$@๗E dใa’<ๅ‚]฿] ., ”bลŠqืfZPX0h˜ L‘"…5้w฿ี[วยฝ ๘ ]ปvIณfอไ‘รคbŽ;า,ถƒŠ@๙7•„%— 6Tฟููศ \ฟ~]Wc‹yฌี‚ž`p kฦซgฯž’(Q"y็wdธqr๘๐a™={ถ 5ฑHˆHฝz๕”หฝูR่๑_bW๏"ธ/ฏต+w‚’ศฦ๏ซ์ทnา;^bึ:ฺคิ=ฝ ŒžPX0ฮุe๑ๆอ›‚ู๊ &ศฝ{e๙6ิฤ"I v๖ํ' 4ะ‹ฆžฝsTไฮญht๛ฮนu๋ถซŽทn฿–๊s๋ถ'6Žwล!OุtAสร๑Ž>ช|8ชฯ&<žkkšงL•Sซบ€{๔วำ๋ต>Wั8ช์|๊ฑžŸžƒ>๗ฦ"ฟ%่+KTผx!‰๊ฤrช"CฎC"๕•:ื—!ว Œ๛๔วˆฯƒP–ฮฃฮขE›2ใIP๚„\{ฯ-q๑ƒPvH>oฮรCาMœงผ oู(7lZิ๕Zฐ์i๕ไ๚อxzิ€…ภŽ฿E [ถlฺ$w๎๒ึ[o•ฮ&@amร๘ 8P๚๋/ํ d๊ิฉ๚K~ƒHภ_|๖ูgzWPl›ซ,คฉGp†qก5(„ชjtจ`๕ฤ฿o? ภิ๙ฉชDฤ…ŒtผO&ฯฅ็^ค‡กo๗ใ’;ค otศ‰ฉC‹mgชดjiฤYฏร—aฎC๓XTทJ ๗ๆิ<ฝW:ป็๏!'๒(ฤไ๖M{Mฌ7ูRYh\ศ=ฆ•เMำIžˆฐqฆไธ9๊แ๑Ž‘๗DW6 Qึื—:Ÿ๙๖nฤช˜ศปำฬ]f์-9,งž\แ๊ ):ด“+๒๓ปd~ฯ๓†ฺ$&Aย„๒๕ื_‡ฟ‘ืLฎ๖ ช!ฐ๛๕๋ภ$œูu kฦ & Xู;qโD™9sฆฌ[ทN–,YbCM,’bO dษ’ฺฅำํฟ/*ํq[โ™YK๕—?ฬฬ#ฤLGาฤำณœขg)uLศฌ'TฉสขEŒG4{„ˆ>73™(‚ล*ZB]Tยฮš=ฬฝaบ๎ฉฯคc–ืำ˜ฐี!:$งพ;Tไxj ฝFrH{q’เ9„ฯkษงo I๗ก๋_นญ ่๚‘`-ำ“฿ง“๔ะ:๏Nื}0eฉFys่8ฯ•้‹ทK‘ฏ๒่‡(ไ…ๆV]ชๅ8ั ๛* ?๕ตŽืษธ๖Œ",เL—2ฐ๚ สC D„ค›๛๑ฦA็ )SN่ ๏)ำS๎ฐฦแ~ำv๊Pงi Ž:Ÿ's˜xokะฬ( …้1Dลw4u]R<้๊ง'K<]vh|ุ3}ฅ2๒๋UI›!ฝFƒ—์ซณfอชฝ‹aขŽมY(ฌm/˜€œ:uJฆOŸ.sๆฬ‘•+Wส๒ๅหmจ‰E’  w‚ฏC]›K?โก(ARo'[งŠ-*้ำงืLิ18‹…ต ใe]ฐ8o<ม.wื $@$@$@$าฅKk—ฝ้าฅำ;ไF•—iG€ยฺ†1™4i’ภู‚ dแย…ฒhั"M+    DEเีW_•”)Sส3ฯ<#ฃGŽ*+ำ…ต ƒธO๚๐ร๕g๎นฒึฮ,’H€H€F Zตj๒๐รK๊ิฉตท๕ฯํกฐถa„aWฝjี*Yถl™|๒ษ'2mฺ4๙โ‹/lจ‰E’   ธ‰@บuี๑ y๒ษ'นฐีKamร มไฃ>’ีซWหŠ+๔? n`hI$@$@.#ะธqc –ว{L&Ož์ฒนฟ;ึ6Œ๑ว,|๐ฌ]ปV>๔SฝQฬ–-[lจ‰E’   ธ‰@‹-ไ๊ีซ๒่ฃj๏bn๊[ ๔…ยฺ†Q†ศุฑceำฆMZ\:Tถo฿nCM,’H€H€HภMฺตk'—.]าย{a08‹…ต ใ…™j#ฆa[ฟํ%ฤ†ชX$   €‹tํฺUพ{I‘"… รE] ˆฎPX0ฬ˜ฉ๎ีซ—์ทO{้ปท>ทก*I$@$@$เ"ะ 'Ož”ไษ“ ๖ย`p kฦ >ฌ[ทn-GŽุVw๏]๖๏฿oCM,’H€H€HภM๐–๛เมƒZXc/ g ฐถaผพ๚๊+iุฐกœ8qBv์ุ!ํท—C‡ูP‹$  plcพs็Nyไ‘G๔^n๊[ ๔…ยฺ†Q>v์˜Tฏ^]ฟส9ศ›oพ)Gตก&I$@$@$เ&ุmqร† ZX/YฒฤM] ˆพPX0ฬงNlI 1}๘qiฺดฉ|๕ื6ิฤ"I€H€H€D`ย„ z“นdษ’ษ๒ๅหิต€่ …ต ร|๎9)]บด^ฐˆ•ฝ๕๋ืืณื6Tล"I€H€H€\D`๚๔ฺ้ย๎{œE€ยฺ†๑บx๑ข-ZT๛ฎ†/สš5kส้ำงmจ‰E’   ธ‰ภœ9s๔&sฐฑ์ณฯิต€่ …ต รวศ /ผ _~๙ฅ\ปvMชUซฆgฌใวoCm,’H€H€Hภ-/^,“&Mา6ึkึฌqKทฆึ6 ๕?#นs็ƒ–*Uชh! $ฐก6I$@$@$เ+Vฌ#Fhw{๋ืฏwKทฆึ6 ๕ํท%K–,‚ &”J•*้EŒ‰'ถก6I$@$@$เ˜”๋ืฏŸyoพœE€ยฺฆ๑สž=ป,Xฐ@รจXฑข,&iาค6ีฦbI€H€H€@`ใฦาญ[7ญฐษƒณPX4^y๓ๆ•)SฆศSO=%ๅห—ืฤ`…/    DFหa๗ๆ”)Sสถm"หฦx?%@amำภ.\XHeฬ˜Qส”)#ะOŸ6UวbI€H€H€\@ห5iาDRฅJฅwovA—ช ึ6 w‰%คw๏‚™๋RฅJษž={๔?›ชcฑ$@$@$@. pไศํฆ๗๑ว—ปwป Gี k›ฦๆญZต’"EŠD๖ฎ]ปไ‰'žฐฉ6K$@$@$เ'Nœส•+หฃ>*๛๗๏wC—ชึ6 wีชUฅN:ฺพฺl{k   ˆŒภw฿}'ๅส•ำๆฃ0#ep k›ฦซnบZTWฏ^]^z้%มส4iาุT‹%  pŸYJ–,)pxp่ะ!7t) ๚@amำp7mฺT๏พุจQ#มBฦM›6Iบt้lชล’   ธภฏฟช'ไ’$I"วŽsC—ชึ6 7์ซ3gฮฌ]ๆ(P@6lุ ้ำงทฉ6K$@$@$เืฎ]“|๙๒ 6•;~ธบP} ฐถiธ;u๊ค+ยษ;<ƒ`[า 2ุT‹%  p›7oJŽ9๔ฮอ฿|๓บP} ฐถiธ{๖์)‰%’>}๚Hžx๐ ิซWO๛ „?สiำฆษห/ฟlSm,–H€H€Hภ-๊ืฏ/๛๗๏—;vH๊ิฉาญ€่…ตMร ง๎ฏฝ๖š~โ„ธ฿+RคˆMตฑX   ทhาค‰์ฺตKถm&O?ด[บ ฐถi˜๚้')Uช”ถฑ.WฎœL˜0AŠ+fSm,–H€H€Hภ-Zดh![ถlัŸ4iาธฅ[ั k›†๙๗฿—ย… kฏ ีซW์ฤXขD ›jcฑ$@$@$@n!€5Z_|๑…ึ้าฅsKทขึ6 ๓7ด7O?T7n,ฃGึ3ุ6UวbI€H€H€\B K—.c้ำงwIฏฃึ6Žณ๑_ฆM9rคผ๒ส+6ึฦขI€H€H€@ Wฏ^‚›ืฏ_/2dpC—ฆึ6uพ|๙dาคIาฝ{wy็wคL™26ึฦขI€H€H€@๛``วๆตkืJฆL™ะฅ€้…ตC ๗zƒ ’๊O๙๒ๅmฌE“   ธภ!Cห}๙็’%K7t)`๚@amใPc†บcวŽฺพOŸ+Vดฑ6M$@$@$เ01c†ฌ^ฝZฒgฯ๎†.L(ฌm๊J•*IฃFด๋>}๚PXศšE“  €[ภ“LIWญZ%9rไpKทขึ6s:uคB… 2o๙ไ้ปท`›H€H€H€ข"3˜ƒ,]บT๒ๆอUVฆ๙ kn๖เซzแคJ•*6ึฦขI€H€H€@ ‡*}๔‘(Pภ ] ˜>PX8ิ=z๔$I’ศŽ;คkืฎRตjUkcั$@$@$@n ฐhั"0`€vน‡7฿ ฮ!@amใXแล•+Wไศ‘#าฉS'ฉVญšตฑh   7Xฒd‰ภ้ม‚ คpแยn่Rภ๔ยฺฦก5j”œ9sFNŸ>ญ๎Uฏ^ฦฺX4   €ฌ\นRz๖์ฉผ๔าKn่Rภ๔ยฺฦกž2eŠl฿พ].^ผ(ํฺต“š5kฺX‹&  pฌอย›nุZcณ9็ ฐถqฌ๐ฎrฎ_ฟ.ญZต’ฺตkX‹&฿ุธqฃ<๕ิS’ A‰?พ>นsGฬต™s๋1^ผxฦG”฿ดุzฟ9ทๆ์ไลัkœ‰(ฮš฿Žsp@0mฐใฐึฉทo฿6งบ^ำdN๏:†ฯ{?ื1น|ขสฏ4“Žc๘sg=šŽ[ใ":*ŸSgฮ‘ืแƒ‰3Œ*ฟI3๗ไส•+|qผ_~๙ฅภยœ9sคhัขาkwt“ยฺฦq„›œฉSง ˜ตlูRเืšภ/ฟ"ลŠ{ อ„ฐ0โ ัrqฆU–s“ฯƒ‚L.O~[ฐŒg˜&ฮmŽRผๅ™”๖„^ชณะถY๋๓f \ฆแ๎t_kฅg5^%Qื†๒ฑฆ๏ณ<\่kหึ4หนrศŠss๚˜โ)$ขxgช1ืๆจ ำI๋:i-฿ค›ฃพษ’ื\›ฃ5_tฮ#บqึ{Mžจโญyโ๊ฟงNŠซ๊XุบuซดhัB>๘เ)^ผธตŒMน ๋{บ๔๕๋ืห Aƒ$y๒ไาผysฉ[ท๎}”ฦ[I ๎dส”IT‹m‹็ฯ'ห-5lŽทnIp๘าw๛Žฮt\ใ^o*=ไ๚ฟเาCสฤฌซ(az~[n้k%T:ฺฑšฎฮญืฆ %แnซ6Y๓E&จโŽฎok‚๘‚ุึGœ‡|ิ‰ๆ4ไQ๋x˜@>๕uศ=๋x_=Xx๒x๒Zห[–%Ÿ)ืzT็๑Qโ๔ว“?พนIำืh[\{ชฮQ†็ถ#eจŽ"›ืิe๒[ึsห=ึ{M฿ย๕ƒบว<8ฤSou‚ิ{ฅสE๐ ๏๚:$MgP?๐paอ‡บญa๐ด้๒ฃzศก|%K&‰2fด&๓ๅvํฺ%M›6ีš—*UสๅฝuW๗(ฌmฯ;wJถm%Mš4๚H๚๕mฌE“€๏dฮœYบ6h อซT๖]ก~Rะญ[๏ทด‡HทŠm•|WM7ณฐF–Œ๊ิzญSB ๒ๆ ญjัBN *s„ิย94–‰๓\ซ8฿#M\่์]Mf„ร 42TN;'gL—๘?!‰žแ=b๓cBเภอ0}๚tyๅ•Wbr+๓>`ึ6ภแร‡ต]5D ž<)ฌm„อข}J K–,JTW‘.๕๋๙ด\F$=อ –ณ?$”ฐN๐ิำ’0]บ่ศ\ฎ PซV-™6mš”)Sฦ} ”NPX8าgฯž•๒ๅห DJใฦฅaร†6ึฦขIภwฒgห&5_)%}฿xรw…ฒ$ hh:pœ๙g=c0MZI๐ฬ3ัพ—Oเ๘๑ใz๏‹‰'JลŠ฿ก๊…ตƒ 7{Xอ‹k๋FูX‹&฿ศ™3ง”)THFvh๏ปBY @ด 4๎?@พ;^vฬœ! Ÿ}NคNํ{™ั๙ฐh๕ีW_•ฑcวJ๕๖ม9(ฌmซฟ[๒ๆอ+Xa 8@rNฝ๕5kฆ$ส”YโงL้บ>ฒC‘๘Y™•,YR†ส๕Y‘c๒ห k›‡%_พ|๒ธšihาค‰4kึฬๆฺX< ๘†@ต…๎“)RศโกC|S K!ˆฺฝ฿’Ÿ._–ฬ’ฤYณIrส8Œ)้€ด~œž;ฟงึ6!lฌ“$Iขaผ๚๋6ืฦโIภ7J–(!ล’ๅฃF๙ฆ@–B$#ี{๕’ —•=ณ?ฤ9rJะรว่~fv6฿] .,oฟถผมEไŽL k›‡ 6Rุณีึ6รf๑>#PพlY๙๏Ÿไ๓qc}V& r?ธ‡y๔จิ/W^$ˆ๏ุรšฝ{หน_.สนs$I๎<OMะ0kืฎ x๗Vฟoพ๙fเt=ฅฐถykิจ!ฟ๖›~โคฐถ6‹๗ช•+หo—.ษ†I}V& r?s็ษยตkฅSฝz๒f๕j๎๏ฐ=ฌึไ๛ <ย:_~‰—0กตฑh#๐๏ฟJฎ\นค[ทnาฎ];k ๋(เ๘" ถีXขE ฝญน/สd$`7:5kส? [ฆNฑป*–๏"รๆฬ‘ล๋ึKๅ&ฌWำ&.๊Ywฅ๎ึยzฏšฑ~จ`!lล๗`Œภญ[ท$kึฌาฑcG้น๓k+Ž9 ๋˜3‹ัxา๒ˆl>อ–ทoKฒ็๖u่4zŒl:p@บ)SขๆU*๛บ๘€*๏ eF๘อwJXฏX!‰ิCเ€ฐฎฉR‡ xwp)ฌmผu๋ึIืฎ]ฅK—.าชU+›kc๑F mถฺ]R%คœZ*aฝY ๋sfKb‡.ค{ะผ*ฏ* ๛y^แพœ;ทŒฺ๋E’>๔Pœ5 โ3ศ_์ซ๋|1WNน๘๛๒๙๓6”yแืญซ๗๚~OฺŽ)–>อ_—๚ๅห฿oq}หw‘ฏฯ~'{Wฏ–„ฯ=ะ,ต๓๘ปQYํ)0Š;เ:๊W€ยฺๆแฺตk—qฑ{๗๎ึ6ณ๖ทโจ™;์ธ GO>๙คิชUKสช ๓*ญ^]6n฿.;ิbดไษธ•rlว๋ต.]ๅว‹ฅตฺ(ชC:ฑ-&Z๗มž{๊ฒerZํ~๘‹ฺ”๊๘ูณ๗ผ/ฟฒแœ7pภ=๓E7ฤ ์ษ‡ถi-ีJ–Œ๎mฬVj–๒ุ™ณฒWฝ๕H˜6m9ๅv9sๆ”W•O๘ัฃGปฝซฎ๊…ตอรy\-XชVญš@Xc๖’!๐`๋ผy๓ไตE๘7ไูgŸ•2eสH… คP!ต๑ƒ†Vอ›หFตmใไI๒Dส”~ุBg4ษ๋–๊; szถ6‹ฑx0ฒS”สV7gฦŒ’ํนg%ซ๚=L›:ตOMBเ{‚ณเ˜ gˆ=ึร‡หัำgdŸz๋™เ้งc_ะบ๓จ๒xw’y่*0ึ#a]^ฝ๙;vlฌหเqO€ยฺfๆ็ฮ“าฅKK๛๖ํตIˆอีฑx?&๐มศนs๕๗+ืg?ฉ™ลดj& ณุ๘๒,\ธฐ฿ดพ๕oศ—[ทสฺqc%_ ฑ#`„uƒ ๅๅm๕ |๘[=l]Tณห๐chฒd’1]บ๐Yไ๕ฦใ'ตฝ฿๊ˆ<ฉR<*<œ๔ฎ|K7n”3fzใำฉq๛ํฏฟไบบแเ๙’ A|o๚ฝN.\พ,—”ํฤ‰้zŸH๙˜ฤต]v•๎=ดฉษิทzKQผ™นƒ™F-|=ขฬ‰๖}๑…$pศฟมส|‘๒ป๒‰L"lTฟ— ฑ#€-อก09รเึ6ี๊ำ jๆ>ฌ๗ฟู\‹w๑๙P๙ฆฟฟคSB 6ฬุๅ๐ๅนป’rU–?ฺ•6JXoPยzๅปฃ$_Cวz,Œฐ†ษE›š5$qย„ฺTณบฟ=ฦ•ฬ์๓ถผโณ6า3Wฎ’YซVyลฑiศไฝคxพ|ๆR1;๘๑† ๚ผˆฒ้N๗ิSฒhํZ>wžŽ‹๎BT๘N<๋9x๒d˜๒ั‡ู๚E)ฎKดjญๆ(๙่ษ" ฟ˜^ภ^ะฉSr`ำ&‰ฏผฦ๘k๘๒ห/e–ฺ่ฐฒญวนไษ“Kม‚ฅN:๚๛ฬ_ํ„vaถฟx๑โ2iา$'4—m !@am๓ฏ8fQ`7n,ดน6๏$gฮœ‘ีjaา็ส†๒ฌZูณgพœT‚ฟ3+V”๊ีซ๋YŸธ๎Wke ๒ฅ2-๘xุ;’๙็ใบzืิg„๕ฝ:ฏ…ิ๘๗hิPžQ๖๘,}ฆN•5;wzo…)G:•vRฝC๘fKฉฅfณข kีžใ'่,;gฮŒpฆz?ฤt%่ฬ,7า` ฌ3v…œฟท”}2๋m๓›ฟก๏]:bธdแ‚;/—ุœด9J?Pใ?๚hlŠฐํL เ v†˜Nš4ฉผคฎcฟ†|แ๘lkD a๒ห/หดiก} Ž๏"…u !œผืP‹—FŒตฑ 'ุญ|~๚้ง๚ต้%๕ฺ?ƒ0X๔x^yp(RคˆTญZU‹์ ฤI๗Z4m*[•(รฬc^ตญ.C์D&ฌ!คK, g *—Z)ึ&`ๆนฃr[ทๅซฏtTฝreฅฅ๘ตฦƒืห-Zz…๏—“&FนCใ&%€:yO—s/{๙๊๕=|'#@L๗o๑†อ“W&L ‹•๏ฐ9suZT›ฟไnะP็YฃLˆ`ฟอ{ึ_ฉƒ๊แ*Hพ<่€๏ขU๊ํษย… ๅย… บ9ฐnำฆ^`๗ ็ฦ๚๑‚73ิ"r็ ฐŽƒฑ‚ห,Tใ„8€ํ‚*๖*๗hxฝŠู ˜ˆคRฏaฏˆ€…ฐ๐.b๗ฌถ4฿ƒYฉ~}ฅw}‹๕o•ึ˜mฮคฬ~สจลช%๓็ำๆ5๑โล‹ฐ\ซญtx{Xm…xภ@๏}}•ูNdแห}๛คห{ž…OQ‰pฬWV ฌฯ+ปjดuูศ’FอŽ›{฿j‹{ึ_ž~โ sฉ(ฃ€z Cุ ๗Ÿ6ย฿ฑฆ๊ม ๆi qC €ฺL ็ฬ™7ฒŸ ฐ๖ ฦจ ม๋2ฬ:baZBตx OCๆˆ8\ใˆ…lˆว9fดฬฌvI3ืึ#j6;จYใญ็ศcฝŽ่<ข<แใย_‡/็^้ศ>f@ฌๅ =ขพZ๛hฮua๔ใWต๕สCภgŸ}&{๖์ัœภ‹[เฮ&Gพ ตีฯฏี๕IฝzสK!‹้|Uv •c„ue:บsงhuำฎvmi[ซฆพ>ชGซW๐ ีbฤ๐‹วซ๑ศใว๕`ึจฟวO๕‡C‡hW{ธไ?Hํท<‹ฉwฬ˜ฎgฃ{M˜จ‹;๛๏ฎง”=w‹ก๏Dธ-;_cAฃ ืฎ_ืf*ธ^2|˜dKŸ$๑ ^a}่ฤณแแ9|“เฅ3ำิ)o2Oฉฐตี๏a•*U$ฃrำศทเŽkoๆ+> ฮ!@ac…mI1C๛I๋'ช๊Ežศฮ#ปuXƒน6Gkšฯ7"ืึssmŽึ4œใc๕8Gœ5?โLZ๘๛ฬ8š๒เ!ษcŽˆ3ฤ™<&ฮ๚peรC–yะยC๒แณJ+Wฎ”๊u1~ฟ๐GณI=z๔ะ้๗๓ฃบฺŽ๚ิ™ณ๒พ๒GLทiฑ'iDreงพpฐgF๘^ฅมฮ๖ฮ5าc๛‰zkf f1.='Lะ›ฑ ฎจšีำฅณžฦต ฟจ‡ฑr=‚~XปถRE=„!Œ^ฐPๆช4˜}`QใมoOJ๓๛๊bสM^้ )สงe๙ๆ-ฆ(ฉฃ$S& Xhย๘๎ไ•_์๙ี[„๗T[สฝ๘ขษฦc,ดUkr๖Ÿ8)วŽร€X”p๏[เึฬL ถU&<˜‚ ฦŒ)รƒ#a ุต38‡…๕+ˆ\ฌจพy๓ๆ]GฤแŽX‘o=Gœ‰7iH7Ÿ[ทn้ssDœ›ฃ‰ทฦA˜™tsŽฃ9G^svใฺฤ™kคใ<ข#โœ ฒญ!ต5 ็๗JG๐‰Nˆ(_Dq•ีตkWํ7=ขด่ฦUVป}๐ใ9%ฆ:I‰์๚/บm๖ว|FXc3–O”rtยf๕๊‹# ฏ(7f๏* ฿าWฎ-o โ๕ฟีCZท’‚j†ห|ฟzฝนพDz%˜จ1ุ^#ดR‹ช;ช!๑ปU๏ํ>๒อ๗฿๋๘๐?`TD‰w„ส,ฉ฿ด้,๐ัณQc๕ะ—@Œปฝ˜˜พx โI0๛9 S›Œ๙*เ;›Uญ_ฟ^๛šพvํš.:ต๚xๅ•WคAƒ‚7ฌ A a๖‡7 ฮ!@aํœฑr|Kญย*พ่ฦั*ึัa“๘อy๘xคY?Hวต9ZำยวC ›tk~sัั‡sLูธถž›๔ศŽ๗ส‘`Mm*‚/[์n†ืถศƒMgฐP>e๏7”W›ึ๒ห/ฺ.ธ$gญbsภ๔้ฒlำfฉ^ชคฝญฃ]0Žšฟภ๋^DเปnูraL>~Wc›lใ‚ฏ—š1n๒ฺซa๊มโE#คญ ๛0็Hช์ฌฐQอ€้3ย,RฤุwU;F†฿ธๆ#e’4๔ƒู๚>ดmZฬ๘šž๘๑™ถ|นž ฿ฃLJbO ตึ๛ีCะื_๛B,wB ™€7kx๛…ท`๘เ฿C๘Ž5฿ณึ๏%kšI7yM™8†ฟ'ข8|WแญŽๆ- 9"มผ้ณๆ3o๋ฬ=ผนรน5็ˆ3o๙pžD^š๚Šu*๘ ฮzDš‰3๑}๗๊ฦัl–>}z๙๘ใใจFVใ ึพ ศ2H ŽŒ=Zปผ‚๋+ัมKธโkัฆ–VB๐ฒ2#ำน๓]‘D็~ๆ๑๘๋๊55C6งม,sLJWc€†Qm+ŒชŽd*_ฎ์`ฯ*ู๚{EzzตQฒeคถ๒ 1>๚็Ÿ{้gิƒš1; Ÿื03ม 7:ขธ๏ำํ%๕cyMDtฤ˜ถ4‡)ˆฏ„5lu๑V๒15F?p˜ทๆMคy{‰ๆวจDจฝแ๘ฎ2q87jฤ[…5ฮญ้F€ฃnœ๑Žฃ๙ mG€เว9าฬ9˜พ˜ทฤpgj.บหp#|เซ๛๕‰#ฎ“)_๎แ&๙†อrR(WšˆM€opl"ถdษ’ุฮ{ ๋žี’@t ภฟ56ภฦ1๘Cm‚kึฌ):DฯหDt๋ฑๆ+ฆผXฉfCaหkLฌ้O(7–pv€#๖ฟภฺ™eห–™ขxt k ›xเ๕ฆ๐g ๗z˜๕(Wฎœ๔S[Jใหู๎๐ฒzyEู_Nู๊รปลถuฒ| Po*a• ยฺิ€…ฯุ*ปพ"˜‚ฑ9L* z!v 7bgาpŒ่c}h0๗™|xˆฐ~|oใs]ฝลม์ธษc๎C9฿x`‰*@„RžaœC€ยฺ9cล–บœภ7jf ฎ๔๐ฯ์l†?v˜Mzํตืโด๗•mํ?๊ยT๚ฑŽS๎ฌŒ -ฌO~๋3SSn๘#<ƒLœ8Qป๒ผz๕ชžกลฆ$ุA์'ั 1n๘๏๊ ึัภS |‡cฦ›ม9(ฌ3Vlฉ `แแrตุ ๆ˜•ภ๋X|ฉb…>ถ .จผ@<ˆWy€ภ—=6 แฮ‹bXg ฐ{ฦ:"พ›•วlŸ}@yฆมl*l์_Tnตk'pฦ@$poึ๗fฤ$เsุ่e๕๊ี๒๙็Ÿk[:,"ร ˜™nผนฦึ็•ฦ ภ\jAฺฟJXsฃ@cV๐!ธšฑŽฌษ๘nšฃv;|๘ฐูฐ .Zดจ~ƒ†ฝH€"&@a1ฦ’€ฯ |ฏ<(`u7L=๘ใษฌ6 มnŠWฎ\ุ56lุะov7ƒ/[ฬXGต]ถฯฑ@ /-ฌMC`ฃผt้RฝๆJ`#ŒEvลŠ“Ž;J† LVI€ k€อึญ[งnูฒEาฆMซWƒรv๎Iๅกก~๚าHํฎ‡ใเ6_Nš(Oร[€?ต›m!ท€ฐ>๘ํ)9๎ร b|ม;5โƒ5!0y๎ี๗6—เf @'@a่ฟ์ฟm๖ฉํš5kฆgx0๋ƒ€ํiแ›ดˆrgWฆL๊พ฿‚ณซWฝฉU๋ปfอิX฿oyผŸH fUX[{1~x-ฒ/]บคุม”ญ“ฺญ•ณุVJ<4ึ6โ์oœ่ัฃ‡”Uป>๗s’&Mํท4Nหส๐€‡ร ฤฒF$p?|็9t๊ดOท4ฟŸ๖Du๏ฆM›d์ุฑ^&ีชU“1cฦDu ำHภต(ฌ];ด์ ฤž@eB-Vฺ:mj์ แ$@ฑ&€๋รงฯศัฃGc]F\฿xไศ1b„์ปW๛ว1ข=ใบ]ฌโ’…u\าf]$เุ*y5รพj๔ปi1›I๎"a}๔ฬY9ฌฤชำ65j”Lสsง{(ฌ๏Ÿ!K W€ <–ไWๆ ๓pU฿ุp ๋c฿}ฯ]๗œ2`l' „ ฐๆฏ @X้๋2/ผ ใบu “ฦ  ธ!a}๛ไเมƒqS!k!๐  kŸ`d!$เFXื)[F๚ทhแžŽฑ'$เ ญ†Pย๚{๙๊ซฏิj6•H€ยšฟ$@a`ˆ์ูณKซ5คc:aาแ"8๘–฿ V๎oษ๊ฌซYvธิ็ทo๋kฤแ!G๓นmI3qศsKล# ว[ท๏่๛Bฏ=iศoโ๔๑ŽŠWf3wpฏ:".์ตŠ ‰‡yIืypŸๅฎk๑งฏฝ๑žtไ‹/ ฏBขโ‰๗ฤœ…ๆณ็ษ’WๅM๒– ๏3uแค?๑-็ก๑*]ลวGž๔xๆ<^P˜x”ƒ๛ืuู–r=ex๒ฤ_„๛$L@"‹Ÿ๙ฦO ˜r<็^0~z๒ฆึ฿(๗ุ^œHภ9(ฌ3Vl) ฤ ์ธˆ฿~ฝ™4จPA‰ฬ๒๏อ๊sSn„|pn>7•ฟก>ุPFq_ฐ>ว5„๚`ฤy>Zใ\ aˆแ”`EฯนบV๗"อˆgXVโX ๊[Z€F„DDฮจOบถž›8O%•ีย๗@่…ไ๗H‹pTbัˆJ}TyฝืชqบŒ8soŠ7bํG<>๚<ไZE„ bsฟŽนใอ‹J“ใ'~่`.•\‰ฐคy2‡ไ4ษœก๑!๙B๏TI๚`<ื๚!A=H่4๓@ก๒†yx@:โP†zนฅข๓ Rไี%ๆ\ง‡”กJฦฝxศA>๓๐s๋6–<@ึ“Ž{ข ภต8๙ฝะื!ฟ':^‰wฤ%ฤ'aBI„ŠำGuqŸ8ก็:ฑNOค๓%Q็๘D‰t~คฃ O>O9s}ฏงฤ ฉ6แ7Eคฅึ'ฯ“๛๗GทKฬG$เ(ฌ`ุ๐'Wฏ^•๙๓k!w/กb„กi่จ‰ { #{ คย&๓ŠH@ภฟ+รฺท฿~K&$@"@aํ มbSI ฎผฐกไOŸ>d†.Aุูถ6๓*_‹้™V3 >ํึi!G๏ตบฯ{๎9ั๓ณ&ฏบษ{Yพ{ลG”nโ":FgํOฤ้˜}F B่Lดพ๒ฦ{xr ›evZ_†f4๕!ฏ TรL“1ฉ๊จ2„-QWแIฐf -ศั้=๖D>yŒูhO}ึ7˜eyุ “rƒพอzฎŠ ›ฯZฎง”‹<๚ƒไ:Lœ'สำ g๊ม1สธrร›๗ถwWšบ3์๚Mศ[œใฺ„‰“:ญ๒<ž1ฃดเ:  8†…ตc†Š %ธ#|ผ๗๓OqW!k"C ~สว$‘๒'ฯ@$เ,ึฮ/ถ–โ„ภ5{v็Ÿโค.VB$eร”4i Œ"๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†…ตc†Š %   ๐gึ<:l    €cPX;fจุP    &@aํฯฃรถ‘    8†ภFTwJW(NIENDฎB`‚opentelemetry-collector-0.141.0/docs/img/component-status-state-diagram.png000066400000000000000000003117531511331344600270250ustar00rootroot00000000000000‰PNG  IHDR\P{<fiCCPICC ProfilehํšyTSWวฟ/ AมP(D dƒ$$F-R5ˆุVซ(P!ฤ$,.ืN]ช2ƒีj]P๋TซฃŽฎจmีVญ๋ด๎ฅโ22jG{/`Fjk็Žว|ฯy็}๙ฝ๛ป๗“฿ๅw~่๊Ÿa2ๅณb€ฃีฌOˆ ~๓-๏œแ><œaฐ˜b๛๗OQำu๏$(z<œพVหใฟ)ทฌl‹ Dฤd0™ญฤo$พS‰ีD๛ำฤ ฬคSฤ฿ }Nฃgั็ 2/hl3PO|โ3ฏข}ใ๛ะพุCฎษ ฐฝzลK$€Sพอห็ าf฿ภ๘ค ฟxš้[ฃ\“D}z้EŠพแฒฆพ๛ กzAO๖ ๔E8šทิฏ]ไสš]jฅ๗๑…ฆQๆผœ\ซ(–Pฯ% โ0‘L"S๔oศดพ[ว6?ื<M tS‰I~KŽพะ^'žฦBL€G4ฐซกศ\lป=ล’ฟ๗7รู&6้Šbฑ9'.็ฬwqiใ๊ๆ๎ัึำซ];ทะวท}?ืEƒ:‡„v๎าต[๗ฐpq„D*“+"ฃ”*uดFCื3&.พW๏ื๚$พั7)9ฅ_๚ิดA้ครo๚ฮฐแ™†ฌ์wsr฿‘_`,44[ฌEล%ฅฃF๛~Yyลธ๑&Nšย์=@Y&ษตl„ฅSจPแbW( Nทz6JุˆNแ๘šถHดrpเ"…™น>?rB็q,D. D๊ฎgฤFIWค}อว;ฎdฑ( qE๘9PอŽม๗‘สใbฐ๔ซ๔ฤ1{‡โญXgศ็‘์‹”ฝ||^[๙$?Œ`ตมjnkฃt่%”}g’๏msH<‰BE…C;(\๊ยฦฐžlฬ๋ฬมึz'๛qQฑฏ>ส….เTบ‚ฝฤมXผ& Š๖ฦ2Cผ6ำ7สัญฐfํ่„ฺ;มHปŽฃ a่^&ฦอีj<žฌDQ–qฮ โQfot แ๘™~๐^ฌ‡{wัฉf(ฌท‡ฃw@) ›๒aiยนฮ3`Y6ƒ๏•Aณoakฃt่%T๓ป\&]/‹Œlzฟก7>๋o‡^m9ึ฿ฝสrฌฟz•%ำษ๛รกฒ]ิu@‡ \฿ฤ| >…ฎHsvร‹ฎศL๗ลัํะ~๑ัม>]`ุฉยฮj ฮ'Gc๙ั~ศ:—Š๐G0~C>R„fN*lๅ‘:ไPKษๅ,„6ะŽB๊ฯ@ต‰ำs(mQ ie‹›‡Cœœธ\.ฎพ9๓๙|—6tาออƒ.รัตศvooกะ‡ฉล1ษ@QGบืX”d๊qveษๆบdlse–)ฦ1ฅ8บ7lx†!+;'7oD~Aกษl)*.5flY๙ธ๑&M™:}ฦฮž3w‚สช…‹/Yบ|E๕๊ฯึฎ[ฟaใๆ-[ทํฌูณท๖เ—_9z์๘ษSgฯpาๅฏีt๓ึ†๛>~โซ=~ชiฤhY|cž7EาŒึ~‘ไc+hฬ~ŠeXIfMM*>F(‡iN’†x \ PASCIIScreenshotP%๐ pHYs%%IR$๐ืiTXtXML:com.adobe.xmp 848 1116 Screenshot ๓]ดiDOTจ(จจ๎๗๊พ,@IDATx์ Žๅว๑/™ูฒBdŒ๔‹ดะาคAŠฒ"[๖{"ขRDI(IEศศฮ.;Jd…2็s๕{ž9ๆฯyๆ๛ไ9ฯs฿ื}]ฏ๛9วyพ๗u}ฟIฮGmฦ† € € € เ3$\|fIC € € € €€ เย@@@๐ฑƒา € € € @ภ…๗ € € € เc.>ฅ9@@@@€€ ๏@@@@ภว\| Js € € € € € € € €€ธ๘”ๆ@@@@.ผ@@@@ p๑1(อ!€ € € €\x € € € €> เโcPšC@@@ธ๐@@@@|,@ภลว 4‡ € € €pแ=€ € € €๘X€€‹Ai@@@ เย{@@@๐ฑƒา € € € @ภ…๗ € € € เc.>ฅ9@@@@€€ ๏@@@@ภว\| Js € € € € € € € €€ธ๘”ๆ@@@@.ผ@@@@ p๑1(อ!€ € € €\x € € € €> เโcPšC@@@ธ๐@@@@|,@ภลว 4‡ € € €pแ=€ € € €๘X€€‹Ai@@@ เย{@@@๐ฑƒา € € € @ภ…๗ € € € เc.>ฅ9@@@@€€ ๏@@@@ภว\| Js € € € € € € € €€ธ๘”ๆ@@@@.ผ@@@@ p๑1(อ!€ € € €\x € € € €> เโcPšC@@@ธ๐@@@@|,@ภลว 4‡ € € €pแ=€ € € €๘X€€‹Ai@`Xบtiฐw1Q๚w๎ผYิํ๙๓๎o$๊ก๛ใ9ก๛๚_ป๏ฟว่€s๎€จ$‰z์^฿c๗ยฟy,Rาฅฯ๐o๛Q/yฺ๕}มs:๚rฏE๏‡๖๑๎๕๘฿ื๗xฯ>ั฿พ…ฏKbูำF € @]€€Kขs@ ฒพ{[ถlY‚ส—/Ÿ ใu๐๎ปm๏ฝ n็j ๔ำOv์ุฑซํๆ^wž๗ูW“D=๖| ๖4๐ใสž‡a๛wกทธqkฺข/v๐๏ {-บ“^?>๛๓เ~๏>แ๒ Sึ๋-cึœ NRทน6*๙d†eป๖ํ 4่QOŸ8qฬ~ูถ5' ‚#ฏฟฑฐฅN“ฮ๕ฤ;พ๒e{˜)[.หœ#๗e_ื ื็+jืฆIล}ขฟ˜*mzห] D๔งย๒๑ษใฺŸ7๚tl'ต}ฟฤญอC๛๗D€b๖Nuฬ~ฑลง}‹ุลn‰ๅE๕^ธbกี๏9ัjTพำrฆ#เrO € \•&@_ N:ถ๏ฃVท๗”าGุฟหุ๋ึถญ฿L›CQ็ธ๐CtฌOตใ[์ิ_วใr๛H GB–ฺ๊ƒeq้B’ฮ"‰ํ1ืฆMg9๓ฟ๊๎น ทิi3^uฟซํ๐F•ย.เ๒าcwฒค่jXผŽ €€ธ๘’f@.-๐sฯูส•+mภฌฤปร้3Gฮณึ|9ƒ฿H3eฯmืๅศqใŽฯ€5๛ง๓ ๅฌ้ะO์๙{JZึ4ฬp‰#ว € W.qc@8 x.?\๎“;๕q:9;#€€) ๗VวZ.่yWž$\xO € เ'.~‚ๆ4 €@ค x.สQฐ๔‘สภธ˜@๔€Kล“Zๆิ๋ 'F@ ขธDิๅfฐ €€<—j{ZนŸ๕8#.=เrOค–1e„ƒ0|@$@ภลOะœˆTOภๅพg_ณ‡k6Tฦ@ภข\๎/ิาฅXW81 €%@ภ%ข.7ƒE/เ ธปตขฝาeœ;ภˆp่—‡ &ตk“G8รG@ภO\อi@HPภeใฆอ–-Oakิ฿๗ฅก#ี•q#[น๏ ฑฏ?ใ’ๆp‰ญ๛!€ p. 7ค@+(เr์๏๓ถe”†พ‚/!Xั.Nj)ฏIฌ3ั. €D เ]ƒว €>Pภๅ†โๅ์ำ๗ฝร๎๓ะ \Q zภๅฑ"I-yา+๎ฮ‹ € เ#.>‚ค@K (เ๒pฦึซE-๋แrK6ใฅwไYH่—ว‹&ตk’$สih@. เr_"€๘V rๅสVต~;pฉ฿sข,}‡oO@k pE่—งŠ1ฝๅŠXผˆ €€ธ๘“ฆ@.(Xฐ u<‘€หล4=๓ืฑร๖๓†•v๔–ทXห•ฟxŒ}๖“ผn™๕x-K’$๘ฆ){b`Fะ liซฮr9”ธDะ…gจ € เ๐K@@๐ เrๅ๋{๖์ถfฉ-›;ลึ-*ฦฮญ฿œkYsๅ๗>ืท๎๖ว]๖b›กV๚ฎGฝฯหƒ`๏_ฐ8๙ปฃZ?o;6hƒfoฑ'ข–ฑ!€ €€ธ๘ว™ณ €+@ภๅา—ทl๙Wำmล73์ฤ‘ร—้ัŸ[ถ z_๓4๎|์E{ฒ~g๏๓ม๒ ถ;z๘7๔รหSไfห‘ทpฐt?l๛แ ธ ณล”4— @#@ภล?ฮœˆXOภeฐ^๖DŸรๅเพ_lึ๘พ๖ำ๒o/zO๑huป๛‰—ฃ– %ตคื\c™ฒๅŽฑOŸ:๗ุก{ญLล*Vฝี ๗ฺ๙๓็ƒfyQl๛7บอ ๖หO+-Eชkญล๐™v๕ycŒ“/|+ €‹ถƒฆ˜สBณ!€ €€ธ๘ว™ณ €+เ ธL7สด•{๐ูˆดP~“iรํ?ลš ™์๎จœ,ๅ~ฮาคฯใต่_๓๗i๋๕J7FŠ‹–ฑปถฺัCฟน๔ฯ5ด{ชึ‹~˜฿วฅ#฿xึvnZํ๚v]Ž<ึ<*่’2uฟ๕5าNไ ธผ1xŠ=Tˆ€Kค]ฦ‹ 8.ณ็ฬ €@DDธ(y›=\ณyDŒ๛ยAฮรฯzฯ๛ด,๎ชRำŠ•ฝวฎI–๛ผ็มฑรฟผษร์๐๏ฟฺแ฿๖ุo{~๑ผtูฟ๏พ‘=Tฃ้e_๗ๅ ้ŸŽ๚ฃ1ถd๖๛ฎKฏ๕y฿๒—(็ห๎ัV4.ั0xˆ €€ธ๘›S!€‘(@ภๅ฿ซeT๐d”Qท@นชฺใuฺYสkำyŸ‹เƒ-ข*หฬŽTŒวšS(ชฤถfบไ.TาฒๅฮgฉำfŒฑOBฟPB฿-?.rณrถ7*฿J!ปกp)หU Dิlv ๎฿™จY;งNท4้2Y’คฬผH่๕บ๑ž€K›กS์8_ฮ‰็@๐ต_‹า €@ .rจไ๓˜ถ5ข–m๓๚hะ=ฯิตzึาeส๊}^ฆi•P๗S๏s ฐx’๋ๆ/Qึ^๋3ู๛ฺี(p๒gTภไุŸาดณXบจ?WฺฮŸ;gS‡ถฑ•฿ฮผhทฬูsYึœ๙m๓ชEืา?O#œ>ๅ/ษ’งpO) 3gb๛}๏ป้ถ๛์๖จ7lq๐\ฺ ›b๗ๅ'เwAŽ@@ ~\โ็ฦQ €ฑPภฅ๓ะI๖๎[ร,’—‰๋Ÿำ'ํปO฿ฑEณ&yƒ'F-/ช|ษp]๗ิฉGํป™ฃfฎไทผEov t฿ํศ•Ž.vkE{ฅห8ฯกW{ํ’น6slOoฎฯฮส๕๒่หญ<_^๔๗WŽดy ฟ่๙่O.s—หห“yฺS€งKทป/F“ฒๆ.`{6ˆ‘\ธNท๑Vไ–ป=‡x>yˆmŒชz๔žํv}พขV๒๖‡\าa๏ภp้8|ŠUสGภ%ย฿ @ภ\ˆอฉ@HPภฅ๋ฐI6๕ฝ –3๑ˆอแฺ+ม์บจ@ศw3฿น(‰ฎ๒ฐ–~ไ›•๛eูผshl'.Š1ƒวํA๑\z™bทๅ&เA—žก"€X€€K€/งGย] zภฅไํ๗[…ง๊„๛/฿๛šฦศัขTๆ8]ฦ๋พEUููป}ฃฑ—๗ุFงDอXนล๛ตฌZL๔oeกึoฮตฌน๒›)ฃผ`ป6ฏฑาw=b/ถๆfฐx&ชhT๔ึJ๖รOผ๙N„จืใ[๕o`EyO๊vŸ`Yrๆณ9QAQมm—๊‡{แ‰mt่๒yูด]+&-Š 6ญณIฝบฏ/lš๗แ๛๊ƒฎาUƒ๏ู[_ถmk–บ๕อtQฅฃ}ฟl๒>งีhjJDษ›'เา๗อ)vk..‘^`์ € เโ_oฮ†Dœ@๔€หC5šธ%"‘† ฅB#[?Q)่K9hนะS :Gอโx๚ข—ฃ'ณUลž‚ฅn ไ|๎อe๒ZTลอžัฆ —็xSพ“:Q•Ÿึา›้#:ุ๒จœ-ฺน๋wrณMT’Z›๚rGๅใซ'ถS;J˜๋ษฑา๛ใuถ็๏ —VฃๆX๖<…bœ.๚=ฆฌฐำ'Oธใ๗๏ฺcฟ ฟ่๒าจ%Hถ.|-RพVภๅ๔ษใ6dาl.‘rั' €@Pp Šห@'@๐๐\บ6}9*ืฦฟ99ยwด—ู?งOFอ0‰Z:5Cณ0๖l฿`ฟ๏•ฬ6ฅฅJ.jูNvหwSูจ,/X†ฬู/ู’ม๖|ฅย%7ๆ|Q๕ฃฃfรxJ@ซม;yมชูฎM—ันณgmฺ๐vถโ›Os ไT|๊ีจePY๖์๚ๅ=เ โาฟNŸฒ^ฏVด”Q&Oลฅอ+ฺษฟŽวศ'tZVด๗็ึv์W. ๐้ฟŽน`ัก{์ศม–:ชZRฦlน์•ดฮ[๔f{}ภGั›ˆศว ธ์ุ๘ฃM[ดีส\Ÿ$" 4 € เuฮ‰Dภฃ>jีuฐHธ๘๊’ฏnถ[Šฃ€‚6%ฝณr W๚๘ยshหกป-j*‹ D\)aฏ๒วœ<~ิ E%ฉMzอ5๖ใท3ํ๐o{ํพจ*Bqูโา?]NEอผH—1KฌNกๅSIขง]i๓”—Vเ่ฑWฺ\iืˆxอp๙xษV+€KD\t‰ \‚โ2ะ @ |ž{๎9ซ๒R.>ผฤชJดm๒จส;%b]Aศ‡งฟjS์฿_ว[—๊ทน>พิn„•ผใกซ๖7w เ๎W˜๑!€ซ—`ฝ2๔ \ ธt‰๐%Ear9ƒ~ปทฎสSี๕3.–‚~` ่ 'เ๒้๗[ญD6fธ$€’C@ˆ“—8qฑ3 €@\pyเ้ZึทCใˆฮแW7๖Ÿภ๊Eslrๆ–&C&๋๚ฒ๘5fGy.ณ–nตbY ธ„ูๅe8 €A,@ภ%ˆ/]CยA@—%หูGวX๗—[๊ดŸฐ5ฦว'p๔๐o๖ห†V๔–ป-ๅต้\GๆOe_Nfฅ๎|ศjถธฮั™=—9หถZ‘๋ธัฅก+ €a.@ภ%ฬ/0รC- €K’้lลา6`ึ–@w‡๓‡‰ภ๑#Xทowฃษ]ฐคฝึ็=Wึ๚lาฏ์ฑฺญญโำuยdด †'เ๒ล๒ญV(3—„ir4 €ฑ เ{+๖Dˆ‡€.s6ฎ‘€K<8ไาปทฎ‹สี๒Œ๗ล|ลceจj k็žซ้M+^๎^๏๋‘€€K$_}ฦŽ H.ิ็ €@(เฒs๗^K–:ต9'Fฬ%๐มภ–ถjแฌKžฎำคE–>s๖KพiOz.๓~ุj๙31ร%าฎ?ใEœ—ภูsf@ "pYนrฅX์kิJDŒ™A๚O`รฒ๙6mD;qไฐ๗คe*>fี[ ๖~้fŒ้j฿}ฝbซๅอHภ%า฿Œ@ภ\gอ™@ˆ๐\สTฌ๕!xPD0่ฤ8๖็A›=พฏธเ3หU ธ5์๛ห็’ธg ึ็พ7ฤพhŒ-๘qซๅNOภ%tฎ=Eu.ก~้? ไž€ห}ฯพfืlไฝฅ{ก,p๔ะK—1ซ%Iš4”‡แ๓พ{.฿ญฺj9ำp๑90 "€ p.—แi@฿p๑#ญ _.๑•ใ8@&@ภ%a~ pOภฅ~ฯ‰Vฐ๔Wู›—@ภื฿อxfM่oKVoต์i™แโk_ฺC@เr\.'ร๓ €> เโFA ึ|oouฌeKืlตฌiธฤ’@ˆฃ—8‚ฑ; €@lฃGถ๎.ทิi3ฦํ`๖F x.หืmณฬฉ € €@,ธฤŠ@โ'เ ธ ˜ต%~ p$Hภp™9๗ปฉ`žตลม € {.ฑทbO@x(เ2ํใึ๚ํ…๑8šC@ กž€ห่ท'ูƒ•๎Lhs €ฑ เK(vCˆŸ€. ืj๗šฟโqิžํ๋ํิ‰cq:๒๐=v่ทฝq:&.;๏“ŒcŸโาพฟ๗M&ๅ,P฿งu็ห™ฏXิ๒ด๔>;wฆlน์บแ=๓ใ*…ํญ๑“์พŠ\|๖ฦก!@ฎ"@ภๅ*@ผŒ 07รๅ“VบาS—mh๛ฺe—}M/๙๛>;๛ฏW'˜^LŒธ>oแ`๊’฿๛๒๋ฮ-qz๙ฝ“>>aฆฌื[ฦฌ9}า๊๕๙Šฺต้2๘ค-52สhpน—€‹ฯLi@ซ pนšฏ#€$H`๊ิฉ6u๚'๖ฯู๓Wl'ษลSฮ_y๗+ถŸ/<฿…นฐอวูฎŸท^๘4_‡ภuูrุuู \xฃใ‚ทf๔—,!oำ่็ผฺ๛-๚Iใ{ˆกญเแ=“'บ@ด—@_ฮ € € €a'@ภ%์.)B@@@@ p ๔เ € € € v\ย๎’2 @@@ด—@_ฮ € € €a'@ภ%์.)B@@@@ p ๔เ € € € v\ย๎’2 @@@ด—@_ฮ € € €a'@ภ%์.)B@@@@ p ๔เ € € € v\ย๎’2 @@@ด—@_ฮ ‘_ตmถอ๊ืฏ‘ใ‡Aฯ›7ฯ๖๎kตkื‡แ0@๐ฑƒา €Wะ๔nบู7฿|c]บtฑš5k^i๗ |mฺดiVญZต ์›?;5w๎\{๕ืํฮ;๏ด~๚YŽ9yzฮ… €A.@ภ%ศ/C3gฮุ›oพicฦŒฑาฅKป่7pCศ ๎เมƒVพ|y[ธpกๅส•+ไ๚๏๋oฺดษ๊ีซgวŽณ๖ํˆ๒50ํ!€ ย\B๘โัu@ะXถl™๛0~๘qkืฎ=๙ไ“กั๑K๔๒ื_ตป๏พ–,Ybูณgฟฤ‘๗ิ‰'ฌI“&.UกB4heส”)๒ 1 €ฤ เƒƒ/@๐ภฌ{๗๎ฆ\Z‚ฃ`Kบt้|w‚ดดkื.ป๗{m๙๒ๅ–9sๆ๔ xO9aย0`€ฅM›ึ]ฉRฅเํ,=C@D เ’่ฤœ@ าฮž=kใวท‘#Gบผš๑Pฒdษฐ`ุพ}ป=๔ะCถz๕jX‹A๙p๋ืฏท ุ๛ญjีช.OO๊ิฉ}xšB@P เ*WŠ~"€„„ภŠ+๒!%วmิจ‘ซBtอ5ื„D฿cำษอ›7[ๅส•mร† –2eสุq๛(Ÿ‹’้jูUฮœ9ฃฒeหFœF@ าธD๚;€๑#€๘D@ษd{๕๊eณfอฒrๅสูภ‡mŸ4Dh‡rะ(๐Nคฤ V‚ไกC‡šf<ีจQรโR%†4m"€ œ\‚๓บะ+@8w๎œMš4ษ†n)RคpชŸxโ‰้}ปนjี*—fถmq?8ะŒ'อt๚ใ?,w๎6dศ+SฆLJ0d@"O€€Kไ]sFŒ เ#ๅ1Q"ญ[ทบ|:t๙คธWฃ๙แ‡์ฅ—^ฒ7^mW^Ÿ€‚-ชbคjUI’$q~ญ[ทfI๏@ย\€€K˜_`†‡ เ{C‡Y฿พ}ํ“O>ฑผy๓บ7฿|ณ๏O„-~๗./อบu๋‚ฐwมฅ๓็ฯปYPฃF2อŠาlอŠ*UชT๐všž!€ €@‚ธ$ˆƒ@"I@š'Ož์–…œ:uส^{ํ5W‘&Yฒdรฐx๑b7[ใวŒ˜1๛r ๏ญiำฆn‰QาคIญvํฺึฒeKทอ—็ก-@ผ—ภ_z€ ZBำถm[W'œ“โ^ํR|๓อ7ฆๅ0สMย?่KŒิ‚fI1ยŠ/ฟ9 @‚R€€KP^:… ,*๑ฏ_?›:uชeส”ษ%ลU•žHๆอ›g:ur๙H"ีภใึlฉ‘#Gบ@‹–ฉโS:uฌYณf–๘เS"z๕๊Yร† Yโ Oอ๚Yธpaดgy่ U02dˆ ๒iVUถlูืEŠ๑E๓ด €~ เโgpN‡ œ3gฮด>}๚˜f”-[ึ•}V2Sถ˜*…ญฏ฿~๛mฬ๘ส'?๐ƒ[b”2eJหž=ปญ\นาอtัŒ6@-.กuฝ่- €€ถo฿๎–ฉฬqฦŒ]žgŸ}ึวg ŸๆฆOŸnฃG6U+bKอny๕ืmํฺตVนregญเห๐แร์—ฤ9+ญ"€ €€ฏธ๘Z”๖@BBเไษ“6t่P›4i’9sฦชTฉb;vด๋ฎป.$๚จNชZำธqใl๙๊Bฤœwฬ˜1.๎ƒ>hgฯžตล‹ป*Fu๋ึŠ €@( p ๅซG฿@โ% J;ฝ{๗ถ๛๗[ฎ\นRข;๎ธ#^mEฺA~๘กฝ๓ฮ;ฆ๒ะl‰/ Y.ฏฝ๖šฅJ•สชVญjใวทนsปู.y๒ไIp@ˆท—xำq  €@จ ์ฝฺทooK—.uIq_yๅWF๙2ุb'0y๒d{๗wํห/ฟŒ์•`ฃGZห–-])๎&Mš˜JIซขQซVญฌVญZ nŸ@@ qธ$Ž+ญ"€‘ภ้ำงmไศ‘nvภ฿m%K–ด๛[กB…‚จ—กั•๗฿฿t๙โ‹/BฃรaิKบ๚๕๋g+Vดป๎บห-7า{xะ AnฆV •ก € \ยโ22@ห จ|qงNl฿พ}–.]:kัข…ฝ๘โ‹–$I’หย๓Wะ‡~ๅq™3gฮ๖โฅฤุผyณ+W~y๋ัฃ‡M˜0มVญZemถต๊ีซ'ึii@โ!@ภ%h‚ {๗๎ต.]บุ‚ \g•xด[ทn–5kึเ๏|๗PI†งM›fณgฯโ^†wื”๐นC‡๖ูgŸน%r้ำงท^ฝzY๑โลmศ!–-[ถ๐`t €„ˆ—นPt@ vZ2๔ๆ›oฺ[oฝeZJt๕ืปฃ*Tˆ]์uE‰'ฺวlณfอบโ~ผ˜๘บšูRฎ\9Wฺ\ลŸ~๚ษc”`— @+@ภ%ฐœ@ภ‡K–,qw5ป%iาคn้P๋ึญ]…ž&ข›า–O?ิอฎˆhˆ Ž;ฃ'NธสEZrิทo_+SฆŒหํ’%K– ้)@@ ๒ธD5gฤ €@ุ จผs๗๎ฝฅŠ‹)โ’โtำMa7ึ@He‰gฮœIภ%ะโ‚๓w๎ู>๘เkธฑ=๔ำึผys๛๙็Ÿ]๐Eหุ้@@ภ\oฮ@|$pๆฬ{๛ํทmิจQฆผฉSง6•อ}๕ีW †fข ศ[–EC ’‡๓็ฯ7อ่สŸ?ฟซสฅJRดJ•*Yฯž=-SฆLAาSบ €@dp‰Œ๋ฬ(@ฐXฑb…ตiำฦv๎้ฦv๗w[๏ฝ]ฮ–ฐl ˆ€K]ŒKtๅภึจQ#7ปE t|ัฌ—={๖ุ€์ž{๎นฤQ<… €‰!@ภ%1Ti@ ั<่๎ึ{ชไ(GEวŽํฑวKดsา๐ Œ7ฮ-'b†ห›ใ#[4๓ซFฎ:—IkถK•*U\9้ดiำcท้ €a%@ภ%ฌ.'ƒAยWเนsฆ 9ร‡ทใวปVซVอUdแรฃฎ;Y'๔Lห—/wK์2gฮlฃGถณgฯบู.‡rณ]4+Œ @O€€Kโูา2 €€Vฏ^ํสnบีต˜/_>๋ืฏŸrห->:อฤV`์ุฑ. 3\b+ุŽ9bอš53-มSb])‡๊rผ<๓ฬ3ึฅKป๖ฺkIฮŽ €@˜ p ำ หฐ@pะxๅeQbm)Sฆด ธ?ษ“'‡!†ธ„%sV9o}/ฉbั Aƒl๗๎๖๚๋ฏ›สI+SถlูะฝF@ ˆธ๑ลกk €@ค œ?}SŠฃG:} ์ทฏๅอ›7RY‚boฝ๕–)3\‚โrฤฉ6lฐ† บcดฤจpแย6x๐`S0ๆน็žณ๖ํ[ชTฉโิ&;#€ €ภๅธ\†W@ ฐn:ท|hำฆM๎์2dฐถmบฅ่งผ@@[˜ฯœ9ำๆฬ™s้x6$–/_๎๒ธdฮœู†n ดE‹Yห–--K–,nถKBrlt@@ p ”<็E"T`๚๔้.ุขแ'I’ฤŽ?nบƒฎrฯlม/0n8Wฆ›€K๐_ซธ๖Py”š5kf พ(ฑn๕๊ีMฯu๎ูพ๚๊+Q’คI“ฦตi๖G@ "ธDไegะ €€ถmf;vด๕๋ืป;ๆฟป็?qฅžsๆฬ้qฦx ผ๖๖๑ว_|ฏใ9(๘}๗]oฅAƒY๚๔้]ภฅM›6–'O7ๅ†nะC@,@ภ%ภ€ำ#€แ. 2ดC† ฑ &X‘"E์?pUˆฺตkgO>๙dธ?์ฦ7~x—ไxผya76๔ 6lุะดO฿ฟๅส•s฿ปสฏดrๅJWลHีŒุ@@เ๒\.oร+ € ˜={ถ๕๎%TnอnฉZตช[ฎ.]บถฮแPภeส”)nฦC ฮฯ9+ Yiบ พ(ุขMห{๕๊ๅจร† ณ์ูณ๛ทSœ @ เ"Šn"€ก$ฐcวW}H–าฅKๆอ›M–Z™2eBi(๔๕อTRฒใฏฟ๚‚W๘2\ๆฯŸoญ[ทถผy๓ฺศ‘#-Wฎ\vเภ€ูฐaƒ  VซV-\‡ฯธ@ˆท—xำq  €ภ…งOŸvNT:ธlูฒ๖ฯ?ุฦญ~๚.แๆ…๛๓u่ (เข ,ฝฮำใx (ภข„บ๚~๎ัฃ‡UฉRลต๕๛๏ป|/๚~Wๅ1U4bC@ธ๐N@๐‰€>€ซฒIส”)ญhัขถdษทไ@ณZ”h“-<y็›8qข-\ธ0<ฤ(โ$0z๔hi+Vฌฐ}๛๖ูoผaฯ=๗\ะ๖›Ž%ŽภิฉS]๙฿•+W&ฮ h5ค.•PWาฯ QฐEA™%J„๔8้< €ฑ เ%๖A"T .A๊ƒ>h้าฅ3ฯRขฎ]ปR$B฿š้ิงO๛๑ว#T€a_M@ u;v์h3gฮดฆM›บŠF:Fฯซzั'Ÿ|b 4pฯ'K–์jอ๑: €!+@ภ%d/GO`๑โล.f’$I์ูgŸ5อjะc’โ&žyจด<}๚tู๋ณงญ^ฝ:TบL?$๐ๅ—_บไฺ pีฬrไศแzฒ`ม๗|–,Y\Y้|๙๒จ‡œ@ฤ เ’ธพดŽ„”€’_v๋ึอ.\hUซVuษ0็ฯŸ๏๎Fทjี*คฦBgG@ณTX Qูธšภ๛ฝ u๛๖ํk<๒ˆ;D ท;u๊d_ตKฌ๛๊ซฏบ ๎ีฺใu@BI€€K(]-๚Š$ขภ„ \Yืโล‹ปคธ}๔‘้ฮณช‹xใ‰xfš%ฯ>๛ฬฺถmk?๔S(u›พPเนsฎDดช[=๔ะCn†”–(j๛โ‹/๒#อ‚}z7๚_~๙ล^uS`Fษป๏บ๋ฎRaจ €แ @ภ%ฎ"c@ฎ ๐ร?ธธบkฌส3fฬฐŸูMฏYณๆŽไ%.Pษp•๐]พ|9y~.ๆแ™x (ธข„บJญjF พh;sๆŒKฐ๛ๆ›oZตjีฌC‡ฬฌŠง1‡!€๘_€€‹อ9# เC‡นฉ๘ณfอฒฺตk[าคI4‡~ุบvํj$ค๔หeป“,ZดศฝŸพ{ห–-[ุNเŸ1ๅ‘าŒƒU~v์˜u๎ูTฆผy๓ๆnฦK’$I|sRZA@ภG\|I3 €@ ๆฮ๋rตคI“ฦอbQ9UอtัเZตjช[œ7LTHษKUNœ@^˜^ไ ึoฟๆ‚*สใขคนฯ>๛ฌท‡*Sฎ’๖ pมeO@ฦป@ —โsj@ !pี‡๔ธQฃFฆY. ถTจPม%ลอž={Bš็X.) ejO?ด)ณส‹ณ!เ/•ฒืL>U0R™่L™2นSซlt‹-l๕๊ี.ัฎ–ผฑ!€  \‚แ*ะ@ gฯžตฑcวฺจQฃฌL™2n‹Iž:uŠคธqpdื๘ lุฐมžxโ ๛ไ“OฌTฉR๑k„ฃˆง€สGฟ๚๋ฆY/J^ฉR%oK~๘ก๕ํืJ”(aC‡ตฌYณz_ใ € เuฮ‰ฤS@wp[ทnm'NœpS์•Xฐ`[VฉŸ‹Znฝd๙่ัฃ,—ว{ฬ•˜fถ‹ภi@ V\bลฤN €€NŸ>ํ>0hJผ–n<๕ิS๎C‚๒ถ(!d๔$‘๋gBเ__ี๎พ๛n3fŒ=๐ภฐ 4‡veฃ็อ›gํทท่3•ำEkU4โ็hะ\2:‚„ฝ—ฐฟฤ BI`ษ’%ึฎ];K’$‰+ํๅ—_ฺ๔้ำMy[ฺถm๋M Jcขฏแ%๐๛๏ฟํท฿๎‚‚Jžห†@ฐ ่gf๗๎ญdษ’\Wž>ชฒ‘’ํ>๛์ณึฉS'~ฆz`๘@ Qธ$ +"€q8pเ€›ลฒpแBซ[ทฎๅฮๅศœ9ณ 4ศŠ/ทูDะ,%ห8p =๙ไ“‰tšE aš‰ีผys—๏J9^ดœศณญ]ปึ%=w๎œ ศz๋ญž—๘@Ÿ p๑)'!€qะ/'Ntณnบ้&—W–u๋ึนdJษ†@0 ;vฬ•ƒ๎ปท›%L}ฃ/D8ผห54dศ{่ก‡ฌ—t้าน]ดtณOŸ>ฎฺV:u\pฦ“l7zุบuซ `9rฤ†jทv›ท๕ล‹ป@w–,YLเ๒ๅห็} €$T€€KB9ˆฃ€'๙ญส=WซVอชTฉโr =zิM^Œ8‚ฒป_๛oทฤญcวŽVซV-ฟž›“!_๙วฒ5ฃPBๅฤJ‘"…kN?{฿xใ S๐ฅUซVVปvํ๘ž†ใ@ˆ!@ภ%_ €‰+๐ูgŸ™–bdส”ษๅl™9sฆM:ีžy7ห%Mš4‰ZG ZWธpakำฆห7”ภๆ8ฟ ฌXฑย-J•*•1ยŠ-๊=ฟ~kๆ–rfiRถlูผฏ๑@๘p‰ว €qุฝ{ท๛€บaรkฺดฉeอšีz๕๊e้ำงwษGK•*วูภ ,Xะ•ุmุฐaเ:ม™ˆง€fv๎ู>sทิจAƒ–4iRืฺ๛]B]-CRp‘G‰็Y8 @3.ผ @Dะ๒‹ัฃGธqใฌbลŠฆจ๚๕ณั^u{ํตื๑์4@โ+Vฬ๊ืฏoอš5Kœะ*~˜?พ „฿xใ.qนชรiSฒ &ธ F๗฿ฟฉส‘'ูฎบล)@ยH€€K]L†‚ม%ฐlู2—Wฟผซฦ๚๕๋vอf0`€ๅส•+ธ:Loˆฅ€’ๆพ๔าK.๏E,a7‚Rเเมƒnถึ๊ีซฒฮ^xมฯ+%๕๎ฤ@ฎ @ภๅ 8ผ„ฤGเะกCึฃG›;wฎK*ชrคชBค็;t่`?x|šๅ‚F@•ดชVญjํทš>ั"๐๛๏[฿พ}ญ\นr6hะ —gKํ)ูฎพึŒ— “ํ&ไ|‹ \"ใ:3J๐ƒ€fฒLž<ูMCWiัnบ™*}๐มฎ‘>œ)&ภ:@IDAT2-‚S$บ@ูฒeMีด”`” pุนsงห้๒๋ฏฟบY‰ZNไูฎ”lืณ#€ pก— E๘ˆ‡ภ–-[๒Šฝ{๗บeDiำฆuณ\`Qฮ–2eสฤฃUA 8nฟvป๗{]โ็เ์!ฝB ~gฯžuyทFeUชTqAEO๕8%ําฅ‹อ™3็ขdป๑;G!€„ป—pฟยŒUเไษ“ฎสfถhฉPบuญ{๗๎.)ฎโ*1.แ&PกB+_พผ๕๏฿?†ฦxp›6mrA•SงNนัทzซWๆrษvฝ;๐@ pแญ€ฤS@9Z”ซEw?๕มSSฮ‡ fJ(JRxขrXHsฯ=v๓อ7ปข!ัa:‰@<TeN ฯPฏ]ปถตjีส’'O๎ZŠžlทcวŽ๖์ณฯฦใ ‚ ๎\ย 3>๐นภ/*ํจQ#ำ7xร๔ ธ’ใ>๔ำ>?' "L>๘ ,Xะ-ฝฆ~ัC@็T=C† 6t่P+Zดจ๗4๏พ๛ฎ[6zื]wน@{๚๔้ฝฏ๑@.ผ@X hmุฑcMk๛•“EIq๕หถช[(ศาฉS'’โฦา’B[เัGตœ9sฺoฟฺก๗ฤRเุฑcึนsgW}ฎI“&Vฟ~}Kš4ฉ;๚—_~qหGtWE#_ุ@ €@,Vฏ^ํ’แ*iข+ฉRฅฒถmบๅD$)n, ู%|”L4cฦŒ๖{๏…ฯ  ฑธ\–3gฮธ%v B>๓ึกCK‘"E,Zd@p เฮW—ฑ!€@‚Ž9โ*ฑ|๖ูgVฝzu{๙ๅ—ญw๏ถx๑bซWฏž5mฺ4ม็ BM@3บ๔arส”)กึu๚‹@‚4“ฅu๋ึ๖ร?ธeค๚ทมณญYณฦอvQP~ฤˆ1–y๖แo@ศ เ9ืš‘"€@>๚่#— 7Wฎ\nmพ‚,JŠ[คHW™(Ožt่[†ฝZั„ ผŒTษ(mฺด—i…ง@ยI€€K8]Mฦ‚q8z๔จ ฐฬœ9ำjึฌiตjีr_ฯ›7ฯ6l่ฆŠวนQ@ ฬ5jd+Wฎด๗ฟa>R†‡@TญHนพ4SRนŽ:v์h)Sฆt( ำธqcS2๖กC‡ฺmททฦู@ ไธ„%ฃร เ+Uาš๛์ูณปป‘ห–-se= (เ๎Dxใพ:ํ Vสm๔w฿น KX ,‘ฃj6ฑซjณkื.Kš4ฉซnฃ/[x จZQณfอเ\)]บด{ฌฅซ๛๗ทI“&ูK/ฝไfV&Ož<< €€pแM€' mถตตkืบ_ˆ๏พ๛nkีช•หIกฟ_xแ…ˆ3aภฤE@‰@Ue๚๕q9,b๖]ฑb…7ภขŸ7š๕ eŠชxVดhQฒe‹ํุฑรT้LA฿;๎ธ#bl"i งOŸv3&งNju๊ิqx‚+ ๐+ ฃผ`*ญฤบl €แ'@ภ%ฎ)#Bหœ={ึ%6ิ/ทช<ิฝ{w{๗m๘๑VฅJ๋ิฉ“eฮœ๙2G๓4xฺทo๏ สใ้๑ใวM –/_n{๗๎ตs็ฮน2ภื_ฝ)ำ3ฯ:<.9ฃ@ผ\ผ<@pP…•vึฺ๙ฮ;ป J’ซปฮš]พ|๙p>cCภง]บtฑษ“'ถm|ฺn(4ฆ๒๐ ฐ|๛ํทn‰ะพ}๛‡dUชษ–-›•-[ึU5ซTฉ’[:tฅ1๗฿๎ƒธงผvๅส•ํตื^sณ`ฎtฏ…ž€‚+ ๊+?XำฆMญnบ๗‡‚ušuYคH9rค{…้1 €ภฅธ\J…็@ lt๗ธ_ฟ~6eส—ภPำบ่๎FซาJ๋ึญรfฌ  ๔๊ีหT2}บu–:uj6 ็ูพ}ป ฌ,]บิอ`๙๗฿] V3ๆ4#NณS{์1ท,(SฆL๑๊ใขE‹LAฌƒบ/ีชUs-9b /W”HW9ย”\7w๎n€ ไ)๕ฯ?์rŠแ5pFƒDจ—ฝ๐ H๘๚๋ฏล๔้ำปY,สูข)7pƒKŠ[ฐ`มH``Œ๘\@ณยT…E•ŠดL"œ6œะ ๅุะ๘๓OWeF๙8๔ณDห~xเ`๑u@D?ŸFํf8๖o๖๒ห/[ƒ ,kึฌแD๑cQ`MKˆVญZๅfถิจQร™h)ฺ[oฝeร‡7อv๊ึญ›ฅI“&โฝ@BY€€K(_=๚Ž—8pเ€[6คu๓บcx฿}๗น™,ปw๏vฟไพ๘โ‹—<Ž'@ vC† ฑQฃFู’%K\•ฏุ|{)™ญ*)ภขเŠœlฦ๋คaz’+yxบt้\ต6•’~๓อ7M3+Vฌ่–)รบวŽsy“๔oŸTภS›ส™w์ุัอpjัข…KฏR็l €ม!@ภ%8ฎฝ@K่.w›6m์ิฉSึซW/๛๕ื_9rธ… พฤQ<…‰-ฐdษ—+ฉ[ทnVฃFX๎็Ÿv„<%šUAH฿หนs็6•bV€E‰ฏ•๖?๙["ค มM7ซ๖#}'อ๖Sาp-3y์ฑว @UqSเeฦŒn‰‘fผ”.]:าฉBz_}๕•หŸtใ7บ=K่Tข]y•lำM อcCผ—ภ_z€(ฆ,3gฮด—^zษU฿P)LWญegCภ hู–ฏดo฿^yๅ•KvไงŸ~๒–hึ ๅ[ั‡C%ฑUeฑ฿ถlูโfตDฐS™้K,ศŸฐaƒ ผ,]บิ-3zํตืLืB—ฯ?%ีUเ…™BA~!ฏะ=}๏่f„J ทnฺ;ฉ๕=ฆDส*/ญฅfšส† X.๕็์ p€‚, ถdฯžยจปvฃF2%ๆTR\=ฯ†P~•งŸ~ฺ-_QยVm ช(ใ™มขœ+สตคคถ ฐ่รเฆM›\ XดLH3XJ•*ุม„ู้?๘c—T7C† ๎:{๏ฝ.7ฮ[oฝe_ต d+๐ข™lก)0mฺ4๗๏ฅfiv“พืฮŸ?ocวŽuื^๙•z๔่แชx…ๆ้5 ๚\B2ยB`ฯž=n:ด>ศi}บ~T’@M‰๏ทฏUชT),ฦษ อขxโ‰'ฒŸdษ’น`‹*ช”,YาE๕กOํงผ"ัgฐฐคล๏-3R57•Vนhๅ๘P๙hอ~ัŒ- {๑ลญAƒny—zฦ™|% ฅถJ ฏYLสๅโษฉคเฆf7;wฮด`ๆ˜ฏฤiˆ›—ธyฑ7๘Xเ์ูณ.!๎ˆ#\IWM“ึ%ฌYณฆ›.:ujŸ•ๆ@ .Jฬฉๅ šฝฒrๅJ`ั๗ฎrฐrห-๎ฎบ’เ*`š&Mo!•j.SฆL\Nลพ‰ ฐ~z4h}๗.ูช–hS๒cอxั์$-ีิtอˆa =‰'บYกชุืงO—lZ7,4รE3a4ญqใฦnถY่Ž#€ก+@ภ%tฏ=G ไt๗ปeห–ฎซ–i]บฆE๋Cœ๎ส/^<ไวศEC‡น‹–)ภข์ คhvJ–,YLy–,Xเ†ฆ็ฃ/R†-8ศV•7%)nฺดฉKฎซž*ท‹*ม)i๑ซฏพ๊/T ฮkxฅ^)1ต๒œiึK๏ฝํpป๋{U3F๓ไษใJน+Q5 €€ธ๘ว™ณ €@4ฟ๚หTNV%KŸ{๎9ซZตชฉฺษ๖ํ/‹*๗ฬ†ะ4W<%ณUต XT–Yๅูw๎้fฐคM›ึ-าฒ”{๎นว}P๗_O9“/† โ–™่๚i ง'ธญผ/ใวท฿~๛อ๊ิฉใ–๙โ|ดแ_U):tจ[FฆgZึw๘๐ad[ณf+/ํYzไ฿žq6@ ๒ธD5gฤT@ษ;u๊d้ำงwณXtgUeL~๘aฺ๋ตซป{ะrr"@@ม“่K„v์ุแf–)‹,สวขปๅšูข๏UอZั๒ %บี!อpัsส ข๏lก'๐ห/ฟธkงŸมZNคู†ฉRฅr™k9$Ž€สฤFฐ์ทฯ%OU€%cฦŒ.ภข}`QS\Qๅๆ›oพจSส กฤึ>๘ =๚ขืy"tพ๙ๆ7BK:5jไ’่zzฏู. ˆ๋Cน–=๓ž—๘;D”t^ืะSฦ]9ัlSพc”?ํึ[o ‘ัะM@ ๔ธ„5ฃว„”€ช•Lš4ษIี‡;ญ#W’ฦy๓ๆน้๊ชฎภ†พP~$O‰fๅ`ั‡้ ธฅ@šฑขe}บฎpQ}่ŠK™ๆ‚ Z… \฿๖žึ! เŠ‚g*ญคบ+VtPrไ1cฦธฅFสQฏ^=7ณ)}ไœ๑Xฝzต[Nคฃ•'MมTอ^R0ๆฝ๗sณ˜TมJวุ@|+@ภลทžด†ัT–Rอni฿พฝ)็ฐaรฌH‘"nŠณ~ฑgC„ จสŒg‹๙็ŸVดhQ7 E–cวŽนเŠ‚,ž‹>t)ภข@h|6ตฏ@–Ÿฐ…‡€–Ši‰˜>„?๚่ฃ.งV๙เŽ?๎/*1ญ๗Œ/๗฿x <Fกe‚JNฏišญิฎ];7๊eห–น›’a+เ–7oะ`ˆ €€ธ๘ฯš3!1Zn0x๐`7ณๅ๑วทjีชนๅD4•}V’\6ˆŸ€f)ธโ ฐ่๎ตส6—*UสXฎฝ๖ZทT`บuถy๓f—“EณWt+x:}๚t_4GA$ ™O Žkน‘+Jฌ›TแF๙]jิจแํ•/+๐2mฺ4W~ธ~๚—ฬ๗ใ=€A# o]บtฑฯ>๛ฬอnั2m๚ทZ9ีœU•#อŽcCH˜—„๙q4Oเ?0•ŸT€ฅnบnZr/l*ญ‡l puอVัๆ่–)Rธ๏!อ(ัc}ฟ)๐ขไ— zxrฐ”/_ *t๕“๘`;๎ธร%SU>&ถ๐PาีQฃF™–ฝ๚๋ฎธgฤZฆฆภหœ9sL3•Œี_๏AO๘;~๚๗Z7Bฎฟz`ั๕U ญaร†ฆฉร‡wA๘ตฮQ € เย๛, ปb pI95๕|ไศ‘ถvํZwGTฟ|ณ!€ภๅ4{@มY”เVKาคIใ*)1ญ–rhว?่> ๅฬ™ำ%ธ๕,R2@lJชz๎9ำถ๐ะ๛Tm}๗]Wชqใฦ1fO้ฝซภหท฿~๋ช้gฎ\นย&ฤGจูqส็ข ‚* ส+ฏุ™3g\.ฺ^|๑EkถญwIYˆ—๎#€~ เโwrNˆ@๘่๎บึ‚o฿พ%วี‡BU RIY`t็ b ่๛DมO€Eษฅ•ศV฿7บร|อ5ืุฏฟ๊‚/{๗๎ตƒEณ>nธแ7ƒEห๊TQ่็Ÿv9X๓OWYHZ4ƒEAอv ลํน็ž๓ฮุ ลำg฿ ่฿-;ัา8-#Rษ่่ฤ‰]เEeหxy๖ูgฃฟฬใ ุฝ{ทปนขyบuณ*Uช˜žSE#อศ8p UจP!ศzMw@เ เ|ื„!t ฒ๔๊ีหๅา/[JŒจ-Jซ5lD’€–P(?…๒\ธ Hม•qบuซซ"ค๒ซ%K–Œ1ƒ%zพ‹Pvำ๗าฅK’"%๙eC@Kโ”฿e๊ิฉ๖่ฃบภ‹J—{6อ๎Rต#%cU> ฐีƒค?lwu—๕้ำวๅsั5ึ๏ฯ?ผ[zคูMl €— เrižE(ฉWuUMQ)P-ะ/_ส \-Yฒdม ฐุฐaƒ›มโ ฐ(้ญKjฆี+wัๆอ›]€ๅไษ“nพfฐh๖Š’†k0By9”วใฟ/? ยป nิ๗Œชีฉ์ฐช่฿่^hฦค–!)๐ข๏U4าzถเะ ฝfอšนd๛๗weมตผXฯฅJ•ส]kfน็ตฃW x.ฟ๔ ะˆฑcวบ_ข4-\w*ตl(Yฒdึฏ_?+_พ|ะ๕™!เ+•4WๅO€Eๅp‹)โ–Jจšะ_ๅ๒–่‡๎ุk E๔$ท‘rทWข•UA—`M์๋ซ๗ํฤO`แย….ฐขŒ’๊ชโM๔MA}อ”P˜๛๏ฟ฿^J—.}‘€fถ 6ฬ”ฟฉkืฎฎgสๅ6o<—lทVญZAิ[บ‚‡—เธ๔ ะ/ฦJŠซ;-Zดp• T QฃFn Qะt”Ž เ#UซVน‹๒ฐ(ˆข๗M7dฅJ•rๅš•์S฿ฺ/EŠ.ภโษมข<,‘ZyE?”0[‰ณ (เฃซA3แ(๐๑วป.ชpงภK5b S‰—•eฮœ9๎รผฝ –๒็1:ส.Qถ–Ÿ8qยˆั ˜ูณgป$๚%J”ฐ!C†„l^*./ \C•6Aตื์U'P)HๅขะtoญฟWrผU2๓]หด‰฿}๗[Fค ฉ–ฉ V๔Š_gฮœ๑๘”3H9`๎น็žHค ฺ1+–ชอ˜1รอpiฺดฉKชฆM#กnะ^6:†‰,@ภ%‘i`่ำง[7_ฅJ7›Eฅ8ต†พ{๗๎Q ฆ~ำ—ศะ/๐ž%B ฐh)ะตื^๋–ๅอ›ืๅuP๐P—ƒšfต(ภข+ ฒPฎ8๑;&LpK ๚๗๏ฯŒƒฤcŽธ–U๙Jฅข๕ฌู,ฏพ๚j ๅำ2ๅาฬ*^ดd-xพ๖[ทดHK65N?ณ›4ibJจซYด๗w_๐t–ž €‰,@ภ%‘i`ะ,UHš4ฉ›ฒญคธบ[ุซW/ซTฉR0t‘> เ”ซมณDHณXึญ[็*)ˆ’+W.ท\h฿พ}n‰’*๑ญ'ภข ‹~มg๓ภ๛๏ฟ๏๎f+`[ฝzuœ”ณDŒ€–นชR^ชTฉ์หjีชล๛ถmŒ—Yณfู“O>้fฤ0ƒ-Q@ฟ8rไˆKšซเ‹fบhญ–Ž <ุžyท(๚ ฆ€v–“#€‰(@ภ%qi@ ่M๏ี/ค*จ;ƒs็ฮukฉ[ถlcบv ๛ส๙#Sเ่ัฃ‹fฐจณ๒4จŠP๖์ูํ๙๓ถw๏^`Q้rๅ๒”hV’ 2D&\Œz๚๔้๎.ถ*‘ิฎ];zDยMเนs.จข๒ร๙๓็ท ุร?c˜ ฬ๊ƒขE‹๛PK‘๘นƒ( _(‡‹rนจธ–*P์|Gฦ_ฝP ฺข-๎๎ลKK€โRฺโ๎ฌธCกX‘w—ww๗ož9fูป\’ปไ้/ฌอฮฮ๗zท๛ฬ+paŽ1ขฬVลสz{๘โL€ 8€ .€ฬ—`ฮ ฐjี*๚๋ฏฟคKf‘ํ<ˆนท .Lภ!„TšๆำงOSธqe๚eXง ฃะ๕๋ืฅภฑi™• bฐ หื ๐ฯ?P‡d@Lผsa๖"€ษh†[๙ฅ‚ฝ๋หๆอ›ฅ๐r้า%้Š„ฌG\\ƒภ๛๗ q\๐ฝrฐV๊ืฏ!Cฒ!ป&ภ˜€ง`มลS๏,หk ภ4pลจRฅ ?~œnธAฐh• &เHฐชย 4โฐภ‚A›ใล‹Gูณgงoพ๙Fบถ!=,eยuฑ ช?ฬ‚rqMศ*ก^ธ0{ภoฌY–,YBฅK—–ย‹iVฝล‹หŒFศ`†0ปg๏ปby๛ธope†+่˜1cไ๓I=V.ˆ๕’0aBหใšL€ 07!ภ‚‹›(๎&ฐ„Rgโกฉž๑เ‚hศ…9/R>sa๖&€@—˜ลT‹ฟฟฟ์แฅ(A‚๔๎;ย 4,[เ:.Bp‚% ๗! \80;Yj.LภQฮœ9#๋ย]๑[`อ—#}Aบr!<Ž›บ"้๋๒บใพ}[Zลแ7๎ˆEŠ‘ฉภPwศ!TชT)วu†ฏฤ˜p\™/ม์M/ฐฐ`ม์^tึxxฅ&`/๗๎ำd ‚ภหคm…ซะทoฅภ …ˆ**‹้ฬดฝ๚ศํฺ‡,—๊ีซG5’๎๖น ทส‚&qRบqใฦาโEo% ศh„เปศศk,M šง#ฬž=›†.ฐ„๕ ฌ^€ธน0&ภ<… .žr'y^K-๐mG| ฤฟ€+ฒ +&`kHมฌ,X>L็ฯŸ—™`"‹•ืฏ_ฒ‡`ถ2qโฤ2๘-D|>3eสd๋๎p{N$pโฤ ™บvํฺ2=ดปย—๖r[ทn•ย ฌ&F-˜tPn‹^Vฎ\)]mดiC้าฅS‡y้$ืฎ]“้ขฑฤ~3Pู‹pฟ|||œิ3พ,`LภvXpฑKn‰ 8”bณt้า…น%cฦŒ2N\‰๐ะ’2eJ‡๖…/ๆน ฐภ=" bฐ@LA๖ <C`y๙๒%มzฑƒ๐นCv!eมย/4ž๛นภศp฿+Tจ@UซV•มธ={ด<:w €`๑p#‚ๅ]ห–-e }ฟa…‡ Š;vPำฆMๅห>พวธ8—ภไษ“ๅwH๙๒ๅฅ›ัฐaรhใฦ๒‡3 9๗๐ี™;\ยฮ[`%e่ะก4|๓–ฐ*ู่ณงœนshg๘bGเฮ;R`ปˆX0๋ˆฬVฑbลข็ฯŸKท!d€ ข\„ƒ%y๒ไวƒ4ฬJ—(Q‚๐’4~๘ +๒&เ`๘}„ฌ>a๑าคIฃ เ3„—ห—/KQฦืืื่8o8žฤvํฺโ€!›"2S๕๎›ฒeห&ำIs:ว฿พ"`ถ!ภ‚‹m8r+Lภ!v๏M]ปv%คหM’$ มค1ฐ2FŒ้_ฤณ €!ฌW”หล‹ฅY7Pโ3๕์ู3)ฐ| ธฌ@xŒTัฐสาคšF๐ 2ศ๘/%K–ิๆu@,Xปผy๓FZป bบp€n฿พ`6!ภ‚‹M0r#Lภ~VฌX!RFˆ0 —ข:P๓ๆอํwQnูc`fP/ฐ ฃ\„RฅJ%–GIๅำงO2EณX`ล=ztแภฑ=ค๘ฮ’%‹ไ.\h๛ p‹Lภ† BX™9sฆฬ"ธ|ฑbลด+<~Xบ!{ึๅ SV D~~~ิ A*[ถฌดๆ3ฆt1‚›+&ภ˜€;`มล๎๗ั+ ภฆดG•/พx,]บ4๕๏฿_Zทx%tˆ ฐ ศญŠม‚p?K‘"EŽYZG={VŠ-9sๆ”n•‹PฤˆClŸ+0=ผ๔เฅย0&เเF ‹— \TZตj%ีwX!&ั?Cp1B*i|‡rq:ฦ$S๘๐แi๐เม4o<๔ธ{๗๎2ธszลWeL€ XN€หYqM&เ0ณfอ"๘1ฃ ่_ธqฅ๛PกB…ึพ{€0งา4#ศ-ธ›!c D๊fdโP \„Iˆ +ด„ติบu๋ยฺŸฯJย „d6‚‹,^้O•ฝ{๗J7ธ^ย ..ฐ4ๅโxp-8p ม’๎็Ÿ&ธภย๚.cฦŒก8qโ8พS|E&ภ˜€…XpฑWcŽ €cภEสgU่ณ;QขDQปx้ล”ภข‚ยEKฒdษไหˆ.ศ่€‡Q…Mใฝ๘CcวกCธClŸอ›7๑*4ฐ“'OาิฉSiร† ๔ำO?Iqฑ\TYณftEz๑โ…<†8"\œC`ฯž=2qบw๎Yฦลฒ!–&ภ˜€+`มล๏ ๗ษ๋ผ^ฮค!ำึQฒgฯNร† “ฉwฝX#€‡Iธ้dJš4ฉ4ฑพ{๗ฎฬเ€ธ,Xƒ%oผ2ฃึฏ0;@–ขH‘"I;]‚›e!7L/ทoงบu๋Jqฎ˜ช ๖ ,b nทnZฦQวx้8ˆc‡$+Wฎ”๗ฑคชYณfิซW/วu„ฏฤ˜ฐ .‚โjLภ^ฺ35ฐJ@๛P—.]ไŸฝฎษํบ.%ฐจ,0{O˜0ก t‹ ษX๐—!,ฐ0€Kบt้\wP3%Pผxq™I๎\˜€'ุนsง^งI“&ไ๋๋K฿|๓ฺห—/e|ผเ# ๋โ{˜‹ใ เ>แู ๗ฆaร†2เ1\‹9u๊ิŽ๏_‘ 0&\‚รป™€ฝ `–iธ๏๓็ฯ๒r0g๎ำง๛#พ ต็ฮ# ,x€„›>8ŽLBT”‹‚&Ož…Fม]๑Vˆ}q}B .Lภ“ภMVงงN’YaีWL M๑๊ีซฉF๔oฟ๑wฒnำงOฉw๏๔๏ฟส<ธ/bz๔่!39กK|I&ภ˜@ ,ธBย;˜€ ภV,๗๎“CะIˆ/ศิ์}%ฐ( – .ศx+J`AŒค/อ”)“t‚๕ ธqaฎF"1โมR ๐Dkืฎ•ยห๕๋ืฉE‹าEฯ…ซ็ฤ‰ ฟ้ฌ‹xkœํอ๑Ÿ‚M›6ษ๘wฐ,Rค!๑@พ|๙hฤˆ<ๅ๘มWdLภ„ .&@x“ ุ“fcเ{Œt“(„ seคฅไ‡4{’w^˜‡i:โฐ ##ศ(d B็ืฏ_ห์ส=" ๊paฎNฑ.ไฉฦน0O&ฐdษ+ฟใศ”ƒ€๖ช K„—'Ožศ฿tฌซศ8n‰€๑p1‚ต]ญZตไ๛ฦ''-ืพ`Lภ˜ .ฦใว—ฅฏ ธ8ŽโคAFp๏ดiำส฿pค๔ฦ3O~9๎>๐•˜€7`มล›๏>ๆ`แ€T‘H%‰uผ˜รฌ>แย…ณ๙๕ธAxนX”‹\%_ขสทo .D0Mฮ;ทๆ"”%Kw„[dN$ฐaรjถญ>+Wฎ\=A๐๙๓็หTฌI’$1[ฏcวŽาีฑธ0O&ย ฌ[ณgฯ.…—RฅJษ!C˜„KหงOŸdฆฃฺตk{2 —ฟ $'NœXfŒ-šด@ฦo9&ภ˜€= ฐเbOบถW@ZTDศ‡u Jูฒe ๆ๘–สลu ภ฿~๏ฝZ“'Oj f-แB„ภฦz%C† ฎ; ๎ฐkืฎษ๘•+W–/%A59x๐`วq\คาดเ๏๛๏2ณ‹้qfžHเฝ{4u๊Tš3gŽLO W#ค+F™4i’e`๑Šภบjฟ'rpต1)๋c,ใว/ƒุรโ0\˜`๖"ภ‚‹ฝศrป.M/๘ณE๐ดWฏ^ษlC , ฤmมห9^B ,่า ผตsQTšfธA(‹5ชด`ม1|.๐โจ\„ƒ%u๊ิŠ‹วํลเ ฿G ’bTaึ฿%sB$‚ไ"H8ป‰x0M‡ลหขE‹คฐแ%_พ|าR๑]`†ฯเ‚ W$.Ž!€๏,|wมr™#แŒ@วษ’% u`ษ‡ฌUœ‰-ิ๙D&เฑXp๑ุ[ห Š^จ๋ืฏO0Ÿ1cFPี,ฺ๘˜นลlVคH‘จy๓ๆ๒ม)J”(ฯ•์Oฎ]ส‚An9"ณฉ ะ-–/^Pบt้ไ,<ฤคiFJO.Lภ เ๛qศ!มบaถf๚ซWฏฆฌYณBฆโXฐ;Q 4ผร‹ €.,^VฌXAp1‚๐Q.ซ^`!†็ธ ร…•‹ ฃ`งNคป#ฎ+V,™NZ}gYว๓ฤ5.L€ 0=\๔4xใ (ฑAิv์ุ!ำ๗†fะh‘๎‘}Nภfฮค>4ํ๓9ก'€ฌHฉ>|Xฆ`†ภk$ˆ,3f” BdAv .L€ ฐฤญฑ*Hห–- ,๚ิฉS2c ปsๅ-๏%€ ๋ˆ๑ถvํZ*_พผ^2z๓ๆอRุผu๋–t3jฺดฉ๗Brเศ?|๘ -[pO๐์€Rฝzu้Ž/ึ๗Šฟ๏ฌกฦu™€w`มล;๎3๒ ฬ\เๆ๏ฟตู'฿มefจ0GE–ŽZตj1c'Pโ „,(˜ญ‚ภ‚@ท˜y‡ๅ ฐ•Mล‰CเK3—$€๏ฬ€€๙Uœ8q๕ฎ”Ÿฑฤ[๚หXภฐ;‘ž ฏ3’iิงOŸN7nค*UชHแู gฯžM“'O–ู[ฑเธุŸภ™3gd๖(คFk๎ƒต๑ .,ญ\`๑g —u๛œฏภ˜€#ฐเโส| — Zฬ*!‹PpY7‚๊,btํฺUZN N5จgฯžกถ’ ๊:ผ?d‡า,XฐŽY*Xฐ .\ˆ:๑˜7o^)พ„*ื`Lภ”€Šมิฌ-\$บu๋&_ *dtบ2อgw"#,ผม4๘‚uDIปt้’ŒฝฤYuรz๓ๆ 4HบJโ(ว‡J%K– \ูdฌฉ11ซ่นs็RLj๐&`F€oปใ^6^ฬ6TญZUf$Zธpกล๎?pKม|ฐž?~ijสมUํ๓Bฆฤ_ูฝ{7!“bฏ S–ศ๘”3gN้ค\„์ำ n• 0s`ญRดhQ‚{,๔ยhร† ฅ DฅJ•ดCx้@v'า๐ ฐ˜ฒแ๙1ษ@/ุa3rไศr๒็งŸ~ฒธ=s‘žึขมฅ}7wž7ํร๓Š๎ฝ+‡ Kฃฝ{ห็’ 8(+X๘!Dis๑ฏ‚:Ÿ๗3&เyXp๑ผ{ส#๚B@Ÿ‘ศš นฐฎ่น3]พ|Yfฏม+ฒ pฑs็ฮI ,˜ z9ม –,Z`ม‚‡A,X็ย˜€s ภสeผy^Ž;F5kึ”n–ศ๎กJŽ9จmถา๚Eํใ%`ึ€….„Xท4kึŒZตjE~~~2 +\]เฮgฌฺา+<|๘P ฉpS‚(ภล<L๑วา5เVŽ€บ้าฅ3‚ุฏ_?)8ร%๑_8Utจ๘๐ ,ธxลm๖ฮAช นHY Ÿ่ ~T‡ Bฐ„ >ผ๔ฟE\Žนร5 3แ๐O‡ภ๒์ู39C„ูต˜1cสXฐ"ยƒใ๗฿rƒ\ƒ 0‡PV.=z๔0๚>…KลŠejh๕=‹x7ๆ์DฝC|1O&€€3fฬAอ›7—™‡Y!tย #iาคV#€ี ”เV„ุ\‚&€็<>x๐@>ฟ iโด˜+๊๛ข35ฐ๘lŽ๏cC€๏นื^5RทฅrๅสLเอ€฿4ฒpปwOฆ>|8๙๘๘˜ซส๛, ฿p,;v์&ัHก ื ,0ญ…ีJม‚ฅภbmฺE .ฯU˜ฐXน Ž พ/UAUฤ5่฿ฟฟt-ย~ฬ๎ยŸ‰%^2€ภ2sๆLบs็Žดx•หฤ‰ๅoˆ1‹k ฌ5FŽ)SPฃ-.Ax๑โ๕้ำGfผD-ธYโ{1VฌXN‚@žxถ์ีซ—๎ไx90๑&เXp๑Š์]ƒด&n f!๚๖ํ+ณเV1Tgi @๏"๔h๑าeถmR`y๘ฑLฉˆ๘76—'OBสXธอ!Cะ ๑&ภ\–€ŠM ท„H pฝDฌ d5jาค ปIฐ=ฅ†kัฃGจE‹”(Q"๙rฌ}ฐฆ@ŠikJ๗๎ฅตฬฯ?,kฮ๕ฦบxึต &“1ฬน?ใปPeoร9ฐTโx.๘‰แ1{;\ผเใ‡Y;ฬCŠ‚™ขมƒหL˜ฤcึยV)=ซัnผ)ณ(ภ.BX)่ร‡” A)ฐเAKš4iŒฮๅ &ภ—Di๒TV.˜๑EผฬโโeํิฉS„`žœศ}๏1๗}ฬŸ?_Zผ \`EŠภบ4฿ฎ];๙l้h'ศฦcญ`c้5<ฉ&์:u๊$-y‘=BฌŒเ’ฎŠ๚>„[RKgส”IZฤจใผdLภ;ฐเโ๗ูkFฉา—๊g`MT}˜™ภƒEฒdษdฐG\‚&๓e๐ฺผyณXlO , &$˜5#‹ 8&Ož<่†๘`nM@ลgiบต|ู๘๘๑#eฬ˜‘บt้"zโ;xๅส•2^“[”;ฯˆภœ9sคล ,\jีชEทn’A^ซUซ&ใปเYว’RชT)บ~บŒ็’5kVKN๑๚:ฐZK%ˆฯp#าgดTฎEุ๏Mำ8X^0/ ภ‚‹doขšI(Vฌ˜ .g:nD‹Ÿ5k–Œ้‚—ฬฦbF)น€ ‚4อˆ… ธ `๐ พหX'Nl|2o1&เั*Tจ@ฎ‘ูๆ๑™3gึfwq Œi๚hยƒc.BnFxฮม๏u้าฅฅต๏ไ‹>,^B*ศXคHYํ฿ๅ฿๗€}9Žg&Xป ๓b์ุฑ qJX^ร„—ีซWSส”)ีa^2&เแXp๑๐์-รรฬไBT๙็Ÿ๙ศ"K~ ‘Z~ถ‚๑?@IDAT—"E oมโ8๑ ฐw๏^ไ ^ฆ`‹ู2๘†C`มรฒa› `K๑#RYนภ})kแJ„x0Ÿ/Wฎœ๗โ‘3'˜6mšดx‰#†t๑ล๏:&L0ษ„4๎ม•#GŽPํฺตฅต๊–-[ค5kp๕๙ุWK—.•๐L… Fศd„„xFญTฉ’|–B–F,Y`~ฌXฐ ศmูฒeฅภยqmผ็#)ฐ„^เBˆเโฐrมwfpx|ศ!2ฦ †ด„$ืa๖#E /ˆญ†xjˆฝทd3ส—/__ฐ`L(€ ช%K–Y&์ฮ;หgซดiำฒ@ฅK—NฦทBœˆ^pƒต &น0&เ๙Xp๑{์๑#T) ีlซ๐‰'ไ•+WไŒfฬฅ๎S๕=y Kฤ`+ฬ‹แฃ—%X)ฅ|๙๒r๖f\˜`มP๑ฒ,wผyr๖มสแ’ .L€ ธw๏ั”)Sคซ,T๑็Xค!vP๑]๐ฬดbล ยณ7บย=ฯIศธqสZ ธv1B~”กnบ๒ปึ๘„8m:I่Ÿ๎`ถ&ภ‚‹ญ‰r{%€™Vฤl๑๑๑ั๒_ฝz%ศ.\(gtเ>๔w฿Y/ด qโฬ™3r†/๚๖-nศษ<(ฬaษrใฦ ้„.A` \ฐ๐ม3ัNพQ|y&เ†๐=™;wnJš4)E๒็ฯ/…Sแ ‡ฦ]fIเๅห—าโBž"EŠD/^”ฎํท7;fˆGฅ_ี๋ฌ1ฎ]ป&, + bSมฝ฿u–>;]พ|YZดเ9q๏ฦŽ+ล/ˆิI’$‘‚ป™่๑N&เQXp๑จ้}ƒAเ[๘&ฏYณFฮ>ภ\3˜e…ษl‹-d๐ธศ ๓ฦฆM›"~Q ฒเ?ฌ๘ตvv#คkฺ๚๘ฑcวไlXฐ E3ŠXชVญ*วโญV>ถๆอํ1o'€ูqd่@<ฌ 2ศTะœฺ?<~W'€"ฐx[ ,^JqF๐ฬTฝzuฃ๎ฃnลŠeฬXiภฺร ฒ !.โฒ@$ม๓%ึ๑|จžƒณ€มณฮ‡kžวฐั Bน๑ฬŠgY.L€ x.\<๗zศ๐#“Lxaึaภ€2่+f๓ฯ`ฃ๋C`A์AฐAมl-ฒ๎dษ’E ,ฎn๙ hรXฎ^ฝH`ฉRฅ ,X4 `Lภึ0Œ น๑ใวงธqใสเš๋ืฏท๕eธ=&ภ์@™u฿n๖์ู”0aB™๑;t่ Ÿ‡ิ%Ož<)SMC8@L<ธy[ER?C`VB &ฏ HฉDฐ๖C;ˆ/xŽิว/dา„จ‘ฃ`ู ]9k‘ท}ขxผF€oปใ2^p5jิˆ *ภ]ย fh $ƒ9๊‡ฉ\„`๙q๎9M`มL… ๋5iiัขE2›โาภ/3T‚‡๘pฏ‚y?&ภ˜€#`fs#GŽ,]xฆึิ๙Lภv๎ป'] ผ Hƒd–"/*+!ฤธEŒ‘เฎ ทdo,™a ุ6K0ม‡ Žษ“'—–ล˜ƒฅดR”ƒษ<0ฐ&<ลŽ›ž!ะ/ฌY0›„!<@`A :แE† `LภU @(Ž3ฆฬ|ๆช}ไ~1o €lBงOŸ–ึศุˆ‚Iš?j™ ๑๒Ÿ5kViๅ›9sf9)…}ฆ–ตฐxQย ,k๛‹8&C‡ฅ'N,lฝ1]ด)ง ถ1‰๑ ืฐtุข2้ฯ•2\ฤ?}๚DEŠ!???a^gLภฐเโ7ั›†PณfM้‹ m˜ฝA`2/ฎ.ฎเมO f0 ฐเaH ,˜!†๕Jตjีค˜ไM๗”วส˜`L€ ุ–ฎ๛ 1BึXโๅ ,*๐’zฐธH—.tWฦsโยa็5Š6lุ ทK•*E7o”ฯbmฺด‘`ๅว"ๆ„ฤDฺn”ฝ{Kหm‹ใJL€ ธ\โ6q'‘2 0ฺŽ;ไC~L!ฐ ฃโว@`ฉUซ–;๛ฬ˜`L€ ธ):{๖ฌƒต „X รข6B„2f2"& ฑ—“[ฐn๋ ฌf ฎ4šนศึท,'NœH={๖ดuำ`N&ภ‚‹“o_3 ‚?bษ@`‰/ž4฿E ดบu๋zๆ€yTL€ 0&ภ˜€€.DX[;vLบ&ม ฯ2Ÿ?–1ๅเ~t๗๎]บs็Žดศล1L,%NœุmวฮgL€ ุ“ .๖คหm{-พ}๛|ฃ๋ีซ็ต xเL€ 0&ภ˜€๛€๋\‘๐ทkื.‚e „F ข ฌdธ0&ภ˜@`,ธfย{˜`L€ 0&ภ˜0Cเร‡2,D˜๕๋ืหธ0fj๒.&ภ˜`ม…?L€ 0&ภ˜`L€ 0&ภ˜ฐ1\l ”›cL€ 0&ภ˜`L€ 0&ภ˜ .`L€ 0&ภ˜`L€ 0&ภ˜€ ฐเbc `L€ 0&ภ˜`L€ 0&ภXpแฯ`L€ 0&ภ˜`L€ 0&ภlL€ๅๆ˜`L 0={๖ะ๛้้ำงt๎นภ|B#ทงGฎั‚้ `N ๐๔้+ส[f4อšPŸ ไ"ฤฉ์„^๐%™`L€ x\ฌผ฿0‡?sๆŒ•gนwu˜ฦgห–อฝมฝgLภy>ฟข}i๕†“ดm๕oฮ๋_™ x1ฝ/Sณถ พ.๙„เRม‹i๐ะ™`L€ 8†€ื .ˆ#ฐlู2บu๋V ยุgn Šaุ‘;w๎0œฉฯŸ?ง€€€เ+นะั๊า๊๓จถMcฟชc๎˜vž๘DƒาeJ/?ู ฆ- ก3†PฑBล)Aฤช/=˜ภˆMiสฌ],ธx๐=ๆกน6ฝเRฐ`q ซธkw˜{g5<ใผ~…~ฬ‘I=พ}mใหณ—๑๕!ฯp\=ฃ™?๘ต ซึ๔ฤ‰บ‹]ฯ๘ะ—วเฏWา&w๊ฯU’ชถ˜ฺgัR฿W“ ฺคMtB฿ฎzฦ4ฝ\เ!~=W{ฦา„z๗0nั’ญฏm๗็๊™ดez(ธ!†๖˜ษ%๛ฃoิŠพ:M7ภภ{ ?Wwšพาิ๙ะฟiTฐH n^๗b^'ธิฉS‡^}zMfดท๊ถ฿ฟqŸz์9ฏžฝฆkืƒญc๎เ๕€๋๔ฺ Bร๋็ฏ้ๆฅภ–>ๆ๚h้พ๔ูำYZีi๕|rgดตSfLAัc ~hฃซ@ K•9•Zs~3/Ÿพค%:Q…ๆจmง6ไี~๗ร๙ฃๅ(#ถ‚หฺผข5ฅHOํๆ%`"เ7 ๗Ÿt)*Xจ”š[ฤAWๆห8Šžq?ฟE๓sฌ,G1็๋0=๋wQนรYpัCแu๒Rมๅ•\:๐ํgLภ ฮ8Kฃ|วะๅ~ #๚ณเโ„{เŒKŽ๔ M๑*_๖๒ฦ]เk2ฏ&0f๒v้ึ‡ น —ฅ๐1 z5OผApy-—Fž8<py๛Ž] ฝfาyS.BT—๏/wะ1ผRpy๙๑užษ‚‹c>b|&`L@ .ฐ†š0"ฅšธoy$ƒ[‹”ด›Xp๑ศปหƒrJpูฟฉ#ล๛6—\๒ปCทนV‚ห‡74oPC+ฮโชL€ ุŠ€\.œ% ษVอr;nN€7ฟ}&เn”เ?q|Zดeฅšึ†ภ ƒ มe .ก`วง0[P‚ W‡–•ยGัอr.D€บฏ$0kล.1s]8๏/ยแD๐J<่ภผTpy),\:ฆม{˜ฐ;๓6ัฒ1หๅu6ฺฤ‚‹‰ปฦFiO“gฌcมล5n๗โ Sgoำ3ฯฌภž/ .ั……Kด์9๐09sๆค ้Rัผ • 0ะ๐ํ?‡w๐วp -@=ฝฑ<,&เช ธ๘ไฮ(ใธฐ…‹ํ๏าตkืh๙๒ๅ”,Y2J‘"eษ’…โฤ‰c๛ Yูโศแ}h๒ิ…n'ธผŠTOŸผขxqฃS‰ย่G!ผคM•€าง๙†ขE‹l% ฎn/ฟu_F›ท๛ ื š8ผ–E—)๙ำบy๛) P•*—s +‹:ŠJF‚K์R.’gวฌ ขP‚๏eห–ัส•+้๖ํš๘’?~*[ถlจฺ อI{๖์กฦS’$‰iหŒ๖กi‚ฯaL ŒvBGฯ\eม%Œ=ํtฏ\|ฒ๛PW?ถp๑ด3ว=่—>ฃ๚P“*Mœ๑ 6ะพ}๛่เมƒ4y๒dJ™2ฅำ๛ฺเแฟUซV`ิDžฅนsS†์จ›_—พ19&เฉ๔‚Kฝ–๕้ฯ๎8|จ๘.ุธq#mผ™:DฯŸ?ณ‚IจZตjิฉ“gd0Cl™3gาถm่ล‹’ฑบuKnC€)]บ4ๅอ›ื!&๐#GI“งฬq;มๅูณื๔c้Q!~Fฃ K—†ต๓PรZy(QยX!ึ็ ถ'Pฝ๑L:ใ‡|›ค๖ญŠYt\ล†ำซื๏hฦุบT(_:‹ฮqืJF‚KœŠ.ขๅฑnuฬฮ๊ทฉี ๚ก_์!z{ƒเ๒๚ํ;Š…ญ ๕นๆ๋†Lภ ธD‚หฟ!Wๆ^Cภซ๕cฤ‚‹ื|พy .H‚KŽโ9hู˜ๅไHมภX`ษB-mถฅ:u๊จ]ท\ผxฑ;f]k1cฦ”Bำแร‡)cฦŒิคI9 k/๗ฃ‘# มลฯญ—{๗ŸS“6๓eŒบีrQฃ:?Pสไq้๛tํฦฺน๏"-]uŒฎ|ฌ}f ผL]‡๒ไt_+)m0nถRคโXบ๗เ ๘ฝ<ี๗ห’’)๏@YmมดF”+ปg฿3#ม%n !%ˆธN เูs้าฅดvํZฃ–`๙ั–/ถ๘Uฯธธˆ'ZธŒ{ MY๘eL“„:6-Ks๙P๘๐แŒ˜๒†๋@๓m๛ฮา‡ŸจL!ฯvืิS—‚K„(ดdๅzn^๗r^)ธคฯžžบ๛u๕๒[๏Zรฟwฟ~Ÿ๎\ฝC—O_ก—๎Pด˜ั([กฌ”ซxNJ”"่™ธwo฿ำ–[่แญGTฏ[Š)b มฺ|˜\B™๓fฆ&}S„แีแŽ!มฅJซส4สwŒeษ2gฮ๒๗๗7 ฌš5kFๅส•3ฺ๏ษเ“๗+VZ~๘แยƒัึญ[ฅๅ ^:t่`sทช‘#‡ wญ้n%ธฒdLL‹f4ฆฟ—–f์ตชๆ 1ข1ั[ฤคYŒ]าส่ธฺ๘๔้=x๘’>}๚L฿&Š%?ง๊˜นๅ[๑]x๕ฺcŠ;ชจo›Y)ณv‹ส .PVท. ัฬ]šฮŠ˜(ํ{ฌ ์฿%“™|L+Y:–ซืัa1ไEЁพฯš”rdKFI&ƒ–>ธ๑ฆๅญ…๋Wศโ ธf/PฝN“ศฒม:(^œ่๔๖ํG#ซuฑฺBtiUฏ[ฝ( NXบ๗„J7ยŸ(ฺUงše๋xรณ™ง)ธDŒFKVใฉCไq…‚€— .้„KQทPเโSlIเ๒้ห4จ๑ฃ&sอAีฺV%ˆ+(_$ฟพณ4แ%u–TิuFWอาๅร‡ไ›ทตฌ›"C ๊ปจท\ว?๛ึํฃ™โ\Uส4,mฐ’‰ส™Š‰3–-sJ&wฐ™เกลฯฯๆฮ+ญY๐ŠsXท H,b“xr|[฿CS๑Eตธ/` ั*4๑ิหภนฝT“nฑTyE*่ฒ%3ัร6ส~CจhP+7EVwบz๖]#—ขJQ“zyฦˆ๏ซ5N^|kํดน05k7ะC่kั๎ ัยBo๕1ญLพฅ‘dึ*1gถ๎ฃA‹'๊ว_Qrฃๅๆ‰(rdใ>เ€5ใTํบ๊ŸปGฎั‚้)b‚ฦข›\ตซ^/๕‹Xcฆ™ŽBฒzQ฿ฑ€wfร(๚๑ซ๛งญvœ&ธ์\ะ›โฦŠ.ทท๎?Kํ9ญรxฦE3L้‚qI๗.ฎ8cธ_(ษพG฿~‡ฮ]ผญ dp ›ฟ ๅ๙.+v?ิ}2.ั…เbณ)ิ ๒‰Aภซๅ฿š>; .ฮ๔~3ปƒš ฆ+"W=J„qฉh"Tชa)Šอxึ1Z&w™Lงฤ)JJ๙ฉ๙€ฆrน๐ํTช‹\Qจ็-ล+ ๊Žอ๐EํŠ-*าOญซ`•‹“ ุJpมƒ้๒ๅหฅะ‚ภทษ’%“ึ,ฐnaท!d๕๐˜/jๆึ/ฐยรฟ5ย‹zpWมฅpดTชhF๊7ไ฿แ๖้Z–ิฬcTโ‰oืฅดOธ๑˜+ฟต,Bm„๐ข ,6~้ฐุ( ฏ:‘f๏ฆๅ‹@๐NXjฬ]tˆFLชชZ–,โCƒ๛Tขุฑ –,ใฆ๎ I~ปdฝ฿—ขฆ๕ล!8q๚&ีn>[ึEฯŸ=+สukฦQฃdต‰fลู˜๘"า‘–Yน๔lz–Žค‰Rช^หฦ๙ฉs›jำhนt๕Q๊3ศค0$kuโ๕ฉtIrำ็าšqช6]yน๗เe?m็มล|<ขเ๚๚๔i๋)FŒ-Z4)pG]ฎwžปƒufๅฑTฆj?–pื3w\ํ3]ชsี~ต๚๕k้โy้า%บrๅ ฝ{๗N›แhา$ร็Vฯ฿ฑ๛๗๏—๑นฮlKŸ?ผา๖ˆ๕B๕ควO_Qม>4ํภŸแ'ฯ_ั๊-Ghุ ƒ;^๊Œ๒ฅ ฉพ๕ˆ๑ป๒ NœปNฏูC๗=ฃห7๏‹ฅมJ6ธ>ใโ^zRaมล“๎ฆํฦย‚‹ํXrKVุนrอห0™5V๒ัŠขcy๒Rภ๖ฏ3€ž"ฏาoQJž!9บt‹๚ี ๗Uญ•oZNZล YU)Rฝ5๊%ฬงนธฐ .ฐh0`ญYณFฦ‘ข ,0jีชe•V(่o^ฝzE/_พ$<$๘๐Aแม๋Xโ๏๛๗rฉ฿‡‡kตญ–่, "Dˆ -#FŒ(ืM๗ซ:๊8ถี>ตŽcX)a=rไศr‰m๕‡}Xว ”นb*พจX–ุuGมึ ู ฌ๐ ๅKK#๘‰ดš'ฌGพบ:*Vˆ๑R0ojั0Ÿ&จcp]๙ตำMlปQ“บ?Šฯส;š6w/=~๒Šโ w–=:H+ฤŽฉีLX๖}ฑ‚มฑJeฒะมฃื้œฐคAY:ซ}—%ฉํฑ]โŠ2๎iA‡ณ‹๘.]– 9Rศ—ิ฿บ/ฃอe;ๆ\ ิXd…`ฉX&+ ํWY&(7$Qญjkt–ตใ4:ูE7Tะ\R„๘๕\ด—Aw "๚ฮร;ฐQ฿j?–๊˜Zืำฏซ๏RดฃฮQย–a]วweX ฌฒaลฉwEVฝ , ๛๕๋'ม๚ลoxส›ลณฌ:ฮ_ฝ+,•วHคํ„เ‚TรqD6หยา๙สtๅ&๎ำa9}๖C ฯตŠษ4าฺฑrํ๖#/.ฌ฿q\LG=~ญศiูฦƒิo ญž~ฅO๋ชTทb>ฎ0ฏCธq็1ฝx๙†b‹gใD๑cSฌQƒm๗ฉฐ์ั‹?{žงE"F"J/฿ชข ใdช1K9<{๑Z๖Aล^นy๏1™ฝ‘ฐ—ฺล(wถ4d*ธ ฦฌ‘PZ7(Em๊—T—๕่ฅo9๔โmxแRดฦฃวษƒณŽ .ึ๑โฺ6 ๐เึ๊Qูวก^ทบTขNq‹Z=ผๅ0M้>Mึํฟค%K—”๖o8@3zอ”๛,ํG3z๚ั๕๓ืๅvสŒ)ฉ๛,แ—o&ณ‘EไJv! \†ฮJ5Šี๑:*๘ื_2: ภšฅZตjFApฏ_ฟ.€{๗๎ัƒค ข–=’๛?~,ล๑ใวงx๑โ‰ูจRHPb ์ร,> €`‚ึ๕x ว์-๚•(๑C 5=”๕‹:Ž}๚_๕ ^ิK–๚u๕๒€}h#ด/jKบzมภC•้ ฬูัG,!<ก่ 8อš5Kšบี/w\๎?xN…+\รeฮค†rx๗ta™2FXUจ‚8,p Rคj๓็odฆ#Xq @๐(R %Lƒv์พจน ๅศ–œอlB ๒•5ฤA*๊…ำ พUsBt8'โ• VM Š—+ƒPญ๛ขํๅsš,:Lหลหจbฉr7ฌY`ีฒ๏ะejฺfทS'ญ=Xุ”ฏ=UZฟภZd‰_S)PX;4œ_ŒB)SA•›ทžHื#๋)#k ฑฯo ึ&๙หŒั’ภe้ฌฆFฌM\ฏb™ฬ”๕ธ^๖ํซดั{\ขๆฟ-ค๔iา? ม!YB3Nuฎ+/5มๅเ@ŠฏŽ+wีk๛KBฤ$[ฝzต”-ฮาฌzˆU–7o^้nไ7ข3ๅอGq\ป๕>rฑUc๚ตn ๚Mธช๋ฟ—ท‹x/m˜kถˆ+'v „_ฒ]q›๕œaถฎฺYQฤะพš‘ต\›ถื๖๘ฑcP‰Ydีโwฃ๘Urท~ J–(žjB;>}้š0oณั~lL์˜Š‰ุๆŠ„๊WฮOฝZUกฃBp‚•…*฿gJI๓‡ทฟ๕แิ.นด”รล๋๗จJซั”.e"Z=ฉ=" „/ๅ2ทญuำ;ัs!ญ~œrfNIธf,{+ฏฐ@G*๏ฎยญฟi๕BFื๗ิฑs7ักs๗hษ๒ีž:DW(ฐเ h|Jุ&ฬšปL–@$QrCjuเ…ด}ูvYmฎq2ึห?ยOw๕dƒŠŒฬCwฎ‘ว‘จฏจO๊โโZฌ\๐๐9fฬ้>„Q nฺดiฅU ฌ+๎฿ฟ/-- คW ฎภ:b –˜)…pแรt‰}ก1w‡กฌA”ล ฎฅต}ะ[ถ(มC‰jฉ,^๔u๕"Žซcp}ติฏฃก)ฐเAเฦ7สVSK$ฎ^ฝ:•)SฦขฬO\6oZKk็#Xง{}PUsiก๗พ"ฌQ–jBฌWqN๔`'LM˜ฑSึ'L „’ลBlษ.ำ{kํ8.ไยšเrhEˆ[ำ…{๊]]รw-พg‘aฯ฿฿_fุรwซตม—‘](oฆภยซ;“้๗/๙-์Jฅฦฑ$M๒DาB%wึ42k’„qิaนyศŸZ๕›ญํƒH‘]LฮmsJ $8 ทZ0aโM“Ÿ ั< ]ฝ๕ๆ‹x%K/T*7?w&๕oJ)“ฤงJฟŽขห_ฒl.Fบ้ำZ(\kf ๋kU`ีาe่"ํZุ!#Iข8t๑ฺ=YMŸ้G‡ๅ์ปh๘ฬuRAเZํฦkbˆชทlo”YLRชb ‡S7จNว‰๒ิํ๗คพcWะžSMษๅ๏-+SฃŸ ํรFนŸGHk#ฐkืจt ใžธƒOผซa .agศ-XI™‡TŒ•>๓{QJก„‡Tž‰ \=ซ๔‘ฎBˆ๙าaB;yสœ?็าฎUปs๎๏”Fเrq=ึ.+˜}๋gฉฐqD .เOYฅ@ุ€ล…^tPuT=Wึ+สbEีว~Xป@ฬP๕ฐT.Xช87ด‚๚๏jD–อ›7K‘โรj‚ ,‹J”(!]ธฒe3~ก i,\๖ํูJ ฆ†lัR[Ž:Žฯ\ๆ|ƒดห๓ปดัvˆ•7S๎หตุ*ฐT™>ฆŽเf0/_{ ]พ๚Pฦ(+ 2ญฑKn฿}&h๒ k฿ๆ…d|ด‹4ฬีฌ๖7f์ ๊โ3ผk‚\#e๚˜ภฎ"Q|ป,ีฒ(-žู”เฒƒาฅ๏*๚gใiiy3ธo%้ถƒme #7ฤ?ึŽืUi—๕AwU{๚ฅ๊G๎์)h4ƒ(wจ‰Bฌš,RX›Safษชฃิw๐zYอทYAj฿ช˜ั)+ืง#๗ีฎX—ฌm;$^๚.ึŽำ่B.ผ๑Up.—j.S๏่\†6mฺ$'๐][ตjUiอ’2eศฯDๆ .ฃบQŒž5แW ๕ขŸMฤ๐Cvd ส’>ฅJ–ภศยฤŸ—ฏ฿Rฑ†ƒฅลฤŒi6ฃœ"๓%Š^T๐ฎ/m… D<ี๛ษใ+ œDˆ^nซเ’sไ๔eฺ}ไผtO๊าผ‚์หoฮSUhtt็มS:๐ฃl›ืCบ แwฆร ๙šเSฅD.™า:Uา๒น็วš+œทkก˜HV3๚ฒ`ํ^8ล0๑ˆ8)J่A0ฺ‡dี?ื ๊e๒ศuk9ˆ‰ฬjmฦสsมแ์EƒŸ]Xฒœฟ|W๒ฌT, ํุjNe•BJhFPXp๑†ปlYpฑžŸF/žผคŽ%;ษV,q)ยC๗ด฿งำัmGๅ9gvฅ๔9าห๕1"ๅ้ฝ†—ี-ค‡๎<ตลณ\\€5‚ zุK˜บu+พ}[ฌ]๐Q&K–,dญ 5ฤ+’๑ฒeหไƒ?DpE6 ธpฉฌOeห–%ฤm‘‚หmด`Š{=t•i‚|UลX1e€เท}E๖ขต"ๅ3JพRำŒ1uฅŽJ+ผA>๊ึฎค้ฉถ๑}Wข๊-`.ฌ/๚^Ž~ศ™R}_]‹๔'*ฑ๛ฺZTธาd•.Kท๎<“๑QฆˆlD*o๎ๅฉn๕\ฺ้็/ฃส๕งkjลœตŒตcy๙๒-ๅ.1B6ฉbเจ๖M—cงlื„•ขยๅชhก๔ดbํIอา‹฿๘๚2•ต`{eๆธzา็มรTจ‚แฅmทiQXˆJIล R8ฺผ-€ญ<ข]Rน้ญ^oํข [ึŽSkุลW4มๅ๐hŠงฒ‹๗ึ3ปQqYVฎ\)ฟ[a)ˆ`๏ึZณ˜ฃc$ธŒ๒๚[w˜;ว๖•ษn}Lu*ไฃพmชZ๕ฉ‹ทำธนต๓2ฆIB92งข'ฯ_าฦ'ต3ถ |โV,ZพฟvฌIฐb ช1q5-^ฟreMm”๚๕! ฌู๚๕๛Gตก2๔ฌ฿q‚บ[(w›ฦ›A บ ึ%จะ\d๓์ุRpœpAšบhซjV.•ภกD*ฤ™ๅŠต๖ป@-พธ๎หฤ?`7o๘ฏดlรA™*E’ดaFuX[V๑--t‚dดŠด"ดdูJ%ฌXp +A>?Tฺj/ญUเ๚๓ืŠ?ƒG^>}IsฤL[ชZ™*RIปfJ=้.8š:๗ขณบS๔ุ,บ(&ฎฒดVpั๗ฑ\–.]H|AXbไษ“G 0ฅK—ถศอE฿ถ7ฎ/^ผXฆี†;‚งH‘‚ฮž=ซi„Yปญฒ>—Bp1๏๒โช‰ฌD^“;!‚ฺF’Šูดฟ˜ฅ์าwตplำ๒ึ”2y ฏฉ‰jS-7ฆhๅ๑jำh‰+3วึฅoล–3พ}ญฃekŽห:hทw—22Fฬยๅ‡iภฐ F็šn่…ฏ๓๏ ฑišฌ‚˜1ล e๋ึŽำ๔ฎบญ .G&P„ุกO]u|ฎฺ/ๅ2ดbล )bยšลX—žBp1(ีน๎ฐ/kลฒ›~ฎHMชYAeK5&ญ1๔ม\Mว]ป|^๊ืึ๐u๘ิej%nเ๐n๕จBั๏MซkJpัv˜Yมu็ ๗ฅฺํ&ศ~๔มl๋Uส'ใษภm )S„K’>ึสฯฝp๕e“ˆMจาJZ*โช‚เฟS4กˆ"ฦขu๛่ฯIซ A‹วดกะpะ BธFB€w๑˜ถ๔m‚ุ"k“ศ๔&D”ห๚S แnฅ/5…{,bเ–>ช\ŽŠpคซฌŒิ1w_ฒเโ๎wะ>gมล>\นี,ณœ6‰๑(ˆแ๒ณ˜QH!R์ฉ‚Y#ก…รั‹'/ไ๎ bฦก“ฐ\Q)=฿ฝyGm ฆN ดฬ^ไ{‘nฺ7 h Šผรก ธTfท๋ึ“ฅAsอuะœ๘ัณฐ„A๊L%ภภ:#จฬๆฺ๖๔}Zํ ฉF”ฎZศ„ัภš ึp2.‚‹a–อšsYwโ2sNำzy้๗ฅ‚ํ \h๚—Vฏ?Iปm/ใ่ำC0™<ข–pY3~(U"H/\2๛|+ญjูHeๆQu๔Kˆ8ซYบ#!๖ b์ุsQ_Eฆ›ฎ_#7ีฉ–Ss[2ช 6p฿‡๛OŠEฐD้ืต\ ฑ็X;XุŒžผM็ฝ*แช รฆืWศิต฿อข๛๋ kœญŠŠฟŠ็Zkเ:Zตฮ0+]\%“…`‚๒๏–34zาv-ฑ)ซW–…จPพtj—wตF3ฅ;˜ขวฺqช{”’vA'ฏ(มeหฺ?)uๆภฎgN๎žว]^๏2„มๅฮ[ฦฝฒ…5‹9Xzมe๙ฬA”)ฑqTs็ธหพฏศฌ่ohโlฺuŠ:ž/‡ปJ~}๛๖=อ^น‹บDf›)m2๚ฉd.ชT<‡†B”ก]๊ำ*}Y1\`ั๑ฯ๖cZ5ธ0-ื–า$๛†๊t˜Hงฮ฿iญ‹S๛ฦeด์>ส• '=~๖RฦJูบ๏Œึ†ZA๐ฑฝHA๛๔qfเRดpTk-ซัฉ๓7ล๕&ศSฏ๘Cธd๙[อaฎpืปCญ.ฐpA๙๔้3}Wนง\Ÿ%โว˜๋๗+vฺwํnM๙ฒงง™ƒZศz๘งภฟฅ U“j…ฉฯดžฐ"—€‡ดd้ OมFXpฑHnฦ:ฯ?™Š 1Yิ™>น2P†œ>๔เึ}:ถ„–ฺว๓WสO๕ปืฅจ"๊น*ืE ฏ?๊ฉ6 )ฆ‹ี*Jซ„šฏJัšEฉม๏๕ลPวy้xถ\๔=7_เฃฤXo@€หo_เž5pเ@˜‚ \†์"€๋@pน~ํ ๏๓6ชผy๓(nH‡`ฌ„aˆ0•๋Nืˆ$ญš–*ฑbFฅ+ืา๎}—i๛๎๓šฯผษ ้‡\†ุWฏ?ขvะั“7dzeๅค๚ซ™ไยํH\๛มร—"ƒิ'Š5’ศฦe์๏ฏ๊…fšฑŒRƒปN5ซไA†xYˆ?7n>กฯขfาฤฑ5ŽๆNPฎj}ไ๖กฟะ้ ท4๑ฤRรfฌง9+wส6:5-O-j‘๋๊Ÿ&ย ่ฐ๚ญQjUทธฺ-—Hง,Jฐ๎ูตภะปŸQฅ_FI+}€bฃx‚หย๕้่ัฏ‚›‡ปn#^)ธรKธ๘ขโโ\๗Dชน้"‘ย.จ%ZTjป!X.๐Kฺ๙#4ฌๅHyj"ก๊๗?ขH}r๗)'ฬUมฑv"B๛ทฉพUปx้Dฟi/R—.O rนmkฺn*พภสโฌ9๔โKอš5ฅ๘โDป4„–qใฦiiตqasฉตํูกŽ; a !ตof˜ณ็ต\ญmXฎึ};u#ฤฎ! ๓คแต(๑ทฑอึ…›ฮฅซึ#ูณ&5[ฬž`ใถ‹ปfำๆ>๒ทถ —ญ๏๙6AX@Aฐึยzูšขw‹ *ฃŽi{ฐ.QมoKศ*ฌJšVัถแถ๗”)šRœ้){•rิŠCฅc†ีหมๅi๋^qฟๆษบฆ”- ๎T‹ขWึg"ss๑ฬฌ‚ึยšมpg 1)จ+อNรปี5m‚๊užL'D%XิdH•X‹c)dc4uญt%ฺ(b(ข/๚ขbศ ๔ย‘ฦ๗EC}ฤŸ‰&\ŽVm>$c๑`[ๆtง81อ‹แ๚kธำ:—i‹ทั… ฉW;๐*ม3ศฐw†jกธe็{แ•อx๖{€ฎœพ*„—หt[Dก"๐O๎ŒRpูtjฅšึn‚๘‚,[ถlก€€ –/˜y„WšฦS๓ๆอ=าๅ฿yบu3Zซลั/ธมx๘๑ว\ิพi"ปoWn๘ฝ๘ฎ[ฟๅ,อšฟ_หhค๚‹เฏล ฆ—มvKฮ`dญก๊ธาา“ฦWOง&ธL๋F…Jะ๙˜…เ6ิถm[้ส๊ ‘E฿M|วยŠsศ!ไเ๚p฿เrงฏใฎ๋ศTค iกwฝฑtฮ฿ป•ศŸล์้๏…•เc–nญ๚อ’–&mEJc_๑œTู ‚๎vฒ€ช—ฮCvจ!ซ“‰ลฤโOฅri๎?8๋ร฿G.‘YŽฏ๙KC ฤbQbD‘)ฉฑHCญ้Wฃ=g(Xœิฏ’OบGี*๛#}/ฆjB[ึ3 „MOฑR‰œVsˆ*&2w W$*ู2$ำฺU+‚*2‚ŠT”:w้6ี๘อ ”ฉ๚jR\Uฯ–,ธธsLฝJpา๔้ำณเโ˜ฯ–Cฎr๗๊]z(‚ๆ๚๓สˆ&<ึN๛‡ึUy{ฮ๙Šู.ฮ'เHมE?Zˆ_๖x๛๖ําๅฉŽQ ยx’๐‚ฑŽ3Ffย๘T& drV,ร์๋ิฎItษซ \”n~*฿&ˆAq…›‘ปOKp๗ภฦฉ .ำ{Qกโอ‚.ณฌ[NŸ>M ฐ๐ ๛Uำ[ธ๘\O๎K๏ŠŽmAl๏>|NeEVำ๔ฬ–๔dๅๆริ{ฬื‰8X„”สŸ•R'F(?~๎:ํ8pVsษ“- ulZŽ6 ซiธสฤม๎;‘#Eฐศ…ฎ“v"๋ž[ฑ}CdaŠ5ฒH+ศvsf๏ั ฒ^nัGK ฤ#e™s„;RpE฿พi=ฝKŽ!พMำ๊… )ฆ=ฑฐเโ‰w5์cbม%์ น&ภฌ ม%~’๘t@คดท…Kpยฬไฝ{2yŠ๐’#G)"มขฯฑ‚ใฌŽฉ—vMโ‹]ˆะม… 0G๘*ธ๔‚KG^ฺcฏ…ฮฏ^ฝ’฿ทฮ$พcแ>ปvํZ๒?ด>=๊์.น๕OqE,)[V’&–ิuท:Žๆp๓c:๙ๅ๙. ลิลbt7n–๔—K(y_\ผ๏ž๓ˆ™€S @pAนpขS=ฬRB|ม฿นs็จOŸ>”-[6}ทZ‡…‹ฝ4Z D .ํ›&ูaX{:ืgL Œพ .„เา(Œญ๑้ฎF฿ฑ(‡&ร›้รCฎึE—่ฯี[Dุดxฝ!ๆŠพSHฉ\(—•,…R$ฦไ€็ๆ`Ÿ{ซ—UซVน๕sค}่xoซ,ธx๏ฝ็‘3งpEมล) ผ์ขšเา<%}hpๅ๒2<\&เTJp?บ•ฏผ‹€S;สฝเpt+ฝฟต?TํxหIp๋น๘…ˆั๒Bdt‹BIล1Šตยผ…€mว9k๙.แทŽๆฮ๋ฎ†ถทZ,ธ„–Ÿว˜@จ@pyt็1ฝz๑Šึ์_cื นก๊ Ÿdšเา"}๐ภ.ืเF™š€\|ฉMป บ"qKF‚หฑ๔ๆทwš ธ3}วฏˆภฦSYpq็›h‡พณเbจ$`A€เwข๔ูำัค๙“Yp •Gั—Ÿณะ็๗† 5@ pqšเ๒k=๊๕O๏-wฯZF‚ห๑๔ฦ.k›เ๚L€ „‘ภพWฉE),ธ„‘ฃy่K+–IDATงฮ‚‹งQpq,ธธ๘ ฒS๗”เากeN๚๔๎Šฎยอ2&ฏ‚K!ธ ช๏wSF‚ห‰=๔๚7 w› ธ/}งnQ‹๎ใYpq฿[h—žณเbฌ(`A˜k†ฬPฤ.A๒ฬšเ๒k^๚๔&ภ3ษฃb.Lภo>6๎?๒ตก\๚ปpOนkก! \ฮŸฺO๏ฎn M3|`a ฐ๏๔jัm, .a`่‰งฒเโ‰w•วฤ\˜ภส‰ซiฝ฿zv)rแ{dฎi‚KซB๔้๕i{\‚dL {^ฆfmมฅ‘\๚S“น#%ธบu‹๗฿:zwyฃ;ƒ๛ฬšภ3wฉyื14aย*Wฎœ[…;o;^'ธTญU•RๅLEีฺTตEn‰ 0‹ ฐเb1*ชจ .พ%้ำซ#56 pšเาช u๎าวบฬ}ด‚€\pสขฟ่ฅ๕VœอU™ฐgP๓.#ฉu๋ึิฉS'[4ษmx\<เ&๒˜€;P‚KฑšEฉg^4ืn^๚ช .ญหำง—๛ยะŸส˜@h|\š มฅghšเs\˜ภจQฃ่ฟฃ˜1cาขs่…ต.[๎๐L๛ฯ=คๆGฐเโ™ท7ิฃbม%ิ่๘D&ภBC@ .šW :ฐเˆnxŽ\:ถ‰>>็`Žnx นหnN@\|[P็ฮ=|4}S\&MšDนs็ฆล ฆท็W™Vแm&ภ์L`ฟcji .vๆ์nอณเโnwŒ๛หœภแ-GhJ๗ฉฤ‚‹›฿H+ปฏ .ฟีขฯถXy6WgL ฌ”เาฝ{'jูฒuX›ใ๓]Œ€‘เฒhฝ Xแb=ไ๎0ฯ'ฐ?เ)5๏8„ฯฟีVซpqe&ภยJเ์ณ4สw .a้f็k‚Kป†๔๑้:7๋=w— ธ?งO_Q2ฃiฮ?*Xฐˆ๛ˆG`D`๑โลิซW/ƒ…‹X๋ฟิ่8o0&`.ผคfํbมลจ๊ ,ธธีํโฮ2๗'ภ‚‹๛฿ระŒ cวŽt๛๖m๚๑ว์๔๙hšเs˜#ษ~ปDบาูT @ก0ถฤงป={๖Pใฦฟ .ห‰>rตnr˜€G8w7<ีhพหึฮ๋—*ตชP๊œฉ9K‘๕Ÿ>ƒ ุ„€\๗nD ๋6โ.6ก๊๚`๖uล ˜ธฆฯ_~ํpธp_ืลฺญ๗้ฮ‡F๛xรตฤŒ||า|ํ”~บ;ฤ5ญท๊<‰&W1jวhƒH฿O“ำฤว2่ฬๅB{‘#ง‚พžŽdศ†bลŠA#FŒฃ”)Sฺ้*ฌณ˜ .๏.ฌ฿ตoีฝ๎ใ=vl๚%6ฅH_ฟ‹ื- !~Fส”ฟ: .ฐ๒ฆ*^'ธT‚K\^>}Iืฏ;๕sp8ภช๋๛ไ๖ฑชพ#*GReNๅˆKy๕5”เาir*Wธ .^ipเO:Eฯž=ณyฎ_ฟN7oดiปgฮœก็ฯŸฌอร‡ฌ-{5”4iRยŸ;›= ชไอ›7ะกุฑcS–,YŒ๖'OžœE#"ฑ‘>}zอยๅลu๔๙ร+—๘ำฏ้ล[A๖๓ู‹7t๖๒ํ ใภอ้ึ'มึ1=๘ๅ:ๅŽ้n%XBˆฯ๚[ซฮฮ˜& ลŽ=ศs2ใxฬจfปช !Aส”ฏชฐ$œ+, ˜ํ;๏๔>,ธXyฯฯ8g๖Œืฯ_ั๕€fa็5k๔๚๙๋ ซ7.คืโวว™%YฺคMˆฎX.ธษฬBด˜ั(y๚dกF˜,CrŠ'†U็ง๐I.๎[ะ?\ฆ}“4%LžะtทOแ)3ย๚ยหbํจ<.ฆEํ/๕ตsพ์ม๙Z_๗•ฯV†ฬL% •ขxใ™ํ๏dLภ}ุKภ2G`฿>็ฅ‡ฐ#4็eห–-4ง๒9Lภ"… –B%, ฿]@Ÿ฿…Nจ=sแ=๘Ytษหf๛q๐DะVท๏=กVŠ!๊"้S}Kฑb˜แF๙ย.žทฌ)™ำ%ฅุ&m>โหนหA‹/มฝ๘[rmKD#KฺqVเ๎ฏน>ฟrื์็ว\]{์ Nม็)S:ใ็๓ุัฃRๆtIŒบ‚6ฒคท^๔˜๐;ส๘c%\Œh๒†ื .อ5งทnQฦ<ตปoN 9์‚v<ค•เ ผง๐IR”2c Š๒่ข]ถฦk˜*,‡ฎim|&็šฌ …ƒ9 H bนแ‹ภ jขŽ8็•ใฎžป" ฮะ๖ห& gศี… u [h๏๘กcbระส„ ~`‡กึ ?r\ํถู2Ož<ต•)S&Š'Nฐu'Nœศ?FมโƒL€ 0&ภฌ#€เไˆ•UญZ5œ’p)z'8w๑ฆx~จ1gฟ็สš:PŸ‚ฺแ์พี/s๛sfIenทร๗A4ศ”ึXHpx'L.x๐ไ%“=ถ฿ฤgๅลซภŸw[\ษg๖‡๏ำiM‡žˆ&ฯ\ศฯธ^ฏ\FอE›Vmิ๎>ฌNn^ ฺ”QซhๅJ|แ๗˜ภJ฿วะX5จn%H’€‹…ฐ”ฐบิHฑAJ ,iื Y9 –AŒP๕ฅ!ฤY#ืณๅถvพกฤ๕dี†jA๎ำี ิqฬะ†:Cด†}†–dJะP{รยึV็๎ปื๊ฆBrqx๚๔);๗ีrหึๆ๑๚๛๘๘ˆฑไฎแร‡ณษปฏ3&ภ˜ฏฑฒฤฬ๑ยi4V˜=’ล0A๓eใหB3‹งนXย’$ณˆ$V EUีท)žฃdัฎ๑ฅฎัBwb๕2๛ค–ื3: TK[ฒช๖—}ฺetฟœŸ?ฒ4•T=uzเโˆI%นiฒฯ๙ZmEซจM j|บณด๓Œš4ฺ๘Rฐ/P“ฆc‘ตu็kซฺŠัี6d• ๊™ูoิ3วU_ ดCิฒฯ่ั†ฎซ_๗ํยื}จธ๏่yg;pฐiXA ย๕ํๆGšK[ธH1)\ฤจฤฯธ:ผ๊}‚ห‰—ว้แ‡กพ๕Wฯ^• ึ4เ(@พภซษ /๒1ํHแ@๛‘ย‹?ั™Cg.a)๔ป๐๒๕ปmจ‚๓O9ญ6]riฉต„KvยN:tศยš๖ฉฆ7,น‚นุฆ็%K–ŒRคฺb‹ใ˜ใm&ภ˜`L€ 0&ภผ•€ืYธ~w‡~~-E๓–ฐ|๘j๕`ฐœ๎"โ ร:ŽC๘ZGลจPึส2"Ep๛ฯ•#๒อมrฆฏพi๒ๅหgบหฎ์๏oWผ8`L€ 0&ภ˜`LภฎผNpฑ+Mnœ 0&ภ˜`L€ 0&ภ˜`‚ .1`L€ 0&ภ˜`L€ 0&ภ˜€ ฐเbc `L€ 0&ภ˜`L€ 0&ภXpแฯ`L€ 0&ภ˜`L€ 0&ภlL€ๅๆ˜`L€ 0&ภ˜`L€ 0&ภ‚ ˜`L€ 0&ภ˜`L€ 0&`c,ธุ(7ว˜`Lภ›œ8q‚"Dˆ@Yณf๕ฆa๓X™`L€ 0&"\BDฤ\€ๅฬ™“/^์j]ใ0&ภผŽ@้้ำง4z๔hฏ;˜ 0&ภ˜`ม`ม%8:|ฬ% 6Œ(rไศิณgOช[ทฎK๖“;ล˜๐cฦŒกcวŽั์ูณฝaธ€W@*rsseร† ๒อ7฿Hyyyๅ๋ Z๙o‚ึ แbq$Šซััั’––&๎๎๎ฒhั" ย@ ๒๒๒ฬ/ EEEโโโาภwใ๒ €€ใ ่ –ํท‹ฮh9{๖ฌ  M›6๒๋ฏฟJ“&MฤหหK8เxัcธฉ —›q€# ่—^zIดฦหc=&ษษษ&ใH1ะW@ภ‘Nž<)C† ‘C‡‰‡‡‡#uพ"€ &๐ห/ฟHFF†|๘แ‡RRRb๎ำฎ]; 1ณ[๔;k‡LาE๊lmXO€„‹๕ฦ”ˆฎ DEEษงŸ~jjปฤววS… €@ ”––Šฟฟฟ์ปWผฝฝ่.\ฐŠŠ ๙ไ“OdวŽข •nปM๗_yโ‰'dธqาซW/4h๘ใ๒ฬ3ฯศG}dfท่2#XS€„‹5ว•จฎ dggKLLŒ๙็Ÿ๒๘ใหโล‹ลำำ@z8w๎œ๔๎[าำำลืืทฏฬฅ@วศษษ‘;wสž={L‚ๅ๒ๅหาตkWy๖ูg%88Xnฟv9x๐ DDDศ•+Wdษ’%&ูขu\tvห๘๑ใ#Pz‰ต แRk2Np$E`ฺดif]ฌV‹‹“1cฦ8R๔ฐk}zนsgIII‘Gyฤฎ๛J็@๚ศฯฯ7IฉํZ]–๖ํหจQฃฬ2KŸส[ญZตJ–/_n้2ฃร‡Kddค๙์ิู4ฐฎ ๋Ž-‘—ภ–-[D—๓ฯ?fถห๙๓อบู:„ฟ"€ิQ [ทn’””dฆสื๑œ†ุฝ€.กฬฬฬ”ิิTS—E …ทlูR†j–ฏ๋’ก๋ห/ฟ,YYYf ฮิฆKŒดฎห๚๕๋Mอม๋ฯแ฿ `.ึK"น‰€n=kึ,ัJ๑๚R—้zZ €ภญ ่’"|ีb4@ภJบ4]kฒ่.Cบ›๎*ไ๊๊jเ้ฌ้วฏ.[ฟQ6l˜ศ๐แรMRZ[ทn,[ถฬ$จ5QMCk pฑ๖๘]๏ผ๓Žผ๖าดiS๓T!66V๎ป๏พ*Žไ%@š<๚่ฃf‡ษ“'ืไpŽA์^@ฟ+๊ฬ”โโbำWwww้฿ฟฟŒ=ZXm๕!฿ุฑcอR#MF‡‡‡›ใuฉ๛ตฅ—Zhผmถี^‡7@ภ๑Hธ8Aดrผึsั-๛สหหอ“ูI“&ีแJœ‚ hjhอ, เ่๗฿ฟY†ฆM๑๓๓3ษ“>}๚ิ(,-žซ฿1ตvเ† คG•็ฝ๖ฺkfฃy๓ๆIXXXๅ๋ฌ+@ยลบcKd5ะบ.|๐ฉฏSโgฯž-]บtฉม™‚ pM@งอ๋/%:c†8บ€๎:ิฏ_?qssซU(s็ฮ•ญ[ทŠทททh1-ZTž์ุ19rค<๐รฆุnๅ,-@ยลารKp5ุฝ{ทhŠŠ ๙๗฿eๆฬ™2u๊ิšœส1 €Wดށ>^ฐ` €€S ่ะ‡2K†tืถ๋เมƒฅฐฐPฒณณฅSงNืฟอฟ@ภข$\,:ฐ„U; .ˆ>•ุตk—4o\บvํjŠ๊v๏ฝvโh@ภ ดนงงงู๖ิ ร'dpbน(44T~๙gSหJ—]฿6ol๎ฝ๐ย ขหŠh เ<$\œgฌ‰ดถm“… J๋ึญอฮจจ(ก&A เ8œZ ""ย์ฑz๕jงv xp.๛๗ห”)Sไส•+ฒt้Rณ=tU๚Oฟ[~๕ีWUฝอk `a.\Bซ›@II‰y ๑w฿™ตป;v4ต]๚๖ํ[ท r `qML๋’ฬM›6YXี!ผ† แbแม%ด[Xณf,YฒD|||ฬ–€๚Wท๖ฃ!€ฏ€N‘?u๊”่๎4@ภ๊:ซeฯž=าญ[7ูพ}ปqวU†œŸŸ/#FŒ   ั œO€„‹๓9ืB@+สฟ๑ฦRVVfฆหทjีส์ย1`ภ€Z\…C@k hอ˜••eํ@‰œZเฬ™3ข5ซŠŠŠD‹เ&''W๋ Z'๐oฟญ๖8D๋ pฑ๎ุY= $&&สฺตkEง‚๊ำЉ'JUEั๊๑–\ p„„๓ดw฿พ}ำg:ŠิF //Oด่ํ๙๓็ๅีW_5ต[ช;_gI๋liฉAำ@ภ9Hธ8็ธurrr$>>^\\\ฬาM›65ณ]X‡ซq  `…"==]f'ข&Mš๔ ปvํ’้ำงKxxธhฒ††ฮ-@ยลนวŸ่oA@ งiAฝ{๗šู.ะะP3ลออํฎฬฉ €€c ฌ_ฟ^|๓M9y๒ค่rK เศ:3E๋ตœ>}ฺฬdึ๏{5m:บYณfขKัi €  p‹›6m2ฟh๔๊ีKฮž=+ทyขx‹Wๆt@ภ1๔sP!9rไˆดhัย1:M/@*>๘c‰ŽŽ6๕๚t6ณ>LซiปถH๋ถ๔์ูณฆงqXX€„‹…—ะl'P\\l~ูะ้๔๚VgฝŒ;ึ์dคึh €€•ถmf>๏tฆ_ถmญ*ฑ!€€…ฎํ,ค‰c-Ž๋็็Wใh/]บ$ปw—~๚™šV5>‘@ภา$\,=ผgkญc””$fชฮxังƒ ฒuWธ `3ดด4๓DX“อ6ป/7B๊C@7Ex๙็%77W๎น็Yทnt่ะกV—5j”H~~~ญฮใ`ฐถ k/ั5‚€NฉืํฃฯŸ?/=๔dffŠVซ‹‹“;๏ผณzฤ-@†ธV$R์าฅKรŒซ#€๕(PXX(SฆL‘าาR๓ภl๕๊ีuบz็ฮe๒ไษสญ“'!`].ึ["kdล‹ห๛๏ฟ/C‡•Ÿ~๚ษฬx‰•   F๎ทG๊Wเณฯ>“ศศHกnAบr5hX์์l™9sฆ่r จจ(™6mZรซ#€€ำ pqบ!'`[ ์ทฯlผysyเ$==]tส้œ9sD_ฃ!€V๘๒ห/อtอ›7›๚Vˆ‰@ภฺ:“e้าฅโโโ"‰‰‰lํ€‰E€„KฃฐsSgจจจนs็JjjชYZTTT$eeefส้!Cœ‰‚X@ภข๛๗๏—‰'šบ’ฐ@ภ*ฏผ๒ŠdeeIซVญdีชUาปwoซ„F `g$\์l@่Žuดถม‚ คSงNโใใ#[ถl1OS4ใ๎๎nภ‰ ,/p๐เA -h๙x S@—xO:UN:efฏYณFผผผ3z!@ยล!†‰NZEเท฿~3G๏ฝ< >z๔จ)า-ร† ณJ˜ฤN&p๘๐a ‘ๅห—๓YๆdcOธ8Š@NNŽLŸ>].^ผ(ร‡š†4ด —†ๆ๚T!ฐu๋VYดh‘๘๙๙Un?๘๔ำO›ฅG-[ถฌโ ^B์Wเ๘๑ใfฦž~ฎ=ฺ~;Jฯ@ภ)6nhfk๐Z$Wgนะ@[pฑ…2๗@  ’’3EgนL˜0ArssE_‹‰‰‘#FTq/!€๖)๐๗฿›'ฦ๓็ฯ—็ž{ฮ>;Iฏ@ภ)๔sI zปบบš"นบ{$ ฐ• [Isn ฐvํZS_“,;v”•+Wš„K\\œดn๚g๑2 `?………2x๐`™={ถLš4ษ~:FO@ภiฮœ9cถy>v์˜xxxศป๏พ+พพพN๋Aเ ะ8$\วป"๐?๙๙๙f๛่าาR?~ผ่ซลลล+บิˆ†ุณ€ |๊ฉงdฦŒiฯ]ฅo เyyyฆ^หนs็คGๆa–๎HDCl-@ยลึโjดเคฮpั>ฺตk'ห–-3(uถหw฿]อ™ผ…4ž€๎ /พ๘ข่vซ4@ ฑRSSๅ๕ื_ •๘๘๘ฦ๊ ๗E„„ ฐ3^UฟTTT˜ู.™™™ขำ๕ตถหศ‘#ํฌทt)++“Hxxธ๙ฌยh ฤฤDัฅฺฺ๔{“~&ั@ฦ แา˜๚j$%%E"""Dงม๊๖…Z่MgปxzzVs&o!€ถ8}๚ด๔๏฿_ฦ'๓ๆอณํอน8ฝภ_ev๚๚๋ฏERR’:ฝ  ะ๘$\ ่7๘โ‹/Lm—ป๎บห์d”––&อึซ7Tใ ฐตภ!}๛๖•Yธpกญoฯ@ภ‰Nœ8a–2j‘\///INN–.]บ8ฑก#€€= pฑงั /T!p้า%๓ฤx็ฮฆœ›››™ํdfปดiำฆŠณx ฐภ… คgฯž,oฝ๕–ํnฬ@ภฉ222dึฌYfหg???Yฑb…4kึฬฉM์Kเ?‹บ…แ@IDAT์|ว๐‡CคhกX‘"ม!ธป]Rม‚ป—เ-ญธป๗ทโ{ฏฝ^’หๅ"wทท๛›~hnmvๆป ไอผ‰๒อPPฝ@@@ 6Œ2dศ@-Zด %K–ะ๙๓็ษหห‹4h ๚๖ฃ€€vฟOูณgงjีช‘ŸŸŸv;ŠžAช˜-Z4J™2%M˜0าฅKงฮฦขU€/€€ พ เไ๓็ฯ—ั.œ;มรรƒ&NœHWฎ\‘ Lํฺตผwh> เ,™3gฆผy๓’ฟฟฟณ4ํ„œD`ฮœ9๒กRœ8qจTฉR’+Š/(€ิ.€€‹ฺŸฺ+._พLC‡ฅ›7oR้ฝ{’ฅz๕๊’%aย„Vิ‚S „_ kึฌฤVฎ\Jp%  œณ๎ท฿~ฃ/_พP๛๖ํe”KSฐ @@ตธจ๖ั aปภ”)ShาคITฟ~}Yนˆง๑|gžrTฃFฐWˆ+ X)3gNJ›6-ญ]ปึส+p 5ดV ๑ว27jิจ2ฺๅ๘๑ใ2ๅจN:4pเ@Š7ฎ•5แ4@– *Dฑcวฆ={๖X>G!„ 0lุ0Y้Œ.)_พผ[B8ป!8….N๑˜ะHDL€?)โOŒ:v์Heส”‘ั.="NDWฉRฅˆUŽซ!xI่(Qขะ๛แ@ L< ฺำำ“Nœ8Aฏ^ฝขฎ]ปR๗๎รTN†  F\ิ๘Tะ&ุ@`๛๖ํ2ฺ%I’$’ห…?…ๆ$ปœ`—Gป๐งI(€ย+PฒdI๚๐แ>|8ผUเ:@@‡gฮœ‘|-๏ฝฃวห๒ฯตkืึกบ hQ->U๔ !ผ^ๆE๓๒ŠIOเแปOŸ>•ั.*TแJ์† `Y t้า๒ษ4O]D `ฏjึฏ_?โƒขE‹&ษq๓ๆอkอฅ8€€S เโ „@ไ ฌ_ฟ^ฆeฬ˜QFทะ๔้ำ‰—[๔๕๕ฅ1bD๎ Q  yฮท๐ไษ:}๚ดๆ๛ŠB˜8q"M:U’ใ๒๏#~~~x‰xอจ€€zpQฯณ@K `Wฟ[–บuซ|บ”-[6 ย๐iฮํRถlYปถ7ƒœ[€๓Aนs‡.\ธเA๋!› ๐Rฯ<สvืฎ]๔้ำ'YIqไศ‘6ฝ'*‡ เ(\%๛B@%ห—/'Eง`ม‚’…ทgอšE2๚…‡๘ข@M€—›ฟ~:]พ|9ดSqะฉภŸIฝz๕"ะ‡“๗๓kN่@@ซธh๕ษข_ƒภฝ{๗dดห‘#GdดKฺดieด ็|้฿ฟ?•*U* ตแT@@5jิั-tA T`วŽิทo_ruu•ไธcฦŒก*Uช= €4%€€‹ฆ':ˆ ,\ธFEœ‹aภ€4|š3g5kึLFปDฌv\ hY N:ฤซ\บt y ด ั7„C€—=z4ฅL™’bลŠ%ษqy*3  ญ เข๕'ŒA Œืฎ]ฃกC‡ส›&’4iRํ๒๙๓gษํยKฟข@*ะ A:qโ;wŽโฤ‰๔0ถ! ๐๏ซWฏ–‘-ูณg'N–?~|j €€pัG!`ฅภฬ™3iธq’ฬn๐เม๒ า‚ จE‹ไใใce-8 ะ‹็}โi‰'Ož$ฝt„BPrดผy“๚๋/ษ 7hะ ฮฦn@ฺ@ภE›ฯฝ‚@ค๐'ี<ฺๅแร‡’ห%nธ4bฤŠ%ŠŒv)VฌXค•@ฮ/ะดiS:t่]%JไB p ๐฿^^^2}่ึญ[๒;CซVญย].„ เฌธ8๋“Cป!`G???š6m5jิˆ|}}eUฃE‹Q๋ึญษŽ-มญ ต ดlู’๖๏฿O dษ’ฉต™h `cฅK—Jท๔้ำหศNŽ[ถlY฿ีCPง.๊|.hT'p๔่Q6l)+qyดKŒ1dŠQแย…Uืf4ฐŸ@›6mhฯž=ด{๗nJ•*•nŒ;Aชเ฿ 8แ>/^}๚8y๏ะ|@ ผ:t ^๖u๛๖ํฤKหฃ@๚x๛๖-๕์ู“N:E฿พ}ฃ H๎ท˜1c๊=… `F3(ุXุทoŸฌ\คŒny๗๎l๓ชผœtผy-W€ฃ€€ๆ:w๎L[ทnฅอ›7ำฯ?ฌนกC€€yฮ๗ฦธ๐j†œฏำอ;a/  O\๔๙ัkDX€?มโี‰?ู๎ฝ;๑jFห—/ง.]บP="|T8ฐqใF  ,Yฒ8OรัR@ ๋ืฏง~๚ษจถ+Wฎศ๏Mš4 w}ธ€€ึpัฺE `gž>ภน]'N,น\?~,ฃ]’'O.9rไฐs‹p;@ภ<€ƒ-kึฌก์ูณ;ข ธ' `Gษ“'ษ”)=}๚”ฦŽKล‹ทc p+@๊@ภEฯ-„€๊8‘.nYฝzตŒlแ.<๚…฿xyzzRงNT฿4ˆ˜O)เŸ๙UซVQ๎น#Vฎ†T-ภึ;wส‡- &”ไธiาคQu›ั8@Ž@ภล๊ธ'4*ฐaรย 3}||ฺ่ตkฒ’Q† $ทKๆฬ™5ฺst เit]ถlๅฯŸ €€nธAฝ{๗ฆ/^ะ๓็ฯษ4ุSt €@ไ เ9Žจ๘ฟฦ+๑ิ‚พ}๛Rํฺตi่ะกฤม~CฦKวข@ฺเ„ูl๙๕ื_ หฤk๏๙ขGุตkyyyั?H/^”ัซ<Š€B@ภ%d" ภำ F%นHว—ํœ9sสh—t้าE v\ จM€งrฐeม‚ศใ ถ‡ƒ๖@ ‚๓็ฯ—ซœ—ํ์ูณ4rไHชWฏ^kลๅ€ด/€€‹๖Ÿ1z‡ xญZตdด ็zแd|fW<‰7ฎณv ํ†€๎”ULฐz‰๎=:ฌOŸ>ษH–#GŽHŽ–>ศฟวผ*  „_—๐แJ@ ฮ;Gร† ฃศๆ”)Sทyด rAD2ช€€xIh”๒ฯ3r2ูท€@$ ๐hSฮื๒ๅหz๚5๓ฯ2=ะีี5’๎€j ่W>{๔ช˜4iM™2…4h ฃ]ฆOŸ.ษ7๙ Aƒ(z๔่ชj/Xถl™ไaโŸื&Mš>ˆ-@@•[ทn%///Y๒๙ิฉSิธqc œชฒฑh '@ภล š ญ ๐ F้๘ห—/%—‹‹‹‹ไvy๗๎ไzqwwืjืั/8ฝภ๊ีซe2ฮหิขE ง๏:ญ ๐2๎œณฅ`ม‚ฤS‰8QnซVญดm๔€€]pฑ+7nX# $ํkฺดฉŒvแœ๓ๆอฃ–-[J ฦš:p `_๕๋ื“งง'ดู—wƒ@ธผฝฝ‰fณeหFืฎ]“ไธeห– W]ธ€B@ภ%d(p่ะ!ํยsส๙๓ฏ_ฟา๐แร)FŒฒ]จP!ถท†‚ lฺด‰บu๋&ำฺตk๔0ถ!<|๘z๕๊E?ฆุฑcSิจQ%y}ฦŒUะ:4€€๖pั3E  )กC‡าขE‹จM›6๒FŽ“r๚๛๛SวŽๅ—FMu€ l฿พ๘sษ?Ÿ(€€บ๘ƒŒ>}๚ศ*D๗๎ฃผy๓Jr˜1cชซกh   เขก‡‰ฎ@@ซปw๏–ั-฿}๗Œny๑โ…l'I’Dถsๅสฅีฎฃ_p={๖H`ดGิฅKงi7 =(Iญ .Lxแ1๚๕๋ง‡ฎฃ€*€€‹C๙qs@ภZฯŸ?หส KcงNจC‡ฒoฟQฯž=ฉs็ฮึV…๓ 8p@’ๅrฐ…ƒ.(€€:FEs็ฮฅ"EŠะมƒๅ฿Nu4ญ€  q\4€ั=hM€—ฐไ\.I“&•ั-w๎ก#FP† hเภ„y่Z{โ่ณ=zT–”ลt?gybhงึฟ/‰ฌOŸ>MฉSงฆปw๏สชDE‹ีzืั?@ช@ภE5 ฌเeข9— nแOา5jDC† ก-[ถฏผ€%iญ•ฤyˆ<“'OR๚๕ฉmถิทo฿ศซ5Aaธx๑ขไk‰-}๘‘\]]%9nส”)ร\.€ ๐ เ~;\ 8X @FทคM›VFปœ={–x ้‚ สrา)Rคpp q{่G€jืฎMญ[ท–ภง~zŽžB@]›7o– gŽ9่๙๓TฆL ถจซ•h  } เข็Œ^B@ณฯŸ?—ั-|แี*Wฎ,วŽ“7} 4ะl฿ั1จIเ๒ๅหTตjUjผ9 0@MMC[  3fHpฅx๑โด~Yช—kG ว เโwˆdีซW'tss“\.๛๖ํ“ั.sป$H ’๏ˆ๊ S๋ืฏSลЉ“q๒”?@ภพ<•oร† ฒ3็Tโkึฌi฿Fเn€ H—@ุ€œYเ๑ใว4lุ0ฺพ}ป,wYจP!:t(ธqCฆUฉRล™ป‡ถC@ีทo฿–ฉ 6”ŸCU7ƒ€†7ดฐ ภKG+น\xjรบu๋hาคI’ะ“?y#†…ซqภฃGจXฑbTทn]๙d=œRคH!ฃ]ฒfอชน>ฃCฐ—/ห^ฒdIš1c†ฝn‰๛@@[ถl‘iC1‚*Wฎ,ฃ]$H้๗D…p &ะฺตk) €\]]Cl6็oI™2%๙๛๛‡xเึฟ;mฺดษโy8= 9rD’ใrnฑ็ฯŸำ๗฿/S`y€œK็z^h- `cqใฦฯ—็! 6”„บ7o$ พุ๘๖จชเ)œ?ขSงNไ้้bห–-K‰'ฆๅห—‡xเ@fฆL™ศฯฯฯโy8ฝ ๐ฯ{ใ๎๎NG•ๅž๙฿%@pN\œ๓นกี€€ ๘ำลaร†ั?#ฃ]ฮž=+SŽ83x๐`Š-š ๏Žช! Nž={า‰'h฿พ}!6)qใฦฅUซV…xŽผA‚๊‰p@งบD‰6ธ#ช„€zศช*ๆŽ๓>๓๚๕kโŸ-่]เ๚๕๋’—bฦŒI/^ผ% sๆฬฉw๔€€&pัฤcD' [ ๐่^y…- )G...4pเ@ส;ทญo๚!  et O-2—<ืรรC0nธัl{•้DีชUCณBุฉ';w’———ŒjแUˆางO/?ๆ~ถ๔ไ‚พBะ’.Zzš่  `SปwK …sT๐่– 6Hฎ ^บณcวŽ6ฝ7*‡€^พ|Iy๓ๆ•dา 4ึค-Zะร‡i๋ึญมŽ๑___Yมศาด$ณb'4&0|=YชT)โ[š6m*?๋&บ@@๗ธ่[€@Xxฎ='ฮ]ถl™Y2dศ A777๙e9]บtaฉ็Bภฺ้ดiC๑ใว7;Bฅ]ปvtใฦ I๘iฎc<%‰ง>}ฺa์ƒ€.8๐ศ†๐2๊lแU‰8X‰@ฺ@ภE{ฯ=‚์ ภŸเ1B–ภๅฅr9I่ž={$ฯ Oซ@€VVฌX!IoO:ฌ‹]บtก๓็ฯหฯBะƒผฟfอš„้DAeฐญ็ฯŸหฒ๊<}่วคซWฏฏLฤK@ฃ@€€6pัๆsEฏ ;ผ^Fปฌ^ฝšบu๋&9-xeฃ๒ๅหำ Aƒ(aย„vhn๛ ๐ศ.sำ‚,-อวฬ^gเŽฐฏ๊๊ป7%H€๘฿N;n8ยจH๛> €€ฝpฑท8๎hN€„๒h—TฉRษา๔็Ÿส0๑*Uชhฎฟ่BšVิฏ_?ฺทo๑าAKฎ\นdฆ•มถึึญ['yฟ .Lgฯž%žZ็็็GQขDัzืั?@บ@ภE๗฿€"CเีซWฤ+ญ]ปV–๘ไ\/“&Mข† ส~^VZPฆ๑4:ำU87ลๆอ›้่ัฃบบeหโ้F˜Nˆ:˜€ ‰Iๆ๐แร)cฦŒTซV-Zธp!}๘‘ @ลŠ‹ฤ;ก*8N@Y™ฟืMW+โ)u<ลŽ—6-สt"Hfห–อ๔^C@ณ<…hวŽ”;wn:pเ€ไ>ชSงŽf๛‹ŽA€@p\‚›`  ๗฿ฒr/อS,x™E‹Q๛๖ํฉOŸ>ชC@-•+W–ฤŸs็ฮ56‰งI๐๗บ้ด!e)iBnฺดษx.^@@ซ๗๎“‘Žผ"Wผx๑ˆMเไธผค:  ่K}=o๔ฐฃภส•+ๅอ9rPูฒeiฮœ9”4iRY>Ÿ๒๑AเV6˜0aMŸ>]ฆIคNZ๎ม‡W$R O?๊฿ฟฟ9๗ ด,ภ๙‹8ฐฮ?=’^ณ’8qb-w}ƒ p ป!D†ย=t่Pฺนsง|โyๅสษ๓าทo_jถmdu@ภ!สด"ลฅRๆฯŸ/Ÿไ_บtษุ&>ฦน^xš‘iพใ x,[ถLฆ–(QBฆ๑t;๛€๔+€€‹~Ÿ=zุQ`้าฅ2ฺฅ`ม‚”?~š1cๅห—O–N‘"…[‚[A ๒xZฏดย+uqYฒd‰,•~ํฺ5ูV‚2๎๎๎d:๕Hโะภ่ัฃe#[xฅ.ooojบต†zˆฎ@€@xp ฎ žืฯ+๑๓Ž;Jž‹ใวหt‹บu๋†ฃF\ว peิจQ2j‹งษqย\๑r๚ui˜r|๊ิฉTฑbEว6w‡€ >}๚Dœ๚ุฑc”!CโQŒ|)SฆŒ ๎†*!@ภูpqถ'†๖BN/ภIE๙๒’%Kาฯ?,9/xE#ฦฤ‰ว้๛‡่G@มโแแ!#[8Qt=่โล‹3fLโ0œ8t๚AAOu#ภล^ฝzั—/_่ทo๒=?n8JŸ>ฝn ะQ@ฐ,€€‹e… `›7oส“'ORณfอdิหำงOiเภTชT)›•BภTy๓ๆLฃเ%p;t่@gฯž••YJ—.M:u"OOO[uBภaœ—หหห‹2eสDWฏ^ฅขE‹'ว-šรฺ„C€€๚pQ฿3A‹  p’Qž’มำ-&L(90x?ฯG€3(ซ๑ด!^ทE‹ฤDe•ฎ]ปvษŠ-ฮะดึ,Xฐ€†.A–?๘AEkะp  เขำnC๊เฃผ’Oรจ]ปถฌhไโโ"หG็ส•K= EK ‚Ÿ๒ศฌฦSฃF่ศ‘#TณfM๙๔ษrC@รnง็€y:uœฒ/h4 ุ^ใ€ฌ˜={63†ชTฉ"ราืฏ_O}๚๔ก๖ํ[u=N‚€ฃ|}}ษ฿฿_ˆ6mฺ”xไVซVญd/‹gเ\DœŸˆง%Nœ˜^พ|Iœฏ%Ož<ฮ5ด€l(€€‹ qQ5 ฐ \ธpAคธqƒส—/O›6mข9rศ๒ัฉSงku8vP’็ถiำF–ฎQฃ†Œิ:}๚ด]๎›@ภ–็ฯŸ—ไธฑcวฆ็ฯŸSฺดi%_KขD‰ly[ิ @@ภE]€ด'0mฺ4๒๓๓ฃJ•*ั๛๗๏้่ัฃไใใC๕๋ืื^gั#M๐H–ปw๏า“'O(I’$0ไ้(pfอ›7หHC^๖๘๑ใ2mŽW”C X#€€‹5J8€€ฮœ9#ฃ]}Jžžžt๓ๆMŠ+๑Šqœ—๓ถ @€ย*€€KXลp>  ๐/3gฮ”%xฏ_ฟNœดqะ A˜บแภg‚[เdฯ&Lภ๗d`l9ฮ๊ป7ล‰G๒•)SFพ— ้h" จT•>4 €@HGŽ‘.o฿พฅ)R็ฮ๐๖๖ฆึญ[‡t ๖C€€๕๋ื“——eอš•8V๗๎ฉkืฎฎภ!@€@่ธ„n„3 จR`๔่ั4gฮ*RคˆผA(Tจ๑ช0ษ’%Se{ั(@j˜:u*Mœ8‘rไศA—/_ฆQฃFQ๕๊ีีุTด €œL'{`h. Sยน2>|๘ นxYP5LOรk@0#ภyฐ6nHฉRฅ"^a‹W%สž=ป™3ฑ € v\ยn†+ จN€ƒ. .ค|๙๒ั๑ใวฉAƒ4dศŠ-ZธฺฺกCฉ‡๋B  5วKr\R๘‘rๆฬ)๙Zโฦซตฎข?€ เ@\ˆ[CˆLฝ{๗Jn—ฯŸ?SิจQ%ุโ๋๋+SŽยzฎ‹sยิฏ_ŸFŒึหq> ี œ8q‚z๕๊E\นrๅ ตlู’๚๗๏ฏฺ๖ขa€ เผธ8๏ณCห!เ!๑œวeษ’%ฒJฬ๙๓็%๑#'€ k)Vฌ=z๔Hฆ,๑2ฟ(€œ]`ํฺต’7cฦŒ’ฏ…พ๔๐๐p๖nก€  R\T๚`ะ,@ุนsงŒL๙๚๕+ฝy๓†2eส$SŒาฅKguตœ8rืฎ]tใฦ Zตjๅฮ๊kq" ต Lž<™๘O† ˆWy3f .\XmอD{ @@Cธh่aข+€L>}๚$ฃ]–/_N้ำงง{๗๎‘5jิศ๔ด_Ÿ>}š๊ึญ+ x/\ธ@kึฌก8qโ„x>@Pซ@Ÿ>}h๓ๆอไ๊๊JiำฆฅqใฦaE7ต>,ด €€†pัะรDW ˜ุบuซ1ห๛๗%€ย uญIYกBชUซํฝ›’&MJSฆL1w ์ำภ;wˆฟ๔\ไ ปž ั๗‚ า๙๓)kึฌaพฝ’๗๖ํ๔ไษษKลIฦQ @๖@ภลสธ  ผ^ฆ๑ิ ไษ“KBAƒ‘ปปปล–๙๛๛“ŸŸ-]บTFฦดhัBrยXผศFy ์#GŽศŸ7ฟั‡ฯึ฿(Jขo|บแ7/žฐBœ 'H›!#ล_พ฿ ฿๖ก๙ูŽNๅ}\ )กค๐v๒ไ)(u๊T#*QซVญ์xjำฆ ํ฿ฟ_VMใ~…ฅ๐*kœ7z๔่ฤoooI–:p. @ "ธDDืBp2M›6ษh—(†wP>คvํฺIIKจXฑ"Uฎ\™8ษd—.]hม‚TผxqK—ุไฟ๑z๚5๑ง฿|ฃWุไ6แช๔ว๔Y่ปธ.แบV๋=ธq‘ฝyญ๕n๊ข‰พ#Zนp-^ผ8\ซŸ…้าฅKTญZ5•7~๘0]ฮษqyQ๊ิฉ้ีซW4z๔h*]บt˜๊ภษ€ ˆ เQA\@ภษ8hม+s๐ฮgภ $y๙hž.aฎ๖o๒ษ0็?XฑbqB^ฤŠห้6ื A ถxzzา๑๛_้๎+› CfRฤ|I+ไท[ภฅlูฒ๔๔้S:u๊”™ึ„ผKIŽ›,Y2ษำ2v์Xษ๒8@ฐ.ถqEญ€T/ฐn:ใh~Sำฟโ)CๆJ‡ˆW<š={6ีฎ][‚4ผย‡=‹iภๅศฝฏ๔ƒ&์ษ{A€>>Dป4ทKภeผy4rไHI๔า฿Kๆ‰——mธQ๑่ผฐŽŒ1W'๖A€ย+€€Kxๅp  <{๖Œ†J’ื…“ไ๒6|1-ทn"~๓ยy_8q%'า1b„$ 4=ฯ–ฏM.‡๏~5L+ฒๅP7 Tเณ!เโmง€Kฮœ9)qโฤ2ข.h;ฬm๕ื_ิฃGบ~บŒŠแื<€ เH\ฉ{CP‰Oโ ็v‰#†]x8ฟiYธp!๑จžŠฤI,'MšD๋ืฏงŸ~๚ษ๔4›ฝฮ;75mฺ”xJ.6cFลQภ^—~๚ั๊ีซe cผyClrเไษ“’๗ำงOฦ|-•*URใ+ @ภaธ8Œ7†  .„˜Gทpฎ–o†ๅI8I-ฟ๑1-={๖คศกŽ;าปw๏hัขEฆงุ์5็š๑๐๐3ธุŒC D“khู|&อๅeœ9)7Z–-[b[”<:“ใ~๗”$Iโ|-™3gVใ+ @ภกธ8”7‡  >NŒ;|๘p บคM›–FeLจ๛๖ํ[ช^ฝบ,'พ}{ชZตชŒ:ฺ้ตซอ;ย~ฦํCภลๆธ‚ œ6\ ฤr@ึฅI“&t๘๐aฺฝ{7ฅJ•สโ-fฬ˜!9ZbวŽ-+M˜0A–€ถxB€์(€€‹ฑq+@ฮ"ภKFsพ~ำรฃ]|||จy๓ๆาC‡I…W6โO•yิ 'เๅ.ถ,ธุRuC t%เาฉS'™ฺ๚a;ใโล‹ะญQฃFจษn9ษ7O…๙3u๎Y p6 @ภ๖ธุw€ เด2ฺ…฿ิ”,YRนธธศP็uแ7=<iษ’%6ํ'.6ๅEๅUภึ—ส•+ำฝ{๗่์ูณ!ถๅๅห—ิฝ{w:sๆ ๓ฯ?24(€ 5 เขฦง‚6Aˆd˜;vŒ .ๆš๏ฝ+SŽ?N๑ใวงัฃGS™2edษึ 6ะฌYณd9i^:ฺVำ ธัธ„๙ัแDชภ™ต~ดd ฒล—ํท็…โ้‰P1WฮŸ?Oบu#บ$L˜x Q๖์ูอŠ}€ U เขŠว€F@ฐญ็[ูนsงไ7pssฃ,Yฒศž”-[6Y™(ดpr‘#Gส† าฐaรไ 'นฌSงŽ$ธq#ฅOŸ>ดชยu—pฑแ"Dšภูu~๔๋\\J”(AผสOY4Wถlู"+๑JjœTw๘๑๔w฿™;๛ @ช@ภE5  `[žไ็็GัขEฃ”)Sา๛๗๏้๊ีซrำŒ3สส๙๒ๅฃ"EŠ„ธิ๓อ›7%wร… (u๊ิ4u๊T8p %H€ขF*ม˜9sๆDzG๘mN˜ซ$อใฮWz๒6าoƒ ! ถ ธฬŸ?_–ฅ็ัsผ Z”ใผฟ]ปvไๅๅ๔lC€T)€€‹* @ภ6 2Oโ+qโฤ!ฮ™aๆO›y*O-โก;v์ oooโ•F"ณ}šฮœ9#8Y๎_E...ฤ‰vy๚ั๋ืฏ‰งqb[ฮ๕ยŸJsI•*•Œš‰Œ^#เบโ“ปื้่๖ีt|ืz๛๒นู ๚L฿DISe0S.Eซ6กšํ๗;ร‹WฯŸะๅc{(uฆ\”,MFghฒำท๑b€-˜9SŠ๘๏RกB‘ย8ห—/'mล+ขYสืย'lบ•6mฺD(ๆ๒ำO?ษ4ค ศ6@pด.Ž~ธ? 'เQ-œ`๗โล‹t๙๒e๙sใฦ ้O+๚๘๑#}๚•พ}๛&KD๓›ขˆ\B๛มM ˜7Š.์ค"•S๑อ o`ฃRTร๊T ’ฆ tฮศ6ฅู่ใ๛”ปd5j{ผใ็ๆ ำ‹ฆ๗mD7/ž ˜ฑฟ#ฯษ๋(Q๒4๚†ศธdธฬ7\x:แนs#tNุอS‡8W”ซซ+ <˜xT\โฤ‰‰“r›หืยฃ๎xy่mถัร‡ๅ:๔rะฆqใฦTดhัต C€"[—ศE}€t(๐ๅห™~tํฺ5 ภ๐ดสpแ}-ธไ+ซ&B๗ผ่`\ืT“ฅPลื%ไฤลŸ>~ แญJศhZ”97=บs^={"๕๑พฒ :Qฉบํีฏ–ฉ}๊ำํหงฅ9‰’ฅฆž† Kฌ8ึๅ๙PKœญJภEYž=ผํ_ฝzตฌfึขE ๊฿ฟฟฌ@ฦžšศ tM๓ต๐;%ศr็ฮ๚๑ว้้ำงlฉWฏ๑h‡@Pฃ.j|*h เ7Zœ“Ayฃ‡eก‰ึอJ~5:ฅฯ^ŠUkJY๒—ขhัc๗+/^?‹ถ๙Oข็=ค็O๎ั“{7•C!~-ฐ3U๐่โqGเ์\9ƒุฐDšัqไJ—ญ€#›ค๙{GFภ…ƒณ $^…ˆsฎ4jิˆn฿พ-ำ‹F-†œศ{๚๕hแื„ซอ\ฤK>ฯ่็a˜tุ'žTชN[*Xก>ลOฤธŸ_ฌ๐๓2$ิ]kว%นnบl๙ฉใHใฑ^p~—ซงะอ ว่ฦ๙cเH›5ฅฮ˜“าบๅ 1@๓ู๊cฺ๒ซŸแรฒใ?ค ‚ๅ๋QึBๅ(FฬXfou๗ฺYฺบdเถ!)n*Tกฅ5Œ^ฑ&ทฬงHปขวˆ)us@fใย1๔ื[”ต`*lศkƒ>ˆ\ฎ\นBUชTกิฉSำ๛๗)~๘ฒ"'ะผyณ$ใๆ"žžต{๕lใ>~‘ซD๒่ใhŸ7ฎmœHณgNื”ขI“&ั”)SŒ„1bฤ<.๙๒ๅ#ฐ๐Ÿt้าใ @@ ธhแ)ข€t €€‹u๙ึฅt`b:s`ณ๑‚%ซRฝn#ƒMแู0ํ]3Ÿ8แ=7๘ฒาJ๓FสHeป@ู:Tซำ`Rฆํ<{|Wฆณ^NแDปู่oQณ~๎ๅ2Yยนรˆ_้ำวd:เฉMฟ๎อ#^๋HŽ์4žŸ2Cvรจ–Ytฺ{Fฉ‡งต๐™!็ฬ๕m-มžบ]†ฆQ5}๋ๅ’@OฒิŒำญ\&ฅุ฿ล•Dม|ฟAKŽศน/Ÿ>2ณ3ป~ฮxOๅ…brึเ๘๕๋สVธผฑฟส9z๛šู่ajีผYธ.๓ห…๓ฒ(P@’ไ–,Y’$H 7F๔WGผl๙ล‹W’3ํซWฏไธ‹‹ ีญ[WV฿2=๔๕๙๓็%ูดฒ๎ป๔เมe3ะื†Uภ*VฌhŸน ฮง๔๚๕ks‡‚ํ[พ|yฐ}AwL˜0Ž=tทูํZตjษJcf'Š๓๒๒ฒtŠ๑'ไ๎ู3๐‡ฦƒ&/xๅ3e%E“ม^Z๛\๘ยC‡ป^ูQธ๐ฟ#/•m|ี—.๚z่- ง@ภ%lŽ๓ ,ึษธฬsn#(ฟ!ฑฎiQV:2 B˜W^ฐ˜ึฮ&›…+6คฺ‡(‡}]6พ7qะ…ƒ'รWฆ ‰z๋ฎ+hธžหฑฟัสI๒บr๓^†ๅงำ &†้=m#๚g9ว4Mืq+ ฃrr‘2%Š—ฏฎะค}๔‘ผkg“๓•q[๘|คŒžฐ๘ล> M๓j`\Zš4uบ “|4ฏ_Mœ๛…sศpP‡K#ฯฑ”งT ฅZ]~Hภ%gฮœTปvmโน(ฐฅฟA็Aฆ…งซนบบš๎ ๖šƒ#ƒ1€ม %ธมK‘๏ท/XAw๐ฒๅ'Nœบ์vฟ~จM›6f);9˜1}๚teำโืjีช‘ŸŸๅQzg|พy๓ฦb]|0y๒ไดaร†P9เj}|‚5}>x๐ ,oM…ฦ๛qา5ay.SงN 5p5w๎\5jTHท ด฿š๏ฐ™2gฮLƒ tsJฐฎPกBๆ๗qnญlู;j<ˆแ@ภ%\lธ€์-€€หโ<2ใฏ{7$‘,O ฉเ&๙uฏ%#>ŠVmB5 tช2ยE (9฿หCพ–Ÿฒไ6$™๕ žบณfึP9g๚&Jš*ƒrj ฏซ&BGทฏ–}#~3L๊Yห8ส„wr†๏ฅ”QmหาำGwˆWXชาฒ๙6.จ"า๏7ใ6๗yX‹ฒญ?ึฬD7-ฅ 9 S๛a‹ศ๔ๅย๖รŽ‘้Fƒ›’€OcŠ็š&๖จ%งฅH๏&ืว‰๗฿2žž4ษะ๛๛้tท ซ)ีฯ9”ju๙5"]‚กำ6ห๛N:‘งงงล๖๐R^r<ด’1cFโ7อ&;ดย#),pQฎ็‘๕๊ี 5˜ม็s"ค’2eJIJาq์W€M.\ฐŠ#kึฌก>ฎoผy๊ใ็nnไH8ฐgฉpภลรรCˆ[:O9v๚ษ๓•}Aฟ†%ศdM Œฟทyี9.#GŽ 5(ด=zฺFภEOO}… เฤธ๗๐fx{ศ*A<ํฅvง!’xึŠ?wฎžก)ฝ๊ษ…œ(– ฆe๏๏siร‚1ฒkิฺ‹’w…7”-œจถ็ไ๕td๋ Z=u€œRเแ๚™ƒ4หง…œฃ@๚Tห(ส”@‰ฒญ\rญ@ฅ๋wค‰ฟู๑šน…’ค๘7ฏวซ็OhhณbriํŽพโeฑ9 —‘ฟŸง‡ทฎGฑ๐พ ฃzๆnK—Ž๏ฅrบPพ2ตhd›2|šLฉ๊ฅ-†/Gถ›ื†ง$๙,o6Ž\ “%1L)jฮ)E:!B7ํ(Pนreบz๕ชLq3w[ž^ขžฎรซc…V๘ฎ5็…VŽCภึJะศš€ท…Šถm ตY\/Bๅยฟพ}๛JPศš€fจ7ึ๐ ธh๘แขk€ด$`pู็Wz๓QKฝ [_–Œ๎(G _อนMโŸH*zgXq็Ÿ—d๔ˆRs็1ห #V๒(›๒๕”a๚ฯRร4 .Jpให—ฯ4ฝo#บsๅ ๅ,V‰š๔ๅๅ™oา่๖ไ<žzSซƒ/˜.‹Lำ๙๛ม-๚cรc{8™nC๐"fœxิฏฆ›\c๚ฟjญ๛I’ห'๖ัฮๆbแ๛1,ื<ใ—ฆฆงJ~—šํ<๖ฎ™g\mจ^ืaT |}:บm%ญšโ#ื XดŸ๎\=G‹†w’msฆmหฆะ๖ฅS(}๖‚ฤนdf๙4ง๋g›wฯ#]xฅฃ7/j‡’“&ะNn๐ฐ ํฯ›7/ญXฑB‡่ฒšx๚อž={hํฺตกพ9TSปัhE@™๎eอ๔5ญ๔9<@ภ%ผ{-ygž=พG/~Dqโบะ๗ISะC_9h”&s.รˆ•Aซัvิ(D52#เขปฏโs‰.]บฆ3จ๘!กiš0L๓ gp '.ƒ ๛ pย7.<•—ศณ?ฝoƒLหแเฮฟRดЇ,ƒา]ฝ~!ฃCขD‰"#?xดIะยฃG|๊็–ผJฏ*ฤๅๅ฿)Šai`^%ˆฏW J”.pแยำ{xษ้๏โปRœx฿+ง๚สA—ฟ1ิ—8ะ6xสTรQ mฐT”ๅฅKึjMU[๕ตtช.Žล0ฤัชfBภEI:ฉLgpwwท*ญ“t อ„€S pภ%SฆLดqใFงjท=‹€‹=ตq/@ท.แฆ ๕BrQร*<ูd:PจXqภ๙ฅnN9ณ„฿ ugทx•้t%เb๑|๗๚นqลคfS({‘๓ืุ๐–ชฏี?"]6Ÿฎ๋๒ฑฃำ*(^ผธ$ฮตfฅ$5ฎMAภลฎธ „W—๐ส9ๆ:Iข$อต&เrใQšแD;feใิ$Gด๎ตณ†\0uๅึ> ๖ฆg%wD3TuO\T๕8ะ˜ pภ…—hทoL (หM#เ2>.!เ จH= +›2ดy1z๕์ ต0“ ”ถxีำ‡ทiTปrrฮเฅG ำˆX<฿–O๏฿Hczส*Iƒ–ฑๅญœฆ๎X†X•3F%ำŸCงi<ชYผูำ์ฃEวœD?ƒก?(\B7ย€  ำ7zศแข‚bExy้›OP๕6TผFK‹W|๔‘ผkg“sฌcฑฒ0|๕ ผpœ2ฦ๚.พ\นc๙4ฺ๊?‰rญ@M๛M Cmฺ=๕ป่D~7เย# ดY๔ฬi”ฅก๑้บำ<24TcJภeืฎ]”:uj๕.rบƒ€Kไ8ข@ฐฑ.6ถA๕+ผ่๘ฎตฤK9๗˜ธ6ิ;(#bŠUkF5ฺ๙„z~DOx๓๒) nRXชI™!;u๙ซฌžดxDg:wh;Um้E%kท‰่m4qฝiภฅ`ม‚ไ้้ฉ‰~กฮ-ภหาฝ{—ฒe๛7X๋ฝA๋!เ|พพพไ๏๏O‹/ฆ"EŠ8_์ะb\์€Œ[@€@ฤL.›ฎ~ฅ_"^'jฐญภฉ=๋i้๘r“ฮc–ำOY๒Xผแ๊)้ศถU๔ดไ,l๑‚ผ{ํœ!WKc-i๒Rruiๅ$oูgอT(ใล/&Qน๔ŽpAภEใƒBเ`Ÿซซkจ็i„๓็ฯำถm„ท๐ pฑ€ƒC€  ำ€ห†+_้ำW๕ด -1/๐แk๒iWึ๊เKE หM[*ืNAณ;๕จืิ ”,MFKงGสฑฅใzัฉฝf๋ฐh?น$ม์1ฝํt1ฌ]&.z{๎่/ \เ์ูณTปvmrssฃ฿ขG7ฬนD@ธ„ƒ€  .\ิ๕<ฌmอพ5๓่Kจู/ำ(E:7‹—}๒…–Œ๎FฏžEญ}็Pœx๖๙๔๐ย‘ดส0บๆํห็ฦ๖ๅ.Y•๗ž`ึ๛ \๔€;ƒภทoiํฺตTฎ\9Jš4ฉ34ู)8}๚tš0แ฿ถo฿Niำฆuส~ ั๖@ภล>ฮธ  DP€็ _พ|™VฌXAแAL\Lเ๕‹ฟiรผQtา0 ŠsฮtตTฆ6;Qง;pั้ƒGทJ`ษ’%4hะ ๊ะก๕๎๏tNK๘๚๕+๑”7nะCภปJ•*;vlใ%฿พ}ฃ;wา็ฯŸฉbลŠฦzัณgO ๘wdไฆM›(cFฦิปน3๗g~zh;  ๐งIGŽAภEGฯ]}๕์1ล> E‰ีทWํ=ƒนงล”"ี> 4 ๙wrเภิฌYณM=z$Sa8@๓ไษใyีซW7Žเ|LI„บw๏^J‘"…๑\=ฟจZตช|ฤ+Wฎคคืrแ|ๅZพ๔5ื…ศ0 ธ˜ๆrˆŒบQ""€€ I"~๚ #R‰ฯ0$อPxŠO52-Œiำฆ$ร (pแ€‚’๗ฅ[ทnฤB+๏฿ฟ—ฅค;FงNขdษ’I@ŒW๒แ MฌXฑฬVมSsๆอ›Go฿พ%ฮ)ำฐaCโOH%ฌ็s=ผาแุฑc‰”าจQ#YBีีUูeส๙o8Mโฤ‰)n\รผJCYทn๕๊ีK^7iาD–แ– ๙™๑๔2”เธ7ม@Pก\v๎Ieห– ิบB… ฺึำFh‰๚Œ bไแตp8จ๓เQฮ1l๐uฦs๘:“m~ญuLฏ7์๏“sŒ็?ธฤyค๎ ็(๗3žoxกิฌ|’ก(ื๐yZ(๏฿ผ ๛7.ฉฒ+/ก.Qhฺดi’BY*V•Eฃt%€€ IP…ƒ+nnnด~๚@ฯŸƒ œ0w๖๓ฯิฃG*Wฎœ1Q๎๕๋ื) @–9ๆโว/+qooojบu :‚nl฿พ|}}CœŠฤ”้ำง?3ฅpPƒง่m็1ผjRฬ˜1•ำ)ฌ็+r>›3f(›พ๒”4^"[ @๓ฯ?ไ็็' ๅDNคีฺ"#{x$ะG๐—ฟ”aHษ’งคไ)R๗ษqรdฤ5œ/ื^$3ฬฟแวิŽ^โz ๛”z๙ซ‹aภ๑๕น ฌตฯ็9F@๏o๖x ็Tแ2sๆฬ`ฃ@ƒ>๗ˆGip ƒงหpฑ”฿ฅjีชฤA‰๚๕๋ำˆ#‚VgVฮSv 2$ะj>'NœภŠxแ9<อ(w๎ฦU๘Zพฯ/ฟ"ฃvxด YU้ห—/a:ŸฏๅiM๕๊ีใ—Pแ~๐รฒอS`F%ฏ9ล#fMƒ3<ฅŠ๏อ9_๓OJŸ>ฝง”iV›6m’€’T ใ้g0ดG€KhB8@€ จR@๏o๖L—)KเำงOlเi1\8ธภyW‚e๔L๕๊ี‰Gx„T8™๖ถmไ๐ฤ‰‰0A ็wฉRฅŠŒ˜แใ]บtกŠ+OKš4)๑*@œ็…ฯญQฃธqCBฯ{๗๎…ุ้ฑcSำฆMe$ŠržŠห฿3< –๋T „8O x Oฯš3gŽ18ร็ :TFล(ืxyyQปvํ”M~ี๛ฯ`h—ะ„p€ @Pฅ€฿์ํปWฆ๑(•“'O’ฒ๊ฮแร‡้ว u๚฿ภi้าฅ๒l9ฉlขD‰=gด๐(EŒL:ีxŒ!<ˆ— ๆ …p )pรr‡.|mพ|๙ค;v4ึูพ}{๊ำงq›ใrž.OnGXฮ็‡‡‡\ošXv˜IOฮwSทn]9ย๙^8ฟR.\ธ  e›ฟrž›ีซW›๎าๅkฝ †๖ะp Mว!@€ ี ๐”อš5k๊zYh าทo_ ˆ(yQ8pข8ั-ฟ6—w‰๓•p€C™บรS”้IสรnีชํทxdˆiŽ%ภยวy Vูฒe‹ŒFแ‘2ๆV#โไฝœ/†‹งงงœkšฟ%sๆฬดjี*ใRำ•‘)8 @€ จT€๓o๐๊2EŠQi mื,ำBแ,ฆ…G‡p๎^eˆฟr”7oPผx๑$HยSx87K… L/ ๔šฏแ&ๆJะไธ<๒…ง q๒\e%ๅ:^)ˆG#eษ’EูEJPˆ>๓็ฯ—ULง-๑2อผ„3'ฯๅึ๓M ๓ด"žฎฤฃnฬvนy๓ฆ$ํ :ІG๑(— /๘๑ฃŒ์แUxไNœ8qŒว๔๖หOห>8 @€ @@uฆ—={๖PJร๒๎ถ(ผ4D”ยžrciฤศ“'Oˆƒœฤ7I’$-Z4ๅrใืัฃGห4ฆโล‹ำ‚ d?๗‰7<โ%h#ฌ็s…œฃfอš5ฦ{๒(ะ%Ožœ?~,+๑สH”โยI€90ฤž<๕*UชTTฐ`Aณํ็eช๚๋/J–,™ฑ~=พเ<8๑ใวืํ(ณะž9.ก แ8 @€  ๐๔PpาZ[žถฤนax”‰Œยy\8ท ็แ):ก•ฐžฯ๕qะg๘๐แไ๏๏Z๕’ง†Gท๐ˆD–.‘%‰z @€ @ภ*ž~ฤ๙\8ภa:•(ค‹รzพi=ผr'ๆ‘+ฆ…sฐ”)SFFฑTญZ5า‚Iฆ๗ภk} เข๏็C€ @ฐปฮ้ืฏŸ$อผysจ๗๋๙ๆ*ไฅฐy…&^โ™“๒t  +3™ป๛ ^\ย+‡๋ @€ @ \ผไr“&Mdตฃ“'OJพK…๕|Kuแ์%€€‹ฝคq@€ @^Eฉt้า๒šsน”+WฮขLXฯทXBภNธุ ท @€ J–,I๗๏฿ท:KXฯ๏Nxว เโw€  y3gฮศqKK‡j„ hฺดi2ญ่์ูณ!žง๋๙สu๘ G เโ(y€  q___z๕๊๑/ศ(€"[€ง˜pI:udW๚์$๐ไษjผ9ๅห—†๊]รz~จโุXฃz@€€^ฦO.\ ๙๓็๋•†l(PฅJz๚5ํทฯ†wAี€ย/€€K๘ํp% @ๆฬ™C[ทn%^ส€@d dศ2fฬH›6mŠ์ชQ `…ภมƒฉYณfดx๑b*RคˆW่๏\๔๗ฬัc@€€]–-[F , mถูๅ~ธ   /ธไอ›—VฌXกฏŽฃทP‰ภ„ h๚๔้4u๊TชXฑขJZฅฎf เขฎ็ึ@€4#ภŸ:๓œC‡iฆO่  ๓็ฯSอš5ษๆฮซŽFกะ™€pม—<.!เ @8pเu์ุ‘ฮ;Zp) เสT†N:‘งงg๐ฐฐน@ฯž=) SŠ,H#เb‡ @ฟ/๑Yปvmบz๕*E5แJ@AxQ — 0ุ„€4h@'Nœ ๋ืฏ๑ฎฮu+\œ๋yกต€ งธu๋•-[V~suuušvฃก€€๚”ฉ ศกg…jW€W ปrๅ .1.pp€ ๐ <{๖Œ (@ปw๏ฆTฉR…ฟ"\ @ ˆ€ฏฏ/๙๛๛;|*ƒ59ชRคHAฉSงาƒภ›/_พค๙๓็ำ‘#G0ณ?~|โUเB+œfิจQก&วญ \)ำธฌฉx๊ิฉPOอ;ท,ํฺ‰\฿ดiำB] gห–-ไํํ-ufส”‰๘บ ๛dอt4??ฟชด฿ลล…ZทnhŸน ~ึ/^ tศออœ๑ƒ ฌ่1š@ภล, vB€ Q/_พยปqใF๙ั๚p= E@™สภำฌyฃz็ฮบ>>|Xฉ"ะWำ@‡eห–-ะ๑ mฺดก={๖mvš•””$ภf+ฒ3y๒ได {ƒorภe๛๖ํม˜ู3`ภ€P๛ฬ†C† ฑ*@๒ใ?’5 œ]พ|ูL‹‚๏;vlจ+ธ๔๋ืผyผ‚ {ชUซfU9จ`mฑ&ylXพw†Nฝnฉ๐sแ๕ฏ_ฟ–ำ ,โ้|,ฒ–oๆภo[๓bƒtps๕ถlู2ิๅ–รฌใ{X“oฅaร†t๘๑@Mโ๏sE)เแ้D4x๐`e7พ@ภ%6!@ˆ<๙๓ำศ‘#%—KไีŠš ฝ (”x๑โั้ำงCๅเ้0ส่Ž๐๔ …ฤึŒ– zถ! ะCw๏•้ฝึ…8G’i0่มƒ๔๐แCณด&@i๖B์DภE'„ 8Bภบt้B /  @ะ“.zzฺ่+ @ภฮผ‚[xX4  @ะ“.zzฺ่+ @ภฮl)Qขu๋ึอฮwฦํ @€€cpqฌ?๎@ะด@ำฆM%ษฏ๚@€๔$€€‹žž6๚ @ฐณ@‡$9ๅ˜1c์|g€ 8Vว๚ใ๎€ M ๔์ู“>|๘@ำงOืt?ั9@€ T— "ุ† @ า๚๗๏Oทn"HซA€ g@ภลžฺ@pRแร‡ำัฃGiบuNฺ4€ „O—๐นแ*@€ฌ๐๓๓ฃ7าŽ;ฌ8ง@€ ํ เขg‰ž@€T'0cฦ Zดh>|XumCƒ @€€-pฑฅ.๊† ่\`แย…4n8:ผฮ%ะ}@€๔&€€‹ž8๚ @ฐฃภ๒ๅหษวว‡ฎ^ฝJQฃFตใq+@€ เX\๋ปC€4-ฐ~z๒๔๔ค'Nซซซฆ๛ŠฮA€@ุฮž=KัฃG'77ทฐ]ˆณ!เ$ธ8ษƒB3!@ฮ(ภษr;t่@{๖์ก”)S:cะf@ฐ‘ภ€่อ›7ฤ ึQ  E\ด๘Tั'@€€J๖๏฿O-[ถค€€ส’%‹JZ…f@€€FŽIืฏ_งy๓ๆฉก9h"]—H'E…€ (วŽฃFัฒeห(สn|… ศศ–C‡ัส•+กM เขษวŠNA€ิ!p๎9ชUซอž=›J—.ญŽFก€   Yณfัฺตki๓ๆอชhศ@ภ%ฒEQ @FkืฎQฅJ•hย„ Tฝzuใ~ผ€ ,^ผX๒4)€€‹&+:@P‡ภ;wddห AƒจI“&๊hZ@ชXตj 6Œฮœ9ฃŠ๖ ˆl\"[๕A€ `x๒ไ )R„z๗๎-ซเ ่^`ใฦิฝ{wบz๕*EU๗ะž.ฺ{ฆ่ @@5ฏ_ฟฆนsKฐ…ƒ.(€ E`๗๎ิถm[:qโนบบ*ป๑š@ภE3 จOเำงOฒด‡‡ 1t่Py๖ูgQA@ภ#`^;ฒe‹qวžtpƒ7๔"m@@ภมƒ–QฃFIŸ>}D฿ีgC@ภt๊ิIๆฮkrษ’%‹If€+ธธขi €ฮ1b„่่–ฮ;KฃFœ[Qj† ่={๖”)Sฆศ๙๓%_พ|‰|ˆ@0ธS—ฒ@@@ฦ/๛๗—7xCZตj… €สุฑce๒ไษRบtiO:ธA€€‹z‘6 € เ`%บWฏ^าธqcั‹ุ@0fไ˜1cคB… &™=ฎ เโŠnค €8W`ึฌYาตkWฉ[ทฎxqnMฉ €@b L˜0A๚๖ํ+ƒ ’jีช%๖ใyA เT^ G@… J๛๖ํฅjีชข่ฒ!€ `ฆOŸ.บuหฅ^ฝz&™=ฎ เโŠnค €8W`ูฒeาบukฉTฉ’ฝZ‘skJอ@[@'หํะกซ'6<ฯK.‰ยฬC@_UซVIณfอคL™22qโฤ๐… ๅ €>ห—/ท'Toำฆดlูา็: „ฒ—P๎=๊Ž €@lุฐA^~๙e)Rคˆ่|.l €ตkืฺ“ช7mฺิ้bาู#เ.n่Eฺ€ €€ƒถnjO˜›'OYดh‘ƒkJี@[`๓ๆอRฟ~}๛ซG‰xž‡@Pธ•—ย@@เ๋ฏฟ–š5kJถlูdลŠ€ € เุตk—<๗s๖ฟ ๐คs€€ธธกi €8pเ€<๓ฬ3’!CYฟ~ฝƒkJี@[ภ๑๔ำOห๐แร๛๑<  p */…#€ €ภ‘#GคB… rmทษถmA@ภ#p๔่Qy๑วฅ\นr2aยO:ธA€€‹z‘6 € เ`'Nุ+ฅH‘B๖์ูใเšR5@ฤ8y๒ค”,YRŠ+&3fฬH์ว๓<‚*@ภ%จผŽ €งOŸถ‘V‰C‡‚ €€Gเ๙๓R @ษ›7ฏ,\ธะ“ฮn เโ†^ค  €8Xเฯ?”|๙๒ู5ิ toฝ๕Vื–ช!€$ฆภล‹%Wฎ\๒เƒสงŸ~š˜ๆY]€€Kะ‰y €dฯžF๘โ‹/ไ๎ป๏@@๎นํึญ[็Iใ7pqC/า@.3gNนt้’ฌZตJ2gฮ์๐ฺR=@ฤะWŠ’'O.[ทnMฬว๒,‚.@ภ%่ฤ<@yไ๙๋ฏฟd้าฅขม6@Œ@‰%ไนsLฌn@ุปF€€‹kบ’† € เ\ย… หูณge๎นRฐ`A็V”š!€$บ€. ำO?1ฑzขห๓ภ` p ถ0ๅ#€ €€ฝไง.9y๒d)]บ4" €xž|๒I๙๎ป๏„‰ี=$ธD€€‹K:’f € เd๓ืห1cฦH… œ\U๊† ศUซV•ฝ{๗ ซ'2< บ— ๓@0ฝเƒคrๅส€ € เจ]ปถl฿พ‰ี="ธE€€‹[z’v € เ`*Uชศท฿~+๚๕“Zตj9ธฆT @ ฑ^z้%{tหโล‹E—ˆfCภ-\า“ด@ <๓ฒcว้ฝปผ๘โ‹ฎ)UCHl&Mšศš5kd๖์ูข“ฌณ!เ.n้Iฺ €€ƒ๊ืฏ/›7o–ฮ;KฃF\Sช† ุญZต’ๅห—หฤ‰ฅL™2‰xž‡@ะธ–‚@@ภheบuาฎ];iัข…If €€ดo฿^.\(ฃF’J•*!‚€kธธฆ+i €ฮะ หŠ+ไ๕ื_—ถm:ทขิ @ ับvํ*ณfอ’Hอš5๙<` p –,ๅ"€ €€G@ƒ,:โซฏพ*:u๒คs€ €@๏ฝeาคIาซW/ฉ[ท. ธF€€‹kบ’† € เ\Ž;สผy๓D็r้ัฃ‡s+Jอ@]เ๗฿—1cฦศป๏พ+ 4H๔็๓@‚%@ภ%Xฒ”‹ €nบษ๔้ำํ%กuih6@Œภˆ#d่ะกLฌn@ุปF€€‹kบ’† € เ\พ}๛ส„ คJ•*2dศ็V”š!€$บ@DD„h0^'ฯ}ํตื๙<` p –,ๅ"€ €€G@ƒ,#GŽ”Š+ส่ัฃ=้ € 0u๊T๛uำ7xCt‰h6"@ภล-=I;@pฐ€.๕9x๐`)[ถฌ|๘แ‡ฎ)UCHl9sๆุฏ้ŠvํฺตK์ว๓<‚&@ภ%hดŒ €F@ƒ,๏ฝ๗ž/^žหลคณG@@Wฑำี์7n,:ษ:n เโ–žค €8X`ฺดiาฝ{wษŸ?ฟ|๔ัGฎ)UCHl+VˆŽniุฐกผ๓ฮ;‰xž‡@ะธ–‚@@ภ่’ะ๚Wหœ9sสาฅKM2{@dบuาจQ#ฉWฏž๔์ู\#@ภล5]IC@pฎภ’%KคM›6’-[6ัฟdฒ!€ `6o,๕๋ื—Zตjูซ™t๖„บ—P๏A๊ €@ฌ\นRš7o.๗฿ฟฌ]ป6jL@K`็ฮvฐฅZตj2hะ ฤz,ฯA ่\‚Nฬ@@`๚๕๒ส+ฏH๚๔้eใฦ€ € เุทoŸ<๛์ณRนre๙เƒ<้ ๊\Bฝฉ? €! ฐeห๛;๎ธC๔˜ @#p๘๐aฉXฑขTชTIFe’ู#๒\Bพ i €ฮ๘๚๋ฏฅfอš’6mZูพ}ป๓+L @Mเ๘๑ใRถlY)_พผDDD$ฺsyม เlaสG@9pเ€<๓ฬ3’"E ูณg" €xNŸ>-ลŠ“าฅKหไษ“=้ ๊\Bฝฉ? €! p์ุ1y์ฑว$Yฒdฒจ1UDH,?S๒ๅห'ล‹—้ำง'ึcyA เtb€ €'Ož”’%Kฺ‡@(ูณg—‚ สนsฃคs‚@( p ๅฃ๎ €„ˆภ!๙๓็ทkซฏ้ซEl €œ9sJ๎นeแย…&‰=!/@ภ%ไป € ๚ืKv์ุ!iาค JSK@€ฮž=+้าฅปfy๓ๆ•ฬ™3หาฅKcอ;{๖lyเคTฉRฑๆใ"N เโ„^  €„€ๅ๒ย… ฒy๓fน๓ฮ;clฑrฎ[\~Aฑ. €pฃGสใ?.ซWฏ–L™2ลZŸย… 6ฌXฑ"ึ|:ปฎzืธqใX๓q'pqB/P@BX@ฺXงNkถ@฿อ?w๎œlุฐA๎ฝ๗๓ทmึ๋eปvํbฬร@ะะ’$I"ณfอŠตย%J””)Sสš5kbฬg8SฆLa„KŒJ\p’'๕uA@  ( :uบfะE™>u๊”ฌZตส6SSตผ–-[๒ืห˜€HGBH`ำฆMา AนVค\นrr๙๒eYฟ~}Œญำ—.]„ษืc$โ‚รธ8ฌCจ €ก&0x๐`{’รล‹ว๚P๙๒ๅๅว”O>๙Dฬ|.ั๚อ7฿H๕๊ีฏ๙‹y๔๛8Gpฎ@™2e์Q.๋ึญ‹ฑ’•*U’฿]พ๒ห๓่kDว—eห–ล˜‡ 8I€€‹“zƒบ € ‚fˆw‹-$ถื€žz๊)๛ฏ’K–,‘\นr๙miทnd๚๔้๕าฏ‰ €@h ˜‘);vŒq๔bๅส•ๅ็Ÿ–ฏพ๚*ฦF๊ศjีชI=bฬรœ$@ภลIฝA]@Qweํฺต๒๑วว81ขŽ\ั,บไงฎFแoำฟ‚๊r๗‘† เl๏๛๙๓็ํ+MŠฎแ>|ุ^ษฮ_Kฬศ>}๚\๓V๗“†ภ เr#ิy& €.ะื„t•ว{Lฦ๏ทuu๋ึ•ญ[ทส๙๓%_พ|>yฬ/ำบR…5” @ภ=าฏ_?ฉ_ฟพ฿*/ผ๐‚์ทOv๎้ทั๚๚๊จQฃb ฺ๛ฝ‘Dn —ˆฯฃ@p“€๕๒ฤ‰1ฮฟ๒๒ห/+อ™3G *ไำt๓:ัต^M๒น‘@ว œ={Vtb\ๅโo™hX๗๋ฏฟŽ1เขหA๋-1d@รR€€KXv;F@ แLภ$gฮœฒt้RŸ4o\Vฎ\)3gฮ”ขE‹๚\7›#Fˆฮ๗ย† เ.3JฅJ•*2dศ(kาค‰= า_@Eƒ5:๚ั฿}Q แ‡ pqX‡P@BUภผค๕๗๗Žฝฮ๓ข+M›6Mt‰h๏อ๛ุๆx๑พ‡c@ะ0“ฌkญur\๏น\ttใฦeืฎ]>2“๎๚๛ทล'3 8H€€‹ƒ:ƒช € ๊fศwฺดi%๚๒Ÿบ:ลผy๓d๒ไษRบt้(Mีั1:แฎ5?t่P”kœ €ธG@—vึIึฃฟ>ฺฆMYณf฿€‹น'zฦ=*ดฤญ\ฺณด @  “"Ž9Rฎ\น":uŠฒ’„.ใ9u๊T๙๐รฅlูฒQjงฏ;wNŠ)"Z €€;6mฺ$:_Kš4iขฌXิพ}{๛ตS#\t9่Œ3สฒeห‰Bซ\+@ภลต]Kร@H|๓ž}๙๒ๅํั*ณfอ๒Tbภ€2n8๛๋๑ว๗ค›ื‰2dศ 6K& €€{ฬœ]ฏu๎Y–,YbOœ๋rณ žŽ’ไ฿oŽCA€€K(๔uD@ „ฬ/ฤ:d|ส”)RชT)ป๖ร‡—>๘@ฦŒ#*T๐ดH_'าฅ@uจ8๓ทxX8@\+`–ˆึQ+ๆ๕Sท`ม‚>3>ธ๖วมี #เโ๊๎ฅq €$พ€5R_'าQ.บLดๅb~มŽพ ‘ฅSW6ฺถmห}&~w๑D@ ัผ—ˆ6ฃ\tฏ“ใ๊าะ›พNคฏญ_ฟ;™cBB€€KHt•D@ ด๔d}GิจQžQ+บ:Q๗๎ํQ.•+Wถd^'าเŒB}™ะะj5ตEˆซ€นขื€ผพvช๓|ํฝS„๙7"๚ปž  เp.๏ ช‡ €@( ่ะ๐Ÿ~๚ษขh5๒ัGษoฟ-ƒ–ชUซฺอ2๙๖๏฿/-[ถŒ2ษn(ถ›:#€ฤMภLžซน๕•RP]ฟผ.๚oฤ๔้ำe๕๊ี’)SฆธL.$@ภลAAU@p‹€๙ซคพ>คeZนnีช•ผ๛Rฝzuปฉ๚:Q5์‘0Bํ–ง €@ผ'ฯ=u๊”=ว—wภEฏ๋cนฯ่Sชˆ$ค€ŽxิWOซTฉ"นs็–aร†ู6่3ฬ๊DfŽ—„|.e!X\Kš็ € f๚NพฎR๔ุcูฏ5mฺT๊ีซ'๛๗—็ž{Nผ_'b9่0๛แ น €€%p๔่Qy๑วํืO[ทn-ƒ ๒\tŽ—5kึศ็Ÿ.้าฅร  เ’Fฅ@pพ€ฎBQธpaัฟNv้าลพ่Dบ๚๕“Zตj‰/Rคˆ,^ผุ~ๅˆ_จ฿งิHh yเภฉ]ปถ,Zดศธ่ฟ:™ฎ~1™zB‹S^b pILmž… €@˜ ่_(uำ%Ÿ๋ิฉ#C‡ต.นrๅฒ็qั_ฆY(ฬ~(h. เ% ๓ณhP>ฒo฿>ูณg=g‹ ิ—*Uส+7‡„–—ะ๊/j‹ €@H ˜U(4ฐ๒ื_ษๆอ›ฅo฿พr์ุ1{ซฆพvฤ/ิ!ีญTH03R็๙:sๆŒpiธฑœ;wŽษrL™‚n”—%ฯs@ูข›ฎTค{๏ฝ'“&Mฒ๕๊๕๋ืว|CO๓ZQŠ)d๙๒ๅ๖ผ.L–ž? nk5ท๕(ํA@ภaบาDงN์ฟVjีฺทoo/ ญวบBQปvํ๔ @ Lt’u฿+y๒ไ๒ิSOูฏกŒำ—5›€‹ห:”ๆ € เD ๗ฤ‰vีž~๚i๛/˜ฉSงf๕ 'vuBYภฌV”4iRI•*•t์ุัž๗+‘ซมใHp. NJ € ]ภLŠ˜$Iyเ์ฅ@๕j}OŸ @bลŠษ้ำง%C† ผjสƒkธธฆ+i €ฮะIห•+'็ฯŸท+ษ/ิฮํ+j†fอšษชUซxี๔Fเ๓ฬ  p -#€ €€ทภเมƒeิจQvาˆ#์๗๔ฝฏsŒ พ๚๏ยะกCํ ึำฅKพดU\\ี4@็ ˜w๔๏บ๋.๙๒ห/[Qj†a# +ฅ๗฿r้า%นx๑ข\นrE.\ธ`้๙ฟkง{›๋zอ›๛5Ÿ~™sk๏ss๒ๅหvบูk๓ฅi_Z/ฝf๒๊นนฎวบyŸ๋ฑI3y๕\M~s์oo๒๊k f3๗™sณ๗N๗ฮoฎ›}Lื4|i^sl๖๗kšูฬ๕ธ๎๕>sฟฮฃวfoสˆ~n๒่ฝัฏ้นwš9žๆฏl“ื๛šwš96{Sธž›๚šืฺ›๒“%Kๆiำต๎นึuำ6Sถษฏu3ื4M๏ผ๓NMvๅFภล•Jฃ@pฆ@ํฺตๅ‰'ž:ฮ†H}ลฑ@qช‚~(ิอ{oŽ5]?8๊ฆiๆ+๚นI7{๏๋ๆƒงนvญฝ“fสีฝnZ–ู›rอน}ม๚ๆšฟssŸ๎ฝ.้ๆน&-z>sn๖ั๓™๔่{องi&œ๋๓ผำอ๕่iๆ๛บฟ{อuSพนฯœ๋^ท่้ๆพ่๛ศyy_๗>6eFฏ“I๗วTf๔<ฆ|“฿์ฅว5อ”‘{m๋มƒข(ว•Aภลq]B…@@@ ุงN’%JHห–-%Oบด’ิ๚ะงแืษฬ่ซ—tดษี๘๖๋\?”jšUโ}]ฏ™ฏหV9:Dฟฬจ๛K‘#P์c-ฯnldyvซๅ›r<{องๅ[uดย$W๏ณ’ € €$บภฯ?,>๚จDŒ#ลญ.l ธ7็ศ)”y๓ๆษพ}๛๗แ‰๔4.‰อc@@@ภ9'Nœ2eสศ‡cวJัดiœS1j‚@˜`v้cญN5mฺ49pเ€+[Mภล•Jฃ@@@ 6#GŽH… ธฤ†ฤ5‚(}๚]ฅ>—'ฅ@@@pบภมƒๅ้งŸ–Vภๅ.N๏.๊็B›า฿+ณืญ“๎ปหส•+%kึฌฎk%ืu) BWณgฯบvYE๏>-Yฒค๗)ว1\บ"rEฟฌ๋บฟฌ_^วšฎi๖5๋@ฯM>๏kวzฟ็ฝp๕<ญตbhฦ4I"๘Ž@ˆ์฿ฟ_*Wฎ,3ฌIsaา้5ช้&dw%Kv๎”:ศขE‹$OžหmIค`.AEฆ๐ะv?๛์ณ2ำ ธไ%เ’เพn.๐โลKฒเ๓ต๒ด๕€ิท๊ๆฆตmษnฟCVY#อZทn-3fฬขE‹๕y7ขp.7Bg"€,ฐiำ&YฑbEŒม'4rๆฬ)iา$าฃล‹ุ1z๚A]7๓แ ฎ˜Huอ์๚WoฐำฌoWOํ2L @OฬฑูLบu“>O7sฟ๎5ฏnfo‚ vฒ๕อค๋๙Ÿ็ฮสฑ๏๗—_?๛_อc็ทฏ๖ํท“วๅฬษโเปoI•F2dฮ็~ฯ}rวฝ๗Kูj/หร™n—้ ธฤŒŽุปwฏTญZUf[—<\ั'กR‰5ถI๋Aƒฅtพ|2ฆSวPฉถใ๊™ิ๚Cฤ๋[ฏฝ๖šฝ4t0~ฏนั&เrฃ{€็#€\—ภเมƒeม‚RฃF๋บzn๒ XŸไํ €๙ไo๊G?่๋%sู|๐ทำฎV ถ<;ฌฬ:jแjYๅh1ื*ฯ฿usŸฝฟZ†ณ!UsFKณ“ไ้วKK{ธฤวŽผ7^เ›oพ‘๊ีซห+เ’›€ห๏ชมฺฏพ’V๏’๏ฟ_B5wVU“šJถœ>-5b„‹ณบ†ฺ €„ณภพSWd๒˜ม๒อ๖อา{๔์ศ€ƒ๙ะเ‡ŽฤฐGgุว‘ Pุiึฟk&กi0:+ฌIDAT๗›|ๆ=gCoUษ!/u&uช=-น๎"เโ_‰Tง |๕ืRณfM๙ศZ:หB;ต›Y/3ยๅ๎o—ีฃF:ฒŽกPฉ$)n‘]%๕๋ื—ูึ๒ะ… …jวซŽŒp‰™@œ ฐ์ภe๙xา๙n๗fy}ภ,'T‰: –pyขvsi฿พ…๊บ.8yRถYozทlฺตหถxt๋-ทศถmค”5J _-หฌนreฮ,?๘` ล]๓%6Hง‘ฃ$ใwหงร>ธf~2๘H’$ฉ|Ÿ2ฅTญV.‰HE@ ๑ึน,=[ฝ Gฌ€หภลฟ<ไะฎM2ถ๋ห’ปH9=.B๎OKภ…‹ะ0—EใวIึิฉCซ๒ฌํมฃGๅหo๖ศkนํm฿~๋`๑Wๅ*U”.ฏผโ๏Rผา>ตVl?lธdษ˜Q>ถๆTIš4iผ๎oๆkืสปcว1‡K|แไัš8๗ikต0]ฅจXฑb~r„v#\Bปจ= –›ผ,]šp หฮงัŽ0—,น ษ”ณ%c.Ž้*'ํทKํฺตๅใฑc$[ฺดqบ‡Lพ็Sš๕๋/_[ห๛๚4Rถ@y =’Ž;D็=๙็฿eพดจh}ภ.Ÿ๓v,ทFทt>ย~ฺัฃไฮn๓W•K›ฝrฅ๔pขไ{่!™ณG‚•Ž˜*ตsถคOMภลอํฦถ™.‹วŒ–,้านฑ‰‰า&3ฌ๗รสX–Jล‹ูฏ cY‚ฝ™W|๔9K’ฬ2ุินc’Xs„$๔6uูr0uช”|ไืนSBVๅdญT๔”๕J—ฐ๊v‹ เdoO^‘V".บ$m๖ฅœ\]๊†€+ผ.:ูแ)]ูLๅbญ[ทJบue‰5""sGDธ˜Qฮž;/5~[Nž9cO";ฃWOน?}๚Dm๒ฬO?•๗&MถŸ™;K{ํ‘#๖^ฟ=`ีG๋u›5ษmBl“–,•AำงหE‹สะvmขศฐ-ใ๘-)ๅษ5dบๅYผxqื9๐J‘๋บ”!€๎๘ฬiฺ€€‹๛{š:Yภ\nI•F6lู!ทฅprmฉพ›7oถ—ฃ]npนŸ.พ@๑H้5a‚ฬ๙l•ฬ™Sฆt๏;ฏ/๋วŸ.Ÿo฿!ฟXAžƒวŽษŸึคนฑm:A๏า!ƒๅฎ ฌE|ผH>˜5Kช—/'ฝš5‹ํั\ป†ภึJEO?<#\ฎแฤe@Mเว฿ฏHฏ~ƒeีœัRฅQ)[ฃqข=›!€@ค€ ธู่Žฝ‡$ออศ Z›ฌy?4h ŸX#\๎K โก%pต5—ฤ˜ำไ๛”jouˆต๒ZยV๐'އฌๅง3ษฝw%7”,ึ{โsq๘œน2nมฉิSาฑaƒ๘Jh?\yถ^=™9sฆตF นmc„‹z”๖ €a ๐ฟ๓Wไ๗".Oิn.Oฝฤp0่vš่0๏€หž‡$Eย}–qXKฉŽ[6n( 6”Oญ€KF.uณ ธhpc^~>ekM’๛๓ฏฟสษ฿~“[nพYzเนฺู{o/^’งNสฉณg%•5"ๅNkิ‘ฟษo8qBžm๗ฆ๗ญ๖ซLgฮณำ>|งซอ“'ส๕ุN~?^Ž๏rูš๏ๅ6kตช{ฌI}Sคˆ}ศ^฿ษ“eฦ'ŸJS๋U˜VตŸญxฎ]Cเฐี๏U_z‰eกฏแฤe@MเทD๎1ศแBภ%ัุร๚A/+W._’ไ)˜จฤ x\พ=pH’wV๓X๖$˜ภ๚๕๋ๅkIโOGސŒ‰0ฑk‚U™€‹พบ๓ญ%ํญทสNŸ–]ษNk๕ข่+ฝb-ฎ~=OKVZฏw๕<ลžฦ“hผjญ^ำฆ๎ I๖๑็ึ SŽ“"นs‰ฮู๒รฯ?KญŽ‘“ืฮ์K๒>๘ ฯ=ั~ณ4ฆL•ฅ6Dนคm๘จ_฿X็ก้2zด,Zท^ฺY#3^ฉ๒l”๛9‰Ÿภม?”šหผy๓ค€5ูฒ6FธธญGi \iNdภ%w‘rาจ๘0h5Mผ‘๖h"฿n๛\^|{จไ๔™Yว<;เฒ฿๚P•,‰cชFEˆ“€'เ2|˜dผ๋ฎ8C&&เโjิิยนsKำ๊ี์Œ๔ส˜๙ dไนQ2eผ๛n9~๒คV๓ฑ๒าฃiำ(ืฃŸbwžxฝฅ<ถSGOูั๓™๓cV€F—ฒึ‘-fำ@‹ฎจtไ๘q{ฤฬจท;ฤธi3xˆฌฒ&]~็ีFRปBS๛ุ๋{ๆ7ฉำข…ฬต~ ,x%8๛.ฮ๎j‡ เGเ’๕พo‹.‘—,น ษ๋f๙ษE #p้าE้X=rxzมrUค^๛A Spˆ—โp9t่Pˆท†๊‡ฃภ็ึฤซฏพ๚ช,:$ึั แh฿6วpั †พSฆ@~)/Ÿwฯ=Q–ižพ|น=สDŸง๓ฎดณFณส•หฮc‚zmLวทฅtz่wำ•’ฝ”้๗z ฉ่ฃ~๓iขพB๔|็.ž€Nซฺตๅ…Š$ญ๕:ั~็ฎŽ”‰m>šฦ}๚ศๆo๖H_๋Yฯฦ๒ฌ+มภ๖ใ'คแ›oส,kโ"EŠxาr@ภล-=I;@0xอ ธ|6{ดp‰_วy๎Œ|ฟ็+๙ืIๆๅพlQ฿s้๛ฝ๒๎อ๒hี—ฃRฟงธ+๗ษŸพ—ฏ=e7*_้'ๅฅŽรีภ๋l —๋„ใ6วฌYณFš4i"K’L28ฆ^กX๏€‹*๒gฯ.O•,!yฒf‹qฒฺใฟ"OพัฦnฎeFพี^RZ๙็)๛Zsฯ๊Cgห&๚ชP’$‡า๙w)์5๛žอšJ๒ๅํc฿zDDศผUซํK#ฌg–+Tศ“mโโ%2xฦ ฯนŽr)ใ็5—฿ํfฝ.uะ^Z—†fป~/‘&;ณJั๕r' € /ะาzฅ่“™\โ"ซ#4ํ๚B62Kvฑ2ส-ฦ|"w฿—อ“ึฏI๙๕็ฃผ:ใูปeตL์๙‹|ŽฅฅIฏ‰^Wร๗€K๘๖ฝ[Zพjี*if-้ป่’๕พ๛าฌาpน=MY7nlœ๊0uูr0uชmMR;๗ฝ>Q&ศท`ก Ÿ3'J9[ทฒ‚8%ฃค™“sึ< ฅฌy@tฺ๋่ฉSฑขน$kถm“ฉห?‘!mฺˆŽธั‘0บŒt๋:uค‰๕j“ูtไKลVญ=AMฯ’1ฃ,่฿฿'hTปSg๙๖ศ‰ญNฆ\๖ฑ ฌท_Z๖์)ำงO—bลŠลž9ฏ2ย%;*#€ˆด้6H–L'เฯย/วษ–•๓d๊๒วู3~ณพ5j™๓@vฯ5p)์‹Rฝูปž๔p>๘lึH๙t๚6ม}ๆ‘6C†3‡งํ\<„จภส•+ฅy๓ๆฒ`@ษnญšรv&เขอ?ŒSAo)หฌ•ข Zห7O้อพGW*=พฝไr๔Bfผ๓B๎B@ แบ๔$ณ'Žถ ธ๘@ย? KิyFtพณซXKช6๎$)nMc’ข์gผ฿Nv|sฐJGฦ<”ฟ”=าๅ‡‘{๎ฯ*)S฿ฅŒP8น๐ฯ_๖(ดw#ษSคŒw•6าŒzพUo)Vฉvผหpใ \ุซแีฆ… J๛๖ํล|ˆฏึ'lk/_พ,ซถnตƒ๚*P|6ม๒“ตb‘๎3uทฯตeํถ– zจDG$Yฒค—ไŸตƒ#ฤัM-ีส–ตGฌ่H™่%?Ÿ:eOึ{›•7ฆํ๗๓ศถo๗J๋5&๏ภส’ ์[*Yฝ|๓อ1N๚5fYs)๕4ูแRิ…+>1i๎5~ธŒ เLw$3?$เโ;บไ๓่Ž๕ญื€y’๕5 วžk"ลŸฌ-inฟ“ฎณ‡tฐ&ิoX ฐ˜ษuณๅ-*อ๛N’฿฿‰‚|`ว9ผgซฺM’คI%๋รE$SŽ’5Oก4ว~-ŸN๛@NA2ๅฬ'%žฌ#Y๓๓ผY๑อฏ๗zโ{ฒ[๏ ’ฎ2Tญi—({?K ๙๋(s˜ym4฿;S6Hฺ๏๑พ%l ธ„mืปฆแ}๔‘t์ุQ&Zฏšฮ•ห5ํ ๗†hPๆŸ คภC9b „ป“SฺฏซU ดFทฬž=[ y-ัํ”๚Z. r? €ภ ่ัoL เ_Gsฌ[8Qึ/ž์ ž˜<๚:Ly+๘’๎ฮ{ํคฟ๘]ึ}<ษน’M2็*`ฆผ๗บฝtt๎"ๅคQท๑ๆVฟ๛ใ‡ฟ•…czสแฝ_๙ฝฎมžบoพ/yKTˆr}ๅฬฒbฦฐ(iz’1k.๋™ใ<๕3โ›_๏๓^สู”c๖Xj7|q”ภษ‘oทหG#บz‚U๗fส.ีšฝ#ู๓•”๎/ท-ีจๅภจห”š2รqo.wsฏl๙—pt อก+ ๐ฺ้U"ฌีjŠๆษบ กๆ„ฐ@‹dฮ2o<)`อ“ใถ€‹z”๖ €a"ะgภ ™8Ž€KLญเ๎๘‰P™่™ฤไีyX*ีkํw4ษ‘๏สŸฬฒFไ—V๏ฯ5ท๘์wฎ_*ำด’ฎฏๅ*R^gฐูฟ=๒={อ๐๘๓อค’5๏Kฒd7ษฑƒปeXป็ข็}rG๚๛์‘5ทัNŽo~ฝiWŸKD๗&žbu‰๋ฬ9 ศ๎MŸฺม$ฝPณyw)iญุคมe;ฏุว฿๎ผ7“ผ9bฑtฎ•฿N.Uนพิxญ›w–ฐ>6—\๙ ษ’๙ขย๚‡!D?cฦ ้ฝป=9k๑ผyCดTะˆX๘ฑ|`?,X <๒Hh7ฦOํ ธ๘A! @ภ๙“งฯ–^บุe—ุ๛๋ศท_ษ†ESdื†ๅžŒห=+ฯท๎+ษoNแIำƒ%๖“ฯ|(๘่ฑ&ส5๏“ล๚ฺ#iLZฑ ฯI=ไฆไ‘๏ฑŸ฿1๛•กํkูYtข] ๔L๊\๖l^en“๛ณ?bj+;ญนdEDฎ๔๐p๑'ไๅฎ‘มด๘ๆืืz6(-ง่›&='H–‘“ ๊kIรฺีฒŸ]ฑnK;่ค๗kZัฮฏด9 —‘Gศ9kuฆิท)ซ็Žต๏ษ่ำ๒โqŸ าพษๅ฿ช’Cr[—ล\\ำ๎lžNาูซW/v)้ยz๎์5Zๅ61๓ศศนseัขE’ว…#อธธํ'–๖ €a"ฐvFiJCปต\โึ้p˜ิป…g™็ฺญ฿“ขึฤบ›Y้H_ป้>mณ๗ฅ(วO‘…ใzi%ŸzAjพ3สus2sP{ั ‹?๚ฬ้y=ว\o?rฉคฯ๔}๊=งLซ๗็Xฃlฌ%8ฏพฮืซf’Oฆ 5ูํื”ty๋?ฮ%เิฌ๗$ษnMผiษTY0ถ—ฟ–ี†โV[ฬv๖ิ ้J9sj๏๛ฮฦTŠr!LOธ„iวปคู&เ2าZํฆtศ‘l.iอ@ dFฮ'cๆฯ—ๅึ=๙๛@ศT>%เ$ฒ €8O`รฆM๒rƒvลธˆœ๕g9๙ใ๗๖ฤณ๚๊NLฉใ‡eศ5์๚ชM๕f๏FษjFธ˜‰นจ๓ฝ,ฐๆkษ’ป ๕*N(ŠทF-‹qฺนร:ห–•๓์bบN^/ฝ–1Eฺฃ[๒‘็\ะ๛ๅฒ๖yvญื“สJทzล=ืu4L์๙หIŸFๅํถyO์)เ๊w€hbฏfึ|/kD็lysไ2OV xj฿–žWฬ…&=?”5งaฟ'เ๖?! 0u๊T้ำปท kฆ”qแ!9T>l>˜5[">XVZซeอšีuํ&เโบ.ฅA €@xlฒ. ธx:{tง๚๖*A๚*Pอ=%›ตโO๔ื…4๓ัปd๘›ฯ๗ๅ,TF๗˜เ)C>Ÿ!K&ฐำ๚-kฯปข'fD‹Nlvุ"ู้l™7โ;_๋ม๓ไ‡๒ูว฿ฬš–=Iyถั2๔๊Yคร˜Oไ๎๛ฒูiฟŸ๙Ez5ˆ fิlM2Y#Sโ“?Uบ;ejฟึvY:๗ŠฮcฃอVนt้‚—5yข†,_ีS‡ฑ]สก]_ˆ.กผ5โGท -s†u’๋–ฺ็๚๚ี/V0๋ง๏๖Fษg_ ๓opyแ•ๆาปห›a.A๓CQภธ๔้#Cถ‘r.\%๛„:‡Ÿภ ้3dา’%๒๙็Ÿห}๗็:.ฎ๋R„„‡—จ<ญQ^™ัซ:Jk<ึ |+ฟ|ิ>ืoฏ˜eX)ไ9ืƒึ๋?3ฌื€t3มK—.สจท๋สัปฤฬcข#e๚7{าฮงฃCt2ูŒูrAŽSวศฦ%ำ<๕ัษt[œ-'๏—ั_ฒ๏1฿t$J๕ฆ๏Hฺ;๎ฑๆŽ™`6ัkฯท๊-weศฏ:หขˆพvัฝfm“[Rฅ5‰qัํU{‚_}~ํึ}ไึดทหQ=ไวCปํ{tTM‹3ไซU๓ๅฃQ‘ๆ๖˜ฑEnMs[Œe†ำ ธิmิ\zu&เN๎–ถN™2E๚X—แŒpqK—าŽ่o๏pฺ๒Odใฦ’>}๚lA์U&เปW@*@ภ%jวhdD‡|–‚Žš+๒L_ช๑ฺปึhš>—์ุ ใ฿mdง็)๖˜ฝ,๒ฎ หไ‡};ํดๆ}งูฃg๔ฤฬฯb_ˆแ›[š๖žl/๕์ฝzPน์ษyv฿ƒyคๅ€ู๒๎/=ซ ล%7_ฎ”ู้EVmYสT{ู_๑QาVอ-ŸL%อœ่2ะkWnทFฝeอ'Sา~])ฎe›rผื€ห‹ฏ6—๎ธธนŸฺถ9sๆุหBฒ&อ-•ฯw”ž[Mปp’@๏‰e๖Š•๒ีW_Iบt้œTตฉ —aค@ฤ เโ+ฎA}c$ู'วญฏฟ#':"ษSค[Rฆ‘twฅ—ฌตๆ`ฉ+้๎๐Wค‹ึk8ฝ•๕ธ‰>็‹พฒฃฏ m[ต สศญ™พฎTฆjkพ“2’$iRปฒ{ทฌ–‰ฝ^ณu-+ๆศฒ)ƒ<ฯาั.%ฌIk+ิn!7Yซ'ล7_็ณ&นœรEาฐห(ษ[ข‚ผ่฿.]ผ`ู|/๕ง8zหงฺึg_yฎ‡น๗›/?“ษ}ZHลzญคRV&9ฌ๗pyฉqs้ึ‘€KX „hใ—Xฏ1ดmVฦw๎$, ขHตC^ ื„ 2็ณUฒ{๗nI™2eศท'zธDแ@ $LภE_‰ัWcุN`็บ%2wxWฯRษ:J้ส๕%oษJ1>ไOk }ฅ'I’$’ฺšKE&ั7๏.fขใ+—/‹.!}kšt’2uิืtโ›_Ÿท๕ณdฮ<ึ๙W๒–จ(w—ลnฯQkคฮญkญั3‘+0eห[T^{oš่ N?-ฉา!™rไ—๏๑๙Ÿ็ฮXsใbฑ๗Kก-piั๖mi๗z“xEVœ!ฐz๕jiึดฉLxงซuแrดฮPฆฤ.ะ3"BๆฎZ-คW@๛กu•€Kh๕ตEธ*@ภ%ธ? บ*ัก[ฌษp๓ฺฏ%ฤำ๖o_/:gŠn&เ[น๑อoสา‘30ŠหVตq'๋ีฃWโ’•<~4เ2bdy๊ฑา~ฎ’„€ณพ๘โ y้ฅ—drทwฅPฎ\ฮฎ,ตCภฅว—๙kึสมƒ]ูB.ฎ์V…ธ_€€K่๕๑๗฿l‘ั^ด+>เใ}žWbjI|๓{—ฃsฺฌ_8I6-Ÿ้l็(Pฺzๅ้QyธdEน๓L>ืIˆป€\FEL–Jๅ ธฤ]œNุฑc‡<๓2ญGwษŸ#‡SชE=+wว“E๋ึห๛]ูn.ฎ์V…ธ_€€K่๕๑ฏ'~~M+ฺ๏1cณ=mlญˆo~e]นrEฮYหMŸ?{ZRX“฿fฝ*”,ูMฒ’vp;aฒ*ฟŸEญา@ช5ฝ๖<+๑อš*กYk]๊บลไรษSคl้Rกูjึ'Nœ2eสศุž=ๅัB…‚gqแ‚่แA.^ดžq)(ธขฅZฃcฎq9ถ[cผfอม฿fxŸwฃP่0|„ฌถM๖|๓Xณๆ†zs|๊Oภล‡„@P เ ฝไ[วyรปศๆsๅf๋๕ž๎ำพธๆj?๑อ๏๛DR‚%phื&๕e™d\%เ,fส ขภฉSงคD‰ึk†ษ์/]eอlzlฮอ\ำ}๔ด่็yฏuฌฏ>šMต,“ฆ{๏c“O๗&๛ุ;ํZyฝ๏3ycบ฿\wฺŸ{๔4=ฏg#๛ฮˆ'๕๊sปm^็ฆฝืk๏c๛ซ๗˜tณทหปš฿คy๖ๆbด๒49z]ฝฒ&ุแeฯฯœ‘ˆZดฆ^น฿5๓sa๖š.รSฮ?šวไณŽ์‚5›}คื์๋ี{/XมBX#\’$Onป้7๕&mAยHภ\J=SOj4๏F-ํฆนQฦฝ๓Šˆ7G,‘{3ว>Qe|๓‡ถNhี\ฆL™"ฅJ1ย%ดzฺชUซJผyๅข๕ก๏าฅKrู‰bŽ๕\ฝฯMZ๔ฝษ=ฟ๗นyfl{@ฎ_า%rอฑ9ืฝฆtำMž๋šฯฬu“_ฏ™ผ&Ÿy†ฟฝึอ_๚ตาL›4Ÿ)ริ฿\3ย๕|(7{“ว์Mบ๗๛>๏cองiพผำฬฑ้sฝ฿ไำฝ๗นๆ๕พf๎5้บ7ๅ˜kš฿;-๚๖ฎ๓›้ ๕5ฦวๆg@‹7้fo๎ีฝษงวๆบนว;Mฏ™๛Lพ่i๙อฯžwš›็y—กวท-1dศ{๏ถo\ึฃดpฉPงน<๙b0iu่7๓ฒ๕fZึ๒๛™“๒jท๑’2uบX฿ฑฦล เ’ œๆr ๏ฟส๋๕"€ฉ{2pฎ_zฎฮM ฦ›ฝ๗u“฿๛^}Žฟ2Mณ7@๖ฺezฟึM๗ๆปL๏kๆCปๆ3ว{“n๖ๆšž๋fฮuo6๏4“ฎ{ะฝwภ฿q๔€w`@u‹ฉSž๎อฑ pyง้ฑwบ)ฯไ1{“ฎ๛ไึhM7i&iง1`๏l.ฮ๎j‡ ƒ€ ธTkิAญั8†\$#€@ฐธK–r@"@ภล-=I;@00—ถ'Iฦ<ผฮfOs @ภล@@-@ภลัCๅ@b0—๏O’ปsp‰ษ‰t‚%@ภ%Xฒ”‹ เ.n้Iฺ„™€ ธ ™ฑJ.ฆy ฬZOsธ๑\n|P@g pqvP;@Lภe๎๚ƒrไ7ฯ"ƒ1ไ&Z€€KB‹R €€ธธญGi &&เฒ๘‹ƒฒ๏—0้vš้ .๊ ช‚ เH.Ž์*… p-ˆˆ™?พŒ˜พTvLภๅZ^\G กธ$ด(ๅ!€ธM€€‹z”๖ €a"0x๐`ูผyณŒ๘p–์=pนbํ๔ศ฿^YโrํRdQaขH3ธ~.ืoว €แ!@ภ%<๚™V"€ฎะ€หย… ฅFAo›p$ษ} wšฉภ;ัœ‰\พzŸFzLวd1็šฮ๗฿m‘e_=7๙ข฿ง้ž4๋$‰ฉŸนAฏ›2ฎ่ฮค™ฯนwyW๏K™*ญdสžn๛ๅหWฃๅำ:˜2toŸ๋Uฝเ}MฉืตฎZž]g+›ณŽทW๚๓\œ*๕ูฌQ2eส)UŠ•ยโF&@ฐ เVMc@๗ฬž=~ฅศ=- –์฿ฟ_ฮŸ?บ  ๆฑ ›๙!นๅึ4~๓คL.2r่๛’)S&ฟืID@ œธ„s๏ำv@;}mฮŒL๒+„d๒NำJž๓ซว๖ศ%+Qฏš<‰๕eฐ!€ €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภธๆว € € € €€@@@@ภฏจไu ซIENDฎB`‚opentelemetry-collector-0.141.0/docs/internal-architecture.md000066400000000000000000000054401511331344600243070ustar00rootroot00000000000000## Internal architecture This document describes the Collector internal architecture and startup flow. It can be helpful if you are starting to contribute to the Collector codebase. For the end-user focused architecture document, please see the [opentelemetry.io's Architecture documentation](https://opentelemetry.io/docs/collector/architecture/). While it is end user focused, it's still a good place to start if you're trying to learn about the Collector codebase. ### Startup Diagram ```mermaid flowchart TD A("`**command.NewCommand**`") -->|1| B("`**updateSettingsUsingFlags**`") A --> |2| C("`**NewCollector** Creates and returns a new instance of Collector`") A --> |3| D("`**Collector.Run** Starts the collector and blocks until it shuts down`") D --> E("`**setupConfigurationComponents**`") E --> |1| F("`**getConfMap**`") E ---> |2| G("`**Service.New** Initializes telemetry, then initializes the pipelines`") E --> |3| Q("`**Service.Start** 1. Start all extensions. 2. Notify extensions about Collector configuration 3. Start all pipelines. 4. Notify extensions that the pipeline is ready. `") Q --> R("`**Graph.StartAll** Calls Start on each component in reverse topological order`") G --> H("`**initExtensionsAndPipeline** Creates extensions and then builds the pipeline graph`") H --> I("`**Graph.Build** Converts the settings to an internal graph representation`") I --> |1| J("`**createNodes** Builds the node objects from pipeline configuration and adds to graph. Also validates connectors`") I --> |2| K("`**createEdges** Iterates through the pipelines and creates edges between components`") I --> |3| L("`**buildComponents** Topological sort the graph, and create each component in reverse order`") L --> M(Receiver Factory) & N(Processor Factory) & O(Exporter Factory) & P(Connector Factory) ``` ### Where to start to read the code Here is a brief list of useful and/or important files and interfaces that you may find valuable to glance through. Most of these have package-level documentation and function/struct-level comments that help explain the Collector! - [collector.go](../otelcol/collector.go) - [graph.go](../service/internal/graph/graph.go) - [component.go](../component/component.go) #### Factories Each component type contains a `Factory` interface along with its corresponding `NewFactory` function. Implementations of new components use this `NewFactory` function in their implementation to register key functions with the Collector. An example of this is in [receiver.go](../receiver/receiver.go). For example, the Collector uses this interface to give receivers a handle to a `nextConsumer` - which represents where the receiver will send its data next in its telemetry pipeline. opentelemetry-collector-0.141.0/docs/observability.md000066400000000000000000000165241511331344600226760ustar00rootroot00000000000000# OpenTelemetry Collector internal observability The [Internal telemetry] page on OpenTelemetry's website contains the documentation for the Collector's internal observability, including: - Which types of observability are emitted by the Collector. - How to enable and configure these signals. - How to use this telemetry to monitor your Collector instance. If you need to troubleshoot the Collector, see [Troubleshooting]. Read on to learn about experimental features and the project's overall vision for internal telemetry. - [Goals of internal telemetry](#goals-of-internal-telemetry) * [Observable elements](#observable-elements) * [Impact](#impact) * [Configurable level of observability](#configurable-level-of-observability) * [Internal telemetry properties](#internal-telemetry-properties) + [Units](#units) + [Process for defining new metrics](#process-for-defining-new-metrics) - [Experimental trace telemetry](#experimental-trace-telemetry) ## Goals of internal telemetry The Collector's internal telemetry is an important part of fulfilling OpenTelemetry's [project vision](vision.md). The following section explains the priorities for making the Collector an observable service. ### Observable elements The following aspects of the Collector need to be observable. - [Current values] - Some of the current values and rates might be calculated as derivatives of cumulative values in the backend, so it's an open question whether to expose them separately or not. - [Cumulative values] - [Trace or log events] - For start or stop events, an appropriate hysteresis must be defined to avoid generating too many events. Note that start and stop events can't be detected in the backend simply as derivatives of current rates. The events include additional data that is not present in the current value. - [Host metrics] - Host metrics can help users determine if the observed problem in a service is caused by a different process on the same host. ### Impact The impact of these observability improvements on the core performance of the Collector must be assessed. ### Configurable level of observability Some metrics and traces can be high volume and users might not always want to observe them. An observability verbosity โ€œlevelโ€ allows configuration of the Collector to send more or less observability data or with even finer granularity, to allow turning on or off specific metrics. The default level of observability must be defined in a way that has insignificant performance impact on the service. ### Internal telemetry properties Telemetry produced by the Collector has the following properties: - metrics produced by Collector components use the prefix `otelcol_` - metrics produced by any instrumentation library used by Collector components will *not* be prefixed with `otelcol_` - code is instrumented using the OpenTelemetry API for metrics, and traces. Logs are instrumented using zap. Telemetry is collected and produced via the OpenTelemetry Go SDK - instrumentation scope defaults to the package name of the component recording telemetry. It can be configured via the `scope_name` option in mdatagen, but the recommendation is to keep the default - metrics are defined via `metadata.yaml` except in components that have specific cases where it is not possible to do so. See the [issue](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/33523) which list such components - whenever possible, components should leverage core components or helper libraries to capture telemetry, ensuring that all components of the Collector can be consistently observed - telemetry produced by components should include attributes that identify specific instances of the components #### Units The following units should be used for metrics emitted by the Collector for the purpose of its internal telemetry: | Field type | Unit | | -------------------------------------------------------------------------- | -------------- | | Metric counting the number of log records received, processed, or exported | `{records}` | | Metric counting the number of spans received, processed, or exported | `{spans}` | | Metric counting the number of data points received, processed, or exported | `{datapoints}` | #### Process for defining new metrics Metrics in the Collector are defined via `metadata.yaml`, which is used by [mdatagen] to produce: - code to create metric instruments that can be used by components - documentation for internal metrics - a consistent prefix for all internal metrics - convenience accessors for meter and tracer - a consistent instrumentation scope for components - test methods for validating the telemetry The process to generate new metrics is to configure them via `metadata.yaml`, and run `go generate` on the component. ## Experimental trace telemetry The Collector does not expose traces by default, but can be configured. The Collector's internal telemetry uses OpenTelemetry SDK. The following configuration can be used in combination with the aforementioned feature gates to emit internal metrics and traces from the Collector to an OTLP backend: ```yaml service: telemetry: metrics: readers: - periodic: interval: 5000 exporter: otlp: protocol: grpc endpoint: https://backend:4317 traces: processors: - batch: exporter: otlp: protocol: grpc endpoint: https://backend2:4317 ``` See the [example configuration][kitchen-sink] for additional options. > This configuration does not support emitting logs as there is no support for > [logs] in the OpenTelemetry Go SDK at this time. You can also configure the Collector to send its own traces using the OTLP exporter. Send the traces to an OTLP server running on the same Collector, so it goes through configured pipelines. For example: ```yaml service: telemetry: traces: processors: batch: exporter: otlp: protocol: grpc endpoint: ${MY_POD_IP}:4317 ``` [Internal telemetry]: https://opentelemetry.io/docs/collector/internal-telemetry/ [Troubleshooting]: https://opentelemetry.io/docs/collector/troubleshooting/ [issue7532]: https://github.com/open-telemetry/opentelemetry-collector/issues/7532 [issue7454]: https://github.com/open-telemetry/opentelemetry-collector/issues/7454 [logs]: https://github.com/open-telemetry/opentelemetry-go/issues/3827 [OpenTelemetry Configuration]: https://github.com/open-telemetry/opentelemetry-configuration [kitchen-sink]: https://github.com/open-telemetry/opentelemetry-configuration/blob/main/examples/kitchen-sink.yaml [Current values]: https://opentelemetry.io/docs/collector/internal-telemetry/#summary-of-values-observable-with-internal-metrics [Cumulative values]: https://opentelemetry.io/docs/collector/internal-telemetry/#summary-of-values-observable-with-internal-metrics [Trace or log events]: https://opentelemetry.io/docs/collector/internal-telemetry/#events-observable-with-internal-logs [Host metrics]: https://opentelemetry.io/docs/collector/internal-telemetry/#lists-of-internal-metrics [mdatagen]: https://github.com/open-telemetry/opentelemetry-collector/tree/main/cmd/mdatagen opentelemetry-collector-0.141.0/docs/platform-support.md000066400000000000000000000216741511331344600233600ustar00rootroot00000000000000# Platform Support The OpenTelemetry Collector will be supported following a tiered platform support model to balance between the aim to support as many platforms as possible and to guarantee stability for the most important platforms. A platform is described by the pair of operating system and processor architecture family as they are defined by the Go programming language as [known operating systems and architectures for use with the GOOS and GOARCH values](https://go.dev/src/internal/syslist/syslist.go). For a supported platform, the OpenTelemetry Collector is supported when the [minimum requirements](https://github.com/golang/go/wiki/MinimumRequirements) of the Go release used by the collector are met for the operating system and architecture. Each supported platform requires the naming of designated owners. The platform support for the OpenTelemetry Collector is broken into three tiers with different levels of support for each tier and aligns with the current test strategy. For platforms not listed as supported by any of the tiers, support cannot be assumed to be provided. While the project may accept specific changes related to these platforms, there will be no official builds, support of issues and development of enhancements or bug fixes for these platforms. Future development of project for supported platforms may break the functionality of unsupported platforms. ## Current Test Strategy The current verification process of the OpenTelemetry Collector includes unit and performance tests for core and additional end-to-end and integration tests for contrib. In the end-to-end tests, receivers, processors, and exporters etc. are tested in a testbed, while the integration tests rely on actual instances and available container images. Additional stability tests are in preparation for the future as well. All verification tests are run on the linux/amd64 as the primary platform today. In addition, unit tests are run for the _contrib_ collector on windows/amd64. The tests use as execution environments the latest Ubuntu and Windows Server versions [supported as Github runners](https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners#supported-runners-and-hardware-resources). The cross compile supports the following targets: - darwin/amd64 and darwin/arm64 - linux/amd64, linux/arm64, linux/386, linux/arm and linux/ppc64le - windows/amd64, windows/386. Except of the mentioned tests for linux/amd64 and windows/amd64, no other platforms are tested by the CI/CD tooling. Container images of the _core_ and _contrib_ collector are built and published to Docker Hub and ghcr.io for the platforms specified in the [goreleaser configuration](https://github.com/open-telemetry/opentelemetry-collector-releases/blob/bf8002ec6d2109cdb4184fc6eb6f8bda59ea96a2/.goreleaser.yaml#L137). End-to-end tests of the _contrib_ container images are run on the latest Ubuntu Linux supported by GitHub runners and for the four most recent Kubernetes versions. ## Tiered platform support model The platform support for the OpenTelemetry Collector is broken into three tiers with different levels of support for each tier. ### Platform Support - Summary The following tables summarized the platform tiers of support by the verification tests performed for them and by the specification if dummy implementations are allowed for selected features, the availability of precompiled binaries incl. container images and if bugfix releases are provided for previous releases in case of critical defects. | Tier | Unit tests | Performance tests | End-to-end tests | Integrations tests | Dummy implementations | Precompiled binaries | Bugfix releases | |------|------------|-------------------|------------------|--------------------|-----------------------|----------------------|-----------------| | 1 | yes | yes | yes | yes | no | yes | yes | | 2 | yes | optional | optional | optional | yes | yes | no | | 3 | no | no | no | no | yes | yes | no | ### Tier 1 โ€“ Primary Support The Tier 1 supported platforms are _guaranteed to work_. Precompiled binaries are built on the platform, fully supported for all collector add-ons (receivers, processor, exporters etc.), and continuously tested as part of the development processes to ensure any proposed change will function correctly. Build and test infrastructure is provided by the project. All tests are executed on the platform as part of automated continuous integration (CI) for each pull request and the [release cycle](https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/release.md#release-schedule). Any build or test failure block the release of the collector distribution for all platforms. Defects are addressed with priority and depending on severity fixed for previous release(s) in a bug fix release. Tier 1 platforms are currently: | Platform | Owner(s) | |-------------|-------------------------------------------------------------------------------------------------------------| | linux/amd64 | [OpenTelemetry Collector approvers](https://github.com/open-telemetry/opentelemetry-collector#contributing) | ### Tier 2 โ€“ Secondary Support Tier 2 platforms are _guaranteed to work with specified limitations_. Precompiled binaries are built and tested on the platform as part of the release cycle. Build and test infrastructure is provided by the platform maintainers. All tests are executed on the platform as far as they are applicable, and all prerequisites are fulfilled. Not executed tests and not tested collector add-ons (receivers, processors, exporters, etc.) are published on release of the collector distribution. Any build or test failure delays the release of the binaries for the respective platform but not the collector distribution for all other platforms. Defects are addressed but not with the priority as for Tier 1 and, if specific to the platform, require the support of the platform maintainers. Tier 2 platforms are currently: | Platform | Owner(s) | |---------------|----------------------------------------------------| | darwin/arm64 | [@MovieStoreGuy](https://github.com/MovieStoreGuy) | | linux/arm64 | [@atoulme](https://github.com/atoulme) | | windows/amd64 | [@pjanotti](https://github.com/pjanotti) | ### Tier 3 - Community Support Tier 3 platforms are _guaranteed to build_. Precompiled binaries are made available as part of the release process and as result of a cross compile build on Linux amd64 but the binaries are not tested at all. Any build failure delays the release of the binaries for the respective platform but not the collector distribution for all other platforms. Defects are addressed based on community contributions. Core developers might provide guidance or code reviews, but direct fixes may be limited. Tier 3 platforms are currently: | Platform | Owner(s) | |---------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| | darwin/amd64 | [@h0cheung](https://github.com/h0cheung) | | linux/386 | [@andrzej-stencel](https://github.com/andrzej-stencel) | | linux/arm | [@Wal8800](https://github.com/Wal8800), [@atoulme](https://github.com/atoulme) | | linux/ppc64le | [@IBM-Currency-Helper](https://github.com/IBM-Currency-Helper), [@adilhusain-s](https://github.com/adilhusain-s), [@seth-priya](https://github.com/seth-priya) | | linux/riscv64 | [@shanduur](https://github.com/shanduur) | | linux/s390x | [@bwalk-at-ibm](https://github.com/bwalk-at-ibm), [@rrschulze](https://github.com/rrschulze) | | windows/386 | [@pjanotti](https://github.com/pjanotti) | The proposed additional platform aix/ppc64 ([#19195](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/19195)) will be included into Tier 3 once it's added to the OpenTelemetry Collector as platform. opentelemetry-collector-0.141.0/docs/release.md000066400000000000000000000454511511331344600214410ustar00rootroot00000000000000# OpenTelemetry Collector Release Procedure Collector build and testing is currently fully automated. However there are still certain operations that need to be performed manually in order to make a release. We release both core and contrib collectors with the same versions where the contrib release uses the core release as a dependency. Weโ€™ve divided this process into three sections. Each section is assigned to an approver or maintainer of the corresponding repository. The sections are: 1. The [Core](#releasing-opentelemetry-collector) collector, including the collector builder CLI tool. 2. The [Contrib](#releasing-opentelemetry-collector-contrib) collector repository, containing Collector components. 3. The [artifacts](#producing-the-artifacts) **Important Note:** Youโ€™ll need to be able to sign git commits/tags in order to be able to release a collector version. Follow [this guide](https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits) to set it up. ## Release managers A release manager is the person responsible for a specific release. While the manager might request help from other folks, they are ultimately responsible for the success of a release. In order to have more people comfortable with the release process, and in order to decrease the burden on a small number of volunteers, all core, contrib and releases approvers are release managers from time to time, listed under the [Release Schedule](#release-schedule) section. That table is updated at every release, with the current core release manager adding themselves to the bottom of the table, removing themselves from the top of the table. The assigned release managers should coordinate with each other to ensure a smooth release process. The release managers may be the same person for different repositories, but it is not required. To ensure the rest of the community is informed about the release and can properly help the release manager, the core release manager should open a thread on the #otel-collector-dev CNCF Slack channel and provide updates there. The thread should be shared with all Collector leads (core, contrib and releases approvers and maintainers). Before the release, make sure there are no open release blockers in [core](https://github.com/open-telemetry/opentelemetry-collector/labels/release%3Ablocker), [contrib](https://github.com/open-telemetry/opentelemetry-collector-contrib/labels/release%3Ablocker) and [releases](https://github.com/open-telemetry/opentelemetry-collector-releases/labels/release%3Ablocker) repos. ## Releasing opentelemetry-collector (core release manager) 1. Update Contrib to use the latest in development version of Core by running [Update contrib to the latest core source](https://github.com/open-telemetry/opentelemetry-collector-contrib/actions/workflows/update-otel.yaml). This is to ensure that the latest core does not break contrib in any way. If the job is failing for any reason, you can do it locally by running `make update-otel` in Contrib root directory and pushing a PR. If you are unable to run `make update-otel`, it is possible to skip this step and resolve conflicts with Contrib after Core is released, but this is generally inadvisable. - While this PR is open, all merging in Core is automatically halted via the `Merge freeze / Check` CI check. - ๐Ÿ›‘ **Do not move forward until this PR is merged.** 2. Determine the version number that will be assigned to the release. Usually, we increment the minor version number and set the patch number to 0. In this document, we are using `v0.85.0` as the version to be released, following `v0.84.0`. Check if stable modules have any changes since the last release by running the following: - `make check-changes PREVIOUS_VERSION=v1.x.x MODSET=stable`. If there are no changes, there is no need to release new version for stable modules. If there are changes found but .chloggen directory doesn't have any corresponding entries, add missing changelog entries. If the changes are insignificant, consider not releasing a new version for stable modules. 3. Manually run the action [Automation - Prepare Release](https://github.com/open-telemetry/opentelemetry-collector/actions/workflows/prepare-release.yml). This action will create an issue to track the progress of the release and a pull request to update the changelog and version numbers in the repo. - When prompted, enter the version numbers determined in Step 2, but do not include a leading `v`. - If not intending to release stable modules, do not specify a version for `Release candidate version stable`. - While this PR is open all merging in Core is automatically halted via the `Merge freeze / Check` CI check. - If the PR needs updated in any way you can make the changes in a fork and PR those changes into the `prepare-release-prs/x` branch. You do not need to wait for the CI to pass in this prep-to-prep PR. - ๐Ÿ›‘ **Do not move forward until this PR is merged.** ๐Ÿ›‘ 4. On your local machine, make sure you are on the `main` branch and that the PR from step 3 is incorporated **at the head of your branch** (this is required to ensure the proper commit is used for the release tags and branch creation below). Tag the module groups with the new release version by running: โš ๏ธ If you set your remote using `https` you need to include `REMOTE=https://github.com/open-telemetry/opentelemetry-collector.git` in each command. โš ๏ธ - `make push-tags MODSET=beta` for the beta modules group, - `make push-tags MODSET=stable` for the stable modules group, only if there were changes since the last release. **Note**: Pushing the **beta** tags will automatically trigger the [Automation - Release Branch](https://github.com/open-telemetry/opentelemetry-collector/actions/workflows/release-branch.yml) GitHub Action, which will create the release branch (e.g. `release/v0.127.x`) from the commit that prepared the release. Pushing stable tags, if required, will not trigger creation of an additional release branch. 5. Wait for the "Automation - Release Branch" workflow to complete successfully. This workflow will automatically: - Detect the version from the pushed beta tags - Use the commit on which the tags were pushed as the "prepare release" commit - Create a new release branch (e.g. `release/v0.127.x`) from that commit If the workflow fails, you can check the [Actions tab](https://github.com/open-telemetry/opentelemetry-collector/actions) for details. The underlying script (./.github/workflows/scripts/release-branch.sh) can also be tested and run locally if needed by setting the GITHUB_REF environment variable (e.g., `GITHUB_REF=refs/tags/v0.85.0 ./.github/workflows/scripts/release-branch.sh`). 6. Wait for the tag-triggered build workflows to pass successfully. 7. A new `v0.85.0` source code release should be automatically created on Github by now. Its description should already contain the corresponding CHANGELOG.md and CHANGELOG-API.md contents. ## Releasing opentelemetry-collector-contrib (contrib release manager) See the [opentelemetry-collector-contrib release documentation](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/docs/release.md) for the release process in that repository. ## Producing the artifacts ('releases' release manager) See the [opentelemetry-collector-releases release documentation](https://github.com/open-telemetry/opentelemetry-collector-releases/blob/main/docs/release.md) for the release process in that repository. ## Post-release steps (all release managers) After the release is complete, the release manager should do the following steps: 1. Create an issue or update existing issues for each problem encountered throughout the release in the appropriate repositories and label them with the `release:retro` label. The release manager should share the list of issues that affected the release with the Collector leads. 2. Update the [release schedule](#release-schedule) section of this document to remove the completed releases and add new schedules to the bottom of the list. To update the release schedule, follow these rules: 1. If the core release manager is also eligible as a contrib and 'releases' release manager, assign them to all roles they can perform. 2. Otherwise, pick a contrib/'releases' approver/maintainer that is not a core approver/maintainer, rotating through the list of eligible people. The contrib approvers/maintainers are all members of the [@collector-contrib-approvers](https://github.com/orgs/open-telemetry/teams/collector-contrib-approvers) team, and the 'releases' approvers/maintainers are all members of the [@collector-releases-approvers](https://github.com/orgs/open-telemetry/teams/collector-releases-approvers) team. ## Troubleshooting 1. `unknown revision internal/coreinternal/v0.85.0` -- This is typically an indication that there's a dependency on a new module. You can fix it by adding a new `replaces` entry to the `go.mod` for the affected module. 2. `unable to tag modules: unable to load repo config: branch config: invalid merge` when running `make push-tags` -- This is a [known issue](https://github.com/open-telemetry/opentelemetry-go-build-tools/issues/47) with our release tooling, caused by a bug in `go-git`. It occurs if you have branches in your local repository whose entry in `.git/config` has a `merge` attribute not starting with `refs/heads`. This can typically happen when checking out PR branches using the Github CLI tool, for which the `merge` attribute starts with `refs/pull`. A possible workaround is to: - Comment out the problematic lines with `sed -E -i.bak 's/(merge = refs\/pull)/#\1/' .git/config`; - Try `make push-tags` again; - Restore the config with `mv .git/config.bak .git/config`. If that doesn't work, you can clone a fresh copy of the repository and try again. Note that you may need to set up a `fork` remote pointing to your own fork for the release tooling to work properly. 3. `could not run Go Mod Tidy: go mod tidy failed` when running `multimod` -- This is a [known issue](https://github.com/open-telemetry/opentelemetry-go-build-tools/issues/46) with our release tooling. The current workaround is to run `make gotidy` manually after the multimod tool fails and commit the result. 4. `Incorrect version "X" of "go.opentelemetry.io/collector/component" is included in "X"` in CI after `make update-otel` -- It could be because the make target was run too soon after updating Core and the goproxy hasn't updated yet. Try running `export GOPROXY=direct` and then `make update-otel`. 5. `error: failed to push some refs to 'https://github.com/open-telemetry/opentelemetry-collector-contrib.git'` during `make push-tags` -- If you encounter this error the `make push-tags` target will terminate without pushing all the tags. Using the output of the `make push-tags` target, save all the un-pushed the tags in `tags.txt` and then use this make target to complete the push: ```bash .PHONY: temp-push-tags temp-push-tags: for tag in `cat tags.txt`; do \ echo "pushing tag $${tag}"; \ git push ${REMOTE} $${tag}; \ done; ``` 6. `unable to tag modules: git tag failed for v0.112.0: unable to create tag: "error: gpg failed to sign the data:`. Make sure you have GPG set up to sign commits. You can run `gpg --gen-key` to generate a GPG key. 7. When using a new GitHub Actions workflow in opentelemetry-collector-releases for the first time during a release, a workflow may fail. If it is possible to fix the workflow, a maintainer can update the release tag to the commit with the fix and re-run the release. (Note: This cannot be done by approvers.) It is safe to re-run the workflows that already succeeded. Publishing container images can be done multiple times, and publishing artifacts or pushing OCB/Supervisor tags to GitHub will fail without any adverse effects. ## Bugfix releases ### Bugfix release criteria All OpenTelemetry Collector repositories have very short 2 week release cycles. Because of this, we put a high bar when considering making a patch release, to avoid wasting engineering time unnecessarily. When considering making a bugfix release on the `v0.N.x` release cycle, the bug in question needs to fulfill the following criteria: 1. The bug has no workaround or the workaround is significantly harder to put in place than updating the version. Examples of simple workarounds are: - Reverting a feature gate. - Changing the configuration to an easy to find value. 2. The bug happens in common setups. To gauge this, maintainers can consider the following: - If the bug is specific to a certain platform, and if that platform is in [Tier 1](../docs/platform-support.md#tiered-platform-support-model). - The bug happens with the default configuration or with one that is known to be used in production. 3. The bug is sufficiently severe. For example (non-exhaustive list): - The bug makes the Collector crash reliably - The bug makes the Collector fail to start under an accepted configuration - The bug produces significant data loss - The bug makes the Collector negatively affect its environment (e.g. significantly affects its host machine) - The bug makes it difficult to troubleshoot or debug Collector setups We aim to provide a release that fixes security-related issues in at most 30 days since they are publicly announced; with the current release schedule this means security issues will typically not warrant a bugfix release. An exception is critical vulnerabilities (CVSSv3 score >= 9.0), which will warrant a release within five business days. The OpenTelemetry Collector maintainers will ultimately have the responsibility to assess if a given bug or security issue fulfills all the necessary criteria and may grant exceptions in a case-by-case basis. If the maintainers are unable to reach consensus within one working day, we will lean towards releasing a bugfix version. ### Bugfix release procedure The release manager of a minor version is responsible for releasing any bugfix versions on this release series for their repository. The following documents the procedure to release a bugfix: 1. Create a pull request against the `release/` (e.g. `release/v0.90.x`) branch to apply the fix. 2. Make sure you are on `release/`. Prepare release commits with `prepare-release` make target, e.g. `make prepare-release PREVIOUS_VERSION=0.90.0 RELEASE_CANDIDATE=0.90.1 MODSET=beta`, and create a pull request against the `release/` branch. 3. Once those changes have been merged, create a pull request to the `main` branch from the `release/` branch. 4. If you see merge conflicts when creating the pull request, do the following: 1. Create a new branch from `origin:main`. 2. Merge the `release/` branch into the new branch. 3. Resolve the conflicts. 4. Create another pull request to the `main` branch from the new branch to replace the pull request from the `release/` branch. 5. Disable the merge queue. An admin of the repo needs to be available for this. 6. Enable the **Merge pull request** setting in the repository's **Settings** tab. 7. Make sure you are on `release/`. Push the new release version tags for a target module set by running `make push-tags MODSET=`. Wait for the new tag build to pass successfully. 8. **IMPORTANT**: The pull request to bring the changes from the release branch *MUST* be merged using the **Merge pull request** method, and *NOT* squashed using โ€œ**Squash and merge**โ€. This is important as it allows us to ensure the commit SHA from the release branch is also on the main branch. **Not following this step will cause much go dependency sadness.** 9. If the pull request was created from the `release/` branch, it will be auto-deleted. Restore the release branch via GitHub. 10. Once the patch is released, disable the **Merge pull request** setting and re-enable the merge queue. ## 1.0 release Stable modules adhere to our [versioning document guarantees](../VERSIONING.md), so we need to be careful before releasing. Before adding a module to the stable module set and making a first 1.x release, please [open a new stabilization issue](https://github.com/open-telemetry/opentelemetry-collector/issues/new/choose) and follow the instructions in the issue template. Once a module is ready to be released under the `1.x` version scheme, file a PR to move the module to the `stable` module set and remove it from the `beta` module set. Note that we do not make `v1.x.y-rc.z` style releases for new stable modules; we instead treat the last two beta minor releases as release candidates and the module moves directly from the `0.x` to the `1.x` release series. ## Release schedule | Date | Version | Core Release manager | Contrib release manager | 'Releases' release manager | |------------|----------|-----------------------|-------------------------|----------------------------| | 2025-12-01 | v0.141.0 | [@dmathieu][12] | [@braydonk][13] | [@MovieStoreGuy][17] | | 2025-12-15 | v0.142.0 | [@atoulme][5] | [@atoulme][5] | [@atoulme][5] | | 2026-01-05 | v0.143.0 | [@jmacd][1] | [@ArthurSens][11] | [@mowies][15] | | 2026-01-19 | v0.144.0 | [@mx-psi][14] | [@mx-psi][14] | [@mx-psi][14] | | 2026-02-02 | v0.145.0 | [@TylerHelmuth][3] | [@TylerHelmuth][3] | [@TylerHelmuth][3] | | 2026-02-16 | v0.146.0 | [@evan-bradley][2] | [@evan-bradley][2] | [@evan-bradley][2] | | 2026-03-02 | v0.147.0 | [@songy23][6] | [@songy23][6] | [@songy23][6] | | 2026-03-16 | v0.148.0 | [@dmitryax][7] | [@dmitryax][7] | [@dmitryax][7] | | 2026-03-30 | v0.149.0 | [@codeboten][8] | [@codeboten][8] | [@codeboten][8] | | 2026-04-13 | v0.150.0 | [@axw][18] | [@ChrsMark][19] | [@crobert-1][20] | | 2026-04-27 | v0.151.0 | [@bogdandrutu][9] | [@bogdandrutu][9] | [@bogdandrutu][9] | | 2025-05-11 | v0.152.0 | [@jade-guiton-dd][10] | [@andrzej-stencel][4] | [@dehaansa][16] | [1]: https://github.com/jmacd [2]: https://github.com/evan-bradley [3]: https://github.com/TylerHelmuth [4]: https://github.com/andrzej-stencel [5]: https://github.com/atoulme [6]: https://github.com/songy23 [7]: https://github.com/dmitryax [8]: https://github.com/codeboten [9]: https://github.com/bogdandrutu [10]: https://github.com/jade-guiton-dd [11]: https://github.com/ArthurSens [12]: https://github.com/dmathieu [13]: https://github.com/braydonk [14]: https://github.com/mx-psi [15]: https://github.com/mowies [16]: https://github.com/dehaansa [17]: https://github.com/MovieStoreGuy [18]: https://github.com/axw [19]: https://github.com/ChrsMark [20]: https://github.com/crobert-1 opentelemetry-collector-0.141.0/docs/rfcs/000077500000000000000000000000001511331344600204235ustar00rootroot00000000000000opentelemetry-collector-0.141.0/docs/rfcs/README.md000066400000000000000000000102501511331344600217000ustar00rootroot00000000000000# Collector RFCs This folder contains accepted design documents for the Collector. Proposals here imply changes only on the OpenTelemetry Collector and not on other parts of OpenTelemetry; if you have a cross-cutting proposal, file an [OTEP][1] instead. # RFC Process ## Scope The Request For Comments (RFC) process is intended to be used for significant changes to the Collector. Major design decisions, especially those that imply a change that is hard to reverse, should generally be documented as an RFC. Controversial changes should also be documented as an RFC, so that the community can have a chance to provide feedback. The goal of this process is to ensure we have a coherent vision before embarking on significant work. Ultimately, if any opentelemetry-collector maintainer feels that a change requires an RFC, then a merged RFC is a requirement for said change. ## Contents We are purposefully light on the structure of RFCs, with the focus being the decision process and not the document itself. When in doubt, the [OTEP template][2] can be a good starting point. Regardless of the structure, the RFC should make clear what commitments are being made by the Collector SIG when merging it. ## Announcement RFCs should be announced in a Collector SIG meeting and on the #otel-collector-dev Slack channel. ## Approval process An RFC is just like any other PR in this repository, with the exception of more stringent criteria for merging it. ### Stakeholders To define merge criteria and voting, each RFC has a set of 'stakeholders'. All opentelemetry-collector approvers are considered stakeholders. Additional stakeholders (e.g. maintainers of related SIGs or experts) may be explicitly noted in the RFC. ### Merge rules We use a [Lazy Consensus](https://www.apache.org/foundation/glossary.html#LazyConsensus) method with the following rules: 1. *Quorum*: For an RFC to be mergeable, it needs to have at least **two approvals** from the approvers set as well as approvals from any additional stakeholders. 2. *Waiting period*: Maintainers need to announce their intent to merge the RFC with a GitHub comment. They will need to add a `rfc:final-comment-period` label to the PR, comment on the PR and note the final comment period in the #otel-collector-dev CNCF Slack channel, and wait for at least **4 business days** after making the announcement to merge the RFC. 3. *Objections*: Objections should be communicated as a 'request changes' review. All objections must be addressed before merging an RFC. If addressing an objection does not appear feasible, any maintainer may call for a vote to be made on the objection (see below). This will be signified by adding a `rfc:vote-needed` label to the PR. The voting result is binding and a maintainer can drop any 'request changes' reviews based on the vote results or consensus. 4. *Modifications*: Non-trivial modifications to an RFC reset the waiting period. RFC authors must re-request any approving, comment, or 'request changes' reviews if the RFC has been modified significantly. 5. *All conversations are resolved*: All Github conversations on the PR must be marked as resolved before merging. The RFC author may resolve conversations at their discretion, but they must explain in the conversation thread why they believe it is appropriate to do so. ### Voting If there is no consensus on a particular issue, a vote may be called by any of the maintainers. The vote will be open to all stakeholders for at least **5 business days** or until at least one third of the stakeholders have voted, whichever comes last. The vote will be decided by simple majority, restricting the set to approvers and then maintainers in case of a tie among stakeholders. Voting should be done on a dedicated issue via comments. The related discussion threads should be linked in the issue. The voting result should be documented in the RFC itself. # Modifications to existing RFCs and to this document Non-trivial modifications to this document and to existing RFCs should be done through the RFC process itself and have the same merge criteria. [1]: https://github.com/open-telemetry/oteps [2]: https://github.com/open-telemetry/oteps/blob/main/0000-template.md opentelemetry-collector-0.141.0/docs/rfcs/component-status-reporting.md000066400000000000000000000246361511331344600263120ustar00rootroot00000000000000# Component Status Reporting ## Overview Since the OpenTelemetry Collector is made up of pipelines with components, it needs a way for the components within those pipelines to emit information about their health. This information allows the collector service, or other interested software or people, to make decisions about how to proceed when something goes wrong. This document describes: 1. The historical state of how components reported health 2. The current state of how components report health 3. The goals component health reporting should achieve 4. Existing deviations from those goals 5. Desired behavior for 1.0 For context throughout this document, component defines a `component.Host` interface, which components may use to interact with the struct that is managing all the collector pipelines and the components. In this repository, our implementation of `component.Host` can be found in `service/internal/graph.Host`. ## Out Of Scope How to get from the current to desired behavior is also considered out of scope and will be discussed on individual PRs. It will likely involve one or multiple feature gates, warnings and transition periods. ## The Collectorโ€™s Historical method of reporting component health Until recently, the Collector relied on four ways to report health. 1. The `error` returned by the Componentโ€™s Start method. During startup, if any component decided to return an error, the Collector would stop gracefully. 2. The `component.Host.ReportFatalError` method. This method let components tell the `component.Host` that something bad happened and the collector needed to shut down. While this method could be used anywhere in the component, it was primarily used with a Componentโ€™s Start method to report errors in async work, such as starting a server. ```golang if errHTTP := fmr.server.Serve(listener); errHTTP != nil && !errors.Is(errHTTP, http.ErrServerClosed) { host.ReportFatalError(errHTTP) } ``` 3. The error returned by `Shutdown`. This error was indicative that the collector did not cleanly shut down, but did not prevent the shutdown process from moving forward. 4. Panicking. During runtime, if the collector experienced an unhandled error, it crashes. These are all the way the components in a collector could report that they were unhealthy. There are several major gaps in the Collectorโ€™s historic reporting of component health. First, many components return recoverable errors from Start, causing the collector to shutdown, while it could recover if the collector was allowed to run. Second, when a component experienced a transient error, such as an endpoint suddenly not working, the component would simply log the error and return it up the pipeline. There was no mechanism for the component to tell the `component.Host` or anything else that something was going wrong. Last, when a component experienced an issue it would never be able to recover from, such as receiving a 404 response from an endpoint, the component would log the error and return it up the pipeline. This situation was handled in the same way as the transient error, which means the component could not tell the `component.Host` or anything else that something was wrong, but worse is that the issue would never get better. ## Current State of Component Health Reporting See [Component Status Reporting](../component-status.md) ## The Goals the Component Health Reporting Should Achieve The following are the goals, as of June 2024 and with Collector 1.0 looming, for a component health reporting system. 1. A `component.Host` implementation, such as `service/internal/graph.Host`, may report statuses Starting, Ok, Stopping and PermanentError on behalf of components. - Additional status may be reported in the future 2. Components may opt-in to reporting health status at runtime. Components must not be required to report health statuses themselves. - The consumers of the health reporting system must be able to identify which components are and are not opting to report their own statuses. 3. Component health reporting must be opt-in for collector users. While the underlying components are always allowed to report their health via the system, the `component.Host` implementation, such as `service/internal/graph.Host`, or any other listener may only take action when the user has configured the collector accordingly. - As one example of compliance, the current health reporting system is dependent on the user configuring an extension that can watch for status updates. 4. Component health must be representable as a finite state machine with clear transitions between states. 5. Component health reporting must only be a mechanism for reporting health - it should have no mechanisms for taking actions on the health it reports. How consumers of the health reporting system respond to component updates is not a concern of the health reporting system. ## Existing deviations from those goals ### Fatal Error Reporting Before the current implementation of component status reporting, a component could stop the collector by using `component.Host.ReportFatalError`. Now, a component MUST use component status reporting and emit a `FatalError`. This fact is in conflict with Goal 1, which states component health reporting must be opt-in for components. A couple solutions: 1. Accept this reality as an exception to Goal 2. 2. Add back `component.Host.ReportFatalError`. 3. Remove the ability for components to stop the collector be removing `FatalError`. ### No way to identify components that are not reporting status Goal 2 states that consumers of component status reporting must be able to identify components in use that have not opted in to component status reporting. Our current implementation does not have this feature. ### Should component health reporting be an opt-in for `component.Host` implementations? The current implementation of component status reporting does not add anything to `component.Host` to force a `component.Host` implementation, such as `service/internal/graph.Host`, to be compatible with component status reporting. Instead, it adds `ReportStatus func(*StatusEvent)` to `component.TelemetrySettings` and things that instantiate components, such as `service/internal/graph.Host`, should, but are not required, to pass in a value for `ReportStatus`. As a result, `component.Host` implementation is not required to engage with the component status reporting system. This could lead to situations where a user adds a status watcher extension that can do nothing because the `component.Host` is not reporting component status updates. Is this acceptable? Should we: 1. Require the `component.Host` implementations be compatible with the component status reporting framework? 2. Add some sort of configuration/build flag then enforces the `component.Host` implementation be compatible (or not) with component status reporting? 3. Accept this edge case. ### Component TelemetrySettings Requirements The current implementation of component status reporting added a new field to `component.TelemetrySettings`, `ReportStatus`. This field is technically optional, but would be marked as stable with component 1.0. Are we ok with 1 of the following? 1. Including a component status reporting feature, `component.TelemetrySettings.ReportStatus`, in the 1.0 version of `component.TelemetrySettings`? 2. Marking `component.TelemetrySettings.ReportStatus` as experimental via godoc comments in the 1.0 version of `component.TelemetrySettings`? Or should we refactor `component` somehow to remove `ReportStatus` from `component.TelemetrySettings`? ## Desired Behavior for 1.0 For each listed deviation, the solution for unblocking component 1.0 is: - `Fatal Error Reporting` :white_check_mark:: The `component` module provides no mechanism for a component to stop a collector after it has started. It is expected that an error returned from `Start` will terminate a starting Collector, but it is ultimately up to the caller of `Start` how to handle the returned error. A `component.Host` implementation may choose to provide a mechanism to stop a running collector via a different Interface, but doing so is not required. - As part of this stance, we agree that the `component.Component.Start` method will continue returning an error. - `No way to identify components that are not reporting status` :white_check_mark:: This can be implemented as a feature addition to component status reporting without blocking `component` 1.0 - `Should component health reporting be an opt-in for component.Host implementations?` :white_check_mark:: Yes. A `component.Host` implementation is not required to provide a component status reporting feature. They may do so via an additional interface, such as `componentstatus.Reporter`. - `Component TelemetrySettings Requirements` :white_check_mark:: `component.TelemetrySettings.ReportStatus` has been removed. Instead, component status reporting is expected to be provided via an additional interface that `component.Host` implements. Components can check if the `component.Host` implements the desired interface, such as `componentstatus.Reporter` to access component status reporting features. ## Reference - Remove FatalError? Looking for opinions either way: https://github.com/open-telemetry/opentelemetry-collector/issues/9823 - In order to prioritize lifecycle events over runtime events for status reporting, allow a component to transition from PermanentError -> Stopping: https://github.com/open-telemetry/opentelemetry-collector/issues/10058 - Runtime status reporting for components in core: https://github.com/open-telemetry/opentelemetry-collector/issues/9957 - Should Start return an error: https://github.com/open-telemetry/opentelemetry-collector/issues/9324 - Should Shutdown return an error: https://github.com/open-telemetry/opentelemetry-collector/issues/9325 - Status reporting doc incoming; preview here: https://github.com/mwear/opentelemetry-collector/blob/cc870fd2a7160da298acdda447511ea9a83455e0/docs/component-status.md - Issues - Closed: https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/8349 - Open: https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/8816 - Status Reporting PRs - Closed - https://github.com/open-telemetry/opentelemetry-collector/pull/5304 - https://github.com/open-telemetry/opentelemetry-collector/pull/6550 - https://github.com/open-telemetry/opentelemetry-collector/pull/6560 - Merged - https://github.com/open-telemetry/opentelemetry-collector/pull/8169 opentelemetry-collector-0.141.0/docs/rfcs/component-universal-telemetry.md000066400000000000000000000301571511331344600267730ustar00rootroot00000000000000# Pipeline Component Telemetry ## Motivation and Scope The collector should be observable and this must naturally include observability of its pipeline components. Pipeline components are those components of the collector which directly interact with data, specifically receivers, processors, exporters, and connectors. It is understood that each _type_ (`filelog`, `otlp`, etc) of component may emit telemetry describing its internal workings, and that these internally derived signals may vary greatly based on the concerns and maturity of each component. Naturally though, there is much we can do to normalize the telemetry emitted from and about pipeline components. Two major challenges in pursuit of broadly normalized telemetry are (1) consistent attributes, and (2) automatic capture. This RFC represents an evolving consensus about the desired end state of component telemetry. It does _not_ claim to describe the final state of all component telemetry, but rather seeks to document some specific aspects. It proposes a set of attributes which are both necessary and sufficient to identify components and their instances. It also articulates one specific mechanism by which some telemetry can be automatically captured. Finally, it describes some specific metrics and logs which should be automatically captured for each kind of pipeline component. ## Goals 1. Define attributes that are (A) specific enough to describe individual component [_instances_](https://github.com/open-telemetry/opentelemetry-collector/issues/10534) and (B) consistent enough for correlation across signals. 2. Articulate a mechanism which enables us to _automatically_ capture telemetry from _all pipeline components_. 3. Define specific metrics for each kind of pipeline component. 4. Define specific logs for all kinds of pipeline component. ## Attributes Traces, logs, and metrics should carry the following instrumentation scope attributes: ### Receivers - `otelcol.component.kind`: `receiver` - `otelcol.component.id`: The component ID - `otelcol.signal`: `logs`, `metrics`, `traces`, `profiles` ### Processors - `otelcol.component.kind`: `processor` - `otelcol.component.id`: The component ID - `otelcol.pipeline.id`: The pipeline ID - `otelcol.signal`: `logs`, `metrics`, `traces`, `profiles` ### Exporters - `otelcol.component.kind`: `exporter` - `otelcol.component.id`: The component ID - `otelcol.signal`: `logs`, `metrics`, `traces`, `profiles` ### Connectors - `otelcol.component.kind`: `connector` - `otelcol.component.id`: The component ID - `otelcol.signal`: `logs`, `metrics` `traces` - `otelcol.signal.output`: `logs`, `metrics`, `traces`, `profiles` Note: The `otelcol.signal`, `otelcol.signal.output`, or `otelcol.pipeline.id` attributes may be omitted if the corresponding component instances are unified by the component implementation. For example, the `otlp` receiver is a singleton, so its telemetry is not specific to a signal. Similarly, the `memory_limiter` processor is a singleton, so its telemetry is not specific to a pipeline. These instrumentation scope attributes are automatically injected into the telemetry associated with a component, by wrapping the Logger, TracerProvider, and MeterProvider provided to it. ## Auto-Instrumentation Mechanism The mechanism of telemetry capture should be _external_ to components. Specifically, we should observe telemetry at each point where a component passes data to another component, and, at each point where a component consumes data from another component. In terms of the component graph, every _edge_ in the graph will have two layers of instrumentation - one for the producing component and one for the consuming component. Importantly, each layer generates telemetry ascribed to a single component instance, so by having two layers per edge we can describe both sides of each handoff independently. Telemetry captured by this mechanism should be associated with an instrumentation scope with a name corresponding to the package which implements the mechanism. Currently, that package is `go.opentelemetry.io/collector/service`, but this may change in the future. Notably, this telemetry is not ascribed to individual component packages, both because the instrumentation scope is intended to describe the origin of the telemetry, and because no mechanism is presently identified which would allow us to determine the characteristics of a component-specific scope. ### Instrumentation Scope All telemetry described in this RFC should include a scope name which corresponds to the package which implements the telemetry. If the package is internal, then the scope name should be that of the module which contains the package. For example, `go.opentelemetry.io/service` should be used instead of `go.opentelemetry.io/service/internal/graph`. ### Auto-Instrumented Metrics There are two straightforward measurements that can be made on any pdata: 1. A count of "items" (spans, data points, or log records). These are low cost but broadly useful, so they should be enabled by default. 2. A measure of size, based on [ProtoMarshaler.Sizer()](https://github.com/open-telemetry/opentelemetry-collector/blob/9907ba50df0d5853c34d2962cf21da42e15a560d/pdata/ptrace/pb.go#l11). These may be high cost to compute, so by default they should be disabled (and not calculated). This default setting may change in the future if it is demonstrated that the cost is generally acceptable. The location of these measurements can be described in terms of whether the data is "consumed" or "produced", from the perspective of the component to which the telemetry is attributed. Metrics which contain the term "produced" describe data which is emitted from the component, while metrics which contain the term "consumed" describe data which is received by the component. For both metrics, an `otelcol.component.outcome` attribute with possible values `success`, `failure`, and `refused` should be automatically recorded, based on whether the corresponding function call returned successfully, returned an error originating from the associated component, or propagated an error from a component further downstream. Specifically, a call to `ConsumeX` is recorded with: - `otelcol.component.outcome = success` if the call returns `nil`; - `otelcol.component.outcome = failure` if the call returns a regular error; - `otelcol.component.outcome = refused` if the call returns an error tagged as coming from downstream. After inspecting the error, the instrumentation layer should tag it as coming from downstream before returning it to the caller. Since there are two instrumentation layers between each pair of successive components (one recording produced data and one recording consumed data), this means that a call recorded with `outcome = failure` by the "consumer" layer will be recorded with `outcome = refused` by the "producer" layer, reflecting the fact that only the "consumer" component failed. In all other cases, the `outcome` recorded by both layers should be identical. Errors should be "tagged as coming from downstream" the same way permanent errors are currently handled: they can be wrapped in a `type downstreamError struct { err error }` wrapper error type, then checked with `errors.As`. Note that care may need to be taken when dealing with the `multiError`s returned by the `fanoutconsumer`. If PR #11085 introducing a single generic `Error` type is merged, an additional `downstream bool` field can be added to it to serve the same purpose instead. ```yaml otelcol.receiver.produced.items: enabled: true description: Number of items emitted from the receiver. unit: "{item}" sum: value_type: int monotonic: true otelcol.processor.consumed.items: enabled: true description: Number of items passed to the processor. unit: "{item}" sum: value_type: int monotonic: true otelcol.processor.produced.items: enabled: true description: Number of items emitted from the processor. unit: "{item}" sum: value_type: int monotonic: true otelcol.connector.consumed.items: enabled: true description: Number of items passed to the connector. unit: "{item}" sum: value_type: int monotonic: true otelcol.connector.produced.items: enabled: true description: Number of items emitted from the connector. unit: "{item}" sum: value_type: int monotonic: true otelcol.exporter.consumed.items: enabled: true description: Number of items passed to the exporter. unit: "{item}" sum: value_type: int monotonic: true otelcol.receiver.produced.size: enabled: false description: Size of items emitted from the receiver. unit: "By" sum: value_type: int monotonic: true otelcol.processor.consumed.size: enabled: false description: Size of items passed to the processor. unit: "By" sum: value_type: int monotonic: true otelcol.processor.produced.size: enabled: false description: Size of items emitted from the processor. unit: "By" sum: value_type: int monotonic: true otelcol.connector.consumed.size: enabled: false description: Size of items passed to the connector. unit: "By" sum: value_type: int monotonic: true otelcol.connector.produced.size: enabled: false description: Size of items emitted from the connector. unit: "By" sum: value_type: int monotonic: true otelcol.exporter.consumed.size: enabled: false description: Size of items passed to the exporter. unit: "By" sum: value_type: int monotonic: true ``` #### Additional Attribute for Connectors Connectors can route telemetry to specific pipelines. Therefore, `otelcol.connector.produced.*` metrics should carry an additional data point attribute, `otelcol.pipeline.id`, to describe the pipeline ID to which the data is sent. ### Auto-Instrumented Logs Metrics provide most of the observability we need but there are some gaps which logs can fill. Although metrics would describe the overall item counts, it is helpful in some cases to record more granular events. For example, if a produced batch of 10,000 spans results in an error, but 100 batches of 100 spans succeed, this may be a matter of batch size that can be detected by analyzing logs, while the corresponding metric reports only that a 50% success rate is observed. For security and performance reasons, it would not be appropriate to log the contents of telemetry. It's very easy for logs to become too noisy. Even if errors are occurring frequently in the data pipeline, only the errors that are not handled automatically will be of interest to most users. With the above considerations, this proposal includes only that we add a DEBUG log for each error, with the attributes from the corresponding metrics as well as the error message and item count. This should be sufficient for detailed troubleshooting but does not impact users otherwise. In the future, it may be helpful to define triggers for reporting repeated failures at a higher severity level. e.g. N number of failures in a row, or a moving average success %. For now, the criteria and necessary configurability is unclear so this is mentioned only as an example of future possibilities. ### Auto-Instrumented Spans It is not clear that any spans can be captured automatically with the proposed mechanism. We have the ability to insert instrumentation both before and after processors and connectors. However, we generally cannot assume a 1:1 relationship between consumed and produced data. ## Additional Context This proposal pulls from a number of issues and PRs: - [Demonstrate graph-based metrics](https://github.com/open-telemetry/opentelemetry-collector/pull/11311) - [Attributes for component instancing](https://github.com/open-telemetry/opentelemetry-collector/issues/11179) - [Simple processor metrics](https://github.com/open-telemetry/opentelemetry-collector/issues/10708) - [Component instancing is complicated](https://github.com/open-telemetry/opentelemetry-collector/issues/10534) opentelemetry-collector-0.141.0/docs/rfcs/configuration-merging-strategy.md000066400000000000000000000225311511331344600271050ustar00rootroot00000000000000# Configuration merging ## Background As part of issue [#8754](https://github.com/open-telemetry/opentelemetry-collector/issues/8754), a new feature gate has been introduced to support merging component lists instead of replacing them ([first PR](https://github.com/open-telemetry/opentelemetry-collector/pull/12097)). This enhancement enables configurations from multiple sources to be combined, preserving all defined components in the final configuration. More information about this feature can be found in the [confmap README](https://github.com/open-telemetry/opentelemetry-collector/blob/d4539dd6b4e554e15066226fa975b156af7b1510/confmap/README.md#experimental-append-merging-strategy-for-lists). The main motivation for this change was to allow users to define configuration fragments in different sources, and have them merged in such a way that all specified components are included under `service::pipeline` in the final configuration. Previously, we relied on Koanfโ€™s default merging strategy, which overrides static values and slices (such as strings, numbers, and lists). This behavior often resulted in configurations being unintentionally overwritten when merged from multiple sources. This issue has been highlighted in several discussions and feature requests: - https://github.com/open-telemetry/opentelemetry-collector/issues/8394 - https://github.com/open-telemetry/opentelemetry-collector/issues/8754 - https://github.com/open-telemetry/opentelemetry-collector/issues/10370 ## Motivation and Scope Weโ€™ve already implemented a feature gate and foundational logic that supports merging lists across configuration files. Currently, this logic is hardcoded to merge lists only for specific keys: receivers, exporters, and extensions. The relevant implementation can be found [here](https://github.com/open-telemetry/opentelemetry-collector/blob/main/confmap/internal/merge.go). The current implementation lacks flexibility. Ideally, users should be able to specify which configuration paths should be merged, rather than relying on hardcoded defaults. This RFC proposes extending the existing functionality by introducing a user-configurable mechanism to define merge behavior. This RFC builds on top of feedback gathered from the [original PR](https://github.com/open-telemetry/opentelemetry-collector/pull/12097). More specifically, this RFC aims to: 1. Add an option to specify which configuration paths should be merged. 2. Introduce support for prepend and append operations when merging list values: - This is good to have for lists that rely on certain ordering, such as: - `processors` - `transformprocessor` statements ## Proposed approaches: ### Approach 1 (Recommended): Use yaml tags The first approach relies on the concept of [yaml tags](https://tutorialreference.com/yaml/yaml-tags). We can specify a custom tag in our configuration files to indicate the lists we want to merge. Consider following two configurations: ```yaml #main.yaml receivers: ... exporters: ... extensions: extension1: service: extensions: [extension1] pipelines: logs: receivers: [...] exporters: [...] ``` ```yaml #extra.yaml extensions: extension2: service: extensions: !mode=append [extension2] ``` After running the collector with above configurations, the `service::extensions` path will get merged and final configuration will look like: ```yaml #final.yaml receivers: ... exporters: ... extensions: extension1: extension2: service: extensions: [extension1, extension2] pipelines: logs: receivers: [...] exporters: [...] ``` This approach completely relies on the configuration files and doesn't introduce any command line option. Internally, we will loop through the yaml tree and fetch the paths we want to merged based on user-defined tags, then merge the lists found at those paths. Our "custom" yaml tag will be in the format of URI query parameters. For starters, we can support following options: 1. `mode`: - This setting will control the ordering of merged list. - The value will be either of `append` or `prepend`. - Default: `append` 2. `duplicates`: - This setting controls the duplication of elements in the final list. - If the user wants to allow duplicates, they can simply turn this flag on. - Default: `false` 3. `recursive`: - This setting controls the merging of child elements of the given yaml path. - This is useful if user wants to merge all the lists under a give sub-tree. - For eg. merging all the lists under the `service` section. #### Examples of first approach 1. _Merge the `service::extensions` list_: ```yaml #main.yaml receivers: ... exporters: ... extensions: extension1: service: extensions: [extension1] pipelines: logs: receivers: [...] exporters: [...] --- #extra.yaml extensions: extension2: service: extensions: !mode=append [extension2] ``` ```yaml #final.yaml receivers: ... exporters: ... extensions: extension1: extension2: service: extensions: [extension1, extension2] pipelines: logs: receivers: [...] exporters: [...] ``` 2. _Merge all the lists under the `service::*` section_: ```yaml #main.yaml receivers: ... exporters: ... extensions: extension1: service: extensions: [extension1] pipelines: logs: receivers: [...] exporters: [...] --- #extra.yaml extensions: extension2: receiver: receiver2: service: !mode=append&recursive=true extensions: [extension2] pipelines: logs: receivers: [receiver2] ``` ```yaml #final.yaml receivers: ... receiver2: exporters: ... extensions: extension1: extension2: service: extensions: [extension1, extension2] pipelines: logs: receivers: [..., receiver2] exporters: [...] ``` ### Approach 2: URI params The proposed approach will rely on concept of URI query parameters([_RFC 3986_](https://datatracker.ietf.org/doc/html/rfc3986#page-23)). Our configuration URIs already adhere to this syntax and we can extend it to support query params instead adding new CLI flags. For now, the new merging strategy is only enabled under `confmap.enableMergeAppendOption` gate. If user specifies the options and tries to run the collector without gate, we will merge as per default behaviour. We will support new parameters to config URIs as follows: 1. `merge_paths`: A comma-separated list of glob patterns which will be used while config merging - This setting will control the paths user wants to merge from the given config. - Example: - `otelcol --config main.yaml --config extra.yaml?merge_paths=service::extensions,service::**::receivers` - In this example, we will merge the list of extensions and receivers from pipeline, excluding lists in the rest of the config. - `otelcol --config main.yaml --config ext.yaml?merge_paths=service::extensions --config rec.yaml?merge_paths=service::**::receivers` - In this example, we will merge all list of extensions from `ext.yml` and list of receivers from `rec.yaml`, excluding lists in the rest of the config. 2. `merge_mode`: One of `prepend` or `append`. - This setting will control the ordering of merged list. #### Examples of second approach Here are some examples: 1. _Append to default mergeable components_: ```bash otelcol --config=main.yaml --config=extra_components.yaml?merge_mode=append --feature-gates=confmap.enableMergeAppendOption ``` - After running above command, the final configuration will include: - Merged component(s) (`receivers`, `exporters` and `extensions`) from `extra_components.yaml` 2. _Specify exact paths for merging_: ```bash otelcol \ --config=main.yaml \ --config=extra_extension.yaml?merge_mode=append&merge_paths=service::extensions \ --config=extra_receiver.yaml?merge_mode=append&merge_paths=service::**::receivers \ --feature-gates=confmap.enableMergeAppendOption ``` - After running above command, the final configuration will include: - Merged extension(s) from `extra_extension.yaml` - Merged receiver(s) from `extra_receiver.yaml` 3. _Prepend processors_: ```bash otelcol --config=main.yaml --config=extra_processor.yaml?merge_mode=prepend&merge_paths=service::**::processors --feature-gates=confmap.enableMergeAppendOption ``` - After running above command, the final configuration will include: - Merged processor(s) from `extra_processor.yaml`, but prepend the existing list. 4. _Exclude a config file from lists merging process_: ```bash otelcol --config=main.yaml --config=extra_components.yaml?merge_mode=append --config override_components.yaml --feature-gates=confmap.enableMergeAppendOption ``` - In the above command, we have no specified any options for `override_components.yaml`. Hence, it will override all the conflicting lists from previous configuration, which is the default behaviour. ## Open questions - What to do if an invalid option is provided for `merge_mode` or `merge_paths`? - I can think of two possibilities: 1. Error out. 2. Log an error and merge the default way - What to do if an invalid query param is provided in config URI? - In this case, I strongly feel that we should error out. ## Extensibility This URI-based approach is highly extensible. In the future, it can enable advanced operations such as map overriding. Currently, it's impossible to do so.opentelemetry-collector-0.141.0/docs/rfcs/configuring-confmap-providers.md000066400000000000000000000163141511331344600267200ustar00rootroot00000000000000# Configuration of confmap Providers ## Motivation The `confmap.Provider` interface is used by the Collector to retrieve map objects representing the Collector's configuration or a subset thereof. Sources of config may include locally-available information such as files on disk or environment variables, or may be remotely accessed over the network. In the process of obtaining configuration from a source, the user may wish to modify the behavior of how the source is obtained. For example, consider the case where the Collector obtains configuration over HTTP from an HTTP endpoint. A user may want to: 1. Poll the HTTP endpoint for configuration at a configurable interval and reload the Collector service if the configuration changes. 2. Authenticate the request to get configuration by including a header in the request. Additional headers may be necessary as part of this flow. This would produce a set of options like the following: - `poll-interval`: Sets an interval for the Provider to check the HTTP endpoint for changes. If the config has changed, the service will be reloaded. - `headers`: Specifies a map of headers to be put into the HTTP request to the server. ## Current state No upstream Providers currently offer any configuration options. The exported interfaces are still able to change before the `confmap` module is declared stable, but avoiding breaking changes in the API would be preferable. ## Desired state We would like the following features available to users to configure Providers: 1. Global configuration of a certain type of Provider (`file`, `http`, etc.). This allows for users to express things such as "all files should be watched for changes" and "all HTTP requests should include authentication". 2. Named configuration for a certain type of provider that can be applied to particular URIs. This will allow users to express things such as "some HTTP URLs should be watched for changes with a certain set of settings applied". 3. Configuration options applied to specific URIs. ## Resolution The `confmap` module APIs will not substantially change for 1.0. The following steps will be taken to ensure that configuration can be made to work post-1.0: 1. Restrict URIs sufficiently to allow for extension after 1.0, e.g. restricting the scheme to allow for things like "named schemes" (`file/auth:`). 2. Stabilize confmap Providers individually, so they can impose any desired restrictions on their own. 3. Offer configuration as an optional interface for things like options that are applied to all instances of a Provider. ## Possible technical solutions *NOTE*: This section is speculative and may not reflect the final implementation for providing options to confmap Providers. Providers are invoked through passing `--config` flags to the Collector binary or by using the braces syntax inside a Collector config file (`${scheme:uri}`). Each invocation contains a scheme specifying how to obtain config and URI specifying the config to be obtained. A single instance of a Provider is created for each scheme and is tasked with retrieving config for its scheme for each corresponding URI passed to the Collector. With the above in mind, we have the following places where it may make sense to support specifying options for Providers: 1. Parts of the URI we are requesting. 1. Separate flags to configure Providers per config URI. 1. Use a separate config file that specifies config sources inside a map structure. 1. Extend the Collector's config schema to support specifying additional places to obtain configuration. All of the above options are targeted toward configuring how specific URIs are resolved into config. To configure how a Provider resolves every URI it receives, we should consider how to extend the above options to be specified without a URI and to ensure the options are always applied to all URI resolutions. ### Configure options inside the URI [RFC 3986](https://datatracker.ietf.org/doc/html/rfc3986#section-3), which specifies the format of a URI, specifies the different parts of a URI and suggests two places where we could pass options to Providers: queries and fragments. #### Queries Breaking changes: - confmap Providers would have breaking changes since they would now consume unescaped URI queries. There would be no breaking changes to the confmap API. Advantages: - Explicitly intended to specify non-hierarchical data in a URI. - Often used for this purpose. - Fits into existing config URIs for URL-based Providers. Disadvantages: - Only allows easily specifying key-value pairs. - Query parameters are somewhat frequently used, which may extend to backend requests, and this may cause some churn for users who are unfamiliar that we would be consuming them. #### Fragments We could specify options in a query parameter-encoded string placed into the URI fragment. Breaking changes: - confmap Providers would have breaking changes since they would now consume fragments. There would be no breaking changes to the confmap API. Advantages: - Not likely to be used by config backends for any of our supported protocols, so has a low chance of conflict when using unescaped fragments. - Fits into existing config URIs for URL-based Providers. Disadvantages: - Even if fragments are likely not useful to backends, we are still preventing unescaped use in upstream Providers. - Doesn't conform to the spirit of how fragments should be used according to RFC 3986. - Only allows easily specifying key-value pairs. We could likely partially circumvent the key-value pair limitation by recursively calling confmap Providers to resolve files, env vars, HTTP URLs, etc. For example: ```text https://config.com/config#refresh-interval=env:REFRESH_INTERVAL&headers=file:headers.yaml ``` Using this strategy would also allow us to more easily get env vars and to get values from files for things like API tokens. ### Separate flags to configure Providers per config URI Breaking changes: - Will need factory options if we provide config through a mechanism similar to `component.Factory`, along with making a Provider instance per URI. - Otherwise will need to break `confmap.Provider` interface to support providing options in `Retrieve`. Advantages: - Allows us to keep config URIs opaque. - Options live right next to config URIs on the command line. Disadvantages: - The flags would need to be placed in a certain position in the arguments list to specify which URI they apply to. - Configuring URIs present in files requires users to look in two places for each URI and is suboptimal UX. - Complicating the flags like this would be suboptimal UX. ### Specify additional config sources inside the main Collector configuration This is a variant of providing a separate config source-only configuration file that instead puts those URIs and their options inside the main configuration file. API changes: - Need a way to specify options, either through a factory option, or an optional interface. Advantages: - Allows us to keep URIs opaque. - Map structures are easier to work with than command-line arguments for complex config. Disadvantages: - There are now two ways to include config inside a Collector config file. - Complicates the config schema and the config resolution process. opentelemetry-collector-0.141.0/docs/rfcs/env-vars.md000066400000000000000000000266031511331344600225150ustar00rootroot00000000000000# Stabilizing environment variable resolution ## Overview The OpenTelemetry Collector supports three different syntaxes for environment variable resolution which differ in their syntax, semantics and allowed variable names. Before we stabilize confmap, we need to address several issues related to environment variables. This document describes: - the current (as of v0.97.0) behavior of the Collector - the goals that an environment variable resolution should aim for - existing deviations from these goals - the desired behavior after making some changes ### Out of scope CLI environment variable resolution has a single syntax (`--config env:ENV`) and it is considered out of scope for this document, focusing instead on expansion within the Collector configuration. How to get from the current to desired behavior is also considered out of scope and will be discussed on individual PRs. It will likely involve one or multiple feature gates, warnings and transition periods. ## Goals of an expansion system The following are considered goals of the expansion system: 1. ***Expansion should happen only when the user expects it***. We should aim to expand when the user expects it and keep the original value when we don't (e.g. because the syntax is used for something different). 2. ***Expansion must have predictable behavior***. 3. ***Multiple expansion methods, if present, should have similar behavior.*** Switching from `${env:ENV}` to `${ENV}` or vice versa should not lead to any surprises. 4. ***When the syntax overlaps, expansion should be aligned with*** [***the expansion defined by the Configuration Working Group***](https://github.com/open-telemetry/opentelemetry-specification/blob/032213cedde54a2171dfbd234a371501a3537919/specification/configuration/file-configuration.md#environment-variable-substitution). See [opentelemetry-specification/issues/3963](https://github.com/open-telemetry/opentelemetry-specification/issues/3963) for the counterpart to this line of work in the SDK File spec. ## Current behavior The Collector supports three different syntaxes for environment variable resolution: 1. The *naked syntax*, `$ENV`. 2. The *braces syntax*, `${ENV}`. 3. The *env provider syntax*, `${env:ENV}`. These differ in the character set allowed for environment variable names as well as the type of parsing they return. Escaping is supported in all syntaxes by using two dollar signs. ### Type casting rules A provider or converter takes a string and returns some sort of value after potentially doing some parsing. This gets stored in a `confmap.Conf`. When unmarshalling, we use [mapstructure](https://github.com/mitchellh/mapstructure) with `WeaklyTypedInput` enabled, which does a lot of implicit casting. The details of this type casting are complex and are outlined on issue [#9532](https://github.com/open-telemetry/opentelemetry-collector/issues/9532). When using this notation in inline mode (e.g. `http://endpoint/${env:PATH}`) we also do manual implicit type casting with a similar approach to mapstructure. These are outlined [here](https://github.com/open-telemetry/opentelemetry-collector/blob/fc4c13d3c2822bec39fa9d9658836d1a020c6844/confmap/expand.go#L124-L139). ### Naked syntax The naked syntax is supported via the expand converter. It is implemented using the [`os.Expand`](https://pkg.go.dev/os#Expand) stdlib function. This syntax supports identifiers made up of: 1. ASCII alphanumerics and the `_` character 2. Certain special characters if they appear alone typically used in Bash: `*`, `#`, `$`, `@`, `!`, `?` and `-`. You can see supported identifiers in this example: [`go.dev/play/p/YfxLtYbsL6j`](https://go.dev/play/p/YfxLtYbsL6j). The environment variable value is taken as-is and the type is always string. ### Braces syntax The braces syntax is supported via the expand converter. It is also implemented using the os.Expand stdlib function. This syntax supports any identifiers that don't contain `}`. Again, refer to the os.Expand example to see how it works in practice: [`go.dev/play/p/YfxLtYbsL6j`](https://go.dev/play/p/YfxLtYbsL6j). The environment variable value is taken as-is and the type is always string. ### `env` provider The `env` provider syntax is supported via the `env` provider. It is a custom implementation with a syntax that supports any identifier that does not contain a `$`. This is done to support recursive resolution (e.g. `${env:${http://example.com}}` would get the environment variable whose name is stored in the URL `http://example.com`). The environment variable value is parsed by the yaml.v3 parser to an any-typed variable. The yaml.v3 parser mostly follows the YAML v1.2 specification with [*some exceptions*](https://github.com/go-yaml/yaml#compatibility). You can see how it works for some edge cases in [this go.dev/play example](https://go.dev/play/p/3vNLznwSZQe). ### Issues of current behavior #### Unintuitive behavior on unset environment variables When an environment variable is empty, all syntaxes return an empty string with no warning given; this is frequently unexpected but can also be used intentionally. This is especially unintuitive when the user did not expect expansion to happen. Three examples where this is unexpected are the following: 1. **Opaque values such as passwords that contain `$`** (issue [#8215](https://github.com/open-telemetry/opentelemetry-collector/issues/8215)). If the $ is followed by an alphanumeric character or one of the special characters, it's going to lead to false positives. 2. **Prometheus relabel config** (issue [`contrib#9984`](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/9984)). Prometheus uses `${1}` in some of its configuration values. We resolve this to the value of the environment variable with name '`1`'. 3. **Other uses of $** (issue [`contrib#11846`](https://github.com/open-telemetry/opentelemetry-collector-contrib/issues/11846)). If a product requires the use of `$` in some field, we would most likely interpret it as an environment variable. This is not intuitive for users. #### Unexpected type casting When using the env syntax we parse its value as YAML. Even if you are familiar with YAML, because of the implicit type casting rules and the way we store intermediate values, we can get unintuitive results. The most clear example of this is issue [*#8565*](https://github.com/open-telemetry/opentelemetry-collector/issues/8565): When setting a variable to value `0123` and using it in a string-typed field, it will end up as the string `"83"` (where as the user would expect the string to be `0123`). #### We are less restrictive than the Configuration WG The Configuration WG defines an [*environment variable expansion feature for SDK configurations*](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/configuration/data-model.md#environment-variable-substitution). This accepts only non empty alphanumeric + underscore identifiers starting with alphabetic or underscore. If the Configuration WG were to expand this in the future (e.g. to include other features present in Bash-like syntax as in [opentelemetry-specification/pull/3948](https://github.com/open-telemetry/opentelemetry-specification/pull/3948)), we would not be able to expand our braces syntax to support new features without breaking users. ## Desired behavior *This section is written as if the changes were already implemented.* The Collector supports **two** different syntaxes for environment variable resolution: 1. The *braces syntax*, `${ENV}`. 2. The *env provider syntax*, `${env:ENV}`. These both have **the same character set and behavior**. They both use the env provider under the hood. This means we support the exact same syntax as the Configuration WG. The naked syntax supported in Bash is not supported in the Collector. Escaping is supported by using two dollar signs. Escaping is also honored for unsupported identifiers like `${1}` (i.e. anything that matches `\${[^$}]+}`). ### Type casting rules The environment variable value is parsed by the yaml.v3 parser to an any-typed variable and the original representation as a string is also stored. The `yaml.v3` parser mostly follows the YAML v1.2 specification with [*some exceptions*](https://github.com/go-yaml/yaml#compatibility). You can see how it works for some edge cases in this example: [*https://go.dev/play/p/RtPmH8aZA1X*](https://go.dev/play/p/RtPmH8aZA1X). When unmarshalling, we use mapstructure with WeaklyTypedInput **disabled**. We check via a hook the original string representation of the data and use its return value when it is valid and we are mapping to a string field. This method has default casting rules for unambiguous scalar types but may return the original representation depending on the construction of confmap.Conf (see the comparison table below for details). For using this notation in inline mode (e.g.`http://endpoint/${env:PATH}`), we use the original string representation as well (see the comparison table below for details). ### Character set An environment variable identifier must be a nonempty ASCII alphanumeric or underscore starting with an alphabetic or underscore character. Its maximum length is 200 characters. Both syntaxes support recursive resolution. When an invalid identifier is found, an error is emitted. To use an invalid identifier, the string must be escaped. ### Comparison table with current behavior This is a comparison between the current and desired behavior for loading a field with the braces syntax, `env` syntax. | Raw value | Field type | Current behavior, `${ENV}`, single field | Current behavior, `${env:ENV}` , single field | Desired behavior, entire field | Desired behavior, inline string field | |--------------|------------|------------------------------------------|------------------------------------------------|--------------------------------|---------------------------------------| | `123` | integer | 123 | 123 | 123 | n/a | | `0123` | integer | 83 | 83 | 83 | n/a | | `0123` | string | 0123 | 83 | 0123 | 0123 | | `0xdeadbeef` | string | 0xdeadbeef | 3735928559 | 0xdeadbeef | 0xdeadbeef | | `"0123"` | string | "0123" | 0123 | "0123" | "0123" | | `!!str 0123` | string | !!str 0123 | 0123 | !!str 0123 | !!str 0123 | | `t` | boolean | true | true | Error: mapping string to bool | n/a | | `23` | boolean | true | true | Error: mapping integer to bool | n/a | opentelemetry-collector-0.141.0/docs/rfcs/experimental-profiling.md000066400000000000000000000067751511331344600254500ustar00rootroot00000000000000# Experimental support for profiling ## Overview The OpenTelemetry collector has traces, metrics and logs as stable signals. We want to start experimenting with support for profiles as an experimental signal. But we also don't want to introduce breaking changes in packages otherwise considered stable. This document describes: * The approach we intend to take to introduce profiling with no breaking changes * How the migration will happen once profiling goes stable ### Discarded approaches #### Refactor everything into per-signal subpackages A first approach, discussed in [issue 10207](https://github.com/open-telemetry/opentelemetry-collector/issues/10207) has been discarded. It aimed to refactor the current packages with per-signal subpackages, so each subpackage could have its own stability level, like pdata does. This has been discarded, as the Collector SIG does not want the profiling signal to impact the road to the collector reaching 1.0. #### Use build tags An approach would have been to use build tags to limit the availability of profiles within packages. This approach would make the UX very bad though, as most packages are meant to be imported and not used in a compiled collector. It would therefore not have been possible to specify the appropriate build tags. This has been discarded, as the usage would have been too difficult. ## Proposed approach The proposed approach will consist of two main phases: * Introduce `experimental` packages for each required module of the collector that needs to be profiles-aware. * `consumer`, `receiver`, `connector`, `component`, `processor` * Mark specific APIs as `experimental` in their godoc for parts that can't be a new package. * `service` ### Introduce "experimental" subpackages Each package that needs to be profiling signal-aware will have its public methods and interfaces moves into an internal subpackage. Then, the original package will get similar API methods and interfaces as the ones currently available on the main branch. The profiling methods and interfaces will be made available in a `profiles` subpackage. See [PR #10253](https://github.com/open-telemetry/opentelemetry-collector/pull/10253) for an example. ### Mark specific APIs as `experimental` In order to boot a functional collector with profiles support, some stable packages need to be aware of the experimental ones. To support that case, we will mark new APIs as `experimental` with go docs. Every experimental API will be documented as such: ```golang // # Experimental // // Notice: This method is EXPERIMENTAL and may be changed or removed in a // later release. ``` As documented, APIs marked as experimental may changed or removed across releases, without it being considered as a breaking change. There are no symbols that would need to be marked as experimental today. If there ever are then implementers may add an experimental comment to them #### User specified configuration The user-specified configuration will let users specify a `profiles` pipeline: ``` service: pipelines: profiles: receivers: [otlp] exporters: [otlp] ``` When an experimental signal is being used, the collector will log a warning at boot. ## Signal status change If the profiling signal becomes stable, all the experimental packages will be merged back into their stable counterpart, and the `service` module's imports will be updated. If the profiling signal is removed, all the experimental packages will be removed from the repository, and support for them will be removed in the `service` module. opentelemetry-collector-0.141.0/docs/rfcs/logging-before-config-resolution.md000066400000000000000000000073231511331344600273040ustar00rootroot00000000000000# How To Log Before Config Resolution ## Overview The OpenTelemetry Collector supports configuring a primary logger that the collector and its components use to write logs. This logger cannot be created until the user's configuration has been completely resolved. There is a need to write logs during the collector start-up, before the primary logger is instantiated, such as during configuration resolution or config validation. This document describes - why providing logging capabilities during startup is important - the current (as of v0.99.0) behavior of the Collector - different solutions to the problem - the accepted solution ## Why Logging During Startup is Important When the collector is starting it tries to resolve user configuration as quickly as possible. But the Collector's configuration resolution strategy is not trivial - it allows for complex interactions between multiple, different config sources that must all resolve without error. During this process important information could be shared with users such as: - [Warnings about deprecated syntax](https://github.com/open-telemetry/opentelemetry-collector/issues/9162) - [Warnings about undesired, but handled, situations](https://github.com/open-telemetry/opentelemetry-collector/issues/5615) - Debug information ## Requirements for any solution 1. Once the primary logger is instantiated, it should be usable anywhere in the Collector that does logging. 2. Log timestamps must be accurate to when the log was written, regardless of when the log is written to the user-specified location(s). 3. The EntryCaller (what line number the log originates from) must be accurate to where the log was written. 4. If an error causes the collector to gracefully terminate before the primary logger is created any previously written logs MUST be written to the either stout or stderr if they have not already been written there. ## Current behavior As of v0.99.0, the collector does not provide a way to log before the primary logger is instantiated. ## Solutions ### Buffer Logs in Memory and Write Them Once the Primary Logger Exists The Collector could provide a temporary logger that, when written to, keeps the logs in memory. These logs could then be passed to the primary logger to be written out in the properly configured format/level. Benefits: - Logs are written in the user-specified format/level Downsides: - If the primary logger is used to write any logs before the buffered logs are passed, logs may be out of order. There are no guarantees that logs will be written in order, so the log timestamps should be taken as the source of truth for ordering. ### Create a Logger Using the Primary Logger's Defaults When the user provides no primary logger configuration the Collector creates a Logger using a set of default values. The Collector could, very early in startup, create a logger using these exact defaults and use it until the primary logger is instantiated. Benefits: - Logs order is preserved - Logs are still written when an error occurs before the primary logger can be instantiated Downsides: - Logs may be written in a format/level that differs from the format/level of the primary logger ## Accepted Solution [Buffer Logs in Memory and Write Them Once the Primary Logger Exists](#buffer-logs-in-memory-and-write-them-once-the-primary-logger-exists) This solution, while more complex, allows the collector to write out the logs in the user-specified format whenever possible. A fallback logger must be used in situations where the primary logger could not be created and the collector is shutting down, such as when encountering an error during configuration resolution, but otherwise the primary logger will be used to write logs that occurred before the primary logger existed. opentelemetry-collector-0.141.0/docs/rfcs/metadata.yaml000066400000000000000000000003271511331344600230710ustar00rootroot00000000000000type: rfcs github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: docs codeowners: active: - codeboten - bogdandrutu - dmitryax - mx-psi opentelemetry-collector-0.141.0/docs/rfcs/optional-config-type.md000066400000000000000000000205421511331344600250170ustar00rootroot00000000000000# Optional[T] type for use in configuration structs ## Overview In Go, types are by default set to a "zero-value", a supported value for the respective type that is semantically equivalent or similar to "empty", but which is also a valid value for the type. For many config fields, the zero value is not a valid configuration value and can be taken to mean that the option is disabled, but in certain cases it can indicate a default value, necessitating a way to represent the presence of a value without using a valid value for the type. Using standard Go without inventing any new types, the two most straightforward ways to accomplish this are: 1. Using a separate boolean field to indicate whether the field is enabled or disabled. 2. Making the type a pointer, which makes a `nil` pointer represent that a value is not present, and a valid pointer represent the desired value. Each of these approaches has deficiencies: Using a separate boolean field requires the user to set the boolean field to `true` in addition to setting the actual config option, leading to suboptimal UX. Using a pointer value has a few drawbacks: 1. It may not be immediately obvious to a new user that a pointer type indicates a field is optional. 2. The distinction between values that are conventionally pointers (e.g. gRPC configs) and optional values is lost. 3. Setting a default value for a pointer field when decoding will set the field on the resulting config struct, and additional logic must be done to unset the default if the user has not specified a value. 4. The potential for null pointer exceptions is created. 5. Config structs are generally intended to be immutable and may be passed around a lot, which makes the mutability property of pointer fields an undesirable property. ## Optional types Go does not include any form of Optional type in the standard library, but other popular languages like Rust and Java do. We could implement something similar in our config packages that allows us to address the downsides of using pointers for optional config fields. ## Basic definition A production-grade implementation will not be discussed or shown here, but the basic implementation for an Optional type in Go could look something like: ```golang type Optional[T any] struct { hasValue bool value T defaultVal T } func Some[T any](value T) Optional[T] { return Optional[T]{value: value, hasValue: true} } func None[T any]() Optional[T] { return Optional[T]{} } func WithDefault[T any](defaultVal T) Optional[T] { return Optional[T]{defaultVal: defaultVal} } func (o Optional[T]) HasValue() bool { return o.hasValue } func (o Optional[T]) Value() T { return o.value } func (o Optional[T]) Default() T { return o.defaultVal } ``` ## Use cases Optional types can fulfill the following use cases we have when decoding config. ### Representing optional config fields To use the optional type to mark a config field as optional, the type can simply be used as a type parameter to `Optional[T]`. The YAML representation of `Optional[T]` is the same as that of `T`, except that the type records whether the value is present. The following config struct shows how this may look, both in definition and in usage: ```golang type Protocols struct { GRPC Optional[configgrpc.ServerConfig] `mapstructure:"grpc"` HTTP Optional[HTTPConfig] `mapstructure:"http"` } func (cfg *Config) Validate() error { if !cfg.GRPC.HasValue() && !cfg.HTTP.HasValue() { return errors.New("must specify at least one protocol when using the OTLP receiver") } return nil } func createDefaultConfig() component.Config { return &Config{ Protocols: Protocols{ GRPC: WithDefault(configgrpc.ServerConfig{ // ... }), HTTP: WithDefault(HTTPConfig{ // ... }), }, } } ``` For something like `confighttp.ServerConfig`, using an `Optional[T]` type for optional fields would look like this: ```golang type ServerConfig struct { TLSSetting Optional[configtls.ServerConfig] `mapstructure:"tls"` CORS Optional[CORSConfig] `mapstructure:"cors"` Auth Optional[AuthConfig] `mapstructure:"auth,omitempty"` ResponseHeaders Optional[map[string]configopaque.String] `mapstructure:"response_headers"` } func NewDefaultServerConfig() ServerConfig { return ServerConfig{ TLSSetting: WithDefault(configtls.NewDefaultServerConfig()), CORS: WithDefault(NewDefaultCORSConfig()), WriteTimeout: 30 * time.Second, ReadHeaderTimeout: 1 * time.Minute, IdleTimeout: 1 * time.Minute, } } func (sc *ServerConfig) ToListener(ctx context.Context) (net.Listener, error) { listener, err := net.Listen("tcp", sc.Endpoint) if err != nil { return nil, err } if sc.TLSSetting.HasValue() { var tlsCfg *tls.Config tlsCfg, err = sc.TLSSetting.Value().LoadTLSConfig(ctx) if err != nil { return nil, err } tlsCfg.NextProtos = []string{http2.NextProtoTLS, "http/1.1"} listener = tls.NewListener(listener, tlsCfg) } return listener, nil } func (sc *ServerConfig) ToServer(_ context.Context, host component.Host, settings component.TelemetrySettings, handler http.Handler, opts ...ToServerOption) (*http.Server, error) { // ... handler = httpContentDecompressor( handler, sc.MaxRequestBodySize, serverOpts.ErrHandler, sc.CompressionAlgorithms, serverOpts.Decoders, ) // ... if sc.Auth.HasValue() { server, err := sc.Auth.Value().GetServerAuthenticator(context.Background(), host.GetExtensions()) if err != nil { return nil, err } handler = authInterceptor(handler, server, sc.Auth.Value().RequestParameters) } corsValue := sc.CORS.Value() if sc.CORS.HasValue() && len(sc.CORS.AllowedOrigins) > 0 { co := cors.Options{ AllowedOrigins: corsValue.AllowedOrigins, AllowCredentials: true, AllowedHeaders: corsValue.AllowedHeaders, MaxAge: corsValue.MaxAge, } handler = cors.New(co).Handler(handler) } if sc.CORS.HasValue() && len(sc.CORS.AllowedOrigins) == 0 && len(sc.CORS.AllowedHeaders) > 0 { settings.Logger.Warn("The CORS configuration specifies allowed headers but no allowed origins, and is therefore ignored.") } if sc.ResponseHeaders.HasValue() { handler = responseHeadersHandler(handler, sc.ResponseHeaders.Value()) } // ... } ``` ### Proper unmarshaling of empty values when a default is set Currently, the OTLP receiver requires a workaround to make enabling each protocol optional while providing defaults if a key for the protocol has been set: ```golang type Protocols struct { GRPC *configgrpc.ServerConfig `mapstructure:"grpc"` HTTP *HTTPConfig `mapstructure:"http"` } // Config defines configuration for OTLP receiver. type Config struct { // Protocols is the configuration for the supported protocols, currently gRPC and HTTP (Proto and JSON). Protocols `mapstructure:"protocols"` } func createDefaultConfig() component.Config { return &Config{ Protocols: Protocols{ GRPC: configgrpc.NewDefaultServerConfig(), HTTP: &HTTPConfig{ // ... }, }, } } func (cfg *Config) Unmarshal(conf *confmap.Conf) error { // first load the config normally err := conf.Unmarshal(cfg) if err != nil { return err } // gRPC will be enabled if this line is not run if !conf.IsSet(protoGRPC) { cfg.GRPC = nil } // HTTP will be enabled if this line is not run if !conf.IsSet(protoHTTP) { cfg.HTTP = nil } return nil } ``` With an Optional type, the checks in `Unmarshal` become unnecessary, and it's possible the entire `Unmarshal` function may no longer be needed. Instead, when the config is unmarshaled, no value would be put into the default Optional values and `HasValue` would return false when using this config object. This situation is something of an edge case with our current unmarshaling facilities and while not common, could be a rough edge for users looking to implement similar config structures. ## Disadvantages of an Optional type There is one noteworthy disadvantage of introducing an Optional type: 1. Since the type isn't standard, external packages working with config may require additional adaptations to work with our config structs. For example, if we wanted to generate our types from a JSON schema using a package like [github.com/atombender/go-jsonschema][go-jsonschema], we would need some way to ensure compatibility with an Optional type. [go-jsonschema]: https://github.com/omissis/go-jsonschema opentelemetry-collector-0.141.0/docs/rfcs/processing.md000066400000000000000000000376711511331344600231370ustar00rootroot00000000000000# OpenTelemetry Collector Processor Exploration **Status:** *Draft* ## Objective To describe a user experience and strategies for configuring processors in the OpenTelemetry collector. This work is being prototyped in opentelemetry-collector-contrib, the design doc is here for broader discussion. ## Summary The OpenTelemetry (OTel) collector is a tool to set up pipelines to receive telemetry from an application and export it to an observability backend. Part of the pipeline can include processing stages, which executes various business logic on incoming telemetry before it is exported. Over time, the collector has added various processors to satisfy different use cases, generally in an ad-hoc way to support each feature independently. We can improve the experience for users of the collector by consolidating processing patterns in terms of user experience, and this can be supported by defining a querying model for processors within the collector core, and likely also for use in SDKs, to simplify implementation and promote the consistent user experience and best practices. ## Goals and non-goals Goals: - List out use cases for processing within the collector - Consider what could be an ideal configuration experience for users Non-Goals: - Merge every processor into one. Many use cases overlap and generalize, but not all of them - Technical design or implementation of configuration experience. Currently focused on user experience. ## Use cases for processing ### Telemetry mutation Processors can be used to mutate the telemetry in the collector pipeline. OpenTelemetry SDKs collect detailed telemetry from applications, and it is common to have to mutate this into a way that is appropriate for an individual use case. Some types of mutation include - Remove a forbidden attribute such as `http.request.header.authorization` - Reduce cardinality of an attribute such as translating `http.target` value of `/user/123451/profile` to `/user/{userId}/profile` - Decrease the size of the telemetry payload by removing large resource attributes such as `process.command_line` - Filtering out signals such as by removing all telemetry with a `http.target` of `/health` - Attach information from resource into telemetry, for example adding certain resource fields as metric dimensions The processors implementing this use case are `attributesprocessor`, `filterprocessor`, `metricstransformprocessor`, `resourceprocessor`, `spanprocessor`. ### Metric generation The collector may generate new metrics based on incoming telemetry. This can be for covering gaps in SDK coverage of metrics vs spans, or to create new metrics based on existing ones to model the data better for backend-specific expectations. - Create new metrics based on information in spans, for example to create a duration metric that is not implemented in the SDK yet - Apply arithmetic between multiple incoming metrics to produce an output one, for example divide an `amount` and a `capacity` to create a `utilization` metric The components implementing this use case are `metricsgenerationprocessor` and the former `spanmetricsprocessor` (now `spanmetricsconnector`). ### Grouping Some processors are stateful, grouping telemetry over a window of time based on either a trace ID or an attribute value, or just general batching. - Batch incoming telemetry before sending to exporters to reduce export requests - Group spans by trace ID to allow doing tail sampling - Group telemetry for the same path The processors implementing this use case are `batchprocessor`, `groupbyattrprocessor`, `groupbytraceprocessor`. ### Metric temporality Two processors convert between the two types of temporality, cumulative and delta. The conversion is generally expected to happen as close to the source data as possible, for example within receivers themselves. The same configuration mechanism could be used for selecting metrics for temporality conversion as other cases, but it is expected that in practice configuration will be limited. The processors implementing this use case are `cumulativetodeltaprocessor`. ### Telemetry enrichment OpenTelemetry SDKs focus on collecting application specific data. They also may include resource detectors to populate environment specific data but the collector is commonly used to fill gaps in coverage of environment specific data. - Add environment about a cloud provider to `Resource` of all incoming telemetry The processors implementing this use case are `k8sattributesprocessor`, `resourcedetectionprocessor`. ## OpenTelemetry Transformation Language When looking at the use cases, there are certain common features for telemetry mutation and metric generation. - Identify the type of signal (`span`, `metric`, `log`). - Navigate to a path within the telemetry to operate on it - Define an operation, and possibly operation arguments We can try to model these into a transformation language, in particular allowing the first two points to be shared among all processing operations, and only have implementation of individual types of processing need to implement operators that the user can use within an expression. Telemetry is modeled in the collector as [`pdata`](https://github.com/open-telemetry/opentelemetry-collector/tree/main/pdata) which is roughly a 1:1 mapping of the [OTLP protocol](https://github.com/open-telemetry/opentelemetry-proto/tree/main/opentelemetry/proto). This data can be navigated using field expressions, which are fields within the protocol separated by dots. For example, the status message of a span is `status.message`. A map lookup can include the key as a string, for example `attributes["http.status_code"]`. Operations are scoped to the type of a signal (`span`, `metric`, `log`), with all of the flattened points of that signal being part of a transformation space. Virtual fields are added to access data from a higher level before flattening, for `resource`, `library_info`. For metrics, the structure presented for processing is actual data points, e.g. `NumberDataPoint`, `HistogramDataPoint`, with the information from higher levels like `Metric` or the data type available as virtual fields. Virtual fields for all signals: `resource`, `library_info`. Virtual fields for metrics: `metric`, which contains `name`, `description`, `unit`, `type`, `aggregation_temporality`, and `is_monotonic`. Navigation can then be used with a simple expression language for identifying telemetry to operate on. ``` ... where name = "GET /cats" ``` ``` ... from span where attributes["http.target"] = "/health" ``` ``` ... where resource.attributes["deployment"] = "canary" ``` ``` ... from metric where metric.type = gauge ``` ``` ... from metric where metric.name = "http.active_requests" ``` Fields should always be fully specified - for example `attributes` refers to the `attributes` field in the telemetry, not the `resource`. In the future, we may allow shorthand for accessing scoped information that is not ambiguous. Having selected telemetry to operate on, any needed operations can be defined as functions. Known useful functions should be implemented within the collector itself, provide registration from extension modules to allow customization with contrib components, and in the future can even allow user plugins possibly through WASM, similar to work in [HTTP proxies](https://github.com/proxy-wasm/spec). The arguments to operations will primarily be field expressions, allowing the operation to mutate telemetry as needed. There are times when the transformation language input and the underlying telemetry model do not translate cleanly. For example, a span ID is represented in pdata as a SpanID struct, but in the transformation language it is more natural to represent the span ID as a string or a byte array. The solution to this problem is Factories. Factories are functions that help translate between the transformation language input into the underlying pdata structure. These types of functions do not change the telemetry in any way. Instead, they manipulate the transformation language input into a form that will make working with the telemetry easier or more efficient. ### Examples These examples contain a SQL-like declarative language. Applied statements interact with only one signal, but statements can be declared across multiple signals. Remove a forbidden attribute such as `http.request.header.authorization` from spans only ``` traces: delete(attributes["http.request.header.authorization"]) metrics: delete(attributes["http.request.header.authorization"]) logs: delete(attributes["http.request.header.authorization"]) ``` Remove all attributes except for some ``` traces: keep_keys(attributes, "http.method", "http.status_code") metrics: keep_keys(attributes, "http.method", "http.status_code") logs: keep_keys(attributes, "http.method", "http.status_code") ``` Reduce cardinality of an attribute ``` traces: replace_match(attributes["http.target"], "/user/*/list/*", "/user/{userId}/list/{listId}") ``` Reduce cardinality of a span name ``` traces: replace_match(name, "GET /user/*/list/*", "GET /user/{userId}/list/{listId}") ``` Reduce cardinality of any matching attribute ``` traces: replace_all_matches(attributes, "/user/*/list/*", "/user/{userId}/list/{listId}") ``` Decrease the size of the telemetry payload by removing large resource attributes ``` traces: delete(resource.attributes["process.command_line"]) metrics: delete(resource.attributes["process.command_line"]) logs: delete(resource.attributes["process.command_line"]) ``` Filtering out signals such as by removing all metrics with a `http.target` of `/health` ``` metrics: drop() where attributes["http.target"] = "/health" ``` Attach information from resource into telemetry, for example adding certain resource fields as metric attributes ``` metrics: set(attributes["k8s_pod"], resource.attributes["k8s.pod.name"]) ``` Group spans by trace ID ``` traces: group_by(trace_id, 2m) ``` Update a spans ID ``` logs: set(span_id, SpanID(0x0000000000000000)) traces: set(span_id, SpanID(0x0000000000000000)) ``` Create utilization metric from base metrics. Because navigation expressions only operate on a single piece of telemetry, helper functions for reading values from other metrics need to be provided. ``` metrics: create_gauge("pod.cpu.utilized", read_gauge("pod.cpu.usage") / read_gauge("node.cpu.limit") ``` A lot of processing. Queries are executed in order. While initially performance may degrade compared to more specialized processors, the expectation is that over time, the transform processor's engine would improve to be able to apply optimizations across queries, compile into machine code, etc. ```yaml receivers: otlp: exporters: otlp: processors: transform: # Assuming group_by is defined in a contrib extension module, not baked into the "transform" processor extensions: [group_by] traces: queries: - drop() where attributes["http.target"] = "/health" - delete(attributes["http.request.header.authorization"]) - replace_wildcards("/user/*/list/*", "/user/{userId}/list/{listId}", attributes["http.target"]) - group_by(trace_id, 2m) metrics: queries: - drop() where attributes["http.target"] = "/health" - delete(attributes["http.request.header.authorization"]) - replace_wildcards("/user/*/list/*", "/user/{userId}/list/{listId}", attributes["http.target"]) - set(attributes["k8s_pod"], resource.attributes["k8s.pod.name"]) logs: queries: - drop() where attributes["http.target"] = "/health" - delete(attributes["http.request.header.authorization"]) - replace_wildcards("/user/*/list/*", "/user/{userId}/list/{listId}", attributes["http.target"]) pipelines: - receivers: [otlp] exporters: [otlp] processors: [transform] ``` The expressions would be executed in order, with each expression either mutating an input telemetry, dropping input telemetry, or adding additional telemetry. One caveat to note is that we would like to implement optimizations in the transform engine, for example to only apply filtering once for multiple operations with a shared filter. Functions with unknown side effects may cause issues with optimization we will need to explore. ## Declarative configuration The telemetry transformation language presents an SQL-like experience for defining telemetry transformations - it is made up of the three primary components described above, however, and can be presented declaratively instead depending on what makes sense as a user experience. ```yaml - type: span filter: match: path: status.code value: OK operation: name: drop - type: all operation: name: delete args: - attributes["http.request.header.authorization"] ``` An implementation of the transformation language would likely parse expressions into this sort of structure so given an SQL-like implementation, it would likely be little overhead to support a YAML approach in addition. ## Function syntax Functions should be named and formatted according to the following standards. - Function names MUST start with a verb unless it is a Factory. - Factory functions MUST be UpperCamelCase and named based on the object being created. - Function names that contain multiple words MUST separate those words with `_`. - Functions that interact with multiple items MUST have plurality in the name. Ex: `truncate_all`, `keep_keys`, `replace_all_matches`. - Functions that interact with a single item MUST NOT have plurality in the name. If a function would interact with multiple items due to a condition, like `where`, it is still considered singular. Ex: `set`, `delete`, `drop`, `replace_match`. - Functions that change a specific target MUST set the target as the first parameter. - Functions that take a list MUST set the list as the last parameter. ## Implementing a processor function The `replace_match` function may look like this. ```go package replaceMatch import "regexp" import "github.com/open-telemetry/opentelemetry/processors" // Assuming this is not in "core" processors.register("replace_match", replace_match) func replace_match(path processors.TelemetryPath, pattern regexp.Regexp, replacement string) processors.Result { val := path.Get() if val == nil { return processors.CONTINUE } // replace finds placeholders in "replacement" and swaps them in for regex matched substrings. replaced := replace(val, pattern, replacement) path.Set(replaced) return processors.CONTINUE } ``` Here, the processor framework recognizes the second parameter of the function is `regexp.Regexp` so will compile the string provided by the user in the config when processing it. Similarly for `path`, it recognizes properties of type `TelemetryPath` and will resolve it to the path within a matched telemetry during execution and pass it to the function. The path allows scalar operations on the field within the telemetry. The processor does not need to be aware of telemetry filtering, the `where ...` clause, as that will be handled by the framework before passing to the function. ## Embedded processors The above describes a transformation language for configuring processing logic in the OpenTelemetry collector. There will be a single processor that exposes the processing logic into the collector config; however, the logic will be implemented within core packages rather than directly inside a processor. This is to ensure that where appropriate, processing can be embedded into other components, for example metric processing is often most appropriate to execute within a receiver based on receiver-specific requirements. ## Limitations There are some known issues and limitations that we hope to address while iterating on this idea. - Handling array-typed attributes - Working on a array of points, rather than a single point - Metric alignment - for example defining an expression on two metrics, that may not be at the same timestamp - The collector has separate pipelines per signal - while the transformation language could apply cross-signal, we will need to remain single-signal for now opentelemetry-collector-0.141.0/docs/rfcs/release-approvers.md000066400000000000000000000106151511331344600244070ustar00rootroot00000000000000# OpenTelemetry Collector Releases approvers ## Problem statement Release engineering requires a different set of skills and interests than developing the Collector codebase. As such, the set of contributors for the Collector releases has overlap with but is different from the set of contributors for the Collector codebase. We are missing out on retaining people who are more interested in these aspects. We can see this with the examples of the OpenTelemetry Operator repository and the OpenTelemetry Collector Helm Chart repository; they are able to work independently from the other Collector repositories and have been able to create an independent community. We also have a [growing backlog][1] of issues related to the release process that would benefit from a dedicated set of people. ## Overview I propose we create a new `collector-releases-approvers` Github team that are [approvers][2] on the [opentelemetry-collector-releases][3] repository and code owners for the Builder and release workflows. The existing approvers teams will focus on the Collector and Collector components codebases. This opens future possibilities for creating a separate WG/SIG for this and further improving our release process. ## Team scope and responsibilities The `collector-releases-approvers` team will be [approvers][2] for the opentelemetry-collector-releases repository. They will also be listed as [code owners][4] for the release workflows on the opentelemetry-collector and opentelemetry-collector-contrib repositories. The new team will not acquire any responsibilities related to the release; there will be no changes in the release rotation or release duties after this change. ## Initial team members Initially, all members of the `collector-contrib-approvers` team will be part of the `collector-releases-approvers` team. The Collector maintainers will reach out to existing contributors to the Collector releases to invite them to join the team. ## Prior art This introduces an approver group without a maintainer. It also introduces this team as a code owner for files in other repositories. There are prior instances of both of these patterns within the OpenTelemetry project: 1. There are currently two SIGs that have approver teams without corresponding maintainer teams: - The Docs SIG has multiple localization approver teams that have approver duties for the translations of the OpenTelemetry documentation. - The Semantic Conventions SIG has multiple approver teams corresponding to different Working Groups and/or semantic conventions areas. 2. There are multiple instances of teams being code owners: - [opentelemetry-collector approvers are code owners for `examples/demo` in `opentelemetry-collector-contrib`][5] - [Helm chart and Operator approvers are code owners for the k8s distro in `opentelemetry-collector-releases`][6] - [Go instrumentation approvers are code owners of instrgen in `opentelemetry-go-contrib`][7] ## Future work If we are able to grow a healthy community around the releases repository, in the future we can consider the following: - Having a dedicated SIG/WG for the opentelemetry-collector-releases repository. - Making the `collector-releases-approvers` code owners of the OpenTelemetry Collector Builder. - Having dedicated meetings for release retros that allow us to iteratively improve the Collector release process. - Splitting off the artifact and container release process to be independent from the source code release from opentelemetry-collector and opentelemetry-collector-contrib. This proposal does not require us to do any of the above, but they are interesting possibilities for the future. [1]: https://github.com/search?q=org%3Aopen-telemetry+label%3Arelease-retro++&type=issues&state=open [2]: https://github.com/open-telemetry/community/blob/main/guides/contributor/membership.md#approver [3]: https://github.com/open-telemetry/opentelemetry-collector-releases [4]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/CONTRIBUTING.md#membership-roles-and-responsibilities [5]: https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/40fa8b8a925cadf569e785cbc85d6dfca152bde2/.github/CODEOWNERS#L40 [6]: https://github.com/open-telemetry/opentelemetry-collector-releases/blob/3ba7931410d1696d9df7bef424b634a5d64cffbd/.github/CODEOWNERS#L17 [7]: https://github.com/open-telemetry/opentelemetry-go-contrib/blob/c0cc77f10a2dae774161d6a03441b12c0e8b0816/CODEOWNERS#L73 opentelemetry-collector-0.141.0/docs/scraping-receivers.md000066400000000000000000000217361511331344600236140ustar00rootroot00000000000000# Scraping Metrics Receivers Scraping metrics receivers are receivers that pull data from external sources at regular intervals and translate it into [pdata](../pdata/README.md) which is sent further in the pipeline. The external source of metrics usually is a monitored system providing data about itself in some arbitrary format. There are two types of scraping metrics receivers: - **Generic scraping metrics receivers:** The set of metrics emitted by this type of receiver fully depends on the state of the external source and/or the user settings. Examples: - [Prometheus Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/prometheusreceiver) - [SQL Query Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/sqlqueryreceiver) - **Built-in scraping metrics receivers:** Receivers of this type emit a predefined set of metrics. However, the metrics themselves are configurable via user settings. Examples of scrapings metrics receivers: - [Redis Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/redisreceiver) - [Zookeeper Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/zookeeperreceiver) This document covers built-in scraping metrics receivers. It defines which metrics these receivers can emit, defines stability guarantees and provides guidelines for metric updates. ## Defining emitted metrics Each built-in scraping metrics receiver has a `metadata.yaml` file that MUST define all the metrics emitted by the receiver. The file is being used to generate an API for metrics recording, user settings to customize the emitted metrics and user documentation. The file schema is defined in https://github.com/open-telemetry/opentelemetry-collector/blob/main/cmd/mdatagen/metadata-schema.yaml Defining a metric in `metadata.yaml` DOES NOT guarantee that the metric will always be produced by the receiver. In some cases it may be impossible to fetch particular metrics from a system in a particular state. There are two categories of the metrics emitted by scraping receivers: - **Default metrics**: emitted by default, but can be disabled in user settings. - **Optional metrics**: not emitted by default, but can be enabled in user settings. See also [Semantic Convention compatibility](./coding-guidelines.md#semantic-conventions-compatibility) guidance. ### How to identify if new metric should be default or optional? There is no strict rule to differentiate default metrics from optional. As a rule of thumb, default metrics SHOULD be treated as metrics essential to determine healthiness of a particular monitored system. Optional metrics on the other hand SHOULD be treated as a source of additional information about the monitored system. Additionally, if any of the following conditions can be applied to a metric, it MUST be marked as optional: - **It is redundant with another metric.** For example system CPU usage can be emitted as two different metrics: `system.cpu.time` (CPU time reported as cumulative sum in seconds) or `system.cpu.utilization` (fraction of CPU time spent in different states reported as gauge), one of them has to be marked as option. - **It creates a disproportionately high cardinality of resources and/or data points.** - **There is a notable expected performance impact.** - **The source must be configured in an unusual way.** - **It requires dedicated configuration in the receiver.** ## Stability levels of scraping receivers All the requirements defined for components in [the Collector's README](../README.md#stability-levels) are applicable to the scraping receivers as well. In addition, the following rules applied specifically to scraping metrics receivers: ### Development The receiver is not ready for use. All the metrics emitted by the receiver are not finalized and can change in any way. ### Alpha The receiver is ready for limited non-critical workloads. The list of emitted default metrics SHOULD be considered as complete, but any changes to the `metadata.yaml` still MAY be applied. ### Beta The receiver is ready for non-critical production workloads. The list of emitted default metrics MUST be considered as complete. Breaking changes to the emitted metrics SHOULD be applied following [the deprecation process](#changing-the-emitted-metrics). ### Stable The receiver is ready for production workloads. Breaking changes to the emitted metrics SHOULD be avoided. Nevertheless, metrics that are emitted by default MUST be always kept up-to-date with the latest stable version of the monitored system. Given that, occasional breaking changes in the emitted metrics are expected even in the stable receivers. Any breaking change MUST be applied following [the deprecation process](#changing-the-emitted-metrics). ## Changing the emitted metrics Some changes are not considered breaking and can be applied to metrics emitted by scraping receivers of any stability level: - Adding a new optional metric. Most of other changes to the emitted metrics are considered breaking and MUST be handled according to the stability level of the receiver. Each type of breaking change defines a set of steps that MUST (or SHOULD) be applied across several releases for a Stable (or Beta) components. At least 3 versions SHOULD be kept between the steps to give users time to prepare, e.g. if the first step is released in v0.62.0, the second step SHOULD be released not earlier than 0.65.0. Any warnings SHOULD include the version starting from which the next step will take effect. If a breaking change is more complicated and many metrics are involved in the change, feature gates SHOULD be used instead. ### Removing an optional metric Steps to remove an optional metric: 1. Mark the metric as deprecated in `metadata.yaml` by adding "[DEPRECATED]" in its description. Show a warning that the metric will be removed if the `enabled` option is set explicitly to `true` in user settings. 2. Remove the metric. ### Removing a default metric Steps to remove a default metric: 1. Mark the metric as deprecated in `metadata.yaml` by adding "[DEPRECATED]" in its description. Show a warning that the metric will be removed if the `enabled` option is not explicitly set to `false` in user settings. 2. Make the metric optional. Show a warning that the metric will be removed if the `enabled` option is set to `true` in user settings. 3. Remove the metric. ### Making a default metric optional Steps to turn a metric from default to optional: 1. Add a warning that the metric will be turned into optional if `enabled` field is not set explicitly to any value in user settings. Warning example: "WARNING: Metric `foo.bar` will be disabled by default in v0.65.0. If you want to keep it, please enable it explicitly in the receiver settings." 2. Remove the warning and update `metadata.yaml` to make the metric optional. ### Adding a new default metric or turning an existing optional metric into default Adding a new default metric is a breaking change for a scraping receiver because it introduces an unexpected output for users and additional load on metric backends. Steps to apply such a change: 1. If the metric doesn't exist yet, add one as an optional metric. Add a warning that the metric will be turned into default if the `enabled` option is not set explicitly to any value in user settings. A warning example: "WARNING: Metric `foo.bar` will be enabled by default in v0.65.0. If you don't want the metric to be emitted, please disable it in the receiver settings." 2. Remove the warning and update `metadata.yaml` to make the metric default. ### Other changes Other breaking changes SHOULD follow similar strategies inspecting presence of `enabled` field in user settings. For example, if a metric has to be renamed for any reason, the guidelines for "Removing an optional metric" and "Adding a new default metric" SHOULD be followed simultaneously. Breaking changes that cannot be done through enabling/disabling metrics (e.g. removing or adding an extra attribute) SHOULD be applied using a feature gate with the following steps: 1. Add a feature gate that is disabled by default. Enabling the feature gate changes the metrics behavior in a desired way. For example, if several metrics emitted by host metrics receiver need to be updated to have an additional `direction` attribute, the following feature gate can be used: `receiver.hostmetricsreceiver.emitMetricsWithDirectionAttribute`. Show user a warning if the feature gate is not enabled explicitly, for example: "[WARNING] Metrics `system.network.packets` and `system.network.errors` will be changed in v0.65.0 to emit an additional `direction` attribute, enable a feature gate `receiver.hostmetricsreceiver.emitMetricsWithDirectionAttribute` to apply and test the upcoming changes earlier". 2. Enable the feature gate by default and update the warning thrown if user disables the feature gate explicitly. 3. Remove the feature gate along with the old behavior. opentelemetry-collector-0.141.0/docs/security-best-practices.md000066400000000000000000000072021511331344600245660ustar00rootroot00000000000000# Security The OpenTelemetry Collector defaults to operating in a secure manner but is configuration driven. This document captures important security aspects and considerations for the Collector. This document is intended for component developers. It assumes at least a basic understanding of the Collector architecture and functionality. > Note: Please review the > [configuration documentation](https://opentelemetry.io/docs/collector/configuration/) > prior to this security document. Security documentation for end users can be found on the OpenTelemetry documentation website: - [Collector configuration best practices](https://opentelemetry.io/docs/security/config-best-practices/) - [Collector hosting best practices](https://opentelemetry.io/docs/security/hosting-best-practices/) ## TL;DR - Configuration - MUST come from the central configuration file - SHOULD use configuration helpers - Permissions - SHOULD minimize privileged access - MUST document what requires privileged access and why - Receivers/Exporters - MUST default to encrypted connections - SHOULD leverage helper functions - Extensions - SHOULD NOT expose sensitive health or telemetry data by default > For more information about securing the OpenTelemetry Collector, see > [this blog post](https://medium.com/opentelemetry/securing-your-opentelemetry-collector-1a4f9fa5bd6f). ## Configuration The Collector binary does not contain an embedded or default configuration and MUST NOT start without a configuration file being specified. The configuration file passed to the Collector MUST be validated prior to being loaded. If an invalid configuration is detected, the Collector MUST fail to start as a protective mechanism. Component developers MUST get configuration information from the Collector's configuration file. Component developers SHOULD leverage [configuration helper functions](https://github.com/open-telemetry/opentelemetry-collector/tree/main/config). When defining Go structs for configuration data that may contain sensitive information, use the `configopaque` package to define fields with the `configopaque.String` type. This ensures that the data is masked when serialized to prevent accidental exposure. > For more information, see the > [configopaque](https://pkg.go.dev/go.opentelemetry.io/collector/config/configopaque) > documentation. ## Permissions The Collector supports running as a custom user and SHOULD NOT be run as a root/admin user. For the majority of use-cases, the Collector SHOULD NOT require privileged access to function. Some components MAY require privileged access or external permissions, including network access or RBAC. Component developers SHOULD minimize privileged access requirements and MUST document what requires privileged access and why. ## Receivers and Exporters Receivers and Exporters can be either push or pull-based. In either case, the connection established SHOULD be over a secure and authenticated channel. Component developers MUST default to encrypted connections (using the `insecure: false` configuration setting) and SHOULD leverage [gRPC](https://github.com/open-telemetry/opentelemetry-collector/tree/main/config/configgrpc) and [http](https://github.com/open-telemetry/opentelemetry-collector/tree/main/config/confighttp) helper functions. ## Safeguards against denial of service attacks See the [Collector configuration security documentation](https://opentelemetry.io/docs/security/config-best-practices/#protect-against-denial-of-service-attacks) to learn how to safeguard against denial of service attacks. ## Extensions Component developers SHOULD NOT expose health or telemetry data outside the Collector by default. opentelemetry-collector-0.141.0/docs/standard-warnings.md000066400000000000000000000036721511331344600234460ustar00rootroot00000000000000# Standard Warnings Some components have scenarios that could cause issues. Some components require the collector be interacted with in a specific way in order to ensure the component works as intended. This document describes common warnings that may affect a component in the collector. Visit a component's README to see if it is affected by any of these standard warnings. ## Unsound Transformations Incorrect usage of the component may lead to telemetry data that is unsound i.e. not spec-compliant/meaningless. This would most likely be caused by converting metric data types or creating new metrics from existing metrics. ## Statefulness The component keeps state related to telemetry data and therefore needs all data from a producer to be sent to the same Collector instance to ensure a correct behavior. Examples of scenarios that require state would be computing/exporting delta metrics, tail-based sampling and grouping telemetry. ## Identity Conflict The component may change the [identity of a metric](https://github.com/open-telemetry/opentelemetry-specification/blob/main//specification/metrics/data-model.md#opentelemetry-protocol-data-model-producer-recommendations) or the [identity of a timeseries](https://github.com/open-telemetry/opentelemetry-specification/blob/main//specification/metrics/data-model.md#timeseries-model). This could be done by modifying the metric/timeseries's name, attributes, or instrumentation scope. Modifying a metric/timeseries's identity could result in a metric/timeseries identity conflict, which caused by two metrics/timeseries sharing the same name, attributes, and instrumentation scope. ## Orphaned Telemetry The component modifies the incoming telemetry in such a way that a span becomes orphaned, that is, it contains a `trace_id` or `parent_span_id` that does not exist. This may occur because the component can modify `span_id`, `trace_id`, or `parent_span_id` or because the component can delete telemetry. opentelemetry-collector-0.141.0/docs/vision.md000066400000000000000000000023141511331344600213170ustar00rootroot00000000000000# OpenTelemetry Collector Long-term Vision The following are high-level items that define our long-term vision for OpenTelemetry Collector, what we aspire to achieve. This vision is our daily guidance when we design new features and make changes to the Collector. This is a living document that is expected to evolve over time. ## Performant Highly stable and performant under varying loads. Well-behaved under extreme load, with predictable, low resource consumption. ## Observable Expose own operational metrics in a clear way. Be an exemplar of observable service. Allow configuring the level of observability (more or less metrics, traces, logs, etc reported). See [more details](https://opentelemetry.io/docs/collector/internal-telemetry/). ## Multi-Data Support traces, metrics, logs and other relevant data types. ## Usable Out of the Box Reasonable default configuration, supports popular protocols, runs and collects out of the box. ## Extensible Extensible and customizable without touching the core code. Can create custom agents based on the core and extend with own components. Welcoming 3rd party contribution policy. ## Unified Codebase One codebase for daemon (Agent) and standalone service (Collector). opentelemetry-collector-0.141.0/examples/000077500000000000000000000000001511331344600203545ustar00rootroot00000000000000opentelemetry-collector-0.141.0/examples/README.md000066400000000000000000000002471511331344600216360ustar00rootroot00000000000000# Examples Information on how the examples can be used can be found in the [Getting Started documentation](https://opentelemetry.io/docs/collector/getting-started/). opentelemetry-collector-0.141.0/examples/k8s/000077500000000000000000000000001511331344600210615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/examples/k8s/otel-config.yaml000066400000000000000000000131711511331344600241560ustar00rootroot00000000000000--- apiVersion: v1 kind: ConfigMap metadata: name: otel-agent-conf labels: app: opentelemetry component: otel-agent-conf data: otel-agent-config: | receivers: otlp: protocols: grpc: endpoint: ${env:MY_POD_IP}:4317 http: endpoint: ${env:MY_POD_IP}:4318 exporters: otlp: endpoint: "otel-collector.default:4317" tls: insecure: true sending_queue: num_consumers: 4 queue_size: 100 retry_on_failure: enabled: true processors: memory_limiter: # 80% of maximum memory up to 2G limit_mib: 400 # 25% of limit up to 2G spike_limit_mib: 100 check_interval: 5s extensions: zpages: {} service: extensions: [zpages] pipelines: traces: receivers: [otlp] processors: [memory_limiter] exporters: [otlp] --- apiVersion: apps/v1 kind: DaemonSet metadata: name: otel-agent labels: app: opentelemetry component: otel-agent spec: selector: matchLabels: app: opentelemetry component: otel-agent template: metadata: labels: app: opentelemetry component: otel-agent spec: containers: - command: - "/otelcol" - "--config=/conf/otel-agent-config.yaml" image: otel/opentelemetry-collector:latest name: otel-agent resources: limits: cpu: 500m memory: 500Mi requests: cpu: 100m memory: 100Mi ports: - containerPort: 55679 # ZPages endpoint. - containerPort: 4317 # Default OpenTelemetry receiver port. - containerPort: 8888 # Metrics. env: - name: MY_POD_IP valueFrom: fieldRef: apiVersion: v1 fieldPath: status.podIP - name: GOMEMLIMIT value: 400MiB volumeMounts: - name: otel-agent-config-vol mountPath: /conf volumes: - configMap: name: otel-agent-conf items: - key: otel-agent-config path: otel-agent-config.yaml name: otel-agent-config-vol --- apiVersion: v1 kind: ConfigMap metadata: name: otel-collector-conf labels: app: opentelemetry component: otel-collector-conf data: otel-collector-config: | receivers: otlp: protocols: grpc: endpoint: ${env:MY_POD_IP}:4317 http: endpoint: ${env:MY_POD_IP}:4318 processors: memory_limiter: # 80% of maximum memory up to 2G limit_mib: 1500 # 25% of limit up to 2G spike_limit_mib: 512 check_interval: 5s extensions: zpages: {} exporters: otlp: endpoint: "http://someotlp.target.com:4317" # Replace with a real endpoint. tls: insecure: true service: extensions: [zpages] pipelines: traces/1: receivers: [otlp] processors: [memory_limiter] exporters: [otlp] --- apiVersion: v1 kind: Service metadata: name: otel-collector labels: app: opentelemetry component: otel-collector spec: ports: - name: otlp-grpc # Default endpoint for OpenTelemetry gRPC receiver. port: 4317 protocol: TCP targetPort: 4317 - name: otlp-http # Default endpoint for OpenTelemetry HTTP receiver. port: 4318 protocol: TCP targetPort: 4318 - name: metrics # Default endpoint for querying metrics. port: 8888 selector: component: otel-collector --- apiVersion: apps/v1 kind: Deployment metadata: name: otel-collector labels: app: opentelemetry component: otel-collector spec: selector: matchLabels: app: opentelemetry component: otel-collector minReadySeconds: 5 progressDeadlineSeconds: 120 replicas: 1 #TODO - adjust this to your own requirements template: metadata: labels: app: opentelemetry component: otel-collector spec: containers: - command: - "/otelcol" - "--config=/conf/otel-collector-config.yaml" image: otel/opentelemetry-collector:latest name: otel-collector resources: limits: cpu: 1 memory: 2Gi requests: cpu: 200m memory: 400Mi ports: - containerPort: 55679 # Default endpoint for ZPages. - containerPort: 4317 # Default endpoint for OpenTelemetry receiver. - containerPort: 14250 # Default endpoint for Jaeger gRPC receiver. - containerPort: 14268 # Default endpoint for Jaeger HTTP receiver. - containerPort: 9411 # Default endpoint for Zipkin receiver. - containerPort: 8888 # Default endpoint for querying metrics. env: - name: MY_POD_IP valueFrom: fieldRef: apiVersion: v1 fieldPath: status.podIP - name: GOMEMLIMIT value: 1600MiB volumeMounts: - name: otel-collector-config-vol mountPath: /conf # - name: otel-collector-secrets # mountPath: /secrets volumes: - configMap: name: otel-collector-conf items: - key: otel-collector-config path: otel-collector-config.yaml name: otel-collector-config-vol # - secret: # name: otel-collector-secrets # items: # - key: cert.pem # path: cert.pem # - key: key.pem # path: key.pem opentelemetry-collector-0.141.0/examples/local/000077500000000000000000000000001511331344600214465ustar00rootroot00000000000000opentelemetry-collector-0.141.0/examples/local/otel-config.yaml000066400000000000000000000013201511331344600245340ustar00rootroot00000000000000extensions: zpages: endpoint: localhost:55679 receivers: otlp: protocols: grpc: endpoint: localhost:4317 http: endpoint: localhost:4318 processors: memory_limiter: # 75% of maximum memory up to 2G limit_mib: 1536 # 25% of limit up to 2G spike_limit_mib: 512 check_interval: 5s exporters: debug: verbosity: detailed service: pipelines: traces: receivers: [otlp] processors: [memory_limiter] exporters: [debug] metrics: receivers: [otlp] processors: [memory_limiter] exporters: [debug] logs: receivers: [otlp] processors: [memory_limiter] exporters: [debug] extensions: [zpages] opentelemetry-collector-0.141.0/exporter/000077500000000000000000000000001511331344600204065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/Makefile000066400000000000000000000000331511331344600220420ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/exporter/README.md000066400000000000000000000054621511331344600216740ustar00rootroot00000000000000# General Information An exporter defines how the pipeline data leaves the collector. This repository hosts the following exporters available in traces, metrics and logs pipelines (sorted alphabetically): - [Debug](debugexporter/README.md) - [OTLP gRPC](otlpexporter/README.md) - [OTLP HTTP](otlphttpexporter/README.md) The [contrib repository](https://github.com/open-telemetry/opentelemetry-collector-contrib) has more exporters available in its builds. ## Configuring Exporters Exporters are configured via YAML under the top-level `exporters` tag. The following is a sample configuration for the `exampleexporter`. ```yaml exporters: # Exporter 1. # : exampleexporter: # : endpoint: 1.2.3.4:8080 # ... # Exporter 2. # /: exampleexporter/settings: # : endpoint: 0.0.0.0:9211 ``` An exporter instance is referenced by its full name in other parts of the config, such as in pipelines. A full name consists of the exporter type, '/' and the name appended to the exporter type in the configuration. All exporter full names must be unique. For the example above: - Exporter 1 has full name `exampleexporter`. - Exporter 2 has full name `exampleexporter/settings`. Exporters are enabled upon being added to a pipeline. For example: ```yaml service: pipelines: # Valid pipelines are: traces, metrics or logs # Trace pipeline 1. traces: receivers: [examplereceiver] processors: [] exporters: [exampleexporter, exampleexporter/settings] # Trace pipeline 2. traces/another: receivers: [examplereceiver] processors: [] exporters: [exampleexporter, exampleexporter/settings] ``` ## Data Ownership When multiple exporters are configured to send the same data (e.g. by configuring multiple exporters for the same pipeline): * exporters *not* configured to mutate the data will have shared access to the data * exporters with the Capabilities to mutate the data will receive a copy of the data Exporters access export data when `ConsumeTraces`/`ConsumeMetrics`/`ConsumeLogs` function is called. Unless exporter's capabilities include mutation, the exporter MUST NOT modify the `pdata.Traces`/`pdata.Metrics`/`pdata.Logs` argument of these functions. Any approach that does not mutate the original `pdata.Traces`/`pdata.Metrics`/`pdata.Logs` is allowed without the mutation capability. ## Proxy Support Beyond standard YAML configuration as outlined in the individual READMEs above, exporters that leverage the net/http package (all do today) also respect the following proxy environment variables: - HTTP_PROXY - HTTPS_PROXY - NO_PROXY If set at Collector start time then exporters, regardless of protocol, will or will not proxy traffic as defined by these environment variables. opentelemetry-collector-0.141.0/exporter/debugexporter/000077500000000000000000000000001511331344600232655ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/Makefile000066400000000000000000000000361511331344600247240ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/exporter/debugexporter/README.md000066400000000000000000000171121511331344600245460ustar00rootroot00000000000000# Debug Exporter | Status | | | ------------- |-----------| | Stability | [development]: profiles | | | [alpha]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s] | | Warnings | [Unstable Output Format](#warnings) | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fdebug%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fdebug) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fdebug%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fdebug) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@andrzej-stencel](https://www.github.com/andrzej-stencel) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha [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 Outputs telemetry data to the console for debugging purposes. See also the [Troubleshooting][troubleshooting_docs] document for examples on using this exporter. [troubleshooting_docs]: https://opentelemetry.io/docs/collector/troubleshooting/#local-exporters ## Getting Started The following settings are optional: - `verbosity` (default = `basic`): the verbosity of the debug exporter: `basic`, `normal` or `detailed`. See [Verbosity levels](#verbosity-levels) below for more information. - `sampling_initial` (default = `2`): number of messages initially logged each second. - `sampling_thereafter` (default = `1`): sampling rate after the initial messages are logged (every Mth message is logged). The default value of `1` means that sampling is disabled. To enable sampling, change `sampling_thereafter` to a value higher than `1`. Refer to [Zap docs](https://godoc.org/go.uber.org/zap/zapcore#NewSampler) for more details on how sampling parameters impact number of messages. - `use_internal_logger` (default = `true`): uses the collector's internal logger for output. See [below](#using-the-collectors-internal-logger) for description. - `sending_queue` (disabled by default): see [Sending Queue](../exporterhelper/README.md#sending-queue) for the full set of available options. Example configuration: ```yaml exporters: debug: verbosity: detailed sampling_initial: 5 sampling_thereafter: 200 ``` ## Verbosity levels The following subsections describe the output from the exporter depending on the configured verbosity level - `basic`, `normal` and `detailed`. The default verbosity level is `basic`. To understand how the below example output was generated, see [Generating example output](./generating-example-output.md). ### Basic verbosity With `verbosity: basic`, the exporter outputs a single-line summary of received data with a total count of telemetry records for every batch of received logs, metrics or traces. Here's an example output: ```console 2025-04-17T10:40:44.559+0200 info Traces {"otelcol.component.id": "debug/basic", "otelcol.component.kind": "Exporter", "otelcol.signal": "traces", "resource spans": 1, "spans": 2} ``` ### Normal verbosity With `verbosity: normal`, the exporter outputs about one line for each telemetry record. The "one line per telemetry record" is not a strict rule. For example, logs with multiline body will be output as multiple lines. Here's an example output: ```console 2025-05-09T19:57:16.332+0200 info Traces {"resource": {}, "otelcol.component.id": "debug/normal", "otelcol.component.kind": "exporter", "otelcol.signal": "traces", "resource spans": 1, "spans": 2} 2025-05-09T19:57:16.332+0200 info ResourceTraces #0 [https://opentelemetry.io/schemas/1.25.0] service.name=telemetrygen ScopeTraces #0 telemetrygen okey-dokey-0 ab1030bd4ee554af936542b01d7b4807 1d8c93663d043aa8 net.sock.peer.addr=1.2.3.4 peer.service=telemetrygen-client lets-go ab1030bd4ee554af936542b01d7b4807 0d238e8a2f97733f net.sock.peer.addr=1.2.3.4 peer.service=telemetrygen-server {"resource": {}, "otelcol.component.id": "debug/normal", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"} ``` ### Detailed verbosity With `verbosity: detailed`, the exporter outputs all details of every telemetry record, typically writing multiple lines for every telemetry record. Here's an example output: ```console 2025-04-17T10:40:44.560+0200 info Traces {"otelcol.component.id": "debug/detailed", "otelcol.component.kind": "Exporter", "otelcol.signal": "traces", "resource spans": 1, "spans": 2} 2025-04-17T10:40:44.560+0200 info ResourceSpans #0 Resource SchemaURL: https://opentelemetry.io/schemas/1.25.0 Resource attributes: -> service.name: Str(telemetrygen) ScopeSpans #0 ScopeSpans SchemaURL: InstrumentationScope telemetrygen Span #0 Trace ID : fafdac970271dd2ce89de2442c0518c7 Parent ID : d98de4cb8e2a0ad6 ID : 3875f436d989d0e5 Name : okey-dokey-0 Kind : Server Start time : 2025-04-17 08:40:44.555461596 +0000 UTC End time : 2025-04-17 08:40:44.555584596 +0000 UTC Status code : Unset Status message : Attributes: -> net.sock.peer.addr: Str(1.2.3.4) -> peer.service: Str(telemetrygen-client) Span #1 Trace ID : fafdac970271dd2ce89de2442c0518c7 Parent ID : ID : d98de4cb8e2a0ad6 Name : lets-go Kind : Client Start time : 2025-04-17 08:40:44.555461596 +0000 UTC End time : 2025-04-17 08:40:44.555584596 +0000 UTC Status code : Unset Status message : Attributes: -> net.sock.peer.addr: Str(1.2.3.4) -> peer.service: Str(telemetrygen-server) {"otelcol.component.id": "debug/detailed", "otelcol.component.kind": "Exporter", "otelcol.signal": "traces"} ``` ## Using the collector's internal logger When `use_internal_logger` is set to `true` (the default), the exporter uses the collector's [internal logger][internal_telemetry] for output. This comes with the following consequences: - The output from the exporter may be annotated by additional output from the collector's logger. - The output from the exporter is affected by the collector's [logging configuration][internal_logs_config] specified in `service::telemetry::logs`. When `use_internal_logger` is set to `false`, the exporter does not use the collector's internal logger. Changing the values in `service::telemetry::logs` has no effect on the exporter's output. The exporter's output is sent to `stdout`. [internal_telemetry]: https://opentelemetry.io/docs/collector/internal-telemetry/ [internal_logs_config]: https://opentelemetry.io/docs/collector/internal-telemetry/#configure-internal-logs ## Warnings - Unstable Output Format: The output formats for all verbosity levels is not guaranteed and may be changed at any time without a breaking change. opentelemetry-collector-0.141.0/exporter/debugexporter/config.go000066400000000000000000000033141511331344600250620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package debugexporter // import "go.opentelemetry.io/collector/exporter/debugexporter" import ( "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/exporter/exporterhelper" ) // supportedLevels in this exporter's configuration. // configtelemetry.LevelNone and other future values are not supported. var supportedLevels map[configtelemetry.Level]struct{} = map[configtelemetry.Level]struct{}{ configtelemetry.LevelBasic: {}, configtelemetry.LevelNormal: {}, configtelemetry.LevelDetailed: {}, } // Config defines configuration for debug exporter. type Config struct { // Verbosity defines the debug exporter verbosity. Verbosity configtelemetry.Level `mapstructure:"verbosity,omitempty"` // SamplingInitial defines how many samples are initially logged during each second. SamplingInitial int `mapstructure:"sampling_initial"` // SamplingThereafter defines the sampling rate after the initial samples are logged. SamplingThereafter int `mapstructure:"sampling_thereafter"` // UseInternalLogger defines whether the exporter sends the output to the collector's internal logger. UseInternalLogger bool `mapstructure:"use_internal_logger"` QueueConfig exporterhelper.QueueBatchConfig `mapstructure:"sending_queue"` // prevent unkeyed literal initialization _ struct{} } var _ component.Config = (*Config)(nil) // Validate checks if the exporter configuration is valid func (cfg *Config) Validate() error { if _, ok := supportedLevels[cfg.Verbosity]; !ok { return fmt.Errorf("verbosity level %q is not supported", cfg.Verbosity) } return nil } opentelemetry-collector-0.141.0/exporter/debugexporter/config_test.go000066400000000000000000000060521511331344600261230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package debugexporter import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/exporter/exporterhelper" ) func TestUnmarshalDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) } func TestUnmarshalConfig(t *testing.T) { queueCfg := exporterhelper.NewDefaultQueueConfig() queueCfg.Enabled = false tests := []struct { filename string cfg *Config expectedErr string }{ { filename: "config_verbosity.yaml", cfg: &Config{ Verbosity: configtelemetry.LevelDetailed, SamplingInitial: 10, SamplingThereafter: 50, QueueConfig: queueCfg, }, }, { filename: "config_verbosity_typo.yaml", expectedErr: "'' has invalid keys: verBosity", }, } for _, tt := range tests { t.Run(tt.filename, func(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", tt.filename)) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() err = cm.Unmarshal(&cfg) if tt.expectedErr != "" { assert.ErrorContains(t, err, tt.expectedErr) } else { require.NoError(t, err) assert.Equal(t, tt.cfg, cfg) } }) } } func Test_UnmarshalMarshalled(t *testing.T) { for name, tc := range map[string]struct { inCfg *Config expectedConfig *Config expectedErr string }{ "Base": { inCfg: &Config{}, expectedConfig: &Config{}, }, "VerbositySpecified": { inCfg: &Config{ Verbosity: configtelemetry.LevelDetailed, }, expectedConfig: &Config{ Verbosity: configtelemetry.LevelDetailed, }, }, } { t.Run(name, func(t *testing.T) { conf := confmap.New() err := conf.Marshal(tc.inCfg) require.NoError(t, err) raw := conf.ToStringMap() conf = confmap.NewFromStringMap(raw) outCfg := &Config{} err = conf.Unmarshal(outCfg) if tc.expectedErr == "" { require.NoError(t, err) assert.Equal(t, tc.expectedConfig, outCfg) return } require.Error(t, err) assert.EqualError(t, err, tc.expectedErr) }) } } func TestValidate(t *testing.T) { tests := []struct { name string cfg *Config expectedErr string }{ { name: "verbosity none", cfg: &Config{ Verbosity: configtelemetry.LevelNone, }, expectedErr: "verbosity level \"None\" is not supported", }, { name: "verbosity detailed", cfg: &Config{ Verbosity: configtelemetry.LevelDetailed, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.cfg.Validate() if tt.expectedErr != "" { assert.EqualError(t, err, tt.expectedErr) } else { assert.NoError(t, err) } }) } } opentelemetry-collector-0.141.0/exporter/debugexporter/doc.go000066400000000000000000000004061511331344600243610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package debugexporter exports data to console as logs. package debugexporter // import "go.opentelemetry.io/collector/exporter/debugexporter" opentelemetry-collector-0.141.0/exporter/debugexporter/exporter.go000066400000000000000000000066121511331344600254710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package debugexporter // import "go.opentelemetry.io/collector/exporter/debugexporter" import ( "context" "go.uber.org/zap" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/exporter/debugexporter/internal/normal" "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) type debugExporter struct { verbosity configtelemetry.Level logger *zap.Logger logsMarshaler plog.Marshaler metricsMarshaler pmetric.Marshaler tracesMarshaler ptrace.Marshaler profilesMarshaler pprofile.Marshaler } func newDebugExporter(logger *zap.Logger, verbosity configtelemetry.Level) *debugExporter { var logsMarshaler plog.Marshaler var metricsMarshaler pmetric.Marshaler var tracesMarshaler ptrace.Marshaler var profilesMarshaler pprofile.Marshaler if verbosity == configtelemetry.LevelDetailed { logsMarshaler = otlptext.NewTextLogsMarshaler() metricsMarshaler = otlptext.NewTextMetricsMarshaler() tracesMarshaler = otlptext.NewTextTracesMarshaler() profilesMarshaler = otlptext.NewTextProfilesMarshaler() } else { logsMarshaler = normal.NewNormalLogsMarshaler() metricsMarshaler = normal.NewNormalMetricsMarshaler() tracesMarshaler = normal.NewNormalTracesMarshaler() profilesMarshaler = normal.NewNormalProfilesMarshaler() } return &debugExporter{ verbosity: verbosity, logger: logger, logsMarshaler: logsMarshaler, metricsMarshaler: metricsMarshaler, tracesMarshaler: tracesMarshaler, profilesMarshaler: profilesMarshaler, } } func (s *debugExporter) pushTraces(_ context.Context, td ptrace.Traces) error { s.logger.Info("Traces", zap.Int("resource spans", td.ResourceSpans().Len()), zap.Int("spans", td.SpanCount())) if s.verbosity == configtelemetry.LevelBasic { return nil } buf, err := s.tracesMarshaler.MarshalTraces(td) if err != nil { return err } s.logger.Info(string(buf)) return nil } func (s *debugExporter) pushMetrics(_ context.Context, md pmetric.Metrics) error { s.logger.Info("Metrics", zap.Int("resource metrics", md.ResourceMetrics().Len()), zap.Int("metrics", md.MetricCount()), zap.Int("data points", md.DataPointCount())) if s.verbosity == configtelemetry.LevelBasic { return nil } buf, err := s.metricsMarshaler.MarshalMetrics(md) if err != nil { return err } s.logger.Info(string(buf)) return nil } func (s *debugExporter) pushLogs(_ context.Context, ld plog.Logs) error { s.logger.Info("Logs", zap.Int("resource logs", ld.ResourceLogs().Len()), zap.Int("log records", ld.LogRecordCount())) if s.verbosity == configtelemetry.LevelBasic { return nil } buf, err := s.logsMarshaler.MarshalLogs(ld) if err != nil { return err } s.logger.Info(string(buf)) return nil } func (s *debugExporter) pushProfiles(_ context.Context, pd pprofile.Profiles) error { s.logger.Info("Profiles", zap.Int("resource profiles", pd.ResourceProfiles().Len()), zap.Int("sample records", pd.SampleCount())) if s.verbosity == configtelemetry.LevelBasic { return nil } buf, err := s.profilesMarshaler.MarshalProfiles(pd) if err != nil { return err } s.logger.Info(string(buf)) return nil } opentelemetry-collector-0.141.0/exporter/debugexporter/exporter_test.go000066400000000000000000000111671511331344600265310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package debugexporter // import "go.opentelemetry.io/collector/exporter/debugexporter" import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zaptest" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/exporter/debugexporter/internal/metadata" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) func TestTracesNoErrors(t *testing.T) { for _, tc := range createTestCases() { t.Run(tc.name, func(t *testing.T) { lte, err := createTraces(context.Background(), exportertest.NewNopSettings(metadata.Type), tc.config) require.NotNil(t, lte) assert.NoError(t, err) assert.NoError(t, lte.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, lte.ConsumeTraces(context.Background(), testdata.GenerateTraces(10))) assert.NoError(t, lte.Shutdown(context.Background())) }) } } func TestMetricsNoErrors(t *testing.T) { for _, tc := range createTestCases() { t.Run(tc.name, func(t *testing.T) { lme, err := createMetrics(context.Background(), exportertest.NewNopSettings(metadata.Type), tc.config) require.NotNil(t, lme) assert.NoError(t, err) assert.NoError(t, lme.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsAllTypes())) assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsAllTypesEmpty())) assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetricsMetricTypeInvalid())) assert.NoError(t, lme.ConsumeMetrics(context.Background(), testdata.GenerateMetrics(10))) assert.NoError(t, lme.Shutdown(context.Background())) }) } } func TestLogsNoErrors(t *testing.T) { for _, tc := range createTestCases() { t.Run(tc.name, func(t *testing.T) { lle, err := createLogs(context.Background(), exportertest.NewNopSettings(metadata.Type), tc.config) require.NotNil(t, lle) assert.NoError(t, err) assert.NoError(t, lle.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, lle.ConsumeLogs(context.Background(), testdata.GenerateLogs(10))) assert.NoError(t, lle.Shutdown(context.Background())) }) } } func TestProfilesNoErrors(t *testing.T) { for _, tc := range createTestCases() { t.Run(tc.name, func(t *testing.T) { lle, err := createProfiles(context.Background(), exportertest.NewNopSettings(metadata.Type), tc.config) require.NotNil(t, lle) assert.NoError(t, err) assert.NoError(t, lle.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, lle.ConsumeProfiles(context.Background(), testdata.GenerateProfiles(10))) assert.NoError(t, lle.Shutdown(context.Background())) }) } } func TestErrors(t *testing.T) { le := newDebugExporter(zaptest.NewLogger(t), configtelemetry.LevelDetailed) require.NotNil(t, le) errWant := errors.New("my error") le.tracesMarshaler = &errMarshaler{err: errWant} le.metricsMarshaler = &errMarshaler{err: errWant} le.logsMarshaler = &errMarshaler{err: errWant} le.profilesMarshaler = &errMarshaler{err: errWant} assert.Equal(t, errWant, le.pushTraces(context.Background(), ptrace.NewTraces())) assert.Equal(t, errWant, le.pushMetrics(context.Background(), pmetric.NewMetrics())) assert.Equal(t, errWant, le.pushLogs(context.Background(), plog.NewLogs())) assert.Equal(t, errWant, le.pushProfiles(context.Background(), pprofile.NewProfiles())) } type testCase struct { name string config *Config } func createTestCases() []testCase { return []testCase{ { name: "default config", config: func() *Config { c := createDefaultConfig().(*Config) c.QueueConfig.QueueSize = 10 return c }(), }, { name: "don't use internal logger", config: func() *Config { cfg := createDefaultConfig().(*Config) cfg.QueueConfig.QueueSize = 10 cfg.UseInternalLogger = false return cfg }(), }, } } type errMarshaler struct { err error } func (e errMarshaler) MarshalLogs(plog.Logs) ([]byte, error) { return nil, e.err } func (e errMarshaler) MarshalMetrics(pmetric.Metrics) ([]byte, error) { return nil, e.err } func (e errMarshaler) MarshalTraces(ptrace.Traces) ([]byte, error) { return nil, e.err } func (e errMarshaler) MarshalProfiles(pprofile.Profiles) ([]byte, error) { return nil, e.err } opentelemetry-collector-0.141.0/exporter/debugexporter/factory.go000066400000000000000000000120641511331344600252660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package debugexporter // import "go.opentelemetry.io/collector/exporter/debugexporter" import ( "context" "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/debugexporter/internal/metadata" "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" "go.opentelemetry.io/collector/exporter/xexporter" ) // The value of "type" key in configuration. var componentType = component.MustNewType("debug") const ( defaultSamplingInitial = 2 defaultSamplingThereafter = 1 ) // NewFactory creates and returns a new factory for the Debug exporter. func NewFactory() exporter.Factory { return xexporter.NewFactory( componentType, createDefaultConfig, xexporter.WithTraces(createTraces, metadata.TracesStability), xexporter.WithMetrics(createMetrics, metadata.MetricsStability), xexporter.WithLogs(createLogs, metadata.LogsStability), xexporter.WithProfiles(createProfiles, metadata.ProfilesStability), ) } func createDefaultConfig() component.Config { queueCfg := exporterhelper.NewDefaultQueueConfig() queueCfg.Enabled = false return &Config{ Verbosity: configtelemetry.LevelBasic, SamplingInitial: defaultSamplingInitial, SamplingThereafter: defaultSamplingThereafter, UseInternalLogger: true, QueueConfig: queueCfg, } } func createTraces(ctx context.Context, set exporter.Settings, config component.Config) (exporter.Traces, error) { cfg := config.(*Config) exporterLogger := createLogger(cfg, set.Logger) debug := newDebugExporter(exporterLogger, cfg.Verbosity) return exporterhelper.NewTraces(ctx, set, config, debug.pushTraces, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithQueue(cfg.QueueConfig), exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithShutdown(otlptext.LoggerSync(exporterLogger)), ) } func createMetrics(ctx context.Context, set exporter.Settings, config component.Config) (exporter.Metrics, error) { cfg := config.(*Config) exporterLogger := createLogger(cfg, set.Logger) debug := newDebugExporter(exporterLogger, cfg.Verbosity) return exporterhelper.NewMetrics(ctx, set, config, debug.pushMetrics, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithQueue(cfg.QueueConfig), exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithShutdown(otlptext.LoggerSync(exporterLogger)), ) } func createLogs(ctx context.Context, set exporter.Settings, config component.Config) (exporter.Logs, error) { cfg := config.(*Config) exporterLogger := createLogger(cfg, set.Logger) debug := newDebugExporter(exporterLogger, cfg.Verbosity) return exporterhelper.NewLogs(ctx, set, config, debug.pushLogs, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithQueue(cfg.QueueConfig), exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithShutdown(otlptext.LoggerSync(exporterLogger)), ) } func createProfiles(ctx context.Context, set exporter.Settings, config component.Config) (xexporter.Profiles, error) { cfg := config.(*Config) exporterLogger := createLogger(cfg, set.Logger) debug := newDebugExporter(exporterLogger, cfg.Verbosity) return xexporterhelper.NewProfiles(ctx, set, config, debug.pushProfiles, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithQueue(cfg.QueueConfig), exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithShutdown(otlptext.LoggerSync(exporterLogger)), ) } func createLogger(cfg *Config, logger *zap.Logger) *zap.Logger { var exporterLogger *zap.Logger if cfg.UseInternalLogger { core := zapcore.NewSamplerWithOptions( logger.Core(), 1*time.Second, cfg.SamplingInitial, cfg.SamplingThereafter, ) exporterLogger = zap.New(core) } else { exporterLogger = createCustomLogger(cfg) } return exporterLogger } func createCustomLogger(exporterConfig *Config) *zap.Logger { encoderConfig := zap.NewDevelopmentEncoderConfig() // Do not prefix the output with log level (`info`) encoderConfig.LevelKey = "" // Do not prefix the output with current timestamp. encoderConfig.TimeKey = "" zapConfig := zap.Config{ Level: zap.NewAtomicLevelAt(zap.InfoLevel), DisableCaller: true, Sampling: &zap.SamplingConfig{ Initial: exporterConfig.SamplingInitial, Thereafter: exporterConfig.SamplingThereafter, }, Encoding: "console", EncoderConfig: encoderConfig, // Send exporter's output to stdout. This should be made configurable. OutputPaths: []string{"stdout"}, } return zap.Must(zapConfig.Build()) } opentelemetry-collector-0.141.0/exporter/debugexporter/factory_test.go000066400000000000000000000031751511331344600263300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package debugexporter import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/xexporter" ) func TestCreateDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") assert.NoError(t, componenttest.CheckConfigStruct(cfg)) } func TestCreateMetrics(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() me, err := factory.CreateMetrics(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) assert.NotNil(t, me) } func TestCreateTraces(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() te, err := factory.CreateTraces(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) assert.NotNil(t, te) } func TestCreateLogs(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() te, err := factory.CreateLogs(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) assert.NotNil(t, te) } func TestCreateFactoryProfiles(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() te, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) assert.NotNil(t, te) } opentelemetry-collector-0.141.0/exporter/debugexporter/generated_component_test.go000066400000000000000000000116261511331344600307010ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package debugexporter import ( "context" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) var typ = component.MustNewType("debug") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg) }, }, { name: "metrics", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg) }, }, { name: "traces", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(exporter.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(exporter.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(exporter.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) } } func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/exporter/debugexporter/generated_package_test.go000066400000000000000000000002541511331344600302650ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package debugexporter import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/debugexporter/generating-example-output.md000066400000000000000000000020221511331344600307150ustar00rootroot00000000000000# Generating example output This document describes how to generate the example output used in the [README](./README.md)'s [Verbosity levels](./README.md#verbosity-levels) section. 1. Prepare the configuration of the Collector. ```yaml exporters: debug/basic: verbosity: basic debug/normal: verbosity: normal debug/detailed: verbosity: detailed receivers: otlp: protocols: grpc: service: pipelines: traces: exporters: - debug/basic - debug/normal - debug/detailed receivers: - otlp ``` 2. Run the Collector (download latest version from ). ```console otelcol --config config.yaml ``` 3. Run the `telemetrygen` tool (install latest version with `go install github.com/open-telemetry/opentelemetry-collector-contrib/cmd/telemetrygen@latest`). ```console telemetrygen traces --otlp-insecure ``` opentelemetry-collector-0.141.0/exporter/debugexporter/go.mod000066400000000000000000000141361511331344600244000ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/debugexporter go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configtelemetry v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/exporter/xexporter v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pdata/xpdata v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 golang.org/x/sys v0.38.0 ) require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configoptional v1.47.0 // indirect go.opentelemetry.io/collector/config/configretry v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror/xconsumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumertest v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/receiver v1.47.0 // indirect go.opentelemetry.io/collector/receiver/receivertest v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/consumer/consumererror/xconsumererror => ../../consumer/consumererror/xconsumererror replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/exporter/xexporter => ../xexporter replace go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper => ../exporterhelper/xexporterhelper replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/exporter/debugexporter/go.sum000066400000000000000000000210431511331344600244200ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/debugexporter/internal/000077500000000000000000000000001511331344600251015ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/metadata/000077500000000000000000000000001511331344600266615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/metadata/generated_status.go000066400000000000000000000007131511331344600325520ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("debug") ScopeName = "go.opentelemetry.io/collector/exporter/debugexporter" ) const ( ProfilesStability = component.StabilityLevelDevelopment TracesStability = component.StabilityLevelAlpha MetricsStability = component.StabilityLevelAlpha LogsStability = component.StabilityLevelAlpha ) opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/000077500000000000000000000000001511331344600263715ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/common.go000066400000000000000000000026711511331344600302160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/normal" import ( "fmt" "strings" "go.opentelemetry.io/collector/pdata/pcommon" ) // writeAttributes returns a slice of strings in the form "attrKey=attrValue" func writeAttributes(attributes pcommon.Map) (attributeStrings []string) { for k, v := range attributes.All() { attribute := fmt.Sprintf("%s=%s", k, v.AsString()) attributeStrings = append(attributeStrings, attribute) } return attributeStrings } // writeAttributesString returns a string in the form " attrKey=attrValue attr2=value2" func writeAttributesString(attributesMap pcommon.Map) (attributesString string) { attributes := writeAttributes(attributesMap) if len(attributes) > 0 { attributesString = " " + strings.Join(attributes, " ") } return attributesString } func writeResourceDetails(schemaURL string) (resourceDetails string) { if schemaURL != "" { resourceDetails = " [" + schemaURL + "]" } return resourceDetails } func writeScopeDetails(name, version, schemaURL string) (scopeDetails string) { if name != "" { scopeDetails += name } if version != "" { scopeDetails += "@" + version } if schemaURL != "" { if scopeDetails != "" { scopeDetails += " " } scopeDetails += "[" + schemaURL + "]" } if scopeDetails != "" { scopeDetails = " " + scopeDetails } return scopeDetails } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/logs.go000066400000000000000000000031441511331344600276660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/normal" import ( "bytes" "fmt" "strings" "go.opentelemetry.io/collector/pdata/plog" ) type normalLogsMarshaler struct{} // Ensure normalLogsMarshaller implements interface plog.Marshaler var _ plog.Marshaler = normalLogsMarshaler{} // NewNormalLogsMarshaler returns a plog.Marshaler for normal verbosity. It writes one line of text per log record func NewNormalLogsMarshaler() plog.Marshaler { return normalLogsMarshaler{} } func (normalLogsMarshaler) MarshalLogs(ld plog.Logs) ([]byte, error) { var buffer bytes.Buffer for i := 0; i < ld.ResourceLogs().Len(); i++ { resourceLog := ld.ResourceLogs().At(i) buffer.WriteString(fmt.Sprintf("ResourceLog #%d%s%s\n", i, writeResourceDetails(resourceLog.SchemaUrl()), writeAttributesString(resourceLog.Resource().Attributes()))) for j := 0; j < resourceLog.ScopeLogs().Len(); j++ { scopeLog := resourceLog.ScopeLogs().At(j) buffer.WriteString(fmt.Sprintf("ScopeLog #%d%s%s\n", i, writeScopeDetails(scopeLog.Scope().Name(), scopeLog.Scope().Version(), scopeLog.SchemaUrl()), writeAttributesString(scopeLog.Scope().Attributes()))) for k := 0; k < scopeLog.LogRecords().Len(); k++ { logRecord := scopeLog.LogRecords().At(k) logAttributes := writeAttributes(logRecord.Attributes()) logString := fmt.Sprintf("%s %s", logRecord.Body().AsString(), strings.Join(logAttributes, " ")) buffer.WriteString(logString) buffer.WriteString("\n") } } } return buffer.Bytes(), nil } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/logs_test.go000066400000000000000000000134261511331344600307310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" ) func TestMarshalLogs(t *testing.T) { tests := []struct { name string input plog.Logs expected string }{ { name: "empty logs", input: plog.NewLogs(), expected: "", }, { name: "one log record", input: func() plog.Logs { logs := plog.NewLogs() logRecord := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC))) logRecord.SetSeverityNumber(plog.SeverityNumberInfo) logRecord.SetSeverityText("INFO") logRecord.Body().SetStr("Single line log message") logRecord.Attributes().PutStr("key1", "value1") logRecord.Attributes().PutStr("key2", "value2") return logs }(), expected: `ResourceLog #0 ScopeLog #0 Single line log message key1=value1 key2=value2 `, }, { name: "one log record with resource and scope attributes", input: func() plog.Logs { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() resourceLogs.SetSchemaUrl("https://opentelemetry.io/resource-schema-url") resourceLogs.Resource().Attributes().PutStr("resourceKey1", "resourceValue1") resourceLogs.Resource().Attributes().PutBool("resourceKey2", false) scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() scopeLogs.SetSchemaUrl("http://opentelemetry.io/scope-schema-url") scopeLogs.Scope().SetName("scope-name") scopeLogs.Scope().SetVersion("1.2.3") scopeLogs.Scope().Attributes().PutStr("scopeKey1", "scopeValue1") scopeLogs.Scope().Attributes().PutBool("scopeKey2", true) logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC))) logRecord.SetSeverityNumber(plog.SeverityNumberInfo) logRecord.SetSeverityText("INFO") logRecord.Body().SetStr("Single line log message") logRecord.Attributes().PutStr("key1", "value1") logRecord.Attributes().PutStr("key2", "value2") return logs }(), expected: `ResourceLog #0 [https://opentelemetry.io/resource-schema-url] resourceKey1=resourceValue1 resourceKey2=false ScopeLog #0 scope-name@1.2.3 [http://opentelemetry.io/scope-schema-url] scopeKey1=scopeValue1 scopeKey2=true Single line log message key1=value1 key2=value2 `, }, { name: "multiline log", input: func() plog.Logs { logs := plog.NewLogs() logRecord := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC))) logRecord.SetSeverityNumber(plog.SeverityNumberInfo) logRecord.SetSeverityText("INFO") logRecord.Body().SetStr("First line of the log message\n second line of the log message") logRecord.Attributes().PutStr("key1", "value1") logRecord.Attributes().PutStr("key2", "value2") return logs }(), expected: `ResourceLog #0 ScopeLog #0 First line of the log message second line of the log message key1=value1 key2=value2 `, }, { name: "two log records", input: func() plog.Logs { logs := plog.NewLogs() logRecords := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords() logRecord := logRecords.AppendEmpty() logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2024, 1, 23, 17, 54, 41, 153, time.UTC))) logRecord.SetSeverityNumber(plog.SeverityNumberInfo) logRecord.SetSeverityText("INFO") logRecord.Body().SetStr("Single line log message") logRecord.Attributes().PutStr("key1", "value1") logRecord.Attributes().PutStr("key2", "value2") logRecord = logRecords.AppendEmpty() logRecord.Body().SetStr("Multi-line\nlog message") logRecord.Attributes().PutStr("mykey2", "myvalue2") logRecord.Attributes().PutStr("mykey1", "myvalue1") return logs }(), expected: `ResourceLog #0 ScopeLog #0 Single line log message key1=value1 key2=value2 Multi-line log message mykey2=myvalue2 mykey1=myvalue1 `, }, { name: "log with maps in body and attributes", input: func() plog.Logs { logs := plog.NewLogs() logRecord := logs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() logRecord.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC))) logRecord.SetSeverityNumber(plog.SeverityNumberInfo) logRecord.SetSeverityText("INFO") body := logRecord.Body().SetEmptyMap() body.PutStr("app", "CurrencyConverter") bodyEvent := body.PutEmptyMap("event") bodyEvent.PutStr("operation", "convert") bodyEvent.PutStr("result", "success") conversionAttr := logRecord.Attributes().PutEmptyMap("conversion") conversionSourceAttr := conversionAttr.PutEmptyMap("source") conversionSourceAttr.PutStr("currency", "USD") conversionSourceAttr.PutDouble("amount", 34.22) conversionDestinationAttr := conversionAttr.PutEmptyMap("destination") conversionDestinationAttr.PutStr("currency", "EUR") logRecord.Attributes().PutStr("service", "payments") return logs }(), expected: `ResourceLog #0 ScopeLog #0 {"app":"CurrencyConverter","event":{"operation":"convert","result":"success"}} conversion={"destination":{"currency":"EUR"},"source":{"amount":34.22,"currency":"USD"}} service=payments `, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { output, err := NewNormalLogsMarshaler().MarshalLogs(tt.input) require.NoError(t, err) assert.Equal(t, tt.expected, string(output)) }) } } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/metrics.go000066400000000000000000000127111511331344600303700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/normal" import ( "bytes" "fmt" "strconv" "strings" "go.opentelemetry.io/collector/pdata/pmetric" ) type normalMetricsMarshaler struct{} // Ensure normalMetricsMarshaller implements interface pmetric.Marshaler var _ pmetric.Marshaler = normalMetricsMarshaler{} // NewNormalMetricsMarshaler returns a pmetric.Marshaler for normal verbosity. It writes one line of text per log record func NewNormalMetricsMarshaler() pmetric.Marshaler { return normalMetricsMarshaler{} } func (normalMetricsMarshaler) MarshalMetrics(md pmetric.Metrics) ([]byte, error) { var buffer bytes.Buffer for i := 0; i < md.ResourceMetrics().Len(); i++ { resourceMetrics := md.ResourceMetrics().At(i) buffer.WriteString(fmt.Sprintf("ResourceMetrics #%d%s%s\n", i, writeResourceDetails(resourceMetrics.SchemaUrl()), writeAttributesString(resourceMetrics.Resource().Attributes()))) for j := 0; j < resourceMetrics.ScopeMetrics().Len(); j++ { scopeMetrics := resourceMetrics.ScopeMetrics().At(j) buffer.WriteString(fmt.Sprintf("ScopeMetrics #%d%s%s\n", i, writeScopeDetails(scopeMetrics.Scope().Name(), scopeMetrics.Scope().Version(), scopeMetrics.SchemaUrl()), writeAttributesString(scopeMetrics.Scope().Attributes()))) for k := 0; k < scopeMetrics.Metrics().Len(); k++ { metric := scopeMetrics.Metrics().At(k) var dataPointLines []string switch metric.Type() { case pmetric.MetricTypeGauge: dataPointLines = writeNumberDataPoints(metric, metric.Gauge().DataPoints()) case pmetric.MetricTypeSum: dataPointLines = writeNumberDataPoints(metric, metric.Sum().DataPoints()) case pmetric.MetricTypeHistogram: dataPointLines = writeHistogramDataPoints(metric) case pmetric.MetricTypeExponentialHistogram: dataPointLines = writeExponentialHistogramDataPoints(metric) case pmetric.MetricTypeSummary: dataPointLines = writeSummaryDataPoints(metric) } for _, line := range dataPointLines { buffer.WriteString(line) } } } } return buffer.Bytes(), nil } func writeNumberDataPoints(metric pmetric.Metric, dataPoints pmetric.NumberDataPointSlice) (lines []string) { for i := 0; i < dataPoints.Len(); i++ { dataPoint := dataPoints.At(i) dataPointAttributes := writeAttributes(dataPoint.Attributes()) var value string switch dataPoint.ValueType() { case pmetric.NumberDataPointValueTypeInt: value = strconv.FormatInt(dataPoint.IntValue(), 10) case pmetric.NumberDataPointValueTypeDouble: value = fmt.Sprintf("%v", dataPoint.DoubleValue()) } dataPointLine := fmt.Sprintf("%s{%s} %s\n", metric.Name(), strings.Join(dataPointAttributes, ","), value) lines = append(lines, dataPointLine) } return lines } func writeHistogramDataPoints(metric pmetric.Metric) (lines []string) { for i := 0; i < metric.Histogram().DataPoints().Len(); i++ { dataPoint := metric.Histogram().DataPoints().At(i) dataPointAttributes := writeAttributes(dataPoint.Attributes()) var value strings.Builder fmt.Fprintf(&value, "count=%d", dataPoint.Count()) if dataPoint.HasSum() { fmt.Fprintf(&value, " sum=%v", dataPoint.Sum()) } if dataPoint.HasMin() { fmt.Fprintf(&value, " min=%v", dataPoint.Min()) } if dataPoint.HasMax() { fmt.Fprintf(&value, " max=%v", dataPoint.Max()) } for bucketIndex := 0; bucketIndex < dataPoint.BucketCounts().Len(); bucketIndex++ { bucketBound := "" if bucketIndex < dataPoint.ExplicitBounds().Len() { bucketBound = fmt.Sprintf("le%v=", dataPoint.ExplicitBounds().At(bucketIndex)) } bucketCount := dataPoint.BucketCounts().At(bucketIndex) fmt.Fprintf(&value, " %s%d", bucketBound, bucketCount) } dataPointLine := fmt.Sprintf("%s{%s} %s\n", metric.Name(), strings.Join(dataPointAttributes, ","), value.String()) lines = append(lines, dataPointLine) } return lines } func writeExponentialHistogramDataPoints(metric pmetric.Metric) (lines []string) { for i := 0; i < metric.ExponentialHistogram().DataPoints().Len(); i++ { dataPoint := metric.ExponentialHistogram().DataPoints().At(i) dataPointAttributes := writeAttributes(dataPoint.Attributes()) var value string value = fmt.Sprintf("count=%d", dataPoint.Count()) if dataPoint.HasSum() { value += fmt.Sprintf(" sum=%v", dataPoint.Sum()) } if dataPoint.HasMin() { value += fmt.Sprintf(" min=%v", dataPoint.Min()) } if dataPoint.HasMax() { value += fmt.Sprintf(" max=%v", dataPoint.Max()) } // TODO display buckets dataPointLine := fmt.Sprintf("%s{%s} %s\n", metric.Name(), strings.Join(dataPointAttributes, ","), value) lines = append(lines, dataPointLine) } return lines } func writeSummaryDataPoints(metric pmetric.Metric) (lines []string) { for i := 0; i < metric.Summary().DataPoints().Len(); i++ { dataPoint := metric.Summary().DataPoints().At(i) dataPointAttributes := writeAttributes(dataPoint.Attributes()) var value strings.Builder fmt.Fprintf(&value, "count=%d", dataPoint.Count()) fmt.Fprintf(&value, " sum=%f", dataPoint.Sum()) for quantileIndex := 0; quantileIndex < dataPoint.QuantileValues().Len(); quantileIndex++ { quantile := dataPoint.QuantileValues().At(quantileIndex) fmt.Fprintf(&value, " q%v=%v", quantile.Quantile(), quantile.Value()) } dataPointLine := fmt.Sprintf("%s{%s} %s\n", metric.Name(), strings.Join(dataPointAttributes, ","), value.String()) lines = append(lines, dataPointLine) } return lines } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/metrics_test.go000066400000000000000000000132651511331344600314340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pmetric" ) func TestMarshalMetrics(t *testing.T) { tests := []struct { name string input pmetric.Metrics expected string }{ { name: "empty metrics", input: pmetric.NewMetrics(), expected: "", }, { name: "sum data point", input: func() pmetric.Metrics { metrics := pmetric.NewMetrics() metric := metrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() metric.SetName("system.cpu.time") dataPoint := metric.SetEmptySum().DataPoints().AppendEmpty() dataPoint.SetDoubleValue(123.456) dataPoint.Attributes().PutStr("state", "user") dataPoint.Attributes().PutStr("cpu", "0") return metrics }(), expected: `ResourceMetrics #0 ScopeMetrics #0 system.cpu.time{state=user,cpu=0} 123.456 `, }, { name: "data point with resource and scope attributes", input: func() pmetric.Metrics { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() resourceMetrics.SetSchemaUrl("https://opentelemetry.io/resource-schema-url") resourceMetrics.Resource().Attributes().PutStr("resourceKey1", "resourceValue1") resourceMetrics.Resource().Attributes().PutBool("resourceKey2", false) scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() scopeMetrics.SetSchemaUrl("http://opentelemetry.io/scope-schema-url") scopeMetrics.Scope().SetName("scope-name") scopeMetrics.Scope().SetVersion("1.2.3") scopeMetrics.Scope().Attributes().PutStr("scopeKey1", "scopeValue1") scopeMetrics.Scope().Attributes().PutBool("scopeKey2", true) metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("system.cpu.time") dataPoint := metric.SetEmptySum().DataPoints().AppendEmpty() dataPoint.SetDoubleValue(123.456) dataPoint.Attributes().PutStr("state", "user") dataPoint.Attributes().PutStr("cpu", "0") return metrics }(), expected: `ResourceMetrics #0 [https://opentelemetry.io/resource-schema-url] resourceKey1=resourceValue1 resourceKey2=false ScopeMetrics #0 scope-name@1.2.3 [http://opentelemetry.io/scope-schema-url] scopeKey1=scopeValue1 scopeKey2=true system.cpu.time{state=user,cpu=0} 123.456 `, }, { name: "gauge data point", input: func() pmetric.Metrics { metrics := pmetric.NewMetrics() metric := metrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() metric.SetName("system.cpu.utilization") dataPoint := metric.SetEmptyGauge().DataPoints().AppendEmpty() dataPoint.SetDoubleValue(78.901234567) dataPoint.Attributes().PutStr("state", "free") dataPoint.Attributes().PutStr("cpu", "8") return metrics }(), expected: `ResourceMetrics #0 ScopeMetrics #0 system.cpu.utilization{state=free,cpu=8} 78.901234567 `, }, { name: "histogram", input: func() pmetric.Metrics { metrics := pmetric.NewMetrics() metric := metrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() metric.SetName("http.server.request.duration") dataPoint := metric.SetEmptyHistogram().DataPoints().AppendEmpty() dataPoint.Attributes().PutInt("http.response.status_code", 200) dataPoint.Attributes().PutStr("http.request.method", "GET") dataPoint.ExplicitBounds().FromRaw([]float64{0.125, 0.5, 1, 3}) dataPoint.BucketCounts().FromRaw([]uint64{1324, 13, 0, 2, 1}) dataPoint.SetCount(1340) dataPoint.SetSum(99.573) dataPoint.SetMin(0.017) dataPoint.SetMax(8.13) return metrics }(), expected: `ResourceMetrics #0 ScopeMetrics #0 http.server.request.duration{http.response.status_code=200,http.request.method=GET} count=1340 sum=99.573 min=0.017 max=8.13 le0.125=1324 le0.5=13 le1=0 le3=2 1 `, }, { name: "exponential histogram", input: func() pmetric.Metrics { metrics := pmetric.NewMetrics() metric := metrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() metric.SetName("http.server.request.duration") dataPoint := metric.SetEmptyExponentialHistogram().DataPoints().AppendEmpty() dataPoint.Attributes().PutInt("http.response.status_code", 200) dataPoint.Attributes().PutStr("http.request.method", "GET") dataPoint.SetCount(1340) dataPoint.SetSum(99.573) dataPoint.SetMin(0.017) dataPoint.SetMax(8.13) return metrics }(), expected: `ResourceMetrics #0 ScopeMetrics #0 http.server.request.duration{http.response.status_code=200,http.request.method=GET} count=1340 sum=99.573 min=0.017 max=8.13 `, }, { name: "summary", input: func() pmetric.Metrics { metrics := pmetric.NewMetrics() metric := metrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() metric.SetName("summary") dataPoint := metric.SetEmptySummary().DataPoints().AppendEmpty() dataPoint.Attributes().PutInt("http.response.status_code", 200) dataPoint.Attributes().PutStr("http.request.method", "GET") dataPoint.SetCount(1340) dataPoint.SetSum(99.573) quantile := dataPoint.QuantileValues().AppendEmpty() quantile.SetQuantile(0.01) quantile.SetValue(15) return metrics }(), expected: `ResourceMetrics #0 ScopeMetrics #0 summary{http.response.status_code=200,http.request.method=GET} count=1340 sum=99.573000 q0.01=15 `, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { output, err := NewNormalMetricsMarshaler().MarshalMetrics(tt.input) require.NoError(t, err) assert.Equal(t, tt.expected, string(output)) }) } } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/profiles.go000066400000000000000000000041511511331344600305440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/normal" import ( "bytes" "fmt" "strconv" "strings" "go.opentelemetry.io/collector/pdata/pprofile" ) type normalProfilesMarshaler struct{} // Ensure normalProfilesMarshaller implements interface pprofile.Marshaler var _ pprofile.Marshaler = normalProfilesMarshaler{} // NewNormalProfilesMarshaler returns a pprofile.Marshaler for normal verbosity. It writes one line of text per log record func NewNormalProfilesMarshaler() pprofile.Marshaler { return normalProfilesMarshaler{} } func (normalProfilesMarshaler) MarshalProfiles(pd pprofile.Profiles) ([]byte, error) { var buffer bytes.Buffer dic := pd.Dictionary() for i := 0; i < pd.ResourceProfiles().Len(); i++ { resourceProfiles := pd.ResourceProfiles().At(i) buffer.WriteString(fmt.Sprintf("ResourceProfiles #%d%s%s\n", i, writeResourceDetails(resourceProfiles.SchemaUrl()), writeAttributesString(resourceProfiles.Resource().Attributes()))) for j := 0; j < resourceProfiles.ScopeProfiles().Len(); j++ { scopeProfiles := resourceProfiles.ScopeProfiles().At(j) buffer.WriteString(fmt.Sprintf("ScopeProfiles #%d%s%s\n", i, writeScopeDetails(scopeProfiles.Scope().Name(), scopeProfiles.Scope().Version(), scopeProfiles.SchemaUrl()), writeAttributesString(scopeProfiles.Scope().Attributes()))) for k := 0; k < scopeProfiles.Profiles().Len(); k++ { profile := scopeProfiles.Profiles().At(k) buffer.WriteString(profile.ProfileID().String()) buffer.WriteString(" samples=") buffer.WriteString(strconv.Itoa(profile.Samples().Len())) if profile.AttributeIndices().Len() > 0 { attrs := []string{} for _, i := range profile.AttributeIndices().AsRaw() { a := dic.AttributeTable().At(int(i)) attrs = append(attrs, fmt.Sprintf("%s=%s", dic.StringTable().At(int(a.KeyStrindex())), a.Value().AsString())) } buffer.WriteString(" ") buffer.WriteString(strings.Join(attrs, " ")) } buffer.WriteString("\n") } } } return buffer.Bytes(), nil } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/profiles_test.go000066400000000000000000000042321511331344600316030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pprofile" ) func TestMarshalProfiles(t *testing.T) { tests := []struct { name string input pprofile.Profiles expected string }{ { name: "empty profile", input: pprofile.NewProfiles(), expected: "", }, { name: "one profile", input: func() pprofile.Profiles { profiles := pprofile.NewProfiles() dic := profiles.Dictionary() dic.StringTable().Append("") dic.StringTable().Append("key1") a := dic.AttributeTable().AppendEmpty() a.SetKeyStrindex(1) a.Value().SetStr("value1") profile := profiles.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() profiles.ResourceProfiles().At(0).SetSchemaUrl("https://example.com/resource") profiles.ResourceProfiles().At(0).Resource().Attributes().PutStr("resourceKey", "resourceValue") profiles.ResourceProfiles().At(0).ScopeProfiles().At(0).SetSchemaUrl("https://example.com/scope") profiles.ResourceProfiles().At(0).ScopeProfiles().At(0).Scope().SetName("scope-name") profiles.ResourceProfiles().At(0).ScopeProfiles().At(0).Scope().SetVersion("1.2.3") profiles.ResourceProfiles().At(0).ScopeProfiles().At(0).Scope().Attributes().PutStr("scopeKey", "scopeValue") profile.SetProfileID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) profile.Samples().AppendEmpty() profile.Samples().AppendEmpty() profile.AttributeIndices().Append(0) return profiles }(), expected: `ResourceProfiles #0 [https://example.com/resource] resourceKey=resourceValue ScopeProfiles #0 scope-name@1.2.3 [https://example.com/scope] scopeKey=scopeValue 0102030405060708090a0b0c0d0e0f10 samples=2 key1=value1 `, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { output, err := NewNormalProfilesMarshaler().MarshalProfiles(tt.input) require.NoError(t, err) assert.Equal(t, tt.expected, string(output)) }) } } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/traces.go000066400000000000000000000035311511331344600302030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/normal" import ( "bytes" "fmt" "strings" "go.opentelemetry.io/collector/pdata/ptrace" ) type normalTracesMarshaler struct{} // Ensure normalTracesMarshaller implements interface ptrace.Marshaler var _ ptrace.Marshaler = normalTracesMarshaler{} // NewNormalTracesMarshaler returns a ptrace.Marshaler for normal verbosity. It writes one line of text per log record func NewNormalTracesMarshaler() ptrace.Marshaler { return normalTracesMarshaler{} } func (normalTracesMarshaler) MarshalTraces(md ptrace.Traces) ([]byte, error) { var buffer bytes.Buffer for i := 0; i < md.ResourceSpans().Len(); i++ { resourceTraces := md.ResourceSpans().At(i) buffer.WriteString(fmt.Sprintf("ResourceTraces #%d%s%s\n", i, writeResourceDetails(resourceTraces.SchemaUrl()), writeAttributesString(resourceTraces.Resource().Attributes()))) for j := 0; j < resourceTraces.ScopeSpans().Len(); j++ { scopeTraces := resourceTraces.ScopeSpans().At(j) buffer.WriteString(fmt.Sprintf("ScopeTraces #%d%s%s\n", i, writeScopeDetails(scopeTraces.Scope().Name(), scopeTraces.Scope().Version(), scopeTraces.SchemaUrl()), writeAttributesString(scopeTraces.Scope().Attributes()))) for k := 0; k < scopeTraces.Spans().Len(); k++ { span := scopeTraces.Spans().At(k) buffer.WriteString(span.Name()) buffer.WriteString(" ") buffer.WriteString(span.TraceID().String()) buffer.WriteString(" ") buffer.WriteString(span.SpanID().String()) if span.Attributes().Len() > 0 { spanAttributes := writeAttributes(span.Attributes()) buffer.WriteString(" ") buffer.WriteString(strings.Join(spanAttributes, " ")) } buffer.WriteString("\n") } } } return buffer.Bytes(), nil } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/normal/traces_test.go000066400000000000000000000054521511331344600312460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package normal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestMarshalTraces(t *testing.T) { tests := []struct { name string input ptrace.Traces expected string }{ { name: "empty traces", input: ptrace.NewTraces(), expected: "", }, { name: "one span with resource and scope attributes", input: func() ptrace.Traces { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() resourceSpans.SetSchemaUrl("https://opentelemetry.io/resource-schema-url") resourceSpans.Resource().Attributes().PutStr("resourceKey1", "resourceValue1") resourceSpans.Resource().Attributes().PutBool("resourceKey2", false) scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() scopeSpans.SetSchemaUrl("http://opentelemetry.io/scope-schema-url") scopeSpans.Scope().SetName("scope-name") scopeSpans.Scope().SetVersion("1.2.3") scopeSpans.Scope().Attributes().PutStr("scopeKey1", "scopeValue1") scopeSpans.Scope().Attributes().PutBool("scopeKey2", true) span := scopeSpans.Spans().AppendEmpty() span.SetName("span-name") span.SetTraceID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) span.SetSpanID([8]byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) span.Attributes().PutStr("key1", "value1") span.Attributes().PutStr("key2", "value2") return traces }(), expected: `ResourceTraces #0 [https://opentelemetry.io/resource-schema-url] resourceKey1=resourceValue1 resourceKey2=false ScopeTraces #0 scope-name@1.2.3 [http://opentelemetry.io/scope-schema-url] scopeKey1=scopeValue1 scopeKey2=true span-name 0102030405060708090a0b0c0d0e0f10 1112131415161718 key1=value1 key2=value2 `, }, { name: "one span", input: func() ptrace.Traces { traces := ptrace.NewTraces() span := traces.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.SetName("span-name") span.SetTraceID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) span.SetSpanID([8]byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) span.Attributes().PutStr("key1", "value1") span.Attributes().PutStr("key2", "value2") return traces }(), expected: `ResourceTraces #0 ScopeTraces #0 span-name 0102030405060708090a0b0c0d0e0f10 1112131415161718 key1=value1 key2=value2 `, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { output, err := NewNormalTracesMarshaler().MarshalTraces(tt.input) require.NoError(t, err) assert.Equal(t, tt.expected, string(output)) }) } } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/000077500000000000000000000000001511331344600267645ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/databuffer.go000066400000000000000000000306741511331344600314300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "bytes" "fmt" "math" "strings" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/xpdata/entity" ) type dataBuffer struct { buf bytes.Buffer } func (b *dataBuffer) logEntry(format string, a ...any) { b.buf.WriteString(fmt.Sprintf(format, a...)) b.buf.WriteString("\n") } func (b *dataBuffer) logAttr(attr string, value any) { b.logEntry(" %-15s: %s", attr, value) } func (b *dataBuffer) logAttributes(header string, m pcommon.Map) { if m.Len() == 0 { return } b.logEntry("%s:", header) attrPrefix := " ->" // Add offset to attributes if needed. headerParts := strings.Split(header, "->") if len(headerParts) > 1 { attrPrefix = headerParts[0] + attrPrefix } for k, v := range m.All() { b.logEntry("%s %s: %s", attrPrefix, k, valueToString(v)) } } func (b *dataBuffer) logEntityRefs(resource pcommon.Resource) { entityRefs := entity.ResourceEntityRefs(resource) if entityRefs.Len() == 0 { return } b.logEntry("Resource entity refs:") for i := 0; i < entityRefs.Len(); i++ { entityRef := entityRefs.At(i) b.logEntry(" -> Entity ref #%d:", i) b.logEntry(" -> Type: %s", entityRef.Type()) if entityRef.SchemaUrl() != "" { b.logEntry(" -> Schema URL: %s", entityRef.SchemaUrl()) } idKeys := entityRef.IdKeys() if idKeys.Len() > 0 { b.logEntry(" -> ID keys:") for j := 0; j < idKeys.Len(); j++ { b.logEntry(" -> %s", idKeys.At(j)) } } descKeys := entityRef.DescriptionKeys() if descKeys.Len() > 0 { b.logEntry(" -> Description keys:") for j := 0; j < descKeys.Len(); j++ { b.logEntry(" -> %s", descKeys.At(j)) } } } } func (b *dataBuffer) logAttributesWithIndentation(header string, m pcommon.Map, indentVal int) { if m.Len() == 0 { return } indent := strings.Repeat(" ", indentVal) b.logEntry("%s%s:", indent, header) attrPrefix := indent + " ->" // Add offset to attributes if needed. headerParts := strings.Split(header, "->") if len(headerParts) > 1 { attrPrefix = headerParts[0] + attrPrefix } for k, v := range m.All() { b.logEntry("%s %s: %s", attrPrefix, k, valueToString(v)) } } func (b *dataBuffer) logInstrumentationScope(il pcommon.InstrumentationScope) { b.logEntry( "InstrumentationScope %s %s", il.Name(), il.Version()) b.logAttributes("InstrumentationScope attributes", il.Attributes()) } func (b *dataBuffer) logMetricDescriptor(md pmetric.Metric) { b.logEntry("Descriptor:") b.logEntry(" -> Name: %s", md.Name()) b.logEntry(" -> Description: %s", md.Description()) b.logEntry(" -> Unit: %s", md.Unit()) b.logEntry(" -> DataType: %s", md.Type().String()) } func (b *dataBuffer) logMetricDataPoints(m pmetric.Metric) { switch m.Type() { case pmetric.MetricTypeEmpty: return case pmetric.MetricTypeGauge: b.logNumberDataPoints(m.Gauge().DataPoints()) case pmetric.MetricTypeSum: data := m.Sum() b.logEntry(" -> IsMonotonic: %t", data.IsMonotonic()) b.logEntry(" -> AggregationTemporality: %s", data.AggregationTemporality().String()) b.logNumberDataPoints(data.DataPoints()) case pmetric.MetricTypeHistogram: data := m.Histogram() b.logEntry(" -> AggregationTemporality: %s", data.AggregationTemporality().String()) b.logHistogramDataPoints(data.DataPoints()) case pmetric.MetricTypeExponentialHistogram: data := m.ExponentialHistogram() b.logEntry(" -> AggregationTemporality: %s", data.AggregationTemporality().String()) b.logExponentialHistogramDataPoints(data.DataPoints()) case pmetric.MetricTypeSummary: data := m.Summary() b.logDoubleSummaryDataPoints(data.DataPoints()) } } func (b *dataBuffer) logNumberDataPoints(ps pmetric.NumberDataPointSlice) { for i := 0; i < ps.Len(); i++ { p := ps.At(i) b.logEntry("NumberDataPoints #%d", i) b.logDataPointAttributes(p.Attributes()) b.logEntry("StartTimestamp: %s", p.StartTimestamp()) b.logEntry("Timestamp: %s", p.Timestamp()) switch p.ValueType() { case pmetric.NumberDataPointValueTypeInt: b.logEntry("Value: %d", p.IntValue()) case pmetric.NumberDataPointValueTypeDouble: b.logEntry("Value: %f", p.DoubleValue()) } b.logExemplars("Exemplars", p.Exemplars()) } } func (b *dataBuffer) logHistogramDataPoints(ps pmetric.HistogramDataPointSlice) { for i := 0; i < ps.Len(); i++ { p := ps.At(i) b.logEntry("HistogramDataPoints #%d", i) b.logDataPointAttributes(p.Attributes()) b.logEntry("StartTimestamp: %s", p.StartTimestamp()) b.logEntry("Timestamp: %s", p.Timestamp()) b.logEntry("Count: %d", p.Count()) if p.HasSum() { b.logEntry("Sum: %f", p.Sum()) } if p.HasMin() { b.logEntry("Min: %f", p.Min()) } if p.HasMax() { b.logEntry("Max: %f", p.Max()) } for i := 0; i < p.ExplicitBounds().Len(); i++ { b.logEntry("ExplicitBounds #%d: %f", i, p.ExplicitBounds().At(i)) } for j := 0; j < p.BucketCounts().Len(); j++ { b.logEntry("Buckets #%d, Count: %d", j, p.BucketCounts().At(j)) } b.logExemplars("Exemplars", p.Exemplars()) } } func (b *dataBuffer) logExponentialHistogramDataPoints(ps pmetric.ExponentialHistogramDataPointSlice) { for i := 0; i < ps.Len(); i++ { p := ps.At(i) b.logEntry("ExponentialHistogramDataPoints #%d", i) b.logDataPointAttributes(p.Attributes()) b.logEntry("StartTimestamp: %s", p.StartTimestamp()) b.logEntry("Timestamp: %s", p.Timestamp()) b.logEntry("Count: %d", p.Count()) if p.HasSum() { b.logEntry("Sum: %f", p.Sum()) } if p.HasMin() { b.logEntry("Min: %f", p.Min()) } if p.HasMax() { b.logEntry("Max: %f", p.Max()) } scale := int(p.Scale()) factor := math.Ldexp(math.Ln2, -scale) // Note: the equation used here, which is // math.Exp(index * factor) // reports +Inf as the _lower_ boundary of the bucket nearest // infinity, which is incorrect and can be addressed in various // ways. The OTel-Go implementation of this histogram pending // in https://github.com/open-telemetry/opentelemetry-go/pull/2393 // uses a lookup table for the last finite boundary, which can be // easily computed using `math/big` (for scales up to 20). negB := p.Negative().BucketCounts() posB := p.Positive().BucketCounts() for i := 0; i < negB.Len(); i++ { pos := negB.Len() - i - 1 index := float64(p.Negative().Offset()) + float64(pos) lower := math.Exp(index * factor) upper := math.Exp((index + 1) * factor) b.logEntry("Bucket [%f, %f), Count: %d", -upper, -lower, negB.At(pos)) } if p.ZeroCount() != 0 { b.logEntry("Bucket [0, 0], Count: %d", p.ZeroCount()) } for pos := 0; pos < posB.Len(); pos++ { index := float64(p.Positive().Offset()) + float64(pos) lower := math.Exp(index * factor) upper := math.Exp((index + 1) * factor) b.logEntry("Bucket (%f, %f], Count: %d", lower, upper, posB.At(pos)) } b.logExemplars("Exemplars", p.Exemplars()) } } func (b *dataBuffer) logDoubleSummaryDataPoints(ps pmetric.SummaryDataPointSlice) { for i := 0; i < ps.Len(); i++ { p := ps.At(i) b.logEntry("SummaryDataPoints #%d", i) b.logDataPointAttributes(p.Attributes()) b.logEntry("StartTimestamp: %s", p.StartTimestamp()) b.logEntry("Timestamp: %s", p.Timestamp()) b.logEntry("Count: %d", p.Count()) b.logEntry("Sum: %f", p.Sum()) quantiles := p.QuantileValues() for i := 0; i < quantiles.Len(); i++ { quantile := quantiles.At(i) b.logEntry("QuantileValue #%d: Quantile %f, Value %f", i, quantile.Quantile(), quantile.Value()) } } } func (b *dataBuffer) logDataPointAttributes(attributes pcommon.Map) { b.logAttributes("Data point attributes", attributes) } func (b *dataBuffer) logEvents(description string, se ptrace.SpanEventSlice) { if se.Len() == 0 { return } b.logEntry("%s:", description) for i := 0; i < se.Len(); i++ { e := se.At(i) b.logEntry("SpanEvent #%d", i) b.logEntry(" -> Name: %s", e.Name()) b.logEntry(" -> Timestamp: %s", e.Timestamp()) b.logEntry(" -> DroppedAttributesCount: %d", e.DroppedAttributesCount()) b.logAttributes(" -> Attributes:", e.Attributes()) } } func (b *dataBuffer) logLinks(description string, sl ptrace.SpanLinkSlice) { if sl.Len() == 0 { return } b.logEntry("%s:", description) for i := 0; i < sl.Len(); i++ { l := sl.At(i) b.logEntry("SpanLink #%d", i) b.logEntry(" -> Trace ID: %s", l.TraceID()) b.logEntry(" -> ID: %s", l.SpanID()) b.logEntry(" -> TraceState: %s", l.TraceState().AsRaw()) b.logEntry(" -> DroppedAttributesCount: %d", l.DroppedAttributesCount()) b.logAttributes(" -> Attributes:", l.Attributes()) } } func (b *dataBuffer) logExemplars(description string, se pmetric.ExemplarSlice) { if se.Len() == 0 { return } b.logEntry("%s:", description) for i := 0; i < se.Len(); i++ { e := se.At(i) b.logEntry("Exemplar #%d", i) b.logEntry(" -> Trace ID: %s", e.TraceID()) b.logEntry(" -> Span ID: %s", e.SpanID()) b.logEntry(" -> Timestamp: %s", e.Timestamp()) switch e.ValueType() { case pmetric.ExemplarValueTypeInt: b.logEntry(" -> Value: %d", e.IntValue()) case pmetric.ExemplarValueTypeDouble: b.logEntry(" -> Value: %f", e.DoubleValue()) } b.logAttributes(" -> FilteredAttributes", e.FilteredAttributes()) } } func (b *dataBuffer) logProfileSamples(ss pprofile.SampleSlice, dic pprofile.ProfilesDictionary) { if ss.Len() == 0 { return } for i := 0; i < ss.Len(); i++ { b.logEntry(" Sample #%d", i) sample := ss.At(i) b.logEntry(" Values: %d", sample.Values().AsRaw()) if lai := sample.AttributeIndices().Len(); lai > 0 { b.logEntry(" Attributes:") for j := range lai { attr := dic.AttributeTable().At(int(sample.AttributeIndices().At(j))) b.logEntry(" -> %s: %s", dic.StringTable().At(int(attr.KeyStrindex())), attr.Value().AsRaw()) } } } } func (b *dataBuffer) logProfileMappings(ms pprofile.MappingSlice) { if ms.Len() == 0 { return } for i := 0; i < ms.Len(); i++ { b.logEntry("Mapping #%d", i) mapping := ms.At(i) b.logEntry(" Memory start: %d", mapping.MemoryStart()) b.logEntry(" Memory limit: %d", mapping.MemoryLimit()) b.logEntry(" File offset: %d", mapping.FileOffset()) b.logEntry(" File name: %d", mapping.FilenameStrindex()) b.logEntry(" Attributes: %d", mapping.AttributeIndices().AsRaw()) } } func (b *dataBuffer) logProfileLocations(ls pprofile.LocationSlice) { if ls.Len() == 0 { return } for i := 0; i < ls.Len(); i++ { b.logEntry("Location #%d", i) location := ls.At(i) b.logEntry(" Mapping index: %d", location.MappingIndex()) b.logEntry(" Address: %d", location.Address()) if ll := location.Lines().Len(); ll > 0 { for j := range ll { b.logEntry(" Line #%d", j) line := location.Lines().At(j) b.logEntry(" Function index: %d", line.FunctionIndex()) b.logEntry(" Line: %d", line.Line()) b.logEntry(" Column: %d", line.Column()) } } b.logEntry(" Attributes: %d", location.AttributeIndices().AsRaw()) } } func (b *dataBuffer) logProfileFunctions(fs pprofile.FunctionSlice) { if fs.Len() == 0 { return } for i := 0; i < fs.Len(); i++ { b.logEntry("Function #%d", i) function := fs.At(i) b.logEntry(" Name: %d", function.NameStrindex()) b.logEntry(" System name: %d", function.SystemNameStrindex()) b.logEntry(" Filename: %d", function.FilenameStrindex()) b.logEntry(" Start line: %d", function.StartLine()) } } func (b *dataBuffer) logStringTable(ss pcommon.StringSlice) { if ss.Len() == 0 { return } b.logEntry("String table:") for i := 0; i < ss.Len(); i++ { b.logEntry(" %s", ss.At(i)) } } func keyValueAndUnitsToMap(aus pprofile.KeyValueAndUnitSlice) pcommon.Map { m := pcommon.NewMap() for i := 0; i < aus.Len(); i++ { au := aus.At(i) m.PutInt("Key", int64(au.KeyStrindex())) m.PutStr("Value", au.Value().AsString()) m.PutInt("unit", int64(au.UnitStrindex())) } return m } func linkTableToMap(ls pprofile.LinkSlice) pcommon.Map { m := pcommon.NewMap() for i := 0; i < ls.Len(); i++ { l := ls.At(i) m.PutStr("Trace ID", l.TraceID().String()) m.PutStr("Span ID", l.SpanID().String()) } return m } func valueToString(v pcommon.Value) string { return fmt.Sprintf("%s(%s)", v.Type().String(), v.AsString()) } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/databuffer_test.go000066400000000000000000000015271511331344600324620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestNestedArraySerializesCorrectly(t *testing.T) { ava := pcommon.NewValueSlice() ava.Slice().AppendEmpty().SetStr("foo") ava.Slice().AppendEmpty().SetInt(42) ava.Slice().AppendEmpty().SetEmptySlice().AppendEmpty().SetStr("bar") ava.Slice().AppendEmpty().SetBool(true) ava.Slice().AppendEmpty().SetDouble(5.5) assert.Equal(t, `Slice(["foo",42,["bar"],true,5.5])`, valueToString(ava)) } func TestNestedMapSerializesCorrectly(t *testing.T) { ava := pcommon.NewValueMap() av := ava.Map() av.PutStr("foo", "test") av.PutEmptyMap("zoo").PutInt("bar", 13) assert.Equal(t, `Map({"foo":"test","zoo":{"bar":13}})`, valueToString(ava)) } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/known_sync_error.go000066400000000000000000000014401511331344600327130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build linux || darwin package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "errors" "syscall" ) var knownSyncErrors = []error{ // sync /dev/stdout: invalid argument syscall.EINVAL, // sync /dev/stdout: not supported syscall.ENOTSUP, // sync /dev/stdout: inappropriate ioctl for device syscall.ENOTTY, // sync /dev/stdout: bad file descriptor syscall.EBADF, } // knownSyncError returns true if the given error is one of the known // non-actionable errors returned by Sync on Linux and macOS. func knownSyncError(err error) bool { for _, syncError := range knownSyncErrors { if errors.Is(err, syncError) { return true } } return false } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/known_sync_error_other.go000066400000000000000000000006171511331344600341210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build !linux && !darwin && !windows package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" // knownSyncError returns true if the given error is one of the known // non-actionable errors returned by Sync on Plan 9. func knownSyncError(err error) bool { return false } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/known_sync_error_windows.go000066400000000000000000000010051511331344600344620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build windows package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "errors" "golang.org/x/sys/windows" ) // knownSyncError returns true if the given error is one of the known // non-actionable errors returned by Sync on Windows: // // - sync /dev/stderr: The handle is invalid. func knownSyncError(err error) bool { return errors.Is(err, windows.ERROR_INVALID_HANDLE) } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/logs.go000066400000000000000000000034171511331344600302640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "go.opentelemetry.io/collector/pdata/plog" ) // NewTextLogsMarshaler returns a plog.Marshaler to encode to OTLP text bytes. func NewTextLogsMarshaler() plog.Marshaler { return textLogsMarshaler{} } type textLogsMarshaler struct{} // MarshalLogs plog.Logs to OTLP text. func (textLogsMarshaler) MarshalLogs(ld plog.Logs) ([]byte, error) { buf := dataBuffer{} rls := ld.ResourceLogs() for i := 0; i < rls.Len(); i++ { buf.logEntry("ResourceLog #%d", i) rl := rls.At(i) buf.logEntry("Resource SchemaURL: %s", rl.SchemaUrl()) buf.logAttributes("Resource attributes", rl.Resource().Attributes()) buf.logEntityRefs(rl.Resource()) ills := rl.ScopeLogs() for j := 0; j < ills.Len(); j++ { buf.logEntry("ScopeLogs #%d", j) ils := ills.At(j) buf.logEntry("ScopeLogs SchemaURL: %s", ils.SchemaUrl()) buf.logInstrumentationScope(ils.Scope()) logs := ils.LogRecords() for k := 0; k < logs.Len(); k++ { buf.logEntry("LogRecord #%d", k) lr := logs.At(k) buf.logEntry("ObservedTimestamp: %s", lr.ObservedTimestamp()) buf.logEntry("Timestamp: %s", lr.Timestamp()) buf.logEntry("SeverityText: %s", lr.SeverityText()) buf.logEntry("SeverityNumber: %s(%d)", lr.SeverityNumber(), lr.SeverityNumber()) if lr.EventName() != "" { buf.logEntry("EventName: %s", lr.EventName()) } buf.logEntry("Body: %s", valueToString(lr.Body())) buf.logAttributes("Attributes", lr.Attributes()) buf.logEntry("Trace ID: %s", lr.TraceID()) buf.logEntry("Span ID: %s", lr.SpanID()) buf.logEntry("Flags: %d", lr.Flags()) } } } return buf.buf.Bytes(), nil } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/logs_test.go000066400000000000000000000063331511331344600313230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext import ( "os" "path/filepath" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" ) func TestLogsText(t *testing.T) { tests := []struct { name string in plog.Logs out string }{ { name: "empty_logs", in: plog.NewLogs(), out: "empty.out", }, { name: "logs_with_one_record", in: testdata.GenerateLogs(1), out: "one_record.out", }, { name: "logs_with_two_records", in: testdata.GenerateLogs(2), out: "two_records.out", }, { name: "log_with_event_name", in: func() plog.Logs { ls := plog.NewLogs() l := ls.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC))) l.SetSeverityNumber(plog.SeverityNumberInfo) l.SetSeverityText("Info") l.SetEventName("event_name") l.Body().SetStr("This is a log message") attrs := l.Attributes() attrs.PutStr("app", "server") attrs.PutInt("instance_num", 1) l.SetSpanID([8]byte{0x01, 0x02, 0x04, 0x08}) l.SetTraceID([16]byte{0x08, 0x04, 0x02, 0x01}) return ls }(), out: "log_with_event_name.out", }, { name: "logs_with_embedded_maps", in: func() plog.Logs { ls := plog.NewLogs() l := ls.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC))) l.SetSeverityNumber(plog.SeverityNumberInfo) l.SetSeverityText("INFO") bm := l.Body().SetEmptyMap() bm.PutStr("key1", "val1") bmm := bm.PutEmptyMap("key2") bmm.PutStr("key21", "val21") bmm.PutStr("key22", "val22") am := l.Attributes().PutEmptyMap("key1") am.PutStr("key11", "val11") am.PutStr("key12", "val12") am.PutEmptyMap("key13").PutStr("key131", "val131") l.Attributes().PutStr("key2", "val2") return ls }(), out: "embedded_maps.out", }, { name: "logs_with_entity_refs", in: generateLogsWithEntityRefs(), out: "logs_with_entity_refs.out", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewTextLogsMarshaler().MarshalLogs(tt.in) require.NoError(t, err) out, err := os.ReadFile(filepath.Join("testdata", "logs", tt.out)) require.NoError(t, err) expected := strings.ReplaceAll(string(out), "\r", "") assert.Equal(t, expected, string(got)) }) } } func generateLogsWithEntityRefs() plog.Logs { ld := plog.NewLogs() rl := ld.ResourceLogs().AppendEmpty() setupResourceWithEntityRefs(rl.Resource()) sl := rl.ScopeLogs().AppendEmpty() sl.Scope().SetName("test-scope") lr := sl.LogRecords().AppendEmpty() lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC))) lr.SetSeverityNumber(plog.SeverityNumberInfo) lr.SetSeverityText("Info") lr.Body().SetStr("This is a test log message") lr.Attributes().PutStr("test.attribute", "test-value") return ld } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/metrics.go000066400000000000000000000025101511331344600307570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import "go.opentelemetry.io/collector/pdata/pmetric" // NewTextMetricsMarshaler returns a pmetric.Marshaler to encode to OTLP text bytes. func NewTextMetricsMarshaler() pmetric.Marshaler { return textMetricsMarshaler{} } type textMetricsMarshaler struct{} // MarshalMetrics pmetric.Metrics to OTLP text. func (textMetricsMarshaler) MarshalMetrics(md pmetric.Metrics) ([]byte, error) { buf := dataBuffer{} rms := md.ResourceMetrics() for i := 0; i < rms.Len(); i++ { buf.logEntry("ResourceMetrics #%d", i) rm := rms.At(i) buf.logEntry("Resource SchemaURL: %s", rm.SchemaUrl()) buf.logAttributes("Resource attributes", rm.Resource().Attributes()) buf.logEntityRefs(rm.Resource()) ilms := rm.ScopeMetrics() for j := 0; j < ilms.Len(); j++ { buf.logEntry("ScopeMetrics #%d", j) ilm := ilms.At(j) buf.logEntry("ScopeMetrics SchemaURL: %s", ilm.SchemaUrl()) buf.logInstrumentationScope(ilm.Scope()) metrics := ilm.Metrics() for k := 0; k < metrics.Len(); k++ { buf.logEntry("Metric #%d", k) metric := metrics.At(k) buf.logMetricDescriptor(metric) buf.logMetricDataPoints(metric) } } } return buf.buf.Bytes(), nil } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/metrics_test.go000066400000000000000000000036121511331344600320220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext import ( "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMetricsText(t *testing.T) { tests := []struct { name string in pmetric.Metrics out string }{ { name: "empty_metrics", in: pmetric.NewMetrics(), out: "empty.out", }, { name: "metrics_with_all_types", in: testdata.GenerateMetricsAllTypes(), out: "metrics_with_all_types.out", }, { name: "two_metrics", in: testdata.GenerateMetrics(2), out: "two_metrics.out", }, { name: "invalid_metric_type", in: testdata.GenerateMetricsMetricTypeInvalid(), out: "invalid_metric_type.out", }, { name: "metrics_with_entity_refs", in: generateMetricsWithEntityRefs(), out: "metrics_with_entity_refs.out", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewTextMetricsMarshaler().MarshalMetrics(tt.in) require.NoError(t, err) out, err := os.ReadFile(filepath.Join("testdata", "metrics", tt.out)) require.NoError(t, err) expected := strings.ReplaceAll(string(out), "\r", "") assert.Equal(t, expected, string(got)) }) } } func generateMetricsWithEntityRefs() pmetric.Metrics { md := pmetric.NewMetrics() rm := md.ResourceMetrics().AppendEmpty() setupResourceWithEntityRefs(rm.Resource()) sm := rm.ScopeMetrics().AppendEmpty() sm.Scope().SetName("test-scope") metric := sm.Metrics().AppendEmpty() metric.SetName("test-metric") metric.SetDescription("A test metric") metric.SetUnit("1") gauge := metric.SetEmptyGauge() dp := gauge.DataPoints().AppendEmpty() dp.SetDoubleValue(123.45) dp.Attributes().PutStr("test.attribute", "test-value") return md } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/package_test.go000066400000000000000000000003111511331344600317400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/profiles.go000066400000000000000000000040271511331344600311410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "strconv" "go.opentelemetry.io/collector/pdata/pprofile" ) // NewTextProfilesMarshaler returns a pprofile.Marshaler to encode to OTLP text bytes. func NewTextProfilesMarshaler() pprofile.Marshaler { return textProfilesMarshaler{} } type textProfilesMarshaler struct{} // MarshalProfiles pprofile.Profiles to OTLP text. func (textProfilesMarshaler) MarshalProfiles(pd pprofile.Profiles) ([]byte, error) { buf := dataBuffer{} dic := pd.Dictionary() rps := pd.ResourceProfiles() buf.logProfileMappings(dic.MappingTable()) buf.logProfileLocations(dic.LocationTable()) buf.logProfileFunctions(dic.FunctionTable()) buf.logAttributesWithIndentation( "Attribute table", keyValueAndUnitsToMap(dic.AttributeTable()), 0) buf.logAttributesWithIndentation( "Link table", linkTableToMap(dic.LinkTable()), 0) buf.logStringTable(dic.StringTable()) for i := 0; i < rps.Len(); i++ { buf.logEntry("ResourceProfiles #%d", i) rp := rps.At(i) buf.logEntry("Resource SchemaURL: %s", rp.SchemaUrl()) buf.logAttributes("Resource attributes", rp.Resource().Attributes()) buf.logEntityRefs(rp.Resource()) ilps := rp.ScopeProfiles() for j := 0; j < ilps.Len(); j++ { buf.logEntry("ScopeProfiles #%d", j) ilp := ilps.At(j) buf.logEntry("ScopeProfiles SchemaURL: %s", ilp.SchemaUrl()) buf.logInstrumentationScope(ilp.Scope()) profiles := ilp.Profiles() for k := 0; k < profiles.Len(); k++ { buf.logEntry("Profile #%d", k) profile := profiles.At(k) buf.logAttr("Profile ID", profile.ProfileID()) buf.logAttr("Start time", profile.Time().String()) buf.logAttr("DurationNano", strconv.FormatUint(profile.DurationNano(), 10)) buf.logAttr("Dropped attributes count", strconv.FormatUint(uint64(profile.DroppedAttributesCount()), 10)) buf.logProfileSamples(profile.Samples(), dic) } } } return buf.buf.Bytes(), nil } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/profiles_test.go000066400000000000000000000065601511331344600322040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext import ( "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/testdata" ) func TestProfilesText(t *testing.T) { tests := []struct { name string in pprofile.Profiles out string }{ { name: "empty_profiles", in: pprofile.NewProfiles(), out: "empty.out", }, { name: "two_profiles", in: extendProfiles(testdata.GenerateProfiles(2)), out: "two_profiles.out", }, { name: "profiles_with_entity_refs", in: generateProfilesWithEntityRefs(), out: "profiles_with_entity_refs.out", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewTextProfilesMarshaler().MarshalProfiles(tt.in) require.NoError(t, err) out, err := os.ReadFile(filepath.Join("testdata", "profiles", tt.out)) require.NoError(t, err) expected := strings.ReplaceAll(string(out), "\r", "") assert.Equal(t, expected, string(got)) }) } } // GenerateExtendedProfiles generates dummy profiling data with extended values for tests func extendProfiles(profiles pprofile.Profiles) pprofile.Profiles { dic := profiles.Dictionary() location := dic.LocationTable().AppendEmpty() location.SetMappingIndex(3) location.SetAddress(4) line := location.Lines().AppendEmpty() line.SetFunctionIndex(1) line.SetLine(2) line.SetColumn(3) location.AttributeIndices().FromRaw([]int32{6, 7}) dic.StringTable().Append("intValue") at := dic.AttributeTable() a := at.AppendEmpty() a.SetKeyStrindex(1) a.Value().SetInt(42) attributeUnits := dic.AttributeTable().AppendEmpty() attributeUnits.SetKeyStrindex(2) attributeUnits.SetUnitStrindex(5) dic.StringTable().Append("foobar") mapping := dic.MappingTable().AppendEmpty() mapping.SetMemoryStart(2) mapping.SetMemoryLimit(3) mapping.SetFileOffset(4) mapping.SetFilenameStrindex(5) mapping.AttributeIndices().FromRaw([]int32{7, 8}) function := dic.FunctionTable().AppendEmpty() function.SetNameStrindex(2) function.SetSystemNameStrindex(3) function.SetFilenameStrindex(4) function.SetStartLine(5) linkTable := dic.LinkTable().AppendEmpty() linkTable.SetTraceID([16]byte{0x03, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) linkTable.SetSpanID([8]byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) sc := profiles.ResourceProfiles().At(0).ScopeProfiles().At(0) profilesCount := profiles.ResourceProfiles().At(0).ScopeProfiles().At(0).Profiles().Len() for i := range profilesCount { if i%2 == 0 { profile := sc.Profiles().At(i) profile.AttributeIndices().FromRaw([]int32{1}) } } return profiles } func generateProfilesWithEntityRefs() pprofile.Profiles { pd := pprofile.NewProfiles() rp := pd.ResourceProfiles().AppendEmpty() setupResourceWithEntityRefs(rp.Resource()) sp := rp.ScopeProfiles().AppendEmpty() sp.Scope().SetName("test-scope") profile := sp.Profiles().AppendEmpty() sample := profile.Samples().AppendEmpty() sample.Values().Append(100) dic := pd.Dictionary() dic.StringTable().Append("") dic.StringTable().Append("cpu") dic.StringTable().Append("nanoseconds") sampleType := profile.SampleType() sampleType.SetTypeStrindex(1) sampleType.SetUnitStrindex(2) return pd } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/sync.go000066400000000000000000000012101511331344600302610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "context" "errors" "os" "go.uber.org/zap" ) func LoggerSync(logger *zap.Logger) func(context.Context) error { return func(context.Context) error { // Currently Sync() return a different error depending on the OS. // Since these are not actionable ignore them. err := logger.Sync() osErr := &os.PathError{} if errors.As(err, &osErr) { wrappedErr := osErr.Unwrap() if knownSyncError(wrappedErr) { err = nil } } return err } } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/test_helpers.go000066400000000000000000000021031511331344600320100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/xpdata/entity" ) func addEntityRefsToResource(resource pcommon.Resource) { entityRefs := entity.ResourceEntityRefs(resource) serviceRef := entityRefs.AppendEmpty() serviceRef.SetType("service") serviceRef.SetSchemaUrl("https://opentelemetry.io/schemas/1.21.0") serviceRef.IdKeys().Append("service.name") serviceRef.DescriptionKeys().Append("service.version") if _, exists := resource.Attributes().Get("host.name"); exists { hostRef := entityRefs.AppendEmpty() hostRef.SetType("host") hostRef.IdKeys().Append("host.name") } } func setupResourceWithEntityRefs(resource pcommon.Resource) { resource.Attributes().PutStr("service.name", "my-service") resource.Attributes().PutStr("service.version", "1.0.0") resource.Attributes().PutStr("host.name", "server-01") addEntityRefsToResource(resource) } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/000077500000000000000000000000001511331344600305755ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/logs/000077500000000000000000000000001511331344600315415ustar00rootroot00000000000000embedded_maps.out000066400000000000000000000007211511331344600347640ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/logsResourceLog #0 Resource SchemaURL: ScopeLogs #0 ScopeLogs SchemaURL: InstrumentationScope LogRecord #0 ObservedTimestamp: 1970-01-01 00:00:00 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC SeverityText: INFO SeverityNumber: Info(9) Body: Map({"key1":"val1","key2":{"key21":"val21","key22":"val22"}}) Attributes: -> key1: Map({"key11":"val11","key12":"val12","key13":{"key131":"val131"}}) -> key2: Str(val2) Trace ID: Span ID: Flags: 0 opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/logs/empty.out000066400000000000000000000000001511331344600334160ustar00rootroot00000000000000log_with_event_name.out000066400000000000000000000007011511331344600362260ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/logsResourceLog #0 Resource SchemaURL: ScopeLogs #0 ScopeLogs SchemaURL: InstrumentationScope LogRecord #0 ObservedTimestamp: 1970-01-01 00:00:00 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC SeverityText: Info SeverityNumber: Info(9) EventName: event_name Body: Str(This is a log message) Attributes: -> app: Str(server) -> instance_num: Int(1) Trace ID: 08040201000000000000000000000000 Span ID: 0102040800000000 Flags: 0 logs_with_entity_refs.out000066400000000000000000000015351511331344600366310ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/logsResourceLog #0 Resource SchemaURL: Resource attributes: -> service.name: Str(my-service) -> service.version: Str(1.0.0) -> host.name: Str(server-01) Resource entity refs: -> Entity ref #0: -> Type: service -> Schema URL: https://opentelemetry.io/schemas/1.21.0 -> ID keys: -> service.name -> Description keys: -> service.version -> Entity ref #1: -> Type: host -> ID keys: -> host.name ScopeLogs #0 ScopeLogs SchemaURL: InstrumentationScope test-scope LogRecord #0 ObservedTimestamp: 1970-01-01 00:00:00 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC SeverityText: Info SeverityNumber: Info(9) Body: Str(This is a test log message) Attributes: -> test.attribute: Str(test-value) Trace ID: Span ID: Flags: 0 one_record.out000066400000000000000000000007601511331344600343350ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/logsResourceLog #0 Resource SchemaURL: Resource attributes: -> resource-attr: Str(resource-attr-val-1) ScopeLogs #0 ScopeLogs SchemaURL: InstrumentationScope LogRecord #0 ObservedTimestamp: 1970-01-01 00:00:00 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC SeverityText: Info SeverityNumber: Info(9) Body: Str(This is a log message) Attributes: -> app: Str(server) -> instance_num: Int(1) Trace ID: 08040201000000000000000000000000 Span ID: 0102040800000000 Flags: 0 two_records.out000066400000000000000000000014061511331344600345460ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/logsResourceLog #0 Resource SchemaURL: Resource attributes: -> resource-attr: Str(resource-attr-val-1) ScopeLogs #0 ScopeLogs SchemaURL: InstrumentationScope LogRecord #0 ObservedTimestamp: 1970-01-01 00:00:00 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC SeverityText: Info SeverityNumber: Info(9) Body: Str(This is a log message) Attributes: -> app: Str(server) -> instance_num: Int(1) Trace ID: 08040201000000000000000000000000 Span ID: 0102040800000000 Flags: 0 LogRecord #1 ObservedTimestamp: 1970-01-01 00:00:00 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC SeverityText: Info SeverityNumber: Info(9) Body: Str(something happened) Attributes: -> customer: Str(acme) -> env: Str(dev) Trace ID: Span ID: Flags: 0 opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/metrics/000077500000000000000000000000001511331344600322435ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/metrics/empty.out000066400000000000000000000000001511331344600341200ustar00rootroot00000000000000invalid_metric_type.out000066400000000000000000000004271511331344600367520ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/metricsResourceMetrics #0 Resource SchemaURL: Resource attributes: -> resource-attr: Str(resource-attr-val-1) ScopeMetrics #0 ScopeMetrics SchemaURL: InstrumentationScope Metric #0 Descriptor: -> Name: sum-int -> Description: -> Unit: 1 -> DataType: Empty metrics_with_all_types.out000066400000000000000000000123371511331344600375000ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/metricsResourceMetrics #0 Resource SchemaURL: Resource attributes: -> resource-attr: Str(resource-attr-val-1) ScopeMetrics #0 ScopeMetrics SchemaURL: InstrumentationScope Metric #0 Descriptor: -> Name: gauge-int -> Description: -> Unit: 1 -> DataType: Gauge NumberDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 123 NumberDataPoints #1 Data point attributes: -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 456 Metric #1 Descriptor: -> Name: gauge-double -> Description: -> Unit: 1 -> DataType: Gauge NumberDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 1.230000 NumberDataPoints #1 Data point attributes: -> label-1: Str(label-value-1) -> label-3: Str(label-value-3) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 4.560000 Metric #2 Descriptor: -> Name: sum-int -> Description: -> Unit: 1 -> DataType: Sum -> IsMonotonic: true -> AggregationTemporality: Cumulative NumberDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 123 NumberDataPoints #1 Data point attributes: -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 456 Metric #3 Descriptor: -> Name: sum-double -> Description: -> Unit: 1 -> DataType: Sum -> IsMonotonic: true -> AggregationTemporality: Cumulative NumberDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 1.230000 NumberDataPoints #1 Data point attributes: -> label-1: Str(label-value-1) -> label-3: Str(label-value-3) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 4.560000 Metric #4 Descriptor: -> Name: histogram -> Description: -> Unit: 1 -> DataType: Histogram -> AggregationTemporality: Cumulative HistogramDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) -> label-3: Str(label-value-3) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Count: 1 Sum: 15.000000 HistogramDataPoints #1 Data point attributes: -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Count: 1 Sum: 15.000000 Min: 15.000000 Max: 15.000000 ExplicitBounds #0: 1.000000 Buckets #0, Count: 0 Buckets #1, Count: 1 Exemplars: Exemplar #0 -> Trace ID: 0102030405060708090a0b0c0d0e0f10 -> Span ID: 1112131415161718 -> Timestamp: 2020-02-11 20:26:13.000000123 +0000 UTC -> Value: 15.000000 -> FilteredAttributes: -> exemplar-attachment: Str(exemplar-attachment-value) Metric #5 Descriptor: -> Name: exponential-histogram -> Description: -> Unit: 1 -> DataType: ExponentialHistogram -> AggregationTemporality: Delta ExponentialHistogramDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) -> label-3: Str(label-value-3) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Count: 5 Sum: 0.150000 Bucket [-1.414214, -1.000000), Count: 1 Bucket [-1.000000, -0.707107), Count: 1 Bucket [0, 0], Count: 1 Bucket (1.414214, 2.000000], Count: 1 Bucket (2.000000, 2.828427], Count: 1 ExponentialHistogramDataPoints #1 Data point attributes: -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Count: 3 Sum: 1.250000 Min: 0.000000 Max: 1.000000 Bucket [0, 0], Count: 1 Bucket (0.250000, 1.000000], Count: 1 Bucket (1.000000, 4.000000], Count: 1 Exemplars: Exemplar #0 -> Trace ID: 0102030405060708090a0b0c0d0e0f10 -> Span ID: 1112131415161718 -> Timestamp: 2020-02-11 20:26:13.000000123 +0000 UTC -> Value: 15 -> FilteredAttributes: -> exemplar-attachment: Str(exemplar-attachment-value) Metric #6 Descriptor: -> Name: summary -> Description: -> Unit: 1 -> DataType: Summary SummaryDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) -> label-3: Str(label-value-3) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Count: 1 Sum: 15.000000 SummaryDataPoints #1 Data point attributes: -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Count: 1 Sum: 15.000000 QuantileValue #0: Quantile 0.010000, Value 15.000000 metrics_with_entity_refs.out000066400000000000000000000016121511331344600400310ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/metricsResourceMetrics #0 Resource SchemaURL: Resource attributes: -> service.name: Str(my-service) -> service.version: Str(1.0.0) -> host.name: Str(server-01) Resource entity refs: -> Entity ref #0: -> Type: service -> Schema URL: https://opentelemetry.io/schemas/1.21.0 -> ID keys: -> service.name -> Description keys: -> service.version -> Entity ref #1: -> Type: host -> ID keys: -> host.name ScopeMetrics #0 ScopeMetrics SchemaURL: InstrumentationScope test-scope Metric #0 Descriptor: -> Name: test-metric -> Description: A test metric -> Unit: 1 -> DataType: Gauge NumberDataPoints #0 Data point attributes: -> test.attribute: Str(test-value) StartTimestamp: 1970-01-01 00:00:00 +0000 UTC Timestamp: 1970-01-01 00:00:00 +0000 UTC Value: 123.450000 two_metrics.out000066400000000000000000000023561511331344600352620ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/metricsResourceMetrics #0 Resource SchemaURL: Resource attributes: -> resource-attr: Str(resource-attr-val-1) ScopeMetrics #0 ScopeMetrics SchemaURL: InstrumentationScope Metric #0 Descriptor: -> Name: gauge-int -> Description: -> Unit: 1 -> DataType: Gauge NumberDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 123 NumberDataPoints #1 Data point attributes: -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 456 Metric #1 Descriptor: -> Name: gauge-double -> Description: -> Unit: 1 -> DataType: Gauge NumberDataPoints #0 Data point attributes: -> label-1: Str(label-value-1) -> label-2: Str(label-value-2) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 1.230000 NumberDataPoints #1 Data point attributes: -> label-1: Str(label-value-1) -> label-3: Str(label-value-3) StartTimestamp: 2020-02-11 20:26:12.000000321 +0000 UTC Timestamp: 2020-02-11 20:26:13.000000789 +0000 UTC Value: 4.560000 opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/profiles/000077500000000000000000000000001511331344600324205ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/profiles/empty.out000066400000000000000000000000001511331344600342750ustar00rootroot00000000000000profiles_with_entity_refs.out000066400000000000000000000014601511331344600403640ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/profilesString table: cpu nanoseconds ResourceProfiles #0 Resource SchemaURL: Resource attributes: -> service.name: Str(my-service) -> service.version: Str(1.0.0) -> host.name: Str(server-01) Resource entity refs: -> Entity ref #0: -> Type: service -> Schema URL: https://opentelemetry.io/schemas/1.21.0 -> ID keys: -> service.name -> Description keys: -> service.version -> Entity ref #1: -> Type: host -> ID keys: -> host.name ScopeProfiles #0 ScopeProfiles SchemaURL: InstrumentationScope test-scope Profile #0 Profile ID : Start time : 1970-01-01 00:00:00 +0000 UTC DurationNano : 0 Dropped attributes count: 0 Sample #0 Values: [100] two_profiles.out000066400000000000000000000026111511331344600356060ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/profilesMapping #0 Memory start: 2 Memory limit: 3 File offset: 4 File name: 5 Attributes: [7 8] Location #0 Mapping index: 0 Address: 1 Attributes: [] Location #1 Mapping index: 0 Address: 2 Attributes: [] Location #2 Mapping index: 3 Address: 4 Line #0 Function index: 1 Line: 2 Column: 3 Attributes: [6 7] Function #0 Name: 2 System name: 3 Filename: 4 Start line: 5 Attribute table: -> Key: Int(2) -> Value: Str() -> unit: Int(5) Link table: -> Trace ID: Str(0302030405060708090a0b0c0d0e0f10) -> Span ID: Str(1112131415161718) String table: key intValue foobar ResourceProfiles #0 Resource SchemaURL: Resource attributes: -> resource-attr: Str(resource-attr-val-1) ScopeProfiles #0 ScopeProfiles SchemaURL: InstrumentationScope Profile #0 Profile ID : 0102030405060708090a0b0c0d0e0f10 Start time : 2020-02-11 20:26:12.000000321 +0000 UTC DurationNano : 1000000000 Dropped attributes count: 1 Sample #0 Values: [4] Attributes: -> key: value Profile #1 Profile ID : 0202030405060708090a0b0c0d0e0f10 Start time : 2020-02-11 20:26:12.000000321 +0000 UTC DurationNano : 1000000000 Dropped attributes count: 0 Sample #0 Values: [9] Attributes: -> key: value opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/traces/000077500000000000000000000000001511331344600320565ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/traces/empty.out000066400000000000000000000000001511331344600337330ustar00rootroot00000000000000traces_with_entity_refs.out000066400000000000000000000016361511331344600374650ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/tracesResourceSpans #0 Resource SchemaURL: Resource attributes: -> service.name: Str(my-service) -> service.version: Str(1.0.0) -> host.name: Str(server-01) Resource entity refs: -> Entity ref #0: -> Type: service -> Schema URL: https://opentelemetry.io/schemas/1.21.0 -> ID keys: -> service.name -> Description keys: -> service.version -> Entity ref #1: -> Type: host -> ID keys: -> host.name ScopeSpans #0 ScopeSpans SchemaURL: InstrumentationScope test-scope Span #0 Trace ID : 0102030405060708090a0b0c0d0e0f10 Parent ID : ID : 0102030405060708 Name : test-span Kind : Unspecified Start time : 1970-01-01 00:00:00 +0000 UTC End time : 1970-01-01 00:00:00 +0000 UTC Status code : Unset Status message : two_spans.out000066400000000000000000000027411511331344600345510ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/testdata/tracesResourceSpans #0 Resource SchemaURL: Resource attributes: -> resource-attr: Str(resource-attr-val-1) ScopeSpans #0 ScopeSpans SchemaURL: InstrumentationScope Span #0 Trace ID : 0102030405060708090a0b0c0d0e0f10 Parent ID : ID : 1112131415161718 Name : operationA Kind : Unspecified TraceState : ot=th:0 Start time : 2020-02-11 20:26:12.000000321 +0000 UTC End time : 2020-02-11 20:26:13.000000789 +0000 UTC Status code : Error Status message : status-cancelled Events: SpanEvent #0 -> Name: event-with-attr -> Timestamp: 2020-02-11 20:26:13.000000123 +0000 UTC -> DroppedAttributesCount: 2 -> Attributes:: -> span-event-attr: Str(span-event-attr-val) SpanEvent #1 -> Name: event -> Timestamp: 2020-02-11 20:26:13.000000123 +0000 UTC -> DroppedAttributesCount: 2 Span #1 Trace ID : Parent ID : ID : Name : operationB Kind : Unspecified Start time : 2020-02-11 20:26:12.000000321 +0000 UTC End time : 2020-02-11 20:26:13.000000789 +0000 UTC Status code : Unset Status message : Links: SpanLink #0 -> Trace ID: -> ID: -> TraceState: -> DroppedAttributesCount: 4 -> Attributes:: -> span-link-attr: Str(span-link-attr-val) SpanLink #1 -> Trace ID: -> ID: -> TraceState: -> DroppedAttributesCount: 4 opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/traces.go000066400000000000000000000036211511331344600305760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext // import "go.opentelemetry.io/collector/exporter/debugexporter/internal/otlptext" import ( "go.opentelemetry.io/collector/pdata/ptrace" ) // NewTextTracesMarshaler returns a ptrace.Marshaler to encode to OTLP text bytes. func NewTextTracesMarshaler() ptrace.Marshaler { return textTracesMarshaler{} } type textTracesMarshaler struct{} // MarshalTraces ptrace.Traces to OTLP text. func (textTracesMarshaler) MarshalTraces(td ptrace.Traces) ([]byte, error) { buf := dataBuffer{} rss := td.ResourceSpans() for i := 0; i < rss.Len(); i++ { buf.logEntry("ResourceSpans #%d", i) rs := rss.At(i) buf.logEntry("Resource SchemaURL: %s", rs.SchemaUrl()) buf.logAttributes("Resource attributes", rs.Resource().Attributes()) buf.logEntityRefs(rs.Resource()) ilss := rs.ScopeSpans() for j := 0; j < ilss.Len(); j++ { buf.logEntry("ScopeSpans #%d", j) ils := ilss.At(j) buf.logEntry("ScopeSpans SchemaURL: %s", ils.SchemaUrl()) buf.logInstrumentationScope(ils.Scope()) spans := ils.Spans() for k := 0; k < spans.Len(); k++ { buf.logEntry("Span #%d", k) span := spans.At(k) buf.logAttr("Trace ID", span.TraceID()) buf.logAttr("Parent ID", span.ParentSpanID()) buf.logAttr("ID", span.SpanID()) buf.logAttr("Name", span.Name()) buf.logAttr("Kind", span.Kind().String()) if ts := span.TraceState().AsRaw(); ts != "" { buf.logAttr("TraceState", ts) } buf.logAttr("Start time", span.StartTimestamp().String()) buf.logAttr("End time", span.EndTimestamp().String()) buf.logAttr("Status code", span.Status().Code().String()) buf.logAttr("Status message", span.Status().Message()) buf.logAttributes("Attributes", span.Attributes()) buf.logEvents("Events", span.Events()) buf.logLinks("Links", span.Links()) } } } return buf.buf.Bytes(), nil } opentelemetry-collector-0.141.0/exporter/debugexporter/internal/otlptext/traces_test.go000066400000000000000000000031161511331344600316340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlptext import ( "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) func TestTracesText(t *testing.T) { tests := []struct { name string in ptrace.Traces out string }{ { name: "empty_traces", in: ptrace.NewTraces(), out: "empty.out", }, { name: "two_spans", in: testdata.GenerateTraces(2), out: "two_spans.out", }, { name: "traces_with_entity_refs", in: generateTracesWithEntityRefs(), out: "traces_with_entity_refs.out", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got, err := NewTextTracesMarshaler().MarshalTraces(tt.in) require.NoError(t, err) out, err := os.ReadFile(filepath.Join("testdata", "traces", tt.out)) require.NoError(t, err) expected := strings.ReplaceAll(string(out), "\r", "") assert.Equal(t, expected, string(got)) }) } } func generateTracesWithEntityRefs() ptrace.Traces { td := ptrace.NewTraces() rs := td.ResourceSpans().AppendEmpty() setupResourceWithEntityRefs(rs.Resource()) ss := rs.ScopeSpans().AppendEmpty() ss.Scope().SetName("test-scope") span := ss.Spans().AppendEmpty() span.SetName("test-span") span.SetSpanID([8]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}) span.SetTraceID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) return td } opentelemetry-collector-0.141.0/exporter/debugexporter/metadata.yaml000066400000000000000000000005051511331344600257310ustar00rootroot00000000000000type: debug github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true codeowners: active: - andrzej-stencel class: exporter stability: alpha: [traces, metrics, logs] development: [profiles] distributions: [core, contrib, k8s] warnings: [Unstable Output Format] opentelemetry-collector-0.141.0/exporter/debugexporter/testdata/000077500000000000000000000000001511331344600250765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/debugexporter/testdata/config_verbosity.yaml000066400000000000000000000001341511331344600313330ustar00rootroot00000000000000verbosity: detailed sampling_initial: 10 sampling_thereafter: 50 use_internal_logger: false opentelemetry-collector-0.141.0/exporter/debugexporter/testdata/config_verbosity_typo.yaml000066400000000000000000000001351511331344600324070ustar00rootroot00000000000000# Typo in the configuration that assumes that this property is camelcase verBosity: detailed opentelemetry-collector-0.141.0/exporter/example_test.go000066400000000000000000000062331511331344600234330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporter_test import ( "context" "fmt" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/pdata/pmetric" ) // typeStr defines the unique type identifier for the exporter. var typeStr = component.MustNewType("example") // exampleConfig holds configuration settings for the exporter. type exampleConfig struct { QueueSettings exporterhelper.QueueBatchConfig BackOffConfig configretry.BackOffConfig } // exampleExporter implements the OpenTelemetry exporter interface. type exampleExporter struct { cancel context.CancelFunc config exampleConfig client *loggerClient } // loggerClient wraps a Zap logger to provide logging functionality. type loggerClient struct { logger *zap.Logger } // Example demonstrates the usage of the exporter factory. func Example() { // Instantiate the exporter factory and print its type. exampleExporter := NewFactory() fmt.Println(exampleExporter.Type()) // Output: // example } // NewFactory creates a new exporter factory. func NewFactory() exporter.Factory { return exporter.NewFactory( typeStr, createDefaultConfig, exporter.WithMetrics(createExampleExporter, component.StabilityLevelAlpha), ) } // createDefaultConfig returns the default configuration for the exporter. func createDefaultConfig() component.Config { return &exampleConfig{} } // createExampleExporter initializes an instance of the example exporter. func createExampleExporter(ctx context.Context, params exporter.Settings, baseCfg component.Config) (exporter.Metrics, error) { // Convert baseCfg to the correct type. cfg := baseCfg.(*exampleConfig) // Create a new exporter instance. xptr := newExampleExporter(ctx, cfg, params) // Wrap the exporter with the helper utilities. return exporterhelper.NewMetrics( ctx, params, cfg, xptr.consumeMetrics, exporterhelper.WithQueue(cfg.QueueSettings), exporterhelper.WithRetry(cfg.BackOffConfig), exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithShutdown(xptr.shutdown), ) } // newExampleExporter constructs a new instance of the example exporter. func newExampleExporter(ctx context.Context, cfg *exampleConfig, params exporter.Settings) *exampleExporter { xptr := &exampleExporter{ config: *cfg, client: &loggerClient{logger: params.Logger}, } // Create a cancelable context. _, xptr.cancel = context.WithCancel(ctx) return xptr } // consumeMetrics processes incoming metric data and logs it. func (xptr *exampleExporter) consumeMetrics(_ context.Context, md pmetric.Metrics) error { xptr.client.Push(md) return nil } // Shutdown properly stops the exporter and releases resources. func (xptr *exampleExporter) shutdown(_ context.Context) error { xptr.cancel() return nil } // Push logs the received metric data. func (client *loggerClient) Push(md pmetric.Metrics) { client.logger.Info("Exporting metrics", zap.Any("metrics", md)) } opentelemetry-collector-0.141.0/exporter/exporter.go000066400000000000000000000142511511331344600226100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporter // import "go.opentelemetry.io/collector/exporter" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter/internal/experr" "go.opentelemetry.io/collector/pipeline" ) // Traces is an exporter that can consume traces. type Traces interface { component.Component consumer.Traces } // Metrics is an exporter that can consume metrics. type Metrics interface { component.Component consumer.Metrics } // Logs is an exporter that can consume logs. type Logs interface { component.Component consumer.Logs } // Settings configures exporter creators. type Settings struct { // ID returns the ID of the component that will be created. ID component.ID component.TelemetrySettings // BuildInfo can be used by components for informational purposes BuildInfo component.BuildInfo // prevent unkeyed literal initialization _ struct{} } // Factory is factory interface for exporters. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. type Factory interface { component.Factory // CreateTraces creates a Traces exporter based on this config. // If the exporter type does not support tracing, // this function returns the error [pipeline.ErrSignalNotSupported]. CreateTraces(ctx context.Context, set Settings, cfg component.Config) (Traces, error) // TracesStability gets the stability level of the Traces exporter. TracesStability() component.StabilityLevel // CreateMetrics creates a Metrics exporter based on this config. // If the exporter type does not support metrics, // this function returns the error [pipeline.ErrSignalNotSupported]. CreateMetrics(ctx context.Context, set Settings, cfg component.Config) (Metrics, error) // MetricsStability gets the stability level of the Metrics exporter. MetricsStability() component.StabilityLevel // CreateLogs creates a Logs exporter based on the config. // If the exporter type does not support logs, // this function returns the error [pipeline.ErrSignalNotSupported]. CreateLogs(ctx context.Context, set Settings, cfg component.Config) (Logs, error) // LogsStability gets the stability level of the Logs exporter. LogsStability() component.StabilityLevel unexportedFactoryFunc() } // FactoryOption apply changes to Factory. type FactoryOption interface { // applyOption applies the option. applyOption(o *factory) } var _ FactoryOption = (*factoryOptionFunc)(nil) // factoryOptionFunc is an FactoryOption created through a function. type factoryOptionFunc func(*factory) func (f factoryOptionFunc) applyOption(o *factory) { f(o) } // CreateTracesFunc is the equivalent of Factory.CreateTraces. type CreateTracesFunc func(context.Context, Settings, component.Config) (Traces, error) // CreateMetricsFunc is the equivalent of Factory.CreateMetrics. type CreateMetricsFunc func(context.Context, Settings, component.Config) (Metrics, error) // CreateLogsFunc is the equivalent of Factory.CreateLogs. type CreateLogsFunc func(context.Context, Settings, component.Config) (Logs, error) type factory struct { cfgType component.Type component.CreateDefaultConfigFunc createTracesFunc CreateTracesFunc tracesStabilityLevel component.StabilityLevel createMetricsFunc CreateMetricsFunc metricsStabilityLevel component.StabilityLevel createLogsFunc CreateLogsFunc logsStabilityLevel component.StabilityLevel } func (f *factory) Type() component.Type { return f.cfgType } func (f *factory) unexportedFactoryFunc() {} func (f *factory) TracesStability() component.StabilityLevel { return f.tracesStabilityLevel } func (f *factory) MetricsStability() component.StabilityLevel { return f.metricsStabilityLevel } func (f *factory) LogsStability() component.StabilityLevel { return f.logsStabilityLevel } func (f *factory) CreateTraces(ctx context.Context, set Settings, cfg component.Config) (Traces, error) { if f.createTracesFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, experr.ErrIDMismatch(set.ID, f.Type()) } return f.createTracesFunc(ctx, set, cfg) } func (f *factory) CreateMetrics(ctx context.Context, set Settings, cfg component.Config) (Metrics, error) { if f.createMetricsFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, experr.ErrIDMismatch(set.ID, f.Type()) } return f.createMetricsFunc(ctx, set, cfg) } func (f *factory) CreateLogs(ctx context.Context, set Settings, cfg component.Config) (Logs, error) { if f.createLogsFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, experr.ErrIDMismatch(set.ID, f.Type()) } return f.createLogsFunc(ctx, set, cfg) } // WithTraces overrides the default "error not supported" implementation for Factory.CreateTraces and the default "undefined" stability level. func WithTraces(createTraces CreateTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.tracesStabilityLevel = sl o.createTracesFunc = createTraces }) } // WithMetrics overrides the default "error not supported" implementation for Factory.CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.metricsStabilityLevel = sl o.createMetricsFunc = createMetrics }) } // WithLogs overrides the default "error not supported" implementation for Factory.CreateLogs and the default "undefined" stability level. func WithLogs(createLogs CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.logsStabilityLevel = sl o.createLogsFunc = createLogs }) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { f := &factory{ cfgType: cfgType, CreateDefaultConfigFunc: createDefaultConfig, } for _, opt := range options { opt.applyOption(f) } return f } opentelemetry-collector-0.141.0/exporter/exporter_test.go000066400000000000000000000061311511331344600236450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporter import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter/internal/experr" "go.opentelemetry.io/collector/pipeline" ) var ( testType = component.MustNewType("test") testID = component.NewID(testType) ) func TestNewFactory(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) _, err := f.CreateTraces(context.Background(), Settings{ID: testID}, &defaultCfg) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) _, err = f.CreateMetrics(context.Background(), Settings{ID: testID}, &defaultCfg) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) _, err = f.CreateLogs(context.Background(), Settings{ID: testID}, &defaultCfg) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) } func TestNewFactoryWithOptions(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }, WithTraces(createTraces, component.StabilityLevelDevelopment), WithMetrics(createMetrics, component.StabilityLevelAlpha), WithLogs(createLogs, component.StabilityLevelDeprecated)) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) wrongID := component.MustNewID("wrong") wrongIDErrStr := experr.ErrIDMismatch(wrongID, testType).Error() assert.Equal(t, component.StabilityLevelDevelopment, f.TracesStability()) _, err := f.CreateTraces(context.Background(), Settings{ID: testID}, &defaultCfg) require.NoError(t, err) _, err = f.CreateTraces(context.Background(), Settings{ID: wrongID}, &defaultCfg) require.EqualError(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelAlpha, f.MetricsStability()) _, err = f.CreateMetrics(context.Background(), Settings{ID: testID}, &defaultCfg) require.NoError(t, err) _, err = f.CreateMetrics(context.Background(), Settings{ID: wrongID}, &defaultCfg) require.EqualError(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelDeprecated, f.LogsStability()) _, err = f.CreateLogs(context.Background(), Settings{ID: testID}, &defaultCfg) require.NoError(t, err) _, err = f.CreateLogs(context.Background(), Settings{ID: wrongID}, &defaultCfg) require.EqualError(t, err, wrongIDErrStr) } var nopInstance = &nop{ Consumer: consumertest.NewNop(), } // nop stores consumed traces and metrics for testing purposes. type nop struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createTraces(context.Context, Settings, component.Config) (Traces, error) { return nopInstance, nil } func createMetrics(context.Context, Settings, component.Config) (Metrics, error) { return nopInstance, nil } func createLogs(context.Context, Settings, component.Config) (Logs, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/exporter/exporterhelper/000077500000000000000000000000001511331344600234565ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/Makefile000066400000000000000000000000361511331344600251150ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/exporter/exporterhelper/README.md000066400000000000000000000212201511331344600247320ustar00rootroot00000000000000# Exporter Helper This package provides reusable implementations of common capabilities for exporters. Currently, this includes queuing, batching, timeouts, and retries. ## Configuration The following configuration options can be modified: ### Retry on Failure - `retry_on_failure` - `enabled` (default = true) - `initial_interval` (default = 5s): Time to wait after the first failure before retrying; ignored if `enabled` is `false` - `max_interval` (default = 30s): Is the upper bound on backoff; ignored if `enabled` is `false` - `max_elapsed_time` (default = 300s): Is the maximum amount of time spent trying to send a batch; ignored if `enabled` is `false`. If set to 0, the retries are never stopped. - `multiplier` (default = 1.5): Factor by which the retry interval is multiplied on each attempt; ignored if `enabled` is `false` ### Sending Queue - `sending_queue` - `enabled` (default = true) - `num_consumers` (default = 10): Number of consumers that dequeue batches; ignored if `enabled` is `false` - `wait_for_result` (default = false): determines if incoming requests are blocked until the request is processed or not. - `block_on_overflow` (default = false): If true, blocks the request until the queue has space otherwise rejects the data immediately; ignored if `enabled` is `false` - `sizer` (default = requests): How the queue and batching is measured. Available options: - `requests`: number of incoming batches of metrics, logs, traces (the most performant option); - `items`: number of the smallest parts of each signal (spans, metric data points, log records); - `bytes`: the size of serialized data in bytes (the least performant option). - `queue_size` (default = 1000): Maximum size the queue can accept. Measured in units defined by `sizer` - `batch`: see below. #### Sending queue batch settings Batch settings are available in the sending queue. Batching is disabled, by default. To enable default batch settings, use `batch: {}`. When `batch` is defined, the settings are: - `flush_timeout` (default = 200 ms): time after which a batch will be sent regardless of its size. Must be a non-zero value; - `min_size` (default = 8192): the minimum size of a batch; should be less than or equal to the `sending_queue::queue_size` if `sending_queue::batch::sizer` matches `sending_queue::sizer`. - `max_size` (default = 0): the maximum size of a batch, enables batch splitting. The maximum size of a batch should be greater than or equal to the minimum size of a batch. If set to zero, there is no maximum size; - `sizer`: see below. The `batch::sizer` field is given special treatment because the queue itself also defines a `sizer`. This field supports using different size limits for the queue and batch-related logic. If the `batch::sizer` field is not set, it takes its value from the parent structure. If `sending_queue::sizer` is not set, `batch::sizer` defaults to `items`. Available `batch::sizer` options: - `items`: number of the smallest parts of each signal (spans, metric data points, log records); - `bytes`: the size of serialized data in bytes (the least performant option). ### Timeout - `timeout` (default = 5s): Time to wait per individual attempt to send data to a backend The `initial_interval`, `max_interval`, `max_elapsed_time`, and `timeout` options accept [duration strings](https://pkg.go.dev/time#ParseDuration), valid time units are "ns", "us" (or "ยตs"), "ms", "s", "m", "h". ### Persistent Queue To use the persistent queue, the following setting needs to be set: - `sending_queue` - `storage` (default = none): When set, enables persistence and uses the component specified as a storage extension for the persistent queue. There is no in-memory queue when set. The maximum number of batches stored to disk can be controlled using `sending_queue.queue_size` parameter (which, similarly as for in-memory buffering, defaults to 1000 batches). When persistent queue is enabled, the batches are being buffered using the provided storage extension - [filestorage] is a popular and safe choice. If the collector instance is killed while having some items in the persistent queue, on restart the items will be picked and the exporting is continued. **Context Propagation**: Request context (including client metadata and span context) is preserved when using persistent queues. However, context set by Auth extensions is **not** propagated through the persistent queue. Auth extension context is ignored when data is persisted to disk, which means authentication/authorization information will not be available when the persisted data is processed. ``` โ”Œโ”€Consumer #1โ”€โ” โ”‚ โ”Œโ”€โ”€โ”€โ” โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€Deletedโ”€โ”€โ”€โ”€โ”€โ”€ โ”Œโ”€โ”€โ”€โ–บโ”‚ โ”‚ 1 โ”‚ โ”œโ”€โ”€โ”€โ–บ Success Waiting in channel x x x โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”˜ โ”‚ for consumer โ”€โ”€โ”€โ” x x x โ”‚ โ”‚ โ”‚ โ”‚ x x x โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ผ x x x โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€xโ”€โ”€โ”€โ”€โ”€xโ”€โ”€โ”€โ” โ”‚ โ”Œโ”€Consumer #2โ”€โ” โ”‚ x x x โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ” โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€xโ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€xโ”€โ” โ”Œโ”€xโ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ 2 โ”‚ โ”œโ”€โ”€โ”€โ–บ Permanent -> X โ”‚ n+1 โ”‚ n โ”‚ ... โ”‚ 6 โ”‚ โ”‚ 5 โ”‚ โ”‚ 4 โ”‚ โ”‚ 3 โ”‚ โ”‚ 2 โ”‚ โ”‚ 1 โ”‚ โ”œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ–บโ”‚ โ””โ”€โ”€โ”€โ”˜ โ”‚ failure โ”‚ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ฒ โ–ฒ โ–ฒ โ–ฒ โ”‚ โ”Œโ”€Consumer #3โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ 3 โ”‚ โ”œโ”€โ”€โ”€โ–บ (in progress) write read โ””โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜ โ”œโ”€โ”€โ”€โ–บโ”‚ โ””โ”€โ”€โ”€โ”˜ โ”‚ index index โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ currently โ”‚ โ”Œโ”€Consumer #4โ”€โ” dispatched โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ” โ”‚ Temporary โ””โ”€โ”€โ”€โ–บโ”‚ โ”‚ 4 โ”‚ โ”œโ”€โ”€โ”€โ–บ failure โ”‚ โ””โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ฒ โ”‚ โ””โ”€โ”€ Retry โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ โ”‚ X โ—„โ”€โ”€โ”€โ”€โ”€โ”€ Retry limit exceeded โ”€โ”€โ”€โ”˜ ``` Example: ``` receivers: otlp: protocols: grpc: exporters: otlp: endpoint: sending_queue: storage: file_storage/otc extensions: file_storage/otc: directory: /var/lib/storage/otc timeout: 10s service: extensions: [file_storage] pipelines: metrics: receivers: [otlp] exporters: [otlp] logs: receivers: [otlp] exporters: [otlp] traces: receivers: [otlp] exporters: [otlp] ``` [filestorage]: https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/storage/filestorage opentelemetry-collector-0.141.0/exporter/exporterhelper/common.go000066400000000000000000000032361511331344600253010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" ) // Option apply changes to BaseExporter. type Option = internal.Option // WithStart overrides the default Start function for an exporter. // The default start function does nothing and always returns nil. func WithStart(start component.StartFunc) Option { return internal.WithStart(start) } // WithShutdown overrides the default Shutdown function for an exporter. // The default shutdown function does nothing and always returns nil. func WithShutdown(shutdown component.ShutdownFunc) Option { return internal.WithShutdown(shutdown) } // WithTimeout overrides the default TimeoutConfig for an exporter. // The default TimeoutConfig is 5 seconds. func WithTimeout(timeoutConfig TimeoutConfig) Option { return internal.WithTimeout(timeoutConfig) } // WithRetry overrides the default configretry.BackOffConfig for an exporter. // The default configretry.BackOffConfig is to disable retries. func WithRetry(config configretry.BackOffConfig) Option { return internal.WithRetry(config) } // WithCapabilities overrides the default Capabilities() function for a Consumer. // The default is non-mutable data. // TODO: Verify if we can change the default to be mutable as we do for processors. func WithCapabilities(capabilities consumer.Capabilities) Option { return internal.WithCapabilities(capabilities) } opentelemetry-collector-0.141.0/exporter/exporterhelper/constants.go000066400000000000000000000013271511331344600260240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "errors" ) var ( // errNilConfig is returned when an empty name is given. errNilConfig = errors.New("nil config") // errNilLogger is returned when a logger is nil errNilLogger = errors.New("nil logger") // errNilPushTraces is returned when a nil PushTraces is given. errNilPushTraces = errors.New("nil PushTraces") // errNilPushMetrics is returned when a nil PushMetrics is given. errNilPushMetrics = errors.New("nil PushMetrics") // errNilPushLogs is returned when a nil PushLogs is given. errNilPushLogs = errors.New("nil PushLogs") ) opentelemetry-collector-0.141.0/exporter/exporterhelper/doc.go000066400000000000000000000004211511331344600245470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package exporterhelper provides helper functions for exporters. package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" opentelemetry-collector-0.141.0/exporter/exporterhelper/documentation.md000066400000000000000000000067701511331344600266630ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # exporterhelper ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_exporter_enqueue_failed_log_records Number of log records failed to be added to the sending queue. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Alpha | ### otelcol_exporter_enqueue_failed_metric_points Number of metric points failed to be added to the sending queue. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_exporter_enqueue_failed_spans Number of spans failed to be added to the sending queue. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Alpha | ### otelcol_exporter_queue_batch_send_size Number of units in the batch [Development] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | {units} | Histogram | Int | Development | ### otelcol_exporter_queue_batch_send_size_bytes Number of bytes in batch that was sent. Only available on detailed level. [Development] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | By | Histogram | Int | Development | ### otelcol_exporter_queue_capacity Fixed capacity of the retry queue (in batches). [Alpha] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | {batches} | Gauge | Int | Alpha | ### otelcol_exporter_queue_size Current size of the retry queue (in batches). [Alpha] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | {batches} | Gauge | Int | Alpha | ### otelcol_exporter_send_failed_log_records Number of log records in failed attempts to send to destination. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Alpha | ### otelcol_exporter_send_failed_metric_points Number of metric points in failed attempts to send to destination. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_exporter_send_failed_spans Number of spans in failed attempts to send to destination. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Alpha | ### otelcol_exporter_sent_log_records Number of log record successfully sent to destination. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Alpha | ### otelcol_exporter_sent_metric_points Number of metric points successfully sent to destination. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_exporter_sent_spans Number of spans successfully sent to destination. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Alpha | opentelemetry-collector-0.141.0/exporter/exporterhelper/generated_package_test.go000066400000000000000000000002551511331344600304570ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package exporterhelper import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/exporterhelper/go.mod000066400000000000000000000122031511331344600245620ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/exporterhelper go 1.24.0 require ( github.com/cenkalti/backoff/v5 v5.0.3 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/client v1.47.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/config/configretry v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/extension/extensiontest v0.141.0 go.opentelemetry.io/collector/extension/xextension v0.141.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pdata/xpdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.1 google.golang.org/protobuf v1.36.10 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/exporter/xexporter v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/receiver v1.47.0 // indirect go.opentelemetry.io/collector/receiver/receivertest v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/exporter/xexporter => ../xexporter replace go.opentelemetry.io/collector/exporter/exportertest => ../exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/exporter/exporterhelper/go.sum000066400000000000000000000210431511331344600246110ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/000077500000000000000000000000001511331344600252725ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/base_exporter.go000066400000000000000000000173131511331344600304700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import ( "context" "errors" "go.uber.org/multierr" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" "go.opentelemetry.io/collector/pipeline" ) // Option apply changes to BaseExporter. type Option func(*BaseExporter) error // BaseExporter contains common fields between different exporter types. type BaseExporter struct { component.StartFunc component.ShutdownFunc Set exporter.Settings // Message for the user to be added with an export failure message. ExportFailureMessage string // Chain of senders that the exporter helper applies before passing the data to the actual exporter. // The data is handled by each sender in the respective order starting from the QueueBatch. // Most of the senders are optional, and initialized with a no-op path-through sender. QueueSender sender.Sender[request.Request] RetrySender sender.Sender[request.Request] firstSender sender.Sender[request.Request] ConsumerOptions []consumer.Option timeoutCfg TimeoutConfig retryCfg configretry.BackOffConfig queueBatchSettings queuebatch.Settings[request.Request] queueCfg queuebatch.Config } func NewBaseExporter(set exporter.Settings, signal pipeline.Signal, pusher sender.SendFunc[request.Request], options ...Option) (*BaseExporter, error) { be := &BaseExporter{ Set: set, timeoutCfg: NewDefaultTimeoutConfig(), } for _, op := range options { if err := op(be); err != nil { return nil, err } } // Consumer Sender is always initialized. be.firstSender = sender.NewSender(pusher) // Next setup the timeout Sender since we want the timeout to control only the export functionality. // Only initialize if not explicitly disabled. if be.timeoutCfg.Timeout != 0 { be.firstSender = newTimeoutSender(be.timeoutCfg, be.firstSender) } if be.retryCfg.Enabled { be.RetrySender = newRetrySender(be.retryCfg, set, be.firstSender) be.firstSender = be.RetrySender } var err error be.firstSender, err = newObsReportSender(set, signal, be.firstSender) if err != nil { return nil, err } if be.queueCfg.Batch.HasValue() { // Batcher mutates the data. be.ConsumerOptions = append(be.ConsumerOptions, consumer.WithCapabilities(consumer.Capabilities{MutatesData: true})) } if be.queueCfg.Enabled { qSet := queuebatch.AllSettings[request.Request]{ Settings: be.queueBatchSettings, Signal: signal, ID: set.ID, Telemetry: set.TelemetrySettings, } be.QueueSender, err = NewQueueSender(qSet, be.queueCfg, be.ExportFailureMessage, be.firstSender) if err != nil { return nil, err } be.firstSender = be.QueueSender } return be, nil } // Send sends the request using the first sender in the chain. func (be *BaseExporter) Send(ctx context.Context, req request.Request) error { // Have to read the number of items before sending the request since the request can // be modified by the downstream components like the batcher. itemsCount := req.ItemsCount() err := be.firstSender.Send(ctx, req) if err != nil { be.Set.Logger.Error("Exporting failed. Rejecting data."+be.ExportFailureMessage, zap.Error(err), zap.Int("rejected_items", itemsCount)) } return err } func (be *BaseExporter) Start(ctx context.Context, host component.Host) error { // First start the wrapped exporter. if err := be.StartFunc.Start(ctx, host); err != nil { return err } // Last start the QueueBatch. if be.QueueSender != nil { return be.QueueSender.Start(ctx, host) } return nil } func (be *BaseExporter) Shutdown(ctx context.Context) error { var err error // First shutdown the retry sender, so the queue sender can flush the queue without retries. if be.RetrySender != nil { err = multierr.Append(err, be.RetrySender.Shutdown(ctx)) } // Then shutdown the queue sender. if be.QueueSender != nil { err = multierr.Append(err, be.QueueSender.Shutdown(ctx)) } // Last shutdown the wrapped exporter itself. return multierr.Append(err, be.ShutdownFunc.Shutdown(ctx)) } // WithStart overrides the default Start function for an exporter. // The default start function does nothing and always returns nil. func WithStart(start component.StartFunc) Option { return func(o *BaseExporter) error { o.StartFunc = start return nil } } // WithShutdown overrides the default Shutdown function for an exporter. // The default shutdown function does nothing and always returns nil. func WithShutdown(shutdown component.ShutdownFunc) Option { return func(o *BaseExporter) error { o.ShutdownFunc = shutdown return nil } } // WithTimeout overrides the default TimeoutConfig for an exporter. // The default TimeoutConfig is 5 seconds. func WithTimeout(timeoutConfig TimeoutConfig) Option { return func(o *BaseExporter) error { o.timeoutCfg = timeoutConfig return nil } } // WithRetry overrides the default configretry.BackOffConfig for an exporter. // The default configretry.BackOffConfig is to disable retries. func WithRetry(config configretry.BackOffConfig) Option { return func(o *BaseExporter) error { if !config.Enabled { o.ExportFailureMessage += " Try enabling retry_on_failure config option to retry on retryable errors." return nil } o.retryCfg = config return nil } } // WithQueue overrides the default queuebatch.Config for an exporter. // The default queuebatch.Config is to disable queueing. // This option cannot be used with the new exporter helpers New[Traces|Metrics|Logs]RequestExporter. func WithQueue(cfg queuebatch.Config) Option { return func(o *BaseExporter) error { if o.queueBatchSettings.Encoding == nil { return errors.New("WithQueue option is not available for the new request exporters, use WithQueueBatch instead") } return WithQueueBatch(cfg, o.queueBatchSettings)(o) } } // WithQueueBatch enables queueing for an exporter. // This option should be used with the new exporter helpers New[Traces|Metrics|Logs]RequestExporter. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func WithQueueBatch(cfg queuebatch.Config, set queuebatch.Settings[request.Request]) Option { return func(o *BaseExporter) error { if !cfg.Enabled { o.ExportFailureMessage += " Try enabling sending_queue to survive temporary failures." return nil } if cfg.StorageID != nil && set.Encoding == nil { return errors.New("`Settings.Encoding` must not be nil when persistent queue is enabled") } o.queueBatchSettings = set o.queueCfg = cfg return nil } } // WithCapabilities overrides the default Capabilities() function for a Consumer. // The default is non-mutable data. // TODO: Verify if we can change the default to be mutable as we do for processors. func WithCapabilities(capabilities consumer.Capabilities) Option { return func(o *BaseExporter) error { o.ConsumerOptions = append(o.ConsumerOptions, consumer.WithCapabilities(capabilities)) return nil } } // WithQueueBatchSettings is used to set the queuebatch.Settings for the new request based exporter helper. // It must be provided as the first option when creating a new exporter helper. func WithQueueBatchSettings(set queuebatch.Settings[request.Request]) Option { return func(o *BaseExporter) error { o.queueBatchSettings = set return nil } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/base_exporter_test.go000066400000000000000000000127451511331344600315330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pipeline" ) func TestBaseExporter(t *testing.T) { be, err := NewBaseExporter(exportertest.NewNopSettings(exportertest.NopType), pipeline.SignalMetrics, noopExport) require.NoError(t, err) require.NoError(t, be.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, be.Shutdown(context.Background())) } func TestBaseExporterWithOptions(t *testing.T) { want := errors.New("my error") be, err := NewBaseExporter( exportertest.NewNopSettings(exportertest.NopType), pipeline.SignalMetrics, noopExport, WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want }), WithTimeout(NewDefaultTimeoutConfig()), ) require.NoError(t, err) require.Equal(t, want, be.Start(context.Background(), componenttest.NewNopHost())) require.Equal(t, want, be.Shutdown(context.Background())) } func TestQueueOptionsWithRequestExporter(t *testing.T) { bs, err := NewBaseExporter(exportertest.NewNopSettings(exportertest.NopType), pipeline.SignalMetrics, noopExport, WithRetry(configretry.NewDefaultBackOffConfig())) require.NoError(t, err) require.Nil(t, bs.queueBatchSettings.Encoding) _, err = NewBaseExporter(exportertest.NewNopSettings(exportertest.NopType), pipeline.SignalMetrics, noopExport, WithRetry(configretry.NewDefaultBackOffConfig()), WithQueue(NewDefaultQueueConfig())) require.Error(t, err) qCfg := NewDefaultQueueConfig() storageID := component.NewID(component.MustNewType("test")) qCfg.StorageID = &storageID _, err = NewBaseExporter(exportertest.NewNopSettings(exportertest.NopType), pipeline.SignalMetrics, noopExport, WithQueueBatchSettings(newFakeQueueBatch()), WithRetry(configretry.NewDefaultBackOffConfig()), WithQueueBatch(qCfg, queuebatch.Settings[request.Request]{})) require.Error(t, err) } func TestBaseExporterLogging(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) rCfg := configretry.NewDefaultBackOffConfig() rCfg.Enabled = false qCfg := NewDefaultQueueConfig() qCfg.WaitForResult = true bs, err := NewBaseExporter(set, pipeline.SignalMetrics, errExport, WithQueueBatchSettings(newFakeQueueBatch()), WithQueue(qCfg), WithRetry(rCfg)) require.NoError(t, err) require.NoError(t, bs.Start(context.Background(), componenttest.NewNopHost())) sendErr := bs.Send(context.Background(), &requesttest.FakeRequest{Items: 2}) require.Error(t, sendErr) errorLogs := observed.FilterLevelExact(zap.ErrorLevel).All() require.Len(t, errorLogs, 2) assert.Contains(t, errorLogs[0].Message, "Exporting failed. Dropping data.") assert.Equal(t, "my error", errorLogs[0].ContextMap()["error"]) assert.Contains(t, errorLogs[1].Message, "Exporting failed. Rejecting data.") assert.Equal(t, "my error", errorLogs[1].ContextMap()["error"]) require.NoError(t, bs.Shutdown(context.Background())) } func TestQueueRetryWithDisabledQueue(t *testing.T) { tests := []struct { name string queueOptions []Option }{ { name: "WithQueue", queueOptions: []Option{ WithQueueBatchSettings(newFakeQueueBatch()), func() Option { qs := NewDefaultQueueConfig() qs.Enabled = false return WithQueue(qs) }(), }, }, { name: "WithRequestQueue", queueOptions: []Option{ func() Option { qs := NewDefaultQueueConfig() qs.Enabled = false return WithQueueBatch(qs, newFakeQueueBatch()) }(), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) logger, observed := observer.New(zap.ErrorLevel) set.Logger = zap.New(logger) be, err := NewBaseExporter(set, pipeline.SignalLogs, errExport, tt.queueOptions...) require.NoError(t, err) require.NoError(t, be.Start(context.Background(), componenttest.NewNopHost())) mockR := &requesttest.FakeRequest{Items: 2} require.Error(t, be.Send(context.Background(), mockR)) assert.Len(t, observed.All(), 1) assert.Equal(t, "Exporting failed. Rejecting data. Try enabling sending_queue to survive temporary failures.", observed.All()[0].Message) require.NoError(t, be.Shutdown(context.Background())) }) } } func errExport(context.Context, request.Request) error { return errors.New("my error") } func noopExport(context.Context, request.Request) error { return nil } func newFakeQueueBatch() queuebatch.Settings[request.Request] { return queuebatch.Settings[request.Request]{ Encoding: fakeEncoding{}, } } type fakeEncoding struct{} func (f fakeEncoding) Marshal(context.Context, request.Request) ([]byte, error) { return []byte("mockRequest"), nil } func (f fakeEncoding) Unmarshal([]byte) (context.Context, request.Request, error) { return context.Background(), &requesttest.FakeRequest{}, nil } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/constants.go000066400000000000000000000015241511331344600276370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import "errors" var ( // errNilLogger is returned when a logger is nil errNilLogger = errors.New("nil logger") // errNilConsumeRequest is returned when a nil PushTraces is given. errNilConsumeRequest = errors.New("nil RequestConsumeFunc") // errNilTracesConverter is returned when a nil RequestFromTracesFunc is given. errNilTracesConverter = errors.New("nil RequestFromTracesFunc") // errNilMetricsConverter is returned when a nil RequestFromMetricsFunc is given. errNilMetricsConverter = errors.New("nil RequestFromMetricsFunc") // errNilLogsConverter is returned when a nil RequestFromLogsFunc is given. errNilLogsConverter = errors.New("nil RequestFromLogsFunc") ) opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/experr/000077500000000000000000000000001511331344600265775ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/experr/err.go000066400000000000000000000010541511331344600277160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package experr // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/experr" import ( "errors" ) type shutdownErr struct { err error } func NewShutdownErr(err error) error { return shutdownErr{err: err} } func (s shutdownErr) Error() string { return "interrupted due to shutdown: " + s.err.Error() } func (s shutdownErr) Unwrap() error { return s.err } func IsShutdownErr(err error) bool { var sdErr shutdownErr return errors.As(err, &sdErr) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/experr/err_test.go000066400000000000000000000010421511331344600307520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package experr import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewShutdownErr(t *testing.T) { err := NewShutdownErr(errors.New("some error")) assert.Equal(t, "interrupted due to shutdown: some error", err.Error()) } func TestIsShutdownErr(t *testing.T) { err := errors.New("testError") require.False(t, IsShutdownErr(err)) err = NewShutdownErr(err) require.True(t, IsShutdownErr(err)) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/hosttest/000077500000000000000000000000001511331344600271475ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/hosttest/hosttest.go000066400000000000000000000007631511331344600313610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package hosttest // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/hosttest" import ( "go.opentelemetry.io/collector/component" ) func NewHost(ext map[component.ID]component.Component) component.Host { return &mockHost{ext: ext} } type mockHost struct { ext map[component.ID]component.Component } func (nh *mockHost) GetExtensions() map[component.ID]component.Component { return nh.ext } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/hosttest/hosttest_test.go000066400000000000000000000011551511331344600324140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package hosttest import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) // nopExtension acts as an extension for testing purposes. type nopExtension struct { component.StartFunc component.ShutdownFunc } func TestMockHost(t *testing.T) { componenttest.NewNopHost() ext := map[component.ID]component.Component{ component.MustNewID("test"): &nopExtension{}, } host := NewHost(ext) assert.Equal(t, ext, host.GetExtensions()) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/metadata/000077500000000000000000000000001511331344600270525ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/metadata/generated_telemetry.go000066400000000000000000000171241511331344600334360ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "context" "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/embedded" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/exporter/exporterhelper") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/exporter/exporterhelper") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration ExporterEnqueueFailedLogRecords metric.Int64Counter ExporterEnqueueFailedMetricPoints metric.Int64Counter ExporterEnqueueFailedSpans metric.Int64Counter ExporterQueueBatchSendSize metric.Int64Histogram ExporterQueueBatchSendSizeBytes metric.Int64Histogram ExporterQueueCapacity metric.Int64ObservableGauge ExporterQueueSize metric.Int64ObservableGauge ExporterSendFailedLogRecords metric.Int64Counter ExporterSendFailedMetricPoints metric.Int64Counter ExporterSendFailedSpans metric.Int64Counter ExporterSentLogRecords metric.Int64Counter ExporterSentMetricPoints metric.Int64Counter ExporterSentSpans metric.Int64Counter } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // RegisterExporterQueueCapacityCallback sets callback for observable ExporterQueueCapacity metric. func (builder *TelemetryBuilder) RegisterExporterQueueCapacityCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ExporterQueueCapacity, obs: o}) return nil }, builder.ExporterQueueCapacity) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterExporterQueueSizeCallback sets callback for observable ExporterQueueSize metric. func (builder *TelemetryBuilder) RegisterExporterQueueSizeCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ExporterQueueSize, obs: o}) return nil }, builder.ExporterQueueSize) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } type observerInt64 struct { embedded.Int64Observer inst metric.Int64Observable obs metric.Observer } func (oi *observerInt64) Observe(value int64, opts ...metric.ObserveOption) { oi.obs.ObserveInt64(oi.inst, value, opts...) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.ExporterEnqueueFailedLogRecords, err = builder.meter.Int64Counter( "otelcol_exporter_enqueue_failed_log_records", metric.WithDescription("Number of log records failed to be added to the sending queue. [Alpha]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ExporterEnqueueFailedMetricPoints, err = builder.meter.Int64Counter( "otelcol_exporter_enqueue_failed_metric_points", metric.WithDescription("Number of metric points failed to be added to the sending queue. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ExporterEnqueueFailedSpans, err = builder.meter.Int64Counter( "otelcol_exporter_enqueue_failed_spans", metric.WithDescription("Number of spans failed to be added to the sending queue. [Alpha]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) builder.ExporterQueueBatchSendSize, err = builder.meter.Int64Histogram( "otelcol_exporter_queue_batch_send_size", metric.WithDescription("Number of units in the batch [Development]"), metric.WithUnit("{units}"), metric.WithExplicitBucketBoundaries([]float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}...), ) errs = errors.Join(errs, err) builder.ExporterQueueBatchSendSizeBytes, err = builder.meter.Int64Histogram( "otelcol_exporter_queue_batch_send_size_bytes", metric.WithDescription("Number of bytes in batch that was sent. Only available on detailed level. [Development]"), metric.WithUnit("By"), metric.WithExplicitBucketBoundaries([]float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000}...), ) errs = errors.Join(errs, err) builder.ExporterQueueCapacity, err = builder.meter.Int64ObservableGauge( "otelcol_exporter_queue_capacity", metric.WithDescription("Fixed capacity of the retry queue (in batches). [Alpha]"), metric.WithUnit("{batches}"), ) errs = errors.Join(errs, err) builder.ExporterQueueSize, err = builder.meter.Int64ObservableGauge( "otelcol_exporter_queue_size", metric.WithDescription("Current size of the retry queue (in batches). [Alpha]"), metric.WithUnit("{batches}"), ) errs = errors.Join(errs, err) builder.ExporterSendFailedLogRecords, err = builder.meter.Int64Counter( "otelcol_exporter_send_failed_log_records", metric.WithDescription("Number of log records in failed attempts to send to destination. [Alpha]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ExporterSendFailedMetricPoints, err = builder.meter.Int64Counter( "otelcol_exporter_send_failed_metric_points", metric.WithDescription("Number of metric points in failed attempts to send to destination. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ExporterSendFailedSpans, err = builder.meter.Int64Counter( "otelcol_exporter_send_failed_spans", metric.WithDescription("Number of spans in failed attempts to send to destination. [Alpha]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) builder.ExporterSentLogRecords, err = builder.meter.Int64Counter( "otelcol_exporter_sent_log_records", metric.WithDescription("Number of log record successfully sent to destination. [Alpha]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ExporterSentMetricPoints, err = builder.meter.Int64Counter( "otelcol_exporter_sent_metric_points", metric.WithDescription("Number of metric points successfully sent to destination. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ExporterSentSpans, err = builder.meter.Int64Counter( "otelcol_exporter_sent_spans", metric.WithDescription("Number of spans successfully sent to destination. [Alpha]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) return &builder, errs } generated_telemetry_test.go000066400000000000000000000035011511331344600344100ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/exporter/exporterhelper", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/exporter/exporterhelper", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/metadatatest/000077500000000000000000000000001511331344600277525ustar00rootroot00000000000000generated_telemetrytest.go000066400000000000000000000201441511331344600351530ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" ) func AssertEqualExporterEnqueueFailedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_enqueue_failed_log_records", Description: "Number of log records failed to be added to the sending queue. [Alpha]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_enqueue_failed_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterEnqueueFailedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_enqueue_failed_metric_points", Description: "Number of metric points failed to be added to the sending queue. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_enqueue_failed_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterEnqueueFailedSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_enqueue_failed_spans", Description: "Number of spans failed to be added to the sending queue. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_enqueue_failed_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterQueueBatchSendSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.HistogramDataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_queue_batch_send_size", Description: "Number of units in the batch [Development]", Unit: "{units}", Data: metricdata.Histogram[int64]{ Temporality: metricdata.CumulativeTemporality, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_queue_batch_send_size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterQueueBatchSendSizeBytes(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.HistogramDataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_queue_batch_send_size_bytes", Description: "Number of bytes in batch that was sent. Only available on detailed level. [Development]", Unit: "By", Data: metricdata.Histogram[int64]{ Temporality: metricdata.CumulativeTemporality, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_queue_batch_send_size_bytes") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterQueueCapacity(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_queue_capacity", Description: "Fixed capacity of the retry queue (in batches). [Alpha]", Unit: "{batches}", Data: metricdata.Gauge[int64]{ DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_queue_capacity") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterQueueSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_queue_size", Description: "Current size of the retry queue (in batches). [Alpha]", Unit: "{batches}", Data: metricdata.Gauge[int64]{ DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_queue_size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterSendFailedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_send_failed_log_records", Description: "Number of log records in failed attempts to send to destination. [Alpha]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_send_failed_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterSendFailedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_send_failed_metric_points", Description: "Number of metric points in failed attempts to send to destination. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_send_failed_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterSendFailedSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_send_failed_spans", Description: "Number of spans in failed attempts to send to destination. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_send_failed_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterSentLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_sent_log_records", Description: "Number of log record successfully sent to destination. [Alpha]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_sent_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterSentMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_sent_metric_points", Description: "Number of metric points successfully sent to destination. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_sent_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterSentSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_exporter_sent_spans", Description: "Number of spans successfully sent to destination. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_exporter_sent_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } generated_telemetrytest_test.go000066400000000000000000000065731511331344600362240ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadata" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() require.NoError(t, tb.RegisterExporterQueueCapacityCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) require.NoError(t, tb.RegisterExporterQueueSizeCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) tb.ExporterEnqueueFailedLogRecords.Add(context.Background(), 1) tb.ExporterEnqueueFailedMetricPoints.Add(context.Background(), 1) tb.ExporterEnqueueFailedSpans.Add(context.Background(), 1) tb.ExporterQueueBatchSendSize.Record(context.Background(), 1) tb.ExporterQueueBatchSendSizeBytes.Record(context.Background(), 1) tb.ExporterSendFailedLogRecords.Add(context.Background(), 1) tb.ExporterSendFailedMetricPoints.Add(context.Background(), 1) tb.ExporterSendFailedSpans.Add(context.Background(), 1) tb.ExporterSentLogRecords.Add(context.Background(), 1) tb.ExporterSentMetricPoints.Add(context.Background(), 1) tb.ExporterSentSpans.Add(context.Background(), 1) AssertEqualExporterEnqueueFailedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterEnqueueFailedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterEnqueueFailedSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterQueueBatchSendSize(t, testTel, []metricdata.HistogramDataPoint[int64]{{}}, metricdatatest.IgnoreValue(), metricdatatest.IgnoreTimestamp()) AssertEqualExporterQueueBatchSendSizeBytes(t, testTel, []metricdata.HistogramDataPoint[int64]{{}}, metricdatatest.IgnoreValue(), metricdatatest.IgnoreTimestamp()) AssertEqualExporterQueueCapacity(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterQueueSize(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterSendFailedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterSendFailedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterSendFailedSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterSentLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterSentMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterSentSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/new_request.go000066400000000000000000000120571511331344600301670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import ( "context" "go.uber.org/zap" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" ) type logsExporter struct { *BaseExporter consumer.Logs } // NewLogsRequest creates new logs exporter based on custom LogsConverter and Sender. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewLogsRequest( _ context.Context, set exporter.Settings, converter request.RequestConverterFunc[plog.Logs], pusher request.RequestConsumeFunc, options ...Option, ) (exporter.Logs, error) { if set.Logger == nil { return nil, errNilLogger } if converter == nil { return nil, errNilLogsConverter } if pusher == nil { return nil, errNilConsumeRequest } be, err := NewBaseExporter(set, pipeline.SignalLogs, pusher, options...) if err != nil { return nil, err } lc, err := consumer.NewLogs(newConsumeLogs(converter, be, set.Logger), be.ConsumerOptions...) if err != nil { return nil, err } return &logsExporter{BaseExporter: be, Logs: lc}, nil } func newConsumeLogs(converter request.RequestConverterFunc[plog.Logs], be *BaseExporter, logger *zap.Logger) consumer.ConsumeLogsFunc { return func(ctx context.Context, ld plog.Logs) error { req, err := converter(ctx, ld) if err != nil { logger.Error("Failed to convert logs. Dropping data.", zap.Int("dropped_log_records", ld.LogRecordCount()), zap.Error(err)) return consumererror.NewPermanent(err) } return be.Send(ctx, req) } } type tracesExporter struct { *BaseExporter consumer.Traces } // NewTracesRequest creates a new traces exporter based on a custom TracesConverter and Sender. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewTracesRequest( _ context.Context, set exporter.Settings, converter request.RequestConverterFunc[ptrace.Traces], pusher request.RequestConsumeFunc, options ...Option, ) (exporter.Traces, error) { if set.Logger == nil { return nil, errNilLogger } if converter == nil { return nil, errNilTracesConverter } if pusher == nil { return nil, errNilConsumeRequest } be, err := NewBaseExporter(set, pipeline.SignalTraces, pusher, options...) if err != nil { return nil, err } tc, err := consumer.NewTraces(newConsumeTraces(converter, be, set.Logger), be.ConsumerOptions...) if err != nil { return nil, err } return &tracesExporter{BaseExporter: be, Traces: tc}, nil } func newConsumeTraces(converter request.RequestConverterFunc[ptrace.Traces], be *BaseExporter, logger *zap.Logger) consumer.ConsumeTracesFunc { return func(ctx context.Context, td ptrace.Traces) error { req, err := converter(ctx, td) if err != nil { logger.Error("Failed to convert traces. Dropping data.", zap.Int("dropped_spans", td.SpanCount()), zap.Error(err)) return consumererror.NewPermanent(err) } return be.Send(ctx, req) } } type metricsExporter struct { *BaseExporter consumer.Metrics } // NewMetricsRequest creates a new metrics exporter based on a custom MetricsConverter and Sender. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewMetricsRequest( _ context.Context, set exporter.Settings, converter request.RequestConverterFunc[pmetric.Metrics], pusher request.RequestConsumeFunc, options ...Option, ) (exporter.Metrics, error) { if set.Logger == nil { return nil, errNilLogger } if converter == nil { return nil, errNilMetricsConverter } if pusher == nil { return nil, errNilConsumeRequest } be, err := NewBaseExporter(set, pipeline.SignalMetrics, pusher, options...) if err != nil { return nil, err } mc, err := consumer.NewMetrics(newConsumeMetrics(converter, be, set.Logger), be.ConsumerOptions...) if err != nil { return nil, err } return &metricsExporter{BaseExporter: be, Metrics: mc}, nil } func newConsumeMetrics(converter request.RequestConverterFunc[pmetric.Metrics], be *BaseExporter, logger *zap.Logger) consumer.ConsumeMetricsFunc { return func(ctx context.Context, md pmetric.Metrics) error { req, err := converter(ctx, md) if err != nil { logger.Error("Failed to convert metrics. Dropping data.", zap.Int("dropped_data_points", md.DataPointCount()), zap.Error(err)) return consumererror.NewPermanent(err) } return be.Send(ctx, req) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/new_request_test.go000066400000000000000000000277551511331344600312410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sendertest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestLogsRequest_NilLogger(t *testing.T) { le, err := NewLogsRequest(context.Background(), exporter.Settings{}, requesttest.RequestFromLogsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.Nil(t, le) require.Equal(t, errNilLogger, err) } func TestLogsRequest_NilLogsConverter(t *testing.T) { le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, sendertest.NewNopSenderFunc[request.Request]()) require.Nil(t, le) require.Equal(t, errNilLogsConverter, err) } func TestLogsRequest_NilPushLogsData(t *testing.T) { le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromLogsFunc(nil), nil) require.Nil(t, le) require.Equal(t, errNilConsumeRequest, err) } func TestLogsRequest_Default(t *testing.T) { ld := plog.NewLogs() le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromLogsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, le.Capabilities()) assert.NoError(t, le.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, le.ConsumeLogs(context.Background(), ld)) assert.NoError(t, le.Shutdown(context.Background())) } func TestLogsRequest_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromLogsFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithCapabilities(capabilities)) require.NoError(t, err) require.NotNil(t, le) assert.Equal(t, capabilities, le.Capabilities()) } func TestLogsRequest_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromLogsFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithShutdown(shutdown)) assert.NotNil(t, le) assert.NoError(t, err) assert.NoError(t, le.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestLogsRequest_Default_ConvertError(t *testing.T) { ld := plog.NewLogs() want := errors.New("convert_error") le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromLogsFunc(want), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, le) require.Equal(t, consumererror.NewPermanent(want), le.ConsumeLogs(context.Background(), ld)) } func TestLogsRequest_Default_ExportError(t *testing.T) { ld := plog.NewLogs() want := errors.New("export_error") le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromLogsFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, le) require.Equal(t, want, le.ConsumeLogs(context.Background(), ld)) } func TestLogsRequest_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } le, err := NewLogsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromLogsFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithShutdown(shutdownErr)) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, want, le.Shutdown(context.Background())) } func TestTracesRequest_NilLogger(t *testing.T) { te, err := NewTracesRequest(context.Background(), exporter.Settings{}, requesttest.RequestFromTracesFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.Nil(t, te) require.Equal(t, errNilLogger, err) } func TestTracesRequest_NilTracesConverter(t *testing.T) { te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, sendertest.NewNopSenderFunc[request.Request]()) require.Nil(t, te) require.Equal(t, errNilTracesConverter, err) } func TestTracesRequest_NilPushTraceData(t *testing.T) { te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromTracesFunc(nil), nil) require.Nil(t, te) require.Equal(t, errNilConsumeRequest, err) } func TestTracesRequest_Default(t *testing.T) { td := ptrace.NewTraces() te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromTracesFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) assert.NotNil(t, te) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, te.Capabilities()) assert.NoError(t, te.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, te.ConsumeTraces(context.Background(), td)) assert.NoError(t, te.Shutdown(context.Background())) } func TestTracesRequest_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromTracesFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithCapabilities(capabilities)) assert.NotNil(t, te) require.NoError(t, err) assert.Equal(t, capabilities, te.Capabilities()) } func TestTracesRequest_Default_ConvertError(t *testing.T) { td := ptrace.NewTraces() want := errors.New("convert_error") te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromTracesFunc(want), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, te) require.Equal(t, consumererror.NewPermanent(want), te.ConsumeTraces(context.Background(), td)) } func TestTracesRequest_Default_ExportError(t *testing.T) { td := ptrace.NewTraces() want := errors.New("export_error") te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromTracesFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, te) require.Equal(t, want, te.ConsumeTraces(context.Background(), td)) } func TestTracesRequest_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromTracesFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithShutdown(shutdown)) assert.NotNil(t, te) assert.NoError(t, err) assert.NoError(t, te.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestTracesRequest_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } te, err := NewTracesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromTracesFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithShutdown(shutdownErr)) assert.NotNil(t, te) require.NoError(t, err) assert.Equal(t, want, te.Shutdown(context.Background())) } func TestMetricsRequest_NilLogger(t *testing.T) { me, err := NewMetricsRequest(context.Background(), exporter.Settings{}, requesttest.RequestFromMetricsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.Nil(t, me) require.Equal(t, errNilLogger, err) } func TestMetricsRequest_NilMetricsConverter(t *testing.T) { me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, sendertest.NewNopSenderFunc[request.Request]()) require.Nil(t, me) require.Equal(t, errNilMetricsConverter, err) } func TestMetricsRequest_NilPushMetricsData(t *testing.T) { me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromMetricsFunc(nil), nil) require.Nil(t, me) require.Equal(t, errNilConsumeRequest, err) } func TestMetricsRequest_Default(t *testing.T) { md := pmetric.NewMetrics() me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromMetricsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) assert.NotNil(t, me) assert.Equal(t, consumer.Capabilities{MutatesData: false}, me.Capabilities()) assert.NoError(t, me.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, me.ConsumeMetrics(context.Background(), md)) assert.NoError(t, me.Shutdown(context.Background())) } func TestMetricsRequest_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromMetricsFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithCapabilities(capabilities)) require.NoError(t, err) assert.NotNil(t, me) assert.Equal(t, capabilities, me.Capabilities()) } func TestMetricsRequest_Default_ConvertError(t *testing.T) { md := pmetric.NewMetrics() want := errors.New("convert_error") me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromMetricsFunc(want), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, me) require.Equal(t, consumererror.NewPermanent(want), me.ConsumeMetrics(context.Background(), md)) } func TestMetricsRequest_Default_ExportError(t *testing.T) { md := pmetric.NewMetrics() want := errors.New("export_error") me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromMetricsFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, me) require.Equal(t, want, me.ConsumeMetrics(context.Background(), md)) } func TestMetricsRequest_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromMetricsFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithShutdown(shutdown)) assert.NotNil(t, me) assert.NoError(t, err) assert.NoError(t, me.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, me.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestMetricsRequest_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } me, err := NewMetricsRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requesttest.RequestFromMetricsFunc(nil), sendertest.NewNopSenderFunc[request.Request](), WithShutdown(shutdownErr)) assert.NotNil(t, me) assert.NoError(t, err) assert.NoError(t, me.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, me.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/obs_report_sender.go000066400000000000000000000105751511331344600313470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadata" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" "go.opentelemetry.io/collector/pipeline" ) const ( // spanNameSep is duplicate between receiver and exporter. spanNameSep = "/" // ExporterKey used to identify exporters in metrics and traces. ExporterKey = "exporter" // DataTypeKey used to identify the data type in the queue size metric. DataTypeKey = "data_type" // ItemsSent used to track number of items sent by exporters. ItemsSent = "items.sent" // ItemsFailed used to track number of items that failed to be sent by exporters. ItemsFailed = "items.failed" ) type obsReportSender[K request.Request] struct { component.StartFunc component.ShutdownFunc spanName string tracer trace.Tracer spanAttrs trace.SpanStartEventOption metricAttr metric.MeasurementOption itemsSentInst metric.Int64Counter itemsFailedInst metric.Int64Counter next sender.Sender[K] } func newObsReportSender[K request.Request](set exporter.Settings, signal pipeline.Signal, next sender.Sender[K]) (sender.Sender[K], error) { telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return nil, err } idStr := set.ID.String() expAttr := attribute.String(ExporterKey, idStr) or := &obsReportSender[K]{ spanName: ExporterKey + spanNameSep + idStr + spanNameSep + signal.String(), tracer: metadata.Tracer(set.TelemetrySettings), spanAttrs: trace.WithAttributes(expAttr, attribute.String(DataTypeKey, signal.String())), metricAttr: metric.WithAttributeSet(attribute.NewSet(expAttr)), next: next, } switch signal { case pipeline.SignalTraces: or.itemsSentInst = telemetryBuilder.ExporterSentSpans or.itemsFailedInst = telemetryBuilder.ExporterSendFailedSpans case pipeline.SignalMetrics: or.itemsSentInst = telemetryBuilder.ExporterSentMetricPoints or.itemsFailedInst = telemetryBuilder.ExporterSendFailedMetricPoints case pipeline.SignalLogs: or.itemsSentInst = telemetryBuilder.ExporterSentLogRecords or.itemsFailedInst = telemetryBuilder.ExporterSendFailedLogRecords } return or, nil } func (ors *obsReportSender[K]) Send(ctx context.Context, req K) error { // Have to read the number of items before sending the request since the request can // be modified by the downstream components like the batcher. c := ors.startOp(ctx) items := req.ItemsCount() // Forward the data to the next consumer (this pusher is the next). err := ors.next.Send(c, req) ors.endOp(c, items, err) return err } // StartOp creates the span used to trace the operation. Returning // the updated context and the created span. func (ors *obsReportSender[K]) startOp(ctx context.Context) context.Context { ctx, _ = ors.tracer.Start(ctx, ors.spanName, ors.spanAttrs, trace.WithLinks(queuebatch.LinksFromContext(ctx)...)) return ctx } // EndOp completes the export operation that was started with StartOp. func (ors *obsReportSender[K]) endOp(ctx context.Context, numLogRecords int, err error) { numSent, numFailedToSend := toNumItems(numLogRecords, err) // No metrics recorded for profiles. if ors.itemsSentInst != nil { ors.itemsSentInst.Add(ctx, numSent, ors.metricAttr) } // No metrics recorded for profiles. if ors.itemsFailedInst != nil { ors.itemsFailedInst.Add(ctx, numFailedToSend, ors.metricAttr) } span := trace.SpanFromContext(ctx) defer span.End() // End the span according to errors. if span.IsRecording() { span.SetAttributes( attribute.Int64(ItemsSent, numSent), attribute.Int64(ItemsFailed, numFailedToSend), ) if err != nil { span.SetStatus(codes.Error, err.Error()) } } } func toNumItems(numExportedItems int, err error) (int64, int64) { if err != nil { return 0, int64(numExportedItems) } return int64(numExportedItems), 0 } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/obs_report_sender_test.go000066400000000000000000000214051511331344600324000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadatatest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" "go.opentelemetry.io/collector/pipeline" ) var ( exporterID = component.MustNewID("fakeExporter") errFake = errors.New("errFake") ) func TestExportTraceDataOp(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) parentCtx, parentSpan := tt.NewTelemetrySettings().TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() var exporterErr error obsrep, err := newObsReportSender( exporter.Settings{ID: exporterID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, pipeline.SignalTraces, sender.NewSender(func(context.Context, request.Request) error { return exporterErr }), ) require.NoError(t, err) params := []testParams{ {items: 22, err: nil}, {items: 14, err: errFake}, } for i := range params { exporterErr = params[i].err require.ErrorIs(t, obsrep.Send(parentCtx, &requesttest.FakeRequest{Items: params[i].items}), params[i].err) } spans := tt.SpanRecorder.Ended() require.Len(t, spans, len(params)) var sentSpans, failedToSendSpans int for i, span := range spans { assert.Equal(t, "exporter/"+exporterID.String()+"/traces", span.Name()) switch { case params[i].err == nil: sentSpans += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsSent, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsFailed, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Unset, span.Status().Code) case errors.Is(params[i].err, errFake): failedToSendSpans += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsSent, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsFailed, Value: attribute.Int64Value(int64(params[i].items))}) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) default: t.Fatalf("unexpected error: %v", params[i].err) } } metadatatest.AssertEqualExporterSentSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", exporterID.String())), Value: int64(sentSpans), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) if failedToSendSpans > 0 { metadatatest.AssertEqualExporterSendFailedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", exporterID.String())), Value: int64(failedToSendSpans), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } } func TestExportMetricsOp(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) parentCtx, parentSpan := tt.NewTelemetrySettings().TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() var exporterErr error obsrep, err := newObsReportSender( exporter.Settings{ID: exporterID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, pipeline.SignalMetrics, sender.NewSender(func(context.Context, request.Request) error { return exporterErr }), ) require.NoError(t, err) params := []testParams{ {items: 17, err: nil}, {items: 23, err: errFake}, } for i := range params { exporterErr = params[i].err require.ErrorIs(t, obsrep.Send(parentCtx, &requesttest.FakeRequest{Items: params[i].items}), params[i].err) } spans := tt.SpanRecorder.Ended() require.Len(t, spans, len(params)) var sentMetricPoints, failedToSendMetricPoints int for i, span := range spans { assert.Equal(t, "exporter/"+exporterID.String()+"/metrics", span.Name()) switch { case params[i].err == nil: sentMetricPoints += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsSent, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsFailed, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Unset, span.Status().Code) case errors.Is(params[i].err, errFake): failedToSendMetricPoints += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsSent, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsFailed, Value: attribute.Int64Value(int64(params[i].items))}) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) default: t.Fatalf("unexpected error: %v", params[i].err) } } metadatatest.AssertEqualExporterSentMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", exporterID.String())), Value: int64(sentMetricPoints), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) if failedToSendMetricPoints > 0 { metadatatest.AssertEqualExporterSendFailedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", exporterID.String())), Value: int64(failedToSendMetricPoints), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } } func TestExportLogsOp(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) parentCtx, parentSpan := tt.NewTelemetrySettings().TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() var exporterErr error obsrep, err := newObsReportSender( exporter.Settings{ID: exporterID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, pipeline.SignalLogs, sender.NewSender(func(context.Context, request.Request) error { return exporterErr }), ) require.NoError(t, err) params := []testParams{ {items: 17, err: nil}, {items: 23, err: errFake}, } for i := range params { exporterErr = params[i].err require.ErrorIs(t, obsrep.Send(parentCtx, &requesttest.FakeRequest{Items: params[i].items}), params[i].err) } spans := tt.SpanRecorder.Ended() require.Len(t, spans, len(params)) var sentLogRecords, failedToSendLogRecords int for i, span := range spans { assert.Equal(t, "exporter/"+exporterID.String()+"/logs", span.Name()) switch { case params[i].err == nil: sentLogRecords += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsSent, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsFailed, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Unset, span.Status().Code) case errors.Is(params[i].err, errFake): failedToSendLogRecords += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsSent, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: ItemsFailed, Value: attribute.Int64Value(int64(params[i].items))}) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) default: t.Fatalf("unexpected error: %v", params[i].err) } } metadatatest.AssertEqualExporterSentLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", exporterID.String())), Value: int64(sentLogRecords), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) if failedToSendLogRecords > 0 { metadatatest.AssertEqualExporterSendFailedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", exporterID.String())), Value: int64(failedToSendLogRecords), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } } type testParams struct { items int err error } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/oteltest/000077500000000000000000000000001511331344600271355ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/oteltest/tracetest.go000066400000000000000000000020061511331344600314600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package oteltest // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/oteltest" import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/codes" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" ) func CheckStatus(t *testing.T, sd sdktrace.ReadOnlySpan, err error) { if err != nil { require.Equal(t, codes.Error, sd.Status().Code) require.EqualError(t, err, sd.Status().Description) } else { require.Equal(t, codes.Unset, sd.Status().Code) } } func FakeSpanContext(t *testing.T) trace.SpanContext { traceID, err := trace.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10") require.NoError(t, err) spanID, err := trace.SpanIDFromHex("0102030405060708") require.NoError(t, err) return trace.NewSpanContext(trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: 0x01, TraceState: trace.TraceState{}, Remote: true, }) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/package_test.go000066400000000000000000000003111511331344600302460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/000077500000000000000000000000001511331344600264165ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/async_queue.go000066400000000000000000000034461511331344600312750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" import ( "context" "sync" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) type asyncQueue[T any] struct { readableQueue[T] numConsumers int refCounter ReferenceCounter[T] consumeFunc ConsumeFunc[T] stopWG sync.WaitGroup } func newAsyncQueue[T any](q readableQueue[T], numConsumers int, consumeFunc ConsumeFunc[T], refCounter ReferenceCounter[T]) Queue[T] { return &asyncQueue[T]{ readableQueue: q, numConsumers: numConsumers, refCounter: refCounter, consumeFunc: consumeFunc, } } // Start ensures that queue and all consumers are started. func (qc *asyncQueue[T]) Start(ctx context.Context, host component.Host) error { if err := qc.readableQueue.Start(ctx, host); err != nil { return err } var startWG sync.WaitGroup for i := 0; i < qc.numConsumers; i++ { qc.stopWG.Add(1) startWG.Add(1) go func() { //nolint:contextcheck startWG.Done() defer qc.stopWG.Done() for { ctx, req, done, ok := qc.Read(context.Background()) if !ok { return } qc.consumeFunc(ctx, req, done) if qc.refCounter != nil { qc.refCounter.Unref(req) } } }() } startWG.Wait() return nil } func (qc *asyncQueue[T]) Offer(ctx context.Context, req T) error { span := trace.SpanFromContext(ctx) if err := qc.readableQueue.Offer(ctx, req); err != nil { span.AddEvent("Failed to enqueue item.") return err } span.AddEvent("Enqueued item.") return nil } // Shutdown ensures that queue and all consumers are stopped. func (qc *asyncQueue[T]) Shutdown(ctx context.Context) error { err := qc.readableQueue.Shutdown(ctx) qc.stopWG.Wait() return err } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/async_queue_test.go000066400000000000000000000075231511331344600323340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue import ( "context" "sync" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) func TestAsyncMemoryQueue(t *testing.T) { consumed := &atomic.Int64{} set := newSettings(request.SizerTypeItems, 100) ac := newAsyncQueue(newMemoryQueue[intRequest](set), 1, func(_ context.Context, _ intRequest, done Done) { consumed.Add(1) done.OnDone(nil) }, set.ReferenceCounter) require.NoError(t, ac.Start(context.Background(), componenttest.NewNopHost())) for range 10 { require.NoError(t, ac.Offer(context.Background(), 10)) } require.NoError(t, ac.Shutdown(context.Background())) assert.EqualValues(t, 10, consumed.Load()) } func TestAsyncMemoryQueueBlocking(t *testing.T) { consumed := &atomic.Int64{} set := newSettings(request.SizerTypeItems, 100) set.BlockOnOverflow = true ac := newAsyncQueue(newMemoryQueue[intRequest](set), 4, func(_ context.Context, _ intRequest, done Done) { consumed.Add(1) done.OnDone(nil) }, set.ReferenceCounter) require.NoError(t, ac.Start(context.Background(), componenttest.NewNopHost())) wg := &sync.WaitGroup{} for range 10 { wg.Add(1) go func() { defer wg.Done() for range 100_000 { assert.NoError(t, ac.Offer(context.Background(), 10)) } }() } wg.Wait() require.NoError(t, ac.Shutdown(context.Background())) assert.EqualValues(t, 1_000_000, consumed.Load()) } func TestAsyncMemoryWaitForResultQueueBlocking(t *testing.T) { consumed := &atomic.Int64{} set := newSettings(request.SizerTypeItems, 100) set.BlockOnOverflow = true set.WaitForResult = true ac := newAsyncQueue(newMemoryQueue[intRequest](set), 4, func(_ context.Context, _ intRequest, done Done) { consumed.Add(1) done.OnDone(nil) }, set.ReferenceCounter) require.NoError(t, ac.Start(context.Background(), componenttest.NewNopHost())) wg := &sync.WaitGroup{} for range 10 { wg.Add(1) go func() { defer wg.Done() for range 100_000 { assert.NoError(t, ac.Offer(context.Background(), 10)) } }() } wg.Wait() require.NoError(t, ac.Shutdown(context.Background())) assert.EqualValues(t, 1_000_000, consumed.Load()) } func TestAsyncMemoryQueueBlockingCancelled(t *testing.T) { stop := make(chan struct{}) set := newSettings(request.SizerTypeItems, 10) set.BlockOnOverflow = true ac := newAsyncQueue(newMemoryQueue[intRequest](set), 1, func(_ context.Context, _ intRequest, done Done) { <-stop done.OnDone(nil) }, set.ReferenceCounter) require.NoError(t, ac.Start(context.Background(), componenttest.NewNopHost())) ctx, cancel := context.WithCancel(context.Background()) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() for range 10 { assert.NoError(t, ac.Offer(ctx, 1)) } assert.ErrorIs(t, ac.Offer(ctx, 3), context.Canceled) }() // Sleep some time so that the go-routine blocks, it doesn't have to but even if it // does things will work. <-time.After(1 * time.Second) cancel() wg.Wait() close(stop) require.NoError(t, ac.Shutdown(context.Background())) } func BenchmarkAsyncMemoryQueue(b *testing.B) { b.Skip("Consistently fails with 'sending queue is full'") consumed := &atomic.Int64{} set := newSettings(request.SizerTypeItems, int64(10*b.N)) ac := newAsyncQueue(newMemoryQueue[intRequest](set), 1, func(_ context.Context, _ intRequest, done Done) { consumed.Add(1) done.OnDone(nil) }, set.ReferenceCounter) require.NoError(b, ac.Start(context.Background(), componenttest.NewNopHost())) b.ReportAllocs() for b.Loop() { require.NoError(b, ac.Offer(context.Background(), 10)) } require.NoError(b, ac.Shutdown(context.Background())) assert.EqualValues(b, b.N, consumed.Load()) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/cond.go000066400000000000000000000032131511331344600276670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" import ( "context" "sync" ) // cond is equivalent with sync.Cond, but context.Context aware. // Which means Wait() will return if context is done before any signal is received. // Also, it requires the caller to hold the c.L during all calls. type cond struct { L sync.Locker ch chan struct{} waiting int64 } func newCond(l sync.Locker) *cond { return &cond{L: l, ch: make(chan struct{}, 1)} } // Signal wakes one goroutine waiting on c, if there is any. // It requires for the caller to hold c.L during the call. func (c *cond) Signal() { if c.waiting == 0 { return } c.waiting-- c.ch <- struct{}{} } // Broadcast wakes all goroutines waiting on c. // It requires for the caller to hold c.L during the call. func (c *cond) Broadcast() { for ; c.waiting > 0; c.waiting-- { c.ch <- struct{}{} } } // Wait atomically unlocks c.L and suspends execution of the calling goroutine. After later resuming execution, Wait locks c.L before returning. func (c *cond) Wait(ctx context.Context) error { c.waiting++ c.L.Unlock() select { case <-ctx.Done(): c.L.Lock() if c.waiting == 0 { // If waiting is 0, it means that there was a signal sent and nobody else waits for it. // Consume it, so that we don't unblock other consumer unnecessary, // or we don't block the producer because the channel buffer is full. <-c.ch } else { // Decrease the number of waiting routines. c.waiting-- } return ctx.Err() case <-c.ch: c.L.Lock() return nil } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/fg.go000066400000000000000000000017011511331344600273400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" import "go.opentelemetry.io/collector/featuregate" // PersistRequestContextFeatureGate controls whether request context should be preserved in the persistent queue. var PersistRequestContextFeatureGate = featuregate.GlobalRegistry().MustRegister( "exporter.PersistRequestContext", featuregate.StageBeta, featuregate.WithRegisterFromVersion("v0.128.0"), featuregate.WithRegisterDescription("controls whether context should be stored alongside requests in the persistent queue"), ) // assign the feature gate to separate functions to make it possible to override the behavior in tests // on write and read paths separately. var ( PersistRequestContextOnRead = PersistRequestContextFeatureGate.IsEnabled PersistRequestContextOnWrite = PersistRequestContextFeatureGate.IsEnabled ) opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/memory_queue.go000066400000000000000000000140751511331344600314700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" import ( "context" "errors" "sync" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) var blockingDonePool = sync.Pool{ New: func() any { return &blockingDone{ ch: make(chan error, 1), } }, } var ( errInvalidSize = errors.New("invalid element size") errSizeTooLarge = errors.New("element size too large") ) // memoryQueue is an in-memory implementation of a Queue. type memoryQueue[T request.Request] struct { component.StartFunc refCounter ReferenceCounter[T] sizer request.Sizer cap int64 mu sync.Mutex hasMoreElements *sync.Cond hasMoreSpace *cond items *linkedQueue[T] size int64 stopped bool waitForResult bool blockOnOverflow bool } // newMemoryQueue creates a sized elements channel. Each element is assigned a size by the provided sizer. // capacity is the capacity of the queue. func newMemoryQueue[T request.Request](set Settings[T]) readableQueue[T] { sq := &memoryQueue[T]{ refCounter: set.ReferenceCounter, sizer: request.NewSizer(set.SizerType), cap: set.Capacity, items: &linkedQueue[T]{}, waitForResult: set.WaitForResult, blockOnOverflow: set.BlockOnOverflow, } sq.hasMoreElements = sync.NewCond(&sq.mu) sq.hasMoreSpace = newCond(&sq.mu) return sq } // Offer puts the element into the queue with the given sized if there is enough capacity. // Returns an error if the queue is full. func (mq *memoryQueue[T]) Offer(ctx context.Context, el T) error { elSize := mq.sizer.Sizeof(el) // Ignore empty requests, see https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#empty-telemetry-envelopes if elSize == 0 { return nil } if elSize <= 0 { return errInvalidSize } // If element larger than the capacity, will never been able to add it. if elSize > mq.cap { return errSizeTooLarge } if mq.refCounter != nil { mq.refCounter.Ref(el) } done, err := mq.add(ctx, el, elSize) if err != nil { // Unref in case of an error since there will not be any async worker to pick it up. if mq.refCounter != nil { mq.refCounter.Unref(el) } return err } if mq.waitForResult { // Only re-add the blockingDone instance back to the pool if successfully received the // message from the consumer which guarantees consumer will not use that anymore, // otherwise no guarantee about when the consumer will add the message to the channel so cannot reuse or close. select { case doneErr := <-done.ch: blockingDonePool.Put(done) return doneErr case <-ctx.Done(): return ctx.Err() } } return nil } func (mq *memoryQueue[T]) add(ctx context.Context, el T, elSize int64) (*blockingDone, error) { mq.mu.Lock() defer mq.mu.Unlock() for mq.size+elSize > mq.cap { if !mq.blockOnOverflow { return nil, ErrQueueIsFull } // Wait for more space or before the ctx is Done. if err := mq.hasMoreSpace.Wait(ctx); err != nil { return nil, err } } mq.size += elSize done := blockingDonePool.Get().(*blockingDone) done.reset(elSize, mq) if !mq.waitForResult { // Prevent cancellation and deadline to propagate to the context stored in the queue. // The grpc/http based receivers will cancel the request context after this function returns. ctx = context.WithoutCancel(ctx) } mq.items.push(ctx, el, done) // Signal one consumer if any. mq.hasMoreElements.Signal() return done, nil } // Read removes the element from the queue and returns it. // The call blocks until there is an item available or the queue is stopped. // The function returns true when an item is consumed or false if the queue is stopped and emptied. func (mq *memoryQueue[T]) Read(context.Context) (context.Context, T, Done, bool) { mq.mu.Lock() defer mq.mu.Unlock() for { if mq.items.hasElements() { elCtx, el, done := mq.items.pop() return elCtx, el, done, true } if mq.stopped { var el T return context.Background(), el, nil, false } // TODO: Need to change the Queue interface to return an error to allow distinguish between shutdown and context canceled. // Until then use the sync.Cond. mq.hasMoreElements.Wait() } } func (mq *memoryQueue[T]) onDone(bd *blockingDone, err error) { mq.mu.Lock() defer mq.mu.Unlock() mq.size -= bd.elSize mq.hasMoreSpace.Signal() if mq.waitForResult { // In this case the done will be added back to the queue by the waiter. bd.ch <- err return } blockingDonePool.Put(bd) } // Shutdown closes the queue channel to initiate draining of the queue. func (mq *memoryQueue[T]) Shutdown(context.Context) error { mq.mu.Lock() defer mq.mu.Unlock() mq.stopped = true mq.hasMoreElements.Broadcast() return nil } func (mq *memoryQueue[T]) Size() int64 { mq.mu.Lock() defer mq.mu.Unlock() return mq.size } func (mq *memoryQueue[T]) Capacity() int64 { return mq.cap } type node[T any] struct { ctx context.Context data T done Done next *node[T] } type linkedQueue[T any] struct { head *node[T] tail *node[T] } func (l *linkedQueue[T]) push(ctx context.Context, data T, done Done) { n := &node[T]{ctx: ctx, data: data, done: done} // If tail is nil means list is empty so update both head and tail to point to same element. if l.tail == nil { l.head = n l.tail = n return } l.tail.next = n l.tail = n } func (l *linkedQueue[T]) hasElements() bool { return l.head != nil } func (l *linkedQueue[T]) pop() (context.Context, T, Done) { n := l.head l.head = n.next // If it gets to the last element, then update tail as well. if l.head == nil { l.tail = nil } n.next = nil return n.ctx, n.data, n.done } type blockingDone struct { queue interface { onDone(*blockingDone, error) } elSize int64 ch chan error } func (bd *blockingDone) reset(elSize int64, queue interface{ onDone(*blockingDone, error) }) { bd.elSize = elSize bd.queue = queue } func (bd *blockingDone) OnDone(err error) { bd.queue.onDone(bd, err) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/memory_queue_test.go000066400000000000000000000174401511331344600325260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue import ( "context" "errors" "sync" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) func TestMemoryQueue(t *testing.T) { set := newSettings(request.SizerTypeItems, 7) q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, q.Offer(context.Background(), 1)) assert.EqualValues(t, 1, q.Size()) assert.EqualValues(t, 7, q.Capacity()) require.NoError(t, q.Offer(context.Background(), 3)) assert.EqualValues(t, 4, q.Size()) // should not be able to send to the full queue require.ErrorIs(t, q.Offer(context.Background(), 4), ErrQueueIsFull) assert.EqualValues(t, 4, q.Size()) assert.True(t, consume(q, func(_ context.Context, el intRequest) error { assert.EqualValues(t, 1, el) return nil })) assert.EqualValues(t, 3, q.Size()) assert.True(t, consume(q, func(_ context.Context, el intRequest) error { assert.EqualValues(t, 3, el) return nil })) assert.EqualValues(t, 0, q.Size()) require.NoError(t, q.Shutdown(context.Background())) assert.False(t, consume(q, func(context.Context, intRequest) error { t.FailNow(); return nil })) require.NoError(t, q.Shutdown(context.Background())) } func TestMemoryQueueBlockingCancelled(t *testing.T) { set := newSettings(request.SizerTypeItems, 5) set.BlockOnOverflow = true q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, q.Offer(context.Background(), 3)) ctx, cancel := context.WithCancel(context.Background()) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.ErrorIs(t, q.Offer(ctx, 3), context.Canceled) }() cancel() wg.Wait() assert.EqualValues(t, 3, q.Size()) assert.True(t, consume(q, func(_ context.Context, el intRequest) error { assert.EqualValues(t, 3, el) return nil })) require.NoError(t, q.Shutdown(context.Background())) } func TestMemoryQueueDrainWhenShutdown(t *testing.T) { set := newSettings(request.SizerTypeItems, 7) q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, q.Offer(context.Background(), 1)) require.NoError(t, q.Offer(context.Background(), 3)) assert.True(t, consume(q, func(_ context.Context, el intRequest) error { assert.EqualValues(t, 1, el) return nil })) assert.EqualValues(t, 3, q.Size()) require.NoError(t, q.Shutdown(context.Background())) assert.EqualValues(t, 3, q.Size()) assert.True(t, consume(q, func(_ context.Context, el intRequest) error { assert.EqualValues(t, 3, el) return nil })) assert.EqualValues(t, 0, q.Size()) assert.False(t, consume(q, func(context.Context, intRequest) error { t.FailNow(); return nil })) require.NoError(t, q.Shutdown(context.Background())) } func TestMemoryQueueOfferInvalidSize(t *testing.T) { set := newSettings(request.SizerTypeItems, 1) q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.ErrorIs(t, q.Offer(context.Background(), -1), errInvalidSize) require.NoError(t, q.Shutdown(context.Background())) } func TestMemoryQueueRejectOverCapacityElements(t *testing.T) { set := newSettings(request.SizerTypeItems, 1) set.BlockOnOverflow = true q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.ErrorIs(t, q.Offer(context.Background(), 8), errSizeTooLarge) require.NoError(t, q.Shutdown(context.Background())) } func TestMemoryQueueOfferZeroSize(t *testing.T) { set := newSettings(request.SizerTypeItems, 1) q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, q.Offer(context.Background(), 0)) require.NoError(t, q.Shutdown(context.Background())) // Because the size 0 is ignored, nothing to drain. assert.False(t, consume(q, func(context.Context, intRequest) error { t.FailNow(); return nil })) } func TestMemoryQueueOverflow(t *testing.T) { set := newSettings(request.SizerTypeItems, 1) q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, q.Offer(context.Background(), 1)) require.ErrorIs(t, q.Offer(context.Background(), 1), ErrQueueIsFull) require.NoError(t, q.Shutdown(context.Background())) } func TestMemoryQueueWaitForResultPassErrorBack(t *testing.T) { wg := sync.WaitGroup{} myErr := errors.New("test error") set := newSettings(request.SizerTypeItems, 100) set.WaitForResult = true q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) wg.Add(1) go func() { defer wg.Done() _, req, done, ok := q.Read(context.Background()) assert.True(t, ok) assert.EqualValues(t, 1, req) done.OnDone(myErr) }() require.ErrorIs(t, q.Offer(context.Background(), intRequest(1)), myErr) require.NoError(t, q.Shutdown(context.Background())) wg.Wait() } func TestMemoryQueueWaitForResultCancelIncomingRequest(t *testing.T) { wg := sync.WaitGroup{} stop := make(chan struct{}) set := newSettings(request.SizerTypeItems, 100) set.WaitForResult = true q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) // Consume async new data. wg.Add(1) go func() { defer wg.Done() _, _, done, ok := q.Read(context.Background()) assert.True(t, ok) <-stop done.OnDone(nil) }() ctx, cancel := context.WithCancel(context.Background()) wg.Add(1) go func() { defer wg.Done() <-time.After(time.Second) cancel() }() require.ErrorIs(t, q.Offer(ctx, intRequest(1)), context.Canceled) close(stop) require.NoError(t, q.Shutdown(context.Background())) wg.Wait() } func TestMemoryQueueWaitForResultSizeAndCapacity(t *testing.T) { wg := sync.WaitGroup{} stop := make(chan struct{}) set := newSettings(request.SizerTypeItems, 100) set.WaitForResult = true q := newMemoryQueue[intRequest](set) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) // Consume async new data. wg.Add(1) go func() { defer wg.Done() _, _, done, ok := q.Read(context.Background()) assert.True(t, ok) <-stop done.OnDone(nil) }() assert.EqualValues(t, 0, q.Size()) assert.EqualValues(t, 100, q.Capacity()) wg.Add(1) go func() { defer wg.Done() assert.NoError(t, q.Offer(context.Background(), intRequest(1))) }() assert.Eventually(t, func() bool { return q.Size() == 1 }, 1*time.Second, 10*time.Millisecond) assert.EqualValues(t, 100, q.Capacity()) close(stop) require.NoError(t, q.Shutdown(context.Background())) wg.Wait() } func BenchmarkMemoryQueueWaitForResult(b *testing.B) { wg := sync.WaitGroup{} consumed := &atomic.Int64{} set := newSettings(request.SizerTypeItems, 100) set.WaitForResult = true q := newMemoryQueue[intRequest](set) require.NoError(b, q.Start(context.Background(), componenttest.NewNopHost())) // Consume async new data. wg.Add(1) go func() { defer wg.Done() for { _, req, done, ok := q.Read(context.Background()) if !ok { return } consumed.Add(int64(req)) done.OnDone(nil) } }() b.ReportAllocs() for b.Loop() { for range 100 { require.NoError(b, q.Offer(context.Background(), intRequest(1))) } } require.NoError(b, q.Shutdown(context.Background())) assert.Equal(b, int64(b.N)*100, consumed.Load()) } func consume[T any](q readableQueue[T], consumeFunc func(context.Context, T) error) bool { ctx, req, done, ok := q.Read(context.Background()) if !ok { return false } done.OnDone(consumeFunc(ctx, req)) return true } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/meta.pb.go000066400000000000000000000210121511331344600302670ustar00rootroot00000000000000// Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.26.0 // protoc v3.21.6 // source: exporter/exporterhelper/internal/queue/meta.proto package queue import ( reflect "reflect" sync "sync" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) const ( // Verify that this generated code is sufficiently up-to-date. _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) // Verify that runtime/protoimpl is sufficiently up-to-date. _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) // PersistentMetadata holds all persistent metadata for the queue. // The items and bytes sizes are recorded explicitly, // the requests size can be calculated as (write_index - read_index + len(currently_dispatched_items)). type PersistentMetadata struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields // Current total items size of the queue. ItemsSize int64 `protobuf:"fixed64,1,opt,name=items_size,json=itemsSize,proto3" json:"items_size,omitempty"` // Current total bytes size of the queue. BytesSize int64 `protobuf:"fixed64,2,opt,name=bytes_size,json=bytesSize,proto3" json:"bytes_size,omitempty"` // Index of the next item to be read from the queue. ReadIndex uint64 `protobuf:"fixed64,3,opt,name=read_index,json=readIndex,proto3" json:"read_index,omitempty"` // Index where the next item will be written to the queue. WriteIndex uint64 `protobuf:"fixed64,4,opt,name=write_index,json=writeIndex,proto3" json:"write_index,omitempty"` // List of item indices currently being processed by consumers. CurrentlyDispatchedItems []uint64 `protobuf:"fixed64,5,rep,packed,name=currently_dispatched_items,json=currentlyDispatchedItems,proto3" json:"currently_dispatched_items,omitempty"` } func (x *PersistentMetadata) Reset() { *x = PersistentMetadata{} if protoimpl.UnsafeEnabled { mi := &file_exporter_exporterhelper_internal_queue_meta_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } func (x *PersistentMetadata) String() string { return protoimpl.X.MessageStringOf(x) } func (*PersistentMetadata) ProtoMessage() {} func (x *PersistentMetadata) ProtoReflect() protoreflect.Message { mi := &file_exporter_exporterhelper_internal_queue_meta_proto_msgTypes[0] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms } return mi.MessageOf(x) } // Deprecated: Use PersistentMetadata.ProtoReflect.Descriptor instead. func (*PersistentMetadata) Descriptor() ([]byte, []int) { return file_exporter_exporterhelper_internal_queue_meta_proto_rawDescGZIP(), []int{0} } func (x *PersistentMetadata) GetItemsSize() int64 { if x != nil { return x.ItemsSize } return 0 } func (x *PersistentMetadata) GetBytesSize() int64 { if x != nil { return x.BytesSize } return 0 } func (x *PersistentMetadata) GetReadIndex() uint64 { if x != nil { return x.ReadIndex } return 0 } func (x *PersistentMetadata) GetWriteIndex() uint64 { if x != nil { return x.WriteIndex } return 0 } func (x *PersistentMetadata) GetCurrentlyDispatchedItems() []uint64 { if x != nil { return x.CurrentlyDispatchedItems } return nil } var File_exporter_exporterhelper_internal_queue_meta_proto protoreflect.FileDescriptor var file_exporter_exporterhelper_internal_queue_meta_proto_rawDesc = []byte{ 0x0a, 0x31, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x2f, 0x6d, 0x65, 0x74, 0x61, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x3e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x2e, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x71, 0x75, 0x65, 0x75, 0x65, 0x22, 0xd0, 0x01, 0x0a, 0x12, 0x50, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x10, 0x52, 0x09, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x10, 0x52, 0x09, 0x62, 0x79, 0x74, 0x65, 0x73, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x72, 0x65, 0x61, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x06, 0x52, 0x09, 0x72, 0x65, 0x61, 0x64, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1f, 0x0a, 0x0b, 0x77, 0x72, 0x69, 0x74, 0x65, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x06, 0x52, 0x0a, 0x77, 0x72, 0x69, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x3c, 0x0a, 0x1a, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x5f, 0x64, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x06, 0x52, 0x18, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x6c, 0x79, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x73, 0x42, 0x46, 0x5a, 0x44, 0x67, 0x6f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x74, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x2f, 0x65, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x72, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x71, 0x75, 0x65, 0x75, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( file_exporter_exporterhelper_internal_queue_meta_proto_rawDescOnce sync.Once file_exporter_exporterhelper_internal_queue_meta_proto_rawDescData = file_exporter_exporterhelper_internal_queue_meta_proto_rawDesc ) func file_exporter_exporterhelper_internal_queue_meta_proto_rawDescGZIP() []byte { file_exporter_exporterhelper_internal_queue_meta_proto_rawDescOnce.Do(func() { file_exporter_exporterhelper_internal_queue_meta_proto_rawDescData = protoimpl.X.CompressGZIP(file_exporter_exporterhelper_internal_queue_meta_proto_rawDescData) }) return file_exporter_exporterhelper_internal_queue_meta_proto_rawDescData } var file_exporter_exporterhelper_internal_queue_meta_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_exporter_exporterhelper_internal_queue_meta_proto_goTypes = []interface{}{ (*PersistentMetadata)(nil), // 0: opentelemetry.collector.exporter.exporterhelper.internal.queue.PersistentMetadata } var file_exporter_exporterhelper_internal_queue_meta_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type 0, // [0:0] is the sub-list for method input_type 0, // [0:0] is the sub-list for extension type_name 0, // [0:0] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } func init() { file_exporter_exporterhelper_internal_queue_meta_proto_init() } func file_exporter_exporterhelper_internal_queue_meta_proto_init() { if File_exporter_exporterhelper_internal_queue_meta_proto != nil { return } if !protoimpl.UnsafeEnabled { file_exporter_exporterhelper_internal_queue_meta_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PersistentMetadata); i { case 0: return &v.state case 1: return &v.sizeCache case 2: return &v.unknownFields default: return nil } } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_exporter_exporterhelper_internal_queue_meta_proto_rawDesc, NumEnums: 0, NumMessages: 1, NumExtensions: 0, NumServices: 0, }, GoTypes: file_exporter_exporterhelper_internal_queue_meta_proto_goTypes, DependencyIndexes: file_exporter_exporterhelper_internal_queue_meta_proto_depIdxs, MessageInfos: file_exporter_exporterhelper_internal_queue_meta_proto_msgTypes, }.Build() File_exporter_exporterhelper_internal_queue_meta_proto = out.File file_exporter_exporterhelper_internal_queue_meta_proto_rawDesc = nil file_exporter_exporterhelper_internal_queue_meta_proto_goTypes = nil file_exporter_exporterhelper_internal_queue_meta_proto_depIdxs = nil } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/meta.proto000066400000000000000000000015511511331344600304330ustar00rootroot00000000000000syntax = "proto3"; package opentelemetry.collector.exporter.exporterhelper.internal.queue; option go_package = "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue"; // PersistentMetadata holds all persistent metadata for the queue. // The items and bytes sizes are recorded explicitly, // the requests size can be calculated as (write_index - read_index + len(currently_dispatched_items)). message PersistentMetadata{ // Current total items size of the queue. sfixed64 items_size = 1; // Current total bytes size of the queue. sfixed64 bytes_size = 2; // Index of the next item to be read from the queue. fixed64 read_index = 3; // Index where the next item will be written to the queue. fixed64 write_index = 4; // List of item indices currently being processed by consumers. repeated fixed64 currently_dispatched_items = 5; } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/obs_queue.go000066400000000000000000000064251511331344600307430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadata" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/pipeline" ) const ( // ExporterKey used to identify exporters in metrics and traces. exporterKey = "exporter" // DataTypeKey used to identify the data type in the queue size metric. dataTypeKey = "data_type" ) // obsQueue is a helper to add observability to a queue. type obsQueue[T request.Request] struct { Queue[T] tb *metadata.TelemetryBuilder metricAttr metric.MeasurementOption enqueueFailedInst metric.Int64Counter queueBatchSizeInst metric.Int64Histogram queueBatchSizeBytesInst metric.Int64Histogram tracer trace.Tracer } func newObsQueue[T request.Request](set Settings[T], delegate Queue[T]) (Queue[T], error) { tb, err := metadata.NewTelemetryBuilder(set.Telemetry) if err != nil { return nil, err } exporterAttr := attribute.String(exporterKey, set.ID.String()) asyncAttr := metric.WithAttributeSet(attribute.NewSet(exporterAttr, attribute.String(dataTypeKey, set.Signal.String()))) err = tb.RegisterExporterQueueSizeCallback(func(_ context.Context, o metric.Int64Observer) error { o.Observe(delegate.Size(), asyncAttr) return nil }) if err != nil { return nil, err } err = tb.RegisterExporterQueueCapacityCallback(func(_ context.Context, o metric.Int64Observer) error { o.Observe(delegate.Capacity(), asyncAttr) return nil }) if err != nil { return nil, err } tracer := metadata.Tracer(set.Telemetry) or := &obsQueue[T]{ Queue: delegate, tb: tb, metricAttr: metric.WithAttributeSet(attribute.NewSet(exporterAttr)), tracer: tracer, } switch set.Signal { case pipeline.SignalTraces: or.enqueueFailedInst = tb.ExporterEnqueueFailedSpans case pipeline.SignalMetrics: or.enqueueFailedInst = tb.ExporterEnqueueFailedMetricPoints case pipeline.SignalLogs: or.enqueueFailedInst = tb.ExporterEnqueueFailedLogRecords } or.queueBatchSizeInst = tb.ExporterQueueBatchSendSize or.queueBatchSizeBytesInst = tb.ExporterQueueBatchSendSizeBytes return or, nil } func (or *obsQueue[T]) Shutdown(ctx context.Context) error { defer or.tb.Shutdown() return or.Queue.Shutdown(ctx) } func (or *obsQueue[T]) Offer(ctx context.Context, req T) error { // Have to read the number of items before sending the request since the request can // be modified by the downstream components like the batcher. numItems := req.ItemsCount() or.queueBatchSizeInst.Record(ctx, int64(numItems), or.metricAttr) or.queueBatchSizeBytesInst.Record(ctx, int64(req.BytesSize()), or.metricAttr) ctx, span := or.tracer.Start(ctx, "exporter/enqueue") err := or.Queue.Offer(ctx, req) span.End() // No metrics recorded for profiles, remove enqueueFailedInst check with nil when profiles metrics available. if err != nil && or.enqueueFailedInst != nil { or.enqueueFailedInst.Add(ctx, int64(numItems), or.metricAttr) } return err } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/obs_queue_test.go000066400000000000000000000244151511331344600320010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue import ( "context" "errors" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadatatest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pipeline" ) var exporterID = component.NewID(exportertest.NopType) type fakeQueue[T any] struct { Queue[T] offerErr error size int64 capacity int64 } func (fq *fakeQueue[T]) Size() int64 { return fq.size } func (fq *fakeQueue[T]) Capacity() int64 { return fq.capacity } func (fq *fakeQueue[T]) Offer(context.Context, T) error { return fq.offerErr } func newFakeQueue[T request.Request](offerErr error, size, capacity int64) Queue[T] { return &fakeQueue[T]{offerErr: offerErr, size: size, capacity: capacity} } func TestObsQueueLogsSizeCapacity(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalLogs, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](nil, 7, 9)) require.NoError(t, err) require.NoError(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 2})) metadatatest.AssertEqualExporterQueueSize(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String()), attribute.String(dataTypeKey, pipeline.SignalLogs.String())), Value: int64(7), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualExporterQueueCapacity(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String()), attribute.String(dataTypeKey, pipeline.SignalLogs.String())), Value: int64(9), }, }, metricdatatest.IgnoreTimestamp()) } func TestObsQueueLogsFailure(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalLogs, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](errors.New("my error"), 7, 9)) require.NoError(t, err) require.Error(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 2})) metadatatest.AssertEqualExporterEnqueueFailedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String())), Value: int64(2), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestObsQueueTracesSizeCapacity(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalTraces, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](nil, 17, 19)) require.NoError(t, err) require.NoError(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 12})) metadatatest.AssertEqualExporterQueueSize(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String()), attribute.String(dataTypeKey, pipeline.SignalTraces.String())), Value: int64(17), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualExporterQueueCapacity(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String()), attribute.String(dataTypeKey, pipeline.SignalTraces.String())), Value: int64(19), }, }, metricdatatest.IgnoreTimestamp()) } func TestObsQueueTracesFailure(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalTraces, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](errors.New("my error"), 0, 0)) require.NoError(t, err) require.Error(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 12})) metadatatest.AssertEqualExporterEnqueueFailedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String())), Value: int64(12), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestObsQueueMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalMetrics, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](nil, 27, 29)) require.NoError(t, err) require.NoError(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 22})) metadatatest.AssertEqualExporterQueueSize(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String()), attribute.String(dataTypeKey, pipeline.SignalMetrics.String())), Value: int64(27), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualExporterQueueCapacity(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String()), attribute.String(dataTypeKey, pipeline.SignalMetrics.String())), Value: int64(29), }, }, metricdatatest.IgnoreTimestamp()) } func TestObsQueueMetricsFailure(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalMetrics, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](errors.New("my error"), 0, 0)) require.NoError(t, err) require.Error(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 22})) metadatatest.AssertEqualExporterEnqueueFailedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String())), Value: int64(22), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestObsQueueLogsBatchSize(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalLogs, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](nil, 7, 9)) require.NoError(t, err) require.NoError(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 2, Bytes: 100})) metadatatest.AssertEqualExporterQueueBatchSendSize(t, tt, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String())), Count: 1, Bounds: []float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}, BucketCounts: []uint64{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Min: metricdata.NewExtrema[int64](2), Max: metricdata.NewExtrema[int64](2), Sum: 2, }, }, metricdatatest.IgnoreTimestamp()) } func TestObsQueueTracesBatchSize(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalTraces, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](nil, 17, 19)) require.NoError(t, err) require.NoError(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 12, Bytes: 200})) metadatatest.AssertEqualExporterQueueBatchSendSize(t, tt, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String())), Count: 1, Bounds: []float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}, BucketCounts: []uint64{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Min: metricdata.NewExtrema[int64](12), Max: metricdata.NewExtrema[int64](12), Sum: 12, }, }, metricdatatest.IgnoreTimestamp()) } func TestObsQueueMetricsBatchSize(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := newObsQueue[request.Request](Settings[request.Request]{ Signal: pipeline.SignalMetrics, ID: exporterID, Telemetry: tt.NewTelemetrySettings(), }, newFakeQueue[request.Request](nil, 27, 29)) require.NoError(t, err) require.NoError(t, te.Offer(context.Background(), &requesttest.FakeRequest{Items: 22, Bytes: 300})) metadatatest.AssertEqualExporterQueueBatchSendSize(t, tt, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(exporterKey, exporterID.String())), Count: 1, Bounds: []float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}, BucketCounts: []uint64{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Min: metricdata.NewExtrema[int64](22), Max: metricdata.NewExtrema[int64](22), Sum: 22, }, }, metricdatatest.IgnoreTimestamp()) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/persistent_queue.go000066400000000000000000000470701511331344600323610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" import ( "context" "encoding/binary" "errors" "fmt" "strconv" "sync" "go.uber.org/zap" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/experr" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/extension/xextension/storage" "go.opentelemetry.io/collector/pipeline" ) const ( zapKey = "key" zapErrorCount = "errorCount" zapNumberOfItems = "numberOfItems" legacyReadIndexKey = "ri" legacyWriteIndexKey = "wi" legacyCurrentlyDispatchedItemsKey = "di" // metadataKey is the new single key for all queue metadata. metadataKey = "qmv0" ) var ( errValueNotSet = errors.New("value not set") errInvalidValue = errors.New("invalid value") errNoStorageClient = errors.New("no storage client extension found") errWrongExtensionType = errors.New("requested extension is not a storage extension") ) var indexDonePool = sync.Pool{ New: func() any { return &indexDone{} }, } // persistentQueue provides a persistent queue implementation backed by file storage extension // // Write index describes the position at which next item is going to be stored. // Read index describes which item needs to be read next. // When Write index = Read index, no elements are in the queue. // // The items currently dispatched by consumers are not deleted until the processing is finished. // Their list is stored under a separate key. // // โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€file extension-backed queueโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” // โ”‚ โ”‚ // โ”‚ โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ” โ”‚ // โ”‚ n+1 โ”‚ n โ”‚ ... โ”‚ 4 โ”‚ โ”‚ 3 โ”‚ โ”‚ 2 โ”‚ โ”‚ 1 โ”‚ โ”‚ // โ”‚ โ””โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”˜ โ””โ”€xโ”€โ”˜ โ””โ”€|โ”€โ”˜ โ””โ”€xโ”€โ”˜ โ”‚ // โ”‚ x | x โ”‚ // โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€xโ”€โ”€โ”€โ”€โ”€|โ”€โ”€โ”€โ”€โ”€xโ”€โ”€โ”€โ”€โ”€โ”˜ // โ–ฒ โ–ฒ x | x // โ”‚ โ”‚ x | xxxx deleted // โ”‚ โ”‚ x | // write read x โ””โ”€โ”€ currently dispatched item // index index x // xxxx deleted type persistentQueue[T request.Request] struct { logger *zap.Logger client storage.Client encoding Encoding[T] capacity int64 sizerType request.SizerType activeSizer request.Sizer itemsSizer request.Sizer bytesSizer request.Sizer storageID component.ID id component.ID signal pipeline.Signal // mu guards everything declared below. mu sync.Mutex hasMoreElements *sync.Cond hasMoreSpace *cond metadata PersistentMetadata refClient int64 stopped bool blockOnOverflow bool } // newPersistentQueue creates a new queue backed by file storage; name and signal must be a unique combination that identifies the queue storage func newPersistentQueue[T request.Request](set Settings[T]) readableQueue[T] { pq := &persistentQueue[T]{ logger: set.Telemetry.Logger, encoding: set.Encoding, capacity: set.Capacity, sizerType: set.SizerType, activeSizer: request.NewSizer(set.SizerType), itemsSizer: request.NewItemsSizer(), bytesSizer: request.NewBytesSizer(), storageID: *set.StorageID, id: set.ID, signal: set.Signal, blockOnOverflow: set.BlockOnOverflow, } pq.hasMoreElements = sync.NewCond(&pq.mu) pq.hasMoreSpace = newCond(&pq.mu) return pq } // Start starts the persistentQueue with the given number of consumers. func (pq *persistentQueue[T]) Start(ctx context.Context, host component.Host) error { storageClient, err := toStorageClient(ctx, pq.storageID, host, pq.id, pq.signal) if err != nil { return err } pq.initClient(ctx, storageClient) return nil } func (pq *persistentQueue[T]) Size() int64 { pq.mu.Lock() defer pq.mu.Unlock() return pq.internalSize() } func (pq *persistentQueue[T]) internalSize() int64 { switch pq.sizerType { case request.SizerTypeBytes: return pq.metadata.BytesSize case request.SizerTypeItems: return pq.metadata.ItemsSize default: return pq.requestSize() } } func (pq *persistentQueue[T]) requestSize() int64 { return int64(pq.metadata.WriteIndex-pq.metadata.ReadIndex) + int64(len(pq.metadata.CurrentlyDispatchedItems)) } func (pq *persistentQueue[T]) Capacity() int64 { return pq.capacity } func (pq *persistentQueue[T]) initClient(ctx context.Context, client storage.Client) { pq.client = client // Start with a reference 1 which is the reference we use for the producer goroutines and initialization. pq.refClient = 1 // Try to load from new consolidated metadata first err := pq.loadQueueMetadata(ctx) switch { case err == nil: pq.enqueueNotDispatchedReqs(ctx, pq.metadata.CurrentlyDispatchedItems) pq.metadata.CurrentlyDispatchedItems = nil case !errors.Is(err, errValueNotSet): pq.logger.Error("Failed getting metadata, starting with new ones", zap.Error(err)) pq.metadata = PersistentMetadata{} default: pq.logger.Info("New queue metadata key not found, attempting to load legacy format.") pq.loadLegacyMetadata(ctx) } } // loadQueueMetadata loads queue metadata from the consolidated key func (pq *persistentQueue[T]) loadQueueMetadata(ctx context.Context) error { buf, err := pq.client.Get(ctx, metadataKey) if err != nil { return err } if len(buf) == 0 { return errValueNotSet } if err := proto.Unmarshal(buf, &pq.metadata); err != nil { return err } pq.logger.Info("Loaded queue metadata", zap.Uint64("readIndex", pq.metadata.ReadIndex), zap.Uint64("writeIndex", pq.metadata.WriteIndex), zap.Int64("itemsSize", pq.metadata.ItemsSize), zap.Int64("bytesSize", pq.metadata.BytesSize), zap.Int("dispatchedItems", len(pq.metadata.CurrentlyDispatchedItems))) return nil } // TODO: Remove legacy format support after 6 months (target: December 2025) func (pq *persistentQueue[T]) loadLegacyMetadata(ctx context.Context) { // Fallback to legacy individual keys for backward compatibility riOp := storage.GetOperation(legacyReadIndexKey) wiOp := storage.GetOperation(legacyWriteIndexKey) err := pq.client.Batch(ctx, riOp, wiOp) if err == nil { pq.metadata.ReadIndex, err = bytesToItemIndex(riOp.Value) } if err == nil { pq.metadata.WriteIndex, err = bytesToItemIndex(wiOp.Value) } if err != nil { if errors.Is(err, errValueNotSet) { pq.logger.Info("Initializing new persistent queue") } else { pq.logger.Error("Failed getting read/write index, starting with new ones", zap.Error(err)) } pq.metadata.ReadIndex = 0 pq.metadata.WriteIndex = 0 } pq.retrieveAndEnqueueNotDispatchedReqs(ctx) // Save to a new format and clean up legacy keys metadataBytes, err := proto.Marshal(&pq.metadata) if err != nil { pq.logger.Error("Failed to marshal metadata", zap.Error(err)) return } if err = pq.client.Set(ctx, metadataKey, metadataBytes); err != nil { pq.logger.Error("Failed to persist current metadata to storage", zap.Error(err)) return } if err = pq.client.Batch(ctx, storage.DeleteOperation(legacyReadIndexKey), storage.DeleteOperation(legacyWriteIndexKey), storage.DeleteOperation(legacyCurrentlyDispatchedItemsKey)); err != nil { pq.logger.Warn("Failed to cleanup legacy metadata keys", zap.Error(err)) } else { pq.logger.Info("Successfully migrated to consolidated metadata format") } } func (pq *persistentQueue[T]) Shutdown(ctx context.Context) error { // If the queue is not initialized, there is nothing to shut down. if pq.client == nil { return nil } pq.mu.Lock() defer pq.mu.Unlock() // Mark this queue as stopped, so consumer don't start any more work. pq.stopped = true pq.hasMoreElements.Broadcast() return pq.unrefClient(ctx) } // unrefClient unrefs the client, and closes if no more references. Callers MUST hold the mutex. // This is needed because consumers of the queue may still process the requests while the queue is shutting down or immediately after. func (pq *persistentQueue[T]) unrefClient(ctx context.Context) error { pq.refClient-- if pq.refClient == 0 { return pq.client.Close(ctx) } return nil } // Offer inserts the specified element into this queue if it is possible to do so immediately // without violating capacity restrictions. If success returns no error. // It returns ErrQueueIsFull if no space is currently available. func (pq *persistentQueue[T]) Offer(ctx context.Context, req T) error { pq.mu.Lock() defer pq.mu.Unlock() size := pq.activeSizer.Sizeof(req) for pq.internalSize()+size > pq.capacity { if !pq.blockOnOverflow { return ErrQueueIsFull } if err := pq.hasMoreSpace.Wait(ctx); err != nil { return err } } pq.metadata.ItemsSize += pq.itemsSizer.Sizeof(req) pq.metadata.BytesSize += pq.bytesSizer.Sizeof(req) return pq.putInternal(ctx, req) } // putInternal adds the request to the storage without updating items/bytes sizes. func (pq *persistentQueue[T]) putInternal(ctx context.Context, req T) error { pq.metadata.WriteIndex++ metadataBuf, err := proto.Marshal(&pq.metadata) if err != nil { return err } reqBuf, err := pq.encoding.Marshal(ctx, req) if err != nil { return err } // Carry out a transaction where we both add the item and update the write index ops := []*storage.Operation{ storage.SetOperation(metadataKey, metadataBuf), storage.SetOperation(getItemKey(pq.metadata.WriteIndex-1), reqBuf), } if err := pq.client.Batch(ctx, ops...); err != nil { // At this moment, metadata may be updated in the storage, so we cannot just revert changes to the // metadata, rely on the sizes being fixed on complete draining. return err } pq.hasMoreElements.Signal() return nil } func (pq *persistentQueue[T]) Read(ctx context.Context) (context.Context, T, Done, bool) { pq.mu.Lock() defer pq.mu.Unlock() for { if pq.stopped { var req T return context.Background(), req, nil, false } // Read until either a successful retrieved element or no more elements in the storage. for pq.metadata.ReadIndex != pq.metadata.WriteIndex { index, req, reqCtx, consumed := pq.getNextItem(ctx) // Ensure the used size are in sync when queue is drained. if pq.requestSize() == 0 { pq.metadata.BytesSize = 0 pq.metadata.ItemsSize = 0 } if consumed { id := indexDonePool.Get().(*indexDone) id.reset(index, pq.itemsSizer.Sizeof(req), pq.bytesSizer.Sizeof(req), pq) return reqCtx, req, id, true } // More space available, data was dropped. pq.hasMoreSpace.Signal() } // TODO: Need to change the Queue interface to return an error to allow distinguish between shutdown and context canceled. // Until then use the sync.Cond. pq.hasMoreElements.Wait() } } // getNextItem pulls the next available item from the persistent storage along with its index. Once processing is // finished, the index should be called with onDone to clean up the storage. If no new item is available, // returns false. func (pq *persistentQueue[T]) getNextItem(ctx context.Context) (uint64, T, context.Context, bool) { index := pq.metadata.ReadIndex // Increase here, so even if errors happen below, it always iterates pq.metadata.ReadIndex++ pq.metadata.CurrentlyDispatchedItems = append(pq.metadata.CurrentlyDispatchedItems, index) var req T restoredCtx := context.Background() metadataBytes, err := proto.Marshal(&pq.metadata) if err != nil { return 0, req, restoredCtx, false } getOp := storage.GetOperation(getItemKey(index)) err = pq.client.Batch(ctx, storage.SetOperation(metadataKey, metadataBytes), getOp) if err == nil { restoredCtx, req, err = pq.encoding.Unmarshal(getOp.Value) } if err != nil { pq.logger.Debug("Failed to dispatch item", zap.Error(err)) // We need to make sure that currently dispatched items list is cleaned if err = pq.itemDispatchingFinish(ctx, index); err != nil { pq.logger.Error("Error deleting item from queue", zap.Error(err)) } return 0, req, restoredCtx, false } // Increase the reference count, so the client is not closed while the request is being processed. // The client cannot be closed because we hold the lock since last we checked `stopped`. pq.refClient++ return index, req, restoredCtx, true } // onDone should be called to remove the item of the given index from the queue once processing is finished. func (pq *persistentQueue[T]) onDone(index uint64, itemsSize, bytesSize int64, consumeErr error) { // Delete the item from the persistent storage after it was processed. pq.mu.Lock() // Always unref client even if the consumer is shutdown because we always ref it for every valid request. defer func() { if err := pq.unrefClient(context.Background()); err != nil { pq.logger.Error("Error closing the storage client", zap.Error(err)) } pq.mu.Unlock() }() if experr.IsShutdownErr(consumeErr) { // The queue is shutting down, don't mark the item as dispatched, so it's picked up again after restart. // TODO: Handle partially delivered requests by updating their values in the storage. return } pq.metadata.BytesSize -= bytesSize if pq.metadata.BytesSize < 0 { pq.metadata.BytesSize = 0 } pq.metadata.ItemsSize -= itemsSize if pq.metadata.ItemsSize < 0 { pq.metadata.ItemsSize = 0 } if err := pq.itemDispatchingFinish(context.Background(), index); err != nil { pq.logger.Error("Error deleting item from queue", zap.Error(err)) } // More space available after data are removed from the storage. pq.hasMoreSpace.Signal() } // retrieveAndEnqueueNotDispatchedReqs gets the items for which sending was not finished, cleans the storage // and moves the items at the back of the queue. func (pq *persistentQueue[T]) retrieveAndEnqueueNotDispatchedReqs(ctx context.Context) { var dispatchedItems []uint64 pq.mu.Lock() defer pq.mu.Unlock() pq.logger.Debug("Checking if there are items left for dispatch by consumers") itemKeysBuf, err := pq.client.Get(ctx, legacyCurrentlyDispatchedItemsKey) if err == nil { dispatchedItems, err = bytesToItemIndexArray(itemKeysBuf) } if err != nil { pq.logger.Error("Could not fetch items left for dispatch by consumers", zap.Error(err)) return } pq.enqueueNotDispatchedReqs(ctx, dispatchedItems) } func (pq *persistentQueue[T]) enqueueNotDispatchedReqs(ctx context.Context, dispatchedItems []uint64) { if len(dispatchedItems) == 0 { pq.logger.Debug("No items left for dispatch by consumers") return } pq.logger.Info("Fetching items left for dispatch by consumers", zap.Int(zapNumberOfItems, len(dispatchedItems))) retrieveBatch := make([]*storage.Operation, len(dispatchedItems)) cleanupBatch := make([]*storage.Operation, len(dispatchedItems)) for i, it := range dispatchedItems { key := getItemKey(it) retrieveBatch[i] = storage.GetOperation(key) cleanupBatch[i] = storage.DeleteOperation(key) } retrieveErr := pq.client.Batch(ctx, retrieveBatch...) cleanupErr := pq.client.Batch(ctx, cleanupBatch...) if cleanupErr != nil { pq.logger.Debug("Failed cleaning items left by consumers", zap.Error(cleanupErr)) } if retrieveErr != nil { pq.logger.Warn("Failed retrieving items left by consumers", zap.Error(retrieveErr)) return } errCount := 0 for _, op := range retrieveBatch { if op.Value == nil { pq.logger.Warn("Failed retrieving item", zap.String(zapKey, op.Key), zap.Error(errValueNotSet)) continue } reqCtx, req, err := pq.encoding.Unmarshal(op.Value) // If error happened or item is nil, it will be efficiently ignored if err != nil { pq.logger.Warn("Failed unmarshalling item", zap.String(zapKey, op.Key), zap.Error(err)) continue } if pq.putInternal(reqCtx, req) != nil { //nolint:contextcheck errCount++ } } if errCount > 0 { pq.logger.Error("Errors occurred while moving items for dispatching back to queue", zap.Int(zapNumberOfItems, len(retrieveBatch)), zap.Int(zapErrorCount, errCount)) } else { pq.logger.Info("Moved items for dispatching back to queue", zap.Int(zapNumberOfItems, len(retrieveBatch))) } } // itemDispatchingFinish removes the item from the list of currently dispatched items and deletes it from the persistent queue func (pq *persistentQueue[T]) itemDispatchingFinish(ctx context.Context, index uint64) error { lenCDI := len(pq.metadata.CurrentlyDispatchedItems) for i := range lenCDI { if pq.metadata.CurrentlyDispatchedItems[i] == index { pq.metadata.CurrentlyDispatchedItems[i] = pq.metadata.CurrentlyDispatchedItems[lenCDI-1] pq.metadata.CurrentlyDispatchedItems = pq.metadata.CurrentlyDispatchedItems[:lenCDI-1] break } } // Ensure the used size are in sync when queue is drained. if pq.requestSize() == 0 { pq.metadata.BytesSize = 0 pq.metadata.ItemsSize = 0 } metadataBytes, err := proto.Marshal(&pq.metadata) if err != nil { return err } setOp := storage.SetOperation(metadataKey, metadataBytes) deleteOp := storage.DeleteOperation(getItemKey(index)) err = pq.client.Batch(ctx, setOp, deleteOp) if err == nil { // Everything ok, exit return nil } // got an error, try to gracefully handle it pq.logger.Warn("Failed updating currently dispatched items, trying to delete the item first", zap.Error(err)) if err = pq.client.Batch(ctx, deleteOp); err != nil { // Return an error here, as this indicates an issue with the underlying storage medium return fmt.Errorf("failed deleting item from queue, got error from storage: %w", err) } if err = pq.client.Batch(ctx, setOp); err != nil { // even if this fails, we still have the right dispatched items in memory // at worst, we'll have the wrong list in storage, and we'll discard the nonexistent items during startup return fmt.Errorf("failed updating currently dispatched items, but deleted item successfully: %w", err) } return nil } func toStorageClient(ctx context.Context, storageID component.ID, host component.Host, ownerID component.ID, signal pipeline.Signal) (storage.Client, error) { ext, found := host.GetExtensions()[storageID] if !found { return nil, errNoStorageClient } storageExt, ok := ext.(storage.Extension) if !ok { return nil, errWrongExtensionType } return storageExt.GetClient(ctx, component.KindExporter, ownerID, signal.String()) } func getItemKey(index uint64) string { return strconv.FormatUint(index, 10) } func bytesToItemIndex(buf []byte) (uint64, error) { if buf == nil { return uint64(0), errValueNotSet } // The sizeof uint64 in binary is 8. if len(buf) < 8 { return 0, errInvalidValue } return binary.LittleEndian.Uint64(buf), nil } func bytesToItemIndexArray(buf []byte) ([]uint64, error) { if len(buf) == 0 { return nil, nil } // The sizeof uint32 in binary is 4. if len(buf) < 4 { return nil, errInvalidValue } size := int(binary.LittleEndian.Uint32(buf)) if size == 0 { return nil, nil } buf = buf[4:] // The sizeof uint64 in binary is 8, so we need to have size*8 bytes. if len(buf) < size*8 { return nil, errInvalidValue } val := make([]uint64, size) for i := range size { val[i] = binary.LittleEndian.Uint64(buf) buf = buf[8:] } return val, nil } type indexDone struct { index uint64 itemsSize int64 bytesSize int64 queue interface { onDone(uint64, int64, int64, error) } } func (id *indexDone) reset(index uint64, itemsSize, bytesSize int64, queue interface { onDone(uint64, int64, int64, error) }, ) { id.index = index id.itemsSize = itemsSize id.bytesSize = bytesSize id.queue = queue } func (id *indexDone) OnDone(err error) { id.queue.onDone(id.index, id.itemsSize, id.bytesSize, err) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/persistent_queue_test.go000066400000000000000000001054461511331344600334220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue import ( "context" "encoding/binary" "errors" "fmt" "strconv" "sync" "sync/atomic" "syscall" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/experr" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/hosttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/storagetest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/extension/xextension/storage" "go.opentelemetry.io/collector/pipeline" ) type intRequest int64 func (i intRequest) MergeSplit(context.Context, int, request.SizerType, request.Request) ([]request.Request, error) { panic("implement me") } func (i intRequest) ItemsCount() int { return int(i) } func (i intRequest) BytesSize() int { return int(i) * 10 } type int64Encoding struct { rc ReferenceCounter[intRequest] } func (int64Encoding) Marshal(_ context.Context, val intRequest) ([]byte, error) { str := strconv.FormatInt(int64(val), 10) return []byte(str), nil } func (ie int64Encoding) Unmarshal(bytes []byte) (context.Context, intRequest, error) { val, err := strconv.ParseInt(string(bytes), 10, 64) if err != nil { return context.Background(), 0, err } ie.rc.Ref(intRequest(val)) return context.Background(), intRequest(val), nil } func newFakeBoundedStorageClient(maxSizeInBytes int) *fakeBoundedStorageClient { return &fakeBoundedStorageClient{ st: map[string][]byte{}, maxSizeInBytes: maxSizeInBytes, } } // fakeBoundedStorageClient storage client mimics the behavior of actual storage engines with limited // storage space available in general, real storage engines often have a per-write-transaction // storage overhead, needing to keep both the old and the new value stored until the transaction // is committed this is useful for testing the persistent queue behavior with a full disk. type fakeBoundedStorageClient struct { maxSizeInBytes int st map[string][]byte sizeInBytes int mux sync.Mutex } func (m *fakeBoundedStorageClient) Get(ctx context.Context, key string) ([]byte, error) { op := storage.GetOperation(key) if err := m.Batch(ctx, op); err != nil { return nil, err } return op.Value, nil } func (m *fakeBoundedStorageClient) Set(ctx context.Context, key string, value []byte) error { return m.Batch(ctx, storage.SetOperation(key, value)) } func (m *fakeBoundedStorageClient) Delete(ctx context.Context, key string) error { return m.Batch(ctx, storage.DeleteOperation(key)) } func (m *fakeBoundedStorageClient) Close(context.Context) error { return nil } func (m *fakeBoundedStorageClient) Batch(_ context.Context, ops ...*storage.Operation) error { m.mux.Lock() defer m.mux.Unlock() totalAdded, totalRemoved := m.getTotalSizeChange(ops) // the assumption here is that the new data needs to coexist with the old data on disk // for the transaction to succeed // this seems to be true for the file storage extension at least if m.sizeInBytes+totalAdded-totalRemoved > m.maxSizeInBytes { return fmt.Errorf("insufficient space available: %w", syscall.ENOSPC) } for _, op := range ops { switch op.Type { case storage.Get: op.Value = m.st[op.Key] case storage.Set: m.st[op.Key] = op.Value case storage.Delete: delete(m.st, op.Key) default: return errors.New("wrong operation type") } } m.sizeInBytes += totalAdded - totalRemoved return nil } func (m *fakeBoundedStorageClient) SetMaxSizeInBytes(newMaxSize int) { m.mux.Lock() defer m.mux.Unlock() m.maxSizeInBytes = newMaxSize } func (m *fakeBoundedStorageClient) GetSizeInBytes() int { m.mux.Lock() defer m.mux.Unlock() return m.sizeInBytes } func (m *fakeBoundedStorageClient) getTotalSizeChange(ops []*storage.Operation) (totalAdded, totalRemoved int) { totalAdded, totalRemoved = 0, 0 for _, op := range ops { switch op.Type { case storage.Set: if oldValue, ok := m.st[op.Key]; ok { totalRemoved += len(oldValue) } else { totalAdded += len(op.Key) } totalAdded += len(op.Value) case storage.Delete: if value, ok := m.st[op.Key]; ok { totalRemoved += len(op.Key) totalRemoved += len(value) } default: } } return totalAdded, totalRemoved } func newFakeStorageClientWithErrors(errors []error) *fakeStorageClientWithErrors { return &fakeStorageClientWithErrors{ errors: errors, } } // this storage client just returns errors from a list in order // used for testing error handling type fakeStorageClientWithErrors struct { errors []error nextErrorIndex int mux sync.Mutex } func (m *fakeStorageClientWithErrors) Get(ctx context.Context, key string) ([]byte, error) { op := storage.GetOperation(key) err := m.Batch(ctx, op) if err != nil { return nil, err } return op.Value, nil } func (m *fakeStorageClientWithErrors) Set(ctx context.Context, key string, value []byte) error { return m.Batch(ctx, storage.SetOperation(key, value)) } func (m *fakeStorageClientWithErrors) Delete(ctx context.Context, key string) error { return m.Batch(ctx, storage.DeleteOperation(key)) } func (m *fakeStorageClientWithErrors) Close(context.Context) error { return nil } func (m *fakeStorageClientWithErrors) Batch(context.Context, ...*storage.Operation) error { m.mux.Lock() defer m.mux.Unlock() if m.nextErrorIndex >= len(m.errors) { return nil } m.nextErrorIndex++ return m.errors[m.nextErrorIndex-1] } func (m *fakeStorageClientWithErrors) Reset() { m.mux.Lock() defer m.mux.Unlock() m.nextErrorIndex = 0 } type fakeReferenceCounter struct { mu sync.Mutex ref int64 } func (f *fakeReferenceCounter) Ref(intRequest) { f.mu.Lock() defer f.mu.Unlock() f.ref++ } func (f *fakeReferenceCounter) Unref(intRequest) { f.mu.Lock() defer f.mu.Unlock() f.ref-- if f.ref < 0 { panic("this should never happen") } } func newSettings(sizerType request.SizerType, capacity int64) Settings[intRequest] { rc := &fakeReferenceCounter{} return Settings[intRequest]{ ReferenceCounter: rc, SizerType: sizerType, Capacity: capacity, Signal: pipeline.SignalTraces, Encoding: int64Encoding{rc}, ID: component.NewID(exportertest.NopType), Telemetry: componenttest.NewNopTelemetrySettings(), } } func newSettingsWithStorage(sizerType request.SizerType, capacity int64) Settings[intRequest] { set := newSettings(sizerType, capacity) storageID := component.ID{} set.StorageID = &storageID return set } func createTestPersistentQueueWithClient(client storage.Client) *persistentQueue[intRequest] { pq := newPersistentQueue[intRequest](newSettingsWithStorage(request.SizerTypeRequests, 1000)).(*persistentQueue[intRequest]) pq.initClient(context.Background(), client) return pq } func createTestPersistentQueueWithRequestsSizer(tb testing.TB, ext storage.Extension, capacity int64) *persistentQueue[intRequest] { return createTestPersistentQueue(tb, ext, request.SizerTypeRequests, capacity) } func createTestPersistentQueueWithItemsSizer(tb testing.TB, ext storage.Extension, capacity int64) *persistentQueue[intRequest] { return createTestPersistentQueue(tb, ext, request.SizerTypeItems, capacity) } func createTestPersistentQueue(tb testing.TB, ext storage.Extension, sizerType request.SizerType, capacity int64) *persistentQueue[intRequest] { pq := newPersistentQueue[intRequest](newSettingsWithStorage(sizerType, capacity)) require.NoError(tb, pq.Start(context.Background(), hosttest.NewHost(map[component.ID]component.Component{{}: ext}))) return pq.(*persistentQueue[intRequest]) } func TestPersistentQueue_FullCapacity(t *testing.T) { tests := []struct { name string sizerType request.SizerType capacity int64 sizeMultiplier int64 }{ { name: "requests_capacity", sizerType: request.SizerTypeRequests, capacity: 5, sizeMultiplier: 1, }, { name: "items_capacity", sizerType: request.SizerTypeItems, capacity: 55, sizeMultiplier: 10, }, { name: "bytes_capacity", sizerType: request.SizerTypeBytes, capacity: 550, sizeMultiplier: 100, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ext := storagetest.NewMockStorageExtension(nil) pq := createTestPersistentQueue(t, ext, tt.sizerType, tt.capacity) assert.Equal(t, int64(0), pq.Size()) // The consumer picks first request. Wait until the consumer is blocked on done. require.NoError(t, pq.Offer(context.Background(), intRequest(10))) assert.Equal(t, 1*tt.sizeMultiplier, pq.Size()) _, _, done, ok := pq.Read(context.Background()) assert.True(t, ok) done.OnDone(nil) assert.Equal(t, int64(0), pq.Size()) for i := range 10 { result := pq.Offer(context.Background(), intRequest(10)) if i < 5 { require.NoError(t, result) } else { require.ErrorIs(t, result, ErrQueueIsFull) } } assert.Equal(t, 5*tt.sizeMultiplier, pq.Size()) require.NoError(t, pq.Shutdown(context.Background())) }) } } func TestPersistentQueue_Shutdown(t *testing.T) { ext := storagetest.NewMockStorageExtension(nil) pq := createTestPersistentQueue(t, ext, request.SizerTypeRequests, 1001) req := intRequest(10) for range 1000 { require.NoError(t, pq.Offer(context.Background(), req)) } require.NoError(t, pq.Shutdown(context.Background())) } func TestPersistentQueue_ConsumersProducers(t *testing.T) { cases := []struct { numMessagesProduced int numConsumers int }{ { numMessagesProduced: 1, numConsumers: 1, }, { numMessagesProduced: 100, numConsumers: 1, }, { numMessagesProduced: 100, numConsumers: 3, }, { numMessagesProduced: 1, numConsumers: 100, }, { numMessagesProduced: 100, numConsumers: 100, }, } for _, c := range cases { t.Run(fmt.Sprintf("#messages: %d #consumers: %d", c.numMessagesProduced, c.numConsumers), func(t *testing.T) { consumed := &atomic.Int64{} pq := newPersistentQueue[intRequest](newSettingsWithStorage(request.SizerTypeRequests, 1000)) aq := newAsyncQueue[intRequest](pq, c.numConsumers, func(_ context.Context, _ intRequest, done Done) { consumed.Add(int64(1)) done.OnDone(nil) }, nil) require.NoError(t, aq.Start(context.Background(), hosttest.NewHost(map[component.ID]component.Component{ {}: storagetest.NewMockStorageExtension(nil), }, ))) for i := 0; i < c.numMessagesProduced; i++ { require.NoError(t, aq.Offer(context.Background(), intRequest(10))) } // Because the persistent queue is not draining after Shutdown, need to wait here for the drain. assert.Eventually(t, func() bool { return c.numMessagesProduced == int(consumed.Load()) }, 5*time.Second, 10*time.Millisecond) require.NoError(t, aq.Shutdown(context.Background())) }) } } func TestPersistentBlockingQueue(t *testing.T) { tests := []struct { name string sizerType request.SizerType }{ { name: "requests_based", sizerType: request.SizerTypeRequests, }, { name: "items_based", sizerType: request.SizerTypeItems, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { set := newSettingsWithStorage(tt.sizerType, 1000) set.BlockOnOverflow = true pq := newPersistentQueue[intRequest](set) consumed := &atomic.Int64{} ac := newAsyncQueue(pq, 10, func(_ context.Context, _ intRequest, done Done) { consumed.Add(1) done.OnDone(nil) }, set.ReferenceCounter) require.NoError(t, ac.Start(context.Background(), hosttest.NewHost(map[component.ID]component.Component{ {}: storagetest.NewMockStorageExtension(nil), }))) td := intRequest(10) wg := &sync.WaitGroup{} for range 10 { wg.Add(1) go func() { defer wg.Done() for range 100_000 { assert.NoError(t, pq.Offer(context.Background(), td)) } }() } wg.Wait() // Because the persistent queue is not draining after Shutdown, need to wait here for the drain. assert.Eventually(t, func() bool { return int(consumed.Load()) == 1_000_000 }, 5*time.Second, 10*time.Millisecond) require.NoError(t, ac.Shutdown(context.Background())) }) } } func TestToStorageClient(t *testing.T) { getStorageClientError := errors.New("unable to create storage client") testCases := []struct { name string storage storage.Extension numStorages int storageIndex int expectedError error getClientError error }{ { name: "obtain storage extension by name", numStorages: 2, storageIndex: 0, expectedError: nil, }, { name: "fail on not existing storage extension", numStorages: 2, storageIndex: 100, expectedError: errNoStorageClient, }, { name: "invalid extension type", numStorages: 2, storageIndex: 100, expectedError: errNoStorageClient, }, { name: "fail on error getting storage client from extension", numStorages: 1, storageIndex: 0, expectedError: getStorageClientError, getClientError: getStorageClientError, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { storageID := component.MustNewIDWithName("file_storage", strconv.Itoa(tt.storageIndex)) extensions := map[component.ID]component.Component{} for i := 0; i < tt.numStorages; i++ { extensions[component.MustNewIDWithName("file_storage", strconv.Itoa(i))] = storagetest.NewMockStorageExtension(tt.getClientError) } host := hosttest.NewHost(extensions) ownerID := component.MustNewID("foo_exporter") // execute client, err := toStorageClient(context.Background(), storageID, host, ownerID, pipeline.SignalTraces) // verify if tt.expectedError != nil { require.ErrorIs(t, err, tt.expectedError) assert.Nil(t, client) } else { require.NoError(t, err) assert.NotNil(t, client) } }) } } func TestInvalidStorageExtensionType(t *testing.T) { storageID := component.MustNewIDWithName("extension", "extension") // make a test extension factory := extensiontest.NewNopFactory() extConfig := factory.CreateDefaultConfig() settings := extensiontest.NewNopSettings(factory.Type()) extension, err := factory.Create(context.Background(), settings, extConfig) require.NoError(t, err) extensions := map[component.ID]component.Component{ storageID: extension, } host := hosttest.NewHost(extensions) ownerID := component.MustNewID("foo_exporter") // execute client, err := toStorageClient(context.Background(), storageID, host, ownerID, pipeline.SignalTraces) // we should get an error about the extension type require.ErrorIs(t, err, errWrongExtensionType) assert.Nil(t, client) } func TestPersistentQueue_StopAfterBadStart(t *testing.T) { storageID := component.ID{} pq := newPersistentQueue[intRequest](Settings[intRequest]{StorageID: &storageID}) // verify that stopping a un-start/started w/error queue does not panic assert.NoError(t, pq.Shutdown(context.Background())) } func TestPersistentQueue_CorruptedData(t *testing.T) { cases := []struct { name string corruptAllData bool corruptSomeData bool corruptMetadataKey bool desiredQueueSize int64 }{ { name: "corrupted no items", desiredQueueSize: 3, }, { name: "corrupted all items", corruptAllData: true, desiredQueueSize: 2, // - the dispatched item which was corrupted. }, { name: "corrupted some items", corruptSomeData: true, desiredQueueSize: 2, // - the dispatched item which was corrupted. }, { name: "corrupted metadata", corruptMetadataKey: true, desiredQueueSize: 0, }, { name: "corrupted everything", corruptAllData: true, corruptMetadataKey: true, desiredQueueSize: 0, }, } badBytes := []byte{0, 1, 2} for _, c := range cases { t.Run(c.name, func(t *testing.T) { ext := storagetest.NewMockStorageExtension(nil) ps := createTestPersistentQueueWithRequestsSizer(t, ext, 1000) // Put some items, make sure they are loaded and shutdown the storage... for range 3 { require.NoError(t, ps.Offer(context.Background(), intRequest(50))) } assert.Equal(t, int64(3), ps.Size()) require.True(t, consume(ps, func(context.Context, intRequest) error { return experr.NewShutdownErr(nil) })) assert.Equal(t, int64(3), ps.Size()) // We can corrupt data (in several ways) and not worry since we return ShutdownErr client will not be touched. if c.corruptAllData || c.corruptSomeData { require.NoError(t, ps.client.Set(context.Background(), "0", badBytes)) } if c.corruptAllData { require.NoError(t, ps.client.Set(context.Background(), "1", badBytes)) require.NoError(t, ps.client.Set(context.Background(), "2", badBytes)) } if c.corruptMetadataKey { require.NoError(t, ps.client.Set(context.Background(), metadataKey, badBytes)) } // Cannot close until we corrupt the data because the require.NoError(t, ps.Shutdown(context.Background())) // Reload newPs := createTestPersistentQueueWithRequestsSizer(t, ext, 1000) assert.Equal(t, c.desiredQueueSize, newPs.Size()) require.NoError(t, newPs.Shutdown(context.Background())) }) } } func TestPersistentQueue_CurrentlyProcessedItems(t *testing.T) { req := intRequest(50) ext := storagetest.NewMockStorageExtension(nil) ps := createTestPersistentQueueWithRequestsSizer(t, ext, 1000) for range 5 { require.NoError(t, ps.Offer(context.Background(), req)) } requireCurrentlyDispatchedItemsEqual(t, ps, []uint64{}) // Takes index 0 in process. _, readReq, _, found := ps.Read(context.Background()) require.True(t, found) assert.Equal(t, req, readReq) requireCurrentlyDispatchedItemsEqual(t, ps, []uint64{0}) // This takes item 1 to process. _, secondReadReq, secondDone, found := ps.Read(context.Background()) require.True(t, found) assert.Equal(t, req, secondReadReq) requireCurrentlyDispatchedItemsEqual(t, ps, []uint64{0, 1}) // Lets mark item 1 as finished, it will remove it from the currently dispatched items list. secondDone.OnDone(nil) requireCurrentlyDispatchedItemsEqual(t, ps, []uint64{0}) // Reload the storage. Since items 0 was not finished, this should be re-enqueued at the end. // The queue should be essentially {3,4,0,2}. newPs := createTestPersistentQueueWithRequestsSizer(t, ext, 1000) assert.Equal(t, int64(4), newPs.Size()) requireCurrentlyDispatchedItemsEqual(t, newPs, []uint64{}) // We should be able to pull all remaining items now for range 4 { consume(newPs, func(_ context.Context, val intRequest) error { assert.Equal(t, req, val) return nil }) } // The queue should be now empty requireCurrentlyDispatchedItemsEqual(t, newPs, []uint64{}) assert.Equal(t, int64(0), newPs.Size()) // The writeIndex should be now set accordingly require.EqualValues(t, 6, newPs.metadata.WriteIndex) // There should be no items left in the storage for i := uint64(0); i < newPs.metadata.WriteIndex; i++ { bb, err := newPs.client.Get(context.Background(), getItemKey(i)) require.NoError(t, err) require.Nil(t, bb) } } // this test attempts to check if all the invariants are kept if the queue is recreated while // close to full and with some items dispatched func TestPersistentQueueStartWithNonDispatched(t *testing.T) { req := intRequest(50) ext := storagetest.NewMockStorageExtension(nil) ps := createTestPersistentQueueWithRequestsSizer(t, ext, 5) // Put in items up to capacity for range 5 { require.NoError(t, ps.Offer(context.Background(), req)) } require.Equal(t, int64(5), ps.Size()) require.True(t, consume(ps, func(context.Context, intRequest) error { // Check that size is still full even when consuming the element. require.Equal(t, int64(5), ps.Size()) return experr.NewShutdownErr(nil) })) require.NoError(t, ps.Shutdown(context.Background())) // Reload with extra capacity to make sure we re-enqueue in-progress items. newPs := createTestPersistentQueueWithRequestsSizer(t, ext, 5) require.Equal(t, int64(5), newPs.Size()) } func TestPersistentQueueStartWithNonDispatchedConcurrent(t *testing.T) { req := intRequest(1) ext := storagetest.NewMockStorageExtensionWithDelay(nil, 20*time.Nanosecond) pq := createTestPersistentQueueWithItemsSizer(t, ext, 25) proWg := sync.WaitGroup{} // Sending small amount of data as windows test can't handle the test fast enough for range 5 { proWg.Add(1) go func() { defer proWg.Done() // Put in items up to capacity for range 10 { for { // retry infinitely so the exact amount of items are added to the queue eventually if err := pq.Offer(context.Background(), req); err == nil { break } time.Sleep(50 * time.Nanosecond) } } }() } conWg := sync.WaitGroup{} for range 5 { conWg.Add(1) go func() { defer conWg.Done() for range 10 { assert.True(t, consume(pq, func(context.Context, intRequest) error { return nil })) } }() } conDone := make(chan struct{}) go func() { defer close(conDone) conWg.Wait() }() proDone := make(chan struct{}) go func() { defer close(proDone) proWg.Wait() }() doneCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() select { case <-conDone: case <-doneCtx.Done(): assert.Fail(t, "timed out waiting for consumers to complete") } select { case <-proDone: case <-doneCtx.Done(): assert.Fail(t, "timed out waiting for producers to complete") } assert.Zero(t, pq.Size()) } func TestPersistentQueue_PutCloseReadClose(t *testing.T) { req := intRequest(50) ext := storagetest.NewMockStorageExtension(nil) ps := createTestPersistentQueueWithRequestsSizer(t, ext, 1000) assert.Equal(t, int64(0), ps.Size()) // Put two elements and close the extension require.NoError(t, ps.Offer(context.Background(), req)) require.NoError(t, ps.Offer(context.Background(), req)) assert.Equal(t, int64(2), ps.Size()) // TODO: Remove this, after the initialization writes the readIndex. _, _, _, _ = ps.Read(context.Background()) require.NoError(t, ps.Shutdown(context.Background())) newPs := createTestPersistentQueueWithRequestsSizer(t, ext, 1000) require.Equal(t, int64(2), newPs.Size()) // Let's read both of the elements we put consume(newPs, func(_ context.Context, val intRequest) error { require.Equal(t, req, val) return nil }) assert.Equal(t, int64(1), newPs.Size()) consume(newPs, func(_ context.Context, val intRequest) error { require.Equal(t, req, val) return nil }) require.Equal(t, int64(0), newPs.Size()) require.NoError(t, newPs.Shutdown(context.Background())) } func BenchmarkPersistentQueue(b *testing.B) { ext := storagetest.NewMockStorageExtension(nil) ps := createTestPersistentQueueWithRequestsSizer(b, ext, 10000000) req := intRequest(100) b.ReportAllocs() for b.Loop() { for range 100 { require.NoError(b, ps.Offer(context.Background(), req)) } for range 100 { require.True(b, consume(ps, func(context.Context, intRequest) error { return nil })) } } require.NoError(b, ext.Shutdown(context.Background())) } func TestItemIndexMarshaling(t *testing.T) { cases := []struct { in uint64 out uint64 }{ { in: 0, out: 0, }, { in: 1, out: 1, }, { in: 0xFFFFFFFFFFFFFFFF, out: 0xFFFFFFFFFFFFFFFF, }, } for _, c := range cases { t.Run(fmt.Sprintf("#elements:%v", c.in), func(*testing.T) { buf := binary.LittleEndian.AppendUint64([]byte{}, c.in) out, err := bytesToItemIndex(buf) require.NoError(t, err) require.Equal(t, c.out, out) }) } } func TestItemIndexArrayMarshaling(t *testing.T) { cases := []struct { in []uint64 out []uint64 }{ { in: []uint64{0, 1, 2}, out: []uint64{0, 1, 2}, }, { in: []uint64{}, out: nil, }, { in: nil, out: nil, }, } for _, c := range cases { t.Run(fmt.Sprintf("#elements:%v", c.in), func(_ *testing.T) { buf := itemIndexArrayToBytes(c.in) out, err := bytesToItemIndexArray(buf) require.NoError(t, err) require.Equal(t, c.out, out) }) } } func TestPersistentQueue_ShutdownWhileConsuming(t *testing.T) { ps := createTestPersistentQueueWithRequestsSizer(t, storagetest.NewMockStorageExtension(nil), 1000) assert.Equal(t, int64(0), ps.Size()) assert.False(t, ps.client.(*storagetest.MockStorageClient).IsClosed()) require.NoError(t, ps.Offer(context.Background(), intRequest(50))) _, _, done, ok := ps.Read(context.Background()) require.True(t, ok) assert.False(t, ps.client.(*storagetest.MockStorageClient).IsClosed()) require.NoError(t, ps.Shutdown(context.Background())) assert.False(t, ps.client.(*storagetest.MockStorageClient).IsClosed()) done.OnDone(nil) assert.True(t, ps.client.(*storagetest.MockStorageClient).IsClosed()) } func TestPersistentQueue_StorageFull(t *testing.T) { marshaled, err := int64Encoding{}.Marshal(context.Background(), intRequest(50)) require.NoError(t, err) maxSizeInBytes := len(marshaled)*5 + 60 // arbitrary small number client := newFakeBoundedStorageClient(maxSizeInBytes) ps := createTestPersistentQueueWithClient(client) // Put enough items in to fill the underlying storage reqCount := 0 for { reqCount++ err = ps.Offer(context.Background(), intRequest(50)) if errors.Is(err, syscall.ENOSPC) { break } require.NoError(t, err) } // Check that the size is correct require.EqualValues(t, reqCount, ps.Size(), "Size must be equal to the number of items inserted") // Manually set the storage to support writing the dispatch value. client.SetMaxSizeInBytes(client.GetSizeInBytes() + 19) // Take out all the items except last. Last one is there only in metadata because the data write failed. for i := 0; i < reqCount-1; i++ { require.True(t, consume(ps, func(_ context.Context, val intRequest) error { require.Equal(t, intRequest(50), val) return nil })) } require.Equal(t, int64(1), ps.Size()) // Add one more element, and then read (drain) so metadata will be fixed. require.NoError(t, ps.Offer(context.Background(), intRequest(50))) require.True(t, consume(ps, func(_ context.Context, val intRequest) error { require.Equal(t, intRequest(50), val) return nil })) require.Equal(t, int64(0), ps.Size()) } func TestPersistentQueue_ItemDispatchingFinish_ErrorHandling(t *testing.T) { errDeletingItem := errors.New("error deleting item") errUpdatingDispatched := errors.New("error updating dispatched items") testCases := []struct { storageErrors []error expectedError error name string }{ { name: "no errors", storageErrors: []error{}, expectedError: nil, }, { name: "error on first transaction, success afterwards", storageErrors: []error{ errUpdatingDispatched, }, expectedError: nil, }, { name: "error on first and second transaction", storageErrors: []error{ errUpdatingDispatched, errDeletingItem, }, expectedError: errDeletingItem, }, { name: "error on first and third transaction", storageErrors: []error{ errUpdatingDispatched, nil, errUpdatingDispatched, }, expectedError: errUpdatingDispatched, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { client := newFakeStorageClientWithErrors(tt.storageErrors) ps := createTestPersistentQueueWithClient(client) client.Reset() require.ErrorIs(t, ps.itemDispatchingFinish(context.Background(), 0), tt.expectedError) }) } } func TestPersistentQueue_ItemsCapacityUsageRestoredOnShutdown(t *testing.T) { ext := storagetest.NewMockStorageExtension(nil) pq := createTestPersistentQueueWithItemsSizer(t, ext, 100) assert.Equal(t, int64(0), pq.Size()) // Fill the queue up to the capacity. require.NoError(t, pq.Offer(context.Background(), intRequest(40))) require.NoError(t, pq.Offer(context.Background(), intRequest(40))) require.NoError(t, pq.Offer(context.Background(), intRequest(20))) assert.Equal(t, int64(100), pq.Size()) require.ErrorIs(t, pq.Offer(context.Background(), intRequest(25)), ErrQueueIsFull) assert.Equal(t, int64(100), pq.Size()) assert.True(t, consume(pq, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(40), val) return nil })) assert.Equal(t, int64(60), pq.Size()) require.NoError(t, pq.Shutdown(context.Background())) newPQ := createTestPersistentQueueWithItemsSizer(t, ext, 100) // The queue should be restored to the previous size. assert.Equal(t, int64(60), newPQ.Size()) require.NoError(t, newPQ.Offer(context.Background(), intRequest(10))) // Check the combined queue size. assert.Equal(t, int64(70), newPQ.Size()) assert.True(t, consume(newPQ, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(40), val) return nil })) assert.Equal(t, int64(30), newPQ.Size()) assert.True(t, consume(newPQ, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(20), val) return nil })) assert.Equal(t, int64(10), newPQ.Size()) require.NoError(t, newPQ.Shutdown(context.Background())) } func TestPersistentQueue_ItemsCapacityIsAlwyasRecorder(t *testing.T) { ext := storagetest.NewMockStorageExtension(nil) pq := createTestPersistentQueueWithRequestsSizer(t, ext, 100) assert.Equal(t, int64(0), pq.Size()) require.NoError(t, pq.Offer(context.Background(), intRequest(40))) require.NoError(t, pq.Offer(context.Background(), intRequest(20))) require.NoError(t, pq.Offer(context.Background(), intRequest(25))) assert.Equal(t, int64(3), pq.Size()) assert.True(t, consume(pq, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(40), val) return nil })) assert.Equal(t, int64(2), pq.Size()) require.NoError(t, pq.Shutdown(context.Background())) newPQ := createTestPersistentQueueWithItemsSizer(t, ext, 100) // The queue items size cannot be restored. assert.Equal(t, int64(45), newPQ.Size()) require.NoError(t, newPQ.Offer(context.Background(), intRequest(10))) // Only new items are correctly reflected assert.Equal(t, int64(55), newPQ.Size()) // Consuming a restored request should reduce the restored size by 20 but it should not go to below zero assert.True(t, consume(newPQ, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(20), val) return nil })) assert.Equal(t, int64(35), newPQ.Size()) // Consuming another restored request should not affect the restored size since it's already dropped to 0. assert.True(t, consume(newPQ, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(25), val) return nil })) assert.Equal(t, int64(10), newPQ.Size()) // Adding another batch should update the size accordingly require.NoError(t, newPQ.Offer(context.Background(), intRequest(25))) assert.Equal(t, int64(35), newPQ.Size()) assert.True(t, consume(newPQ, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(10), val) return nil })) assert.Equal(t, int64(25), newPQ.Size()) require.NoError(t, newPQ.Shutdown(context.Background())) } // This test covers the case when the queue is restarted with the less capacity than needed to restore the queued items. // In that case, the queue has to be restored anyway even if it exceeds the capacity limit. func TestPersistentQueue_RequestCapacityLessAfterRestart(t *testing.T) { ext := storagetest.NewMockStorageExtension(nil) pq := createTestPersistentQueueWithRequestsSizer(t, ext, 100) assert.Equal(t, int64(0), pq.Size()) require.NoError(t, pq.Offer(context.Background(), intRequest(40))) require.NoError(t, pq.Offer(context.Background(), intRequest(20))) require.NoError(t, pq.Offer(context.Background(), intRequest(25))) require.NoError(t, pq.Offer(context.Background(), intRequest(5))) // Read the first request just to populate the read index in the storage. // Otherwise, the write index won't be restored either. assert.True(t, consume(pq, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(40), val) return nil })) assert.Equal(t, int64(3), pq.Size()) require.NoError(t, pq.Shutdown(context.Background())) // The queue is restarted with the less capacity than needed to restore the queued items, but with the same // underlying storage. No need to drop requests that are over capacity since they are already in the storage. newPQ := createTestPersistentQueueWithRequestsSizer(t, ext, 2) // The queue items size cannot be restored, fall back to request-based size assert.Equal(t, int64(3), newPQ.Size()) // Queue is full require.Error(t, newPQ.Offer(context.Background(), intRequest(10))) assert.True(t, consume(newPQ, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(20), val) return nil })) assert.Equal(t, int64(2), newPQ.Size()) // Still full require.Error(t, newPQ.Offer(context.Background(), intRequest(10))) assert.True(t, consume(newPQ, func(_ context.Context, val intRequest) error { assert.Equal(t, intRequest(25), val) return nil })) assert.Equal(t, int64(1), newPQ.Size()) // Now it can accept new items require.NoError(t, newPQ.Offer(context.Background(), intRequest(10))) require.NoError(t, newPQ.Shutdown(context.Background())) } // This test covers the case when the persistent storage is recovered from a snapshot which has // bigger value for the used size than the size of the actual items in the storage. func TestPersistentQueue_RestoredUsedSizeIsCorrectedOnDrain(t *testing.T) { ext := storagetest.NewMockStorageExtension(nil) pq := createTestPersistentQueueWithItemsSizer(t, ext, 1000) assert.Equal(t, int64(0), pq.Size()) for range 6 { require.NoError(t, pq.Offer(context.Background(), intRequest(10))) } assert.Equal(t, int64(60), pq.Size()) // Consume 30 items for range 3 { assert.True(t, consume(pq, func(context.Context, intRequest) error { return nil })) } assert.Equal(t, int64(30), pq.Size()) // Corrupt the size, in reality the size is 30. // Once the queue is drained, it will be updated to the correct size. pq.metadata.ItemsSize = 50 assert.Equal(t, int64(50), pq.Size()) assert.True(t, consume(pq, func(context.Context, intRequest) error { return nil })) assert.True(t, consume(pq, func(context.Context, intRequest) error { return nil })) assert.Equal(t, int64(30), pq.Size()) // Now the size must be correctly reflected assert.True(t, consume(pq, func(context.Context, intRequest) error { return nil })) assert.Equal(t, int64(0), pq.Size()) require.NoError(t, pq.Shutdown(context.Background())) } func requireCurrentlyDispatchedItemsEqual(t *testing.T, pq *persistentQueue[intRequest], compare []uint64) { pq.mu.Lock() defer pq.mu.Unlock() assert.ElementsMatch(t, compare, pq.metadata.CurrentlyDispatchedItems) } func itemIndexArrayToBytes(arr []uint64) []byte { size := len(arr) buf := make([]byte, 0, 4+size*8) buf = binary.LittleEndian.AppendUint32(buf, uint32(size)) for _, item := range arr { buf = binary.LittleEndian.AppendUint64(buf, item) } return buf } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue/queue.go000066400000000000000000000101501511331344600300660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queue // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" import ( "context" "errors" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/pipeline" ) // ReferenceCounter is an optional interface that can be implemented to provide a way for the request data // to manage internal locally allocated memory and re-use across multiple requests, etc. // // The queue will only call Ref and Unref when requests are executed asynchronously, otherwise these // funcs are not called. type ReferenceCounter[T any] interface { Ref(T) Unref(T) } type Encoding[T any] interface { // Marshal is a function that can marshal a request into bytes. Marshal(context.Context, T) ([]byte, error) // Unmarshal is a function that can unmarshal bytes into a request. Unmarshal([]byte) (context.Context, T, error) } // ErrQueueIsFull is the error returned when an item is offered to the Queue and the queue is full and setup to // not block. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. var ErrQueueIsFull = errors.New("sending queue is full") // Done represents the callback that will be called when the read request is completely processed by the // downstream components. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. type Done interface { // OnDone needs to be called when processing of the queue item is done. OnDone(error) } type ConsumeFunc[T any] func(context.Context, T, Done) // Queue defines a producer-consumer exchange which can be backed by e.g. the memory-based ring buffer queue // (boundedMemoryQueue) or via a disk-based queue (persistentQueue) // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. type Queue[T any] interface { component.Component // Offer inserts the specified element into this queue if it is possible to do so immediately // without violating capacity restrictions. If success returns no error. // It returns ErrQueueIsFull if no space is currently available. Offer(ctx context.Context, item T) error // Size returns the current Size of the queue Size() int64 // Capacity returns the capacity of the queue. Capacity() int64 } // Settings define internal parameters for a new Queue creation. type Settings[T request.Request] struct { SizerType request.SizerType Capacity int64 NumConsumers int WaitForResult bool BlockOnOverflow bool Signal pipeline.Signal StorageID *component.ID ReferenceCounter ReferenceCounter[T] Encoding Encoding[T] ID component.ID Telemetry component.TelemetrySettings } func NewQueue[T request.Request](set Settings[T], next ConsumeFunc[T]) (Queue[T], error) { q := newBaseQueue(set) oq, err := newObsQueue(set, newAsyncQueue(q, set.NumConsumers, next, set.ReferenceCounter)) if err != nil { return nil, err } return oq, nil } func newBaseQueue[T request.Request](set Settings[T]) readableQueue[T] { // Configure memory queue or persistent based on the config. if set.StorageID == nil { return newMemoryQueue[T](set) } return newPersistentQueue[T](set) } // TODO: Investigate why linter "unused" fails if add a private "read" func on the Queue. type readableQueue[T any] interface { Queue[T] // Read pulls the next available item from the queue along with its done callback. Once processing is // finished, the done callback must be called to clean up the storage. // The function blocks until an item is available or if the queue is stopped. // If the queue is stopped returns false, otherwise true. Read(context.Context) (context.Context, T, Done, bool) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue_sender.go000066400000000000000000000040301511331344600303020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import ( "context" "time" "go.uber.org/zap" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) // NewDefaultQueueConfig returns the default config for queuebatch.Config. // By default, the queue stores 1000 requests of telemetry and is non-blocking when full. func NewDefaultQueueConfig() queuebatch.Config { return queuebatch.Config{ Enabled: true, Sizer: request.SizerTypeRequests, NumConsumers: 10, // By default, batches are 8192 spans, for a total of up to 8 million spans in the queue // This can be estimated at 1-4 GB worth of maximum memory usage // This default is probably still too high, and may be adjusted further down in a future release QueueSize: 1_000, BlockOnOverflow: false, Batch: configoptional.Default(queuebatch.BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 8192, }), } } func NewQueueSender( qSet queuebatch.AllSettings[request.Request], qCfg queuebatch.Config, exportFailureMessage string, next sender.Sender[request.Request], ) (sender.Sender[request.Request], error) { exportFunc := func(ctx context.Context, req request.Request) error { // Have to read the number of items before sending the request since the request can // be modified by the downstream components like the batcher. itemsCount := req.ItemsCount() if errSend := next.Send(ctx, req); errSend != nil { qSet.Telemetry.Logger.Error("Exporting failed. Dropping data."+exportFailureMessage, zap.Error(errSend), zap.Int("dropped_items", itemsCount)) return errSend } return nil } return queuebatch.NewQueueBatch(qSet, qCfg, exportFunc) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queue_sender_test.go000066400000000000000000000041351511331344600313470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pipeline" ) func TestNewQueueSenderFailedRequestDropped(t *testing.T) { qSet := queuebatch.AllSettings[request.Request]{ Signal: pipeline.SignalMetrics, ID: component.NewID(exportertest.NopType), Telemetry: componenttest.NewNopTelemetrySettings(), } logger, observed := observer.New(zap.ErrorLevel) qSet.Telemetry.Logger = zap.New(logger) be, err := NewQueueSender( qSet, NewDefaultQueueConfig(), "", sender.NewSender(func(context.Context, request.Request) error { return errors.New("some error") })) require.NoError(t, err) require.NoError(t, be.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, be.Send(context.Background(), &requesttest.FakeRequest{Items: 2})) require.NoError(t, be.Shutdown(context.Background())) assert.Len(t, observed.All(), 1) assert.Equal(t, "Exporting failed. Dropping data.", observed.All()[0].Message) } func TestQueueConfig_Validate(t *testing.T) { qCfg := NewDefaultQueueConfig() require.NoError(t, qCfg.Validate()) qCfg.NumConsumers = 0 require.EqualError(t, qCfg.Validate(), "`num_consumers` must be positive") qCfg = NewDefaultQueueConfig() qCfg.QueueSize = 0 require.EqualError(t, qCfg.Validate(), "`queue_size` must be positive") // Confirm Validate doesn't return error with invalid config when feature is disabled qCfg.Enabled = false assert.NoError(t, qCfg.Validate()) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/000077500000000000000000000000001511331344600274205ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/batch_context.go000066400000000000000000000020201511331344600325660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "go.opentelemetry.io/otel/trace" ) type traceContextKeyType int const batchSpanLinksKey traceContextKeyType = iota // LinksFromContext returns a list of trace links registered in the context. func LinksFromContext(ctx context.Context) []trace.Link { if ctx == nil { return []trace.Link{} } if links, ok := ctx.Value(batchSpanLinksKey).([]trace.Link); ok { return links } return []trace.Link{} } func parentsFromContext(ctx context.Context) []trace.Link { if spanCtx := trace.SpanContextFromContext(ctx); spanCtx.IsValid() { return []trace.Link{{SpanContext: spanCtx}} } return LinksFromContext(ctx) } func contextWithMergedLinks(mergedCtx, ctx1, ctx2 context.Context) context.Context { return context.WithValue( mergedCtx, batchSpanLinksKey, append(parentsFromContext(ctx1), parentsFromContext(ctx2)...)) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/batch_context_test.go000066400000000000000000000047231511331344600336410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component/componenttest" ) type testTimestampKeyType int const testTimestampKey testTimestampKeyType = iota // mergeCtxFunc corresponds to user specified mergeCtx function in the batcher settings. // This specific merge Context function keeps the greater of timestamps from two contexts. func mergeCtxFunc(ctx1, ctx2 context.Context) context.Context { timestamp1 := ctx1.Value(testTimestampKey) timestamp2 := ctx2.Value(testTimestampKey) if timestamp1 != nil && timestamp2 != nil { if timestamp1.(int) > timestamp2.(int) { return context.WithValue(context.Background(), testTimestampKey, timestamp1) } return context.WithValue(context.Background(), testTimestampKey, timestamp2) } if timestamp1 != nil { return context.WithValue(context.Background(), testTimestampKey, timestamp1) } return context.WithValue(context.Background(), testTimestampKey, timestamp2) } // mergeContextHelper performs the same operation done during batching. func mergeContextHelper(ctx1, ctx2 context.Context) context.Context { return contextWithMergedLinks(mergeCtxFunc(ctx1, ctx2), ctx1, ctx2) } func TestBatchContextLink(t *testing.T) { tracerProvider := componenttest.NewTelemetry().NewTelemetrySettings().TracerProvider tracer := tracerProvider.Tracer("go.opentelemetry.io/collector/exporter/exporterhelper") ctx1 := context.Background() ctx2, span2 := tracer.Start(ctx1, "span2") defer span2.End() ctx3, span3 := tracer.Start(ctx1, "span3") defer span3.End() ctx4, span4 := tracer.Start(ctx1, "span4") defer span4.End() batchContext := mergeContextHelper(ctx2, ctx3) batchContext = mergeContextHelper(batchContext, ctx4) actualLinks := LinksFromContext(batchContext) require.Len(t, actualLinks, 3) require.Equal(t, trace.SpanContextFromContext(ctx2), actualLinks[0].SpanContext) require.Equal(t, trace.SpanContextFromContext(ctx3), actualLinks[1].SpanContext) require.Equal(t, trace.SpanContextFromContext(ctx4), actualLinks[2].SpanContext) } func TestMergedContext_GetValue(t *testing.T) { ctx1 := context.WithValue(context.Background(), testTimestampKey, 1234) ctx2 := context.WithValue(context.Background(), testTimestampKey, 2345) batchContext := mergeContextHelper(ctx1, ctx2) require.Equal(t, 2345, batchContext.Value(testTimestampKey)) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/batcher.go000066400000000000000000000030601511331344600313560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "fmt" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) // Batcher is in charge of reading items from the queue and send them out asynchronously. type Batcher[T any] interface { component.Component Consume(context.Context, T, queue.Done) } type batcherSettings[T any] struct { partitioner Partitioner[T] mergeCtx func(context.Context, context.Context) context.Context next sender.SendFunc[T] maxWorkers int logger *zap.Logger } func NewBatcher(cfg configoptional.Optional[BatchConfig], set batcherSettings[request.Request]) (Batcher[request.Request], error) { if !cfg.HasValue() { return newDisabledBatcher(set.next), nil } sizer := request.NewSizer(cfg.Get().Sizer) if sizer == nil { return nil, fmt.Errorf("queue_batch: unsupported sizer %q", cfg.Get().Sizer) } if set.partitioner == nil { return newPartitionBatcher(*cfg.Get(), sizer, set.mergeCtx, newWorkerPool(set.maxWorkers), set.next, set.logger), nil } return newMultiBatcher(*cfg.Get(), sizer, newWorkerPool(set.maxWorkers), set.partitioner, set.mergeCtx, set.next, set.logger), nil } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/config.go000066400000000000000000000117521511331344600312220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "errors" "fmt" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) // Config defines configuration for queueing and batching incoming requests. type Config struct { // Enabled indicates whether to not enqueue and batch before exporting. Enabled bool `mapstructure:"enabled"` // WaitForResult determines if incoming requests are blocked until the request is processed or not. // Currently, this option is not available when persistent queue is configured using the storage configuration. WaitForResult bool `mapstructure:"wait_for_result"` // Sizer determines the type of size measurement used by this component. // It accepts "requests", "items", or "bytes". Sizer request.SizerType `mapstructure:"sizer"` // QueueSize represents the maximum data size allowed for concurrent storage and processing. QueueSize int64 `mapstructure:"queue_size"` // BlockOnOverflow determines the behavior when the component's TotalSize limit is reached. // If true, the component will wait for space; otherwise, operations will immediately return a retryable error. BlockOnOverflow bool `mapstructure:"block_on_overflow"` // StorageID if not empty, enables the persistent storage and uses the component specified // as a storage extension for the persistent queue. // TODO: This will be changed to Optional when available. // See https://github.com/open-telemetry/opentelemetry-collector/issues/13822 StorageID *component.ID `mapstructure:"storage"` // NumConsumers is the maximum number of concurrent consumers from the queue. // This applies across all different optional configurations from above (e.g. wait_for_result, block_on_overflow, storage, etc.). NumConsumers int `mapstructure:"num_consumers"` // BatchConfig it configures how the requests are consumed from the queue and batch together during consumption. Batch configoptional.Optional[BatchConfig] `mapstructure:"batch"` } func (cfg *Config) Unmarshal(conf *confmap.Conf) error { if err := conf.Unmarshal(cfg); err != nil { return err } // If all of the following hold: // 1. the sizer is set, // 2. the batch sizer is not set and // 3. the batch section is nonempty, // then use the same value as the queue sizer. if conf.IsSet("sizer") && !conf.IsSet("batch::sizer") && conf.IsSet("batch") && conf.Get("batch") != nil { cfg.Batch.Get().Sizer = cfg.Sizer } return nil } // Validate checks if the Config is valid func (cfg *Config) Validate() error { if !cfg.Enabled { return nil } if cfg.NumConsumers <= 0 { return errors.New("`num_consumers` must be positive") } if cfg.QueueSize <= 0 { return errors.New("`queue_size` must be positive") } // Only support request sizer for persistent queue at this moment. if cfg.StorageID != nil && cfg.WaitForResult { return errors.New("`wait_for_result` is not supported with a persistent queue configured with `storage`") } if cfg.Batch.HasValue() && cfg.Batch.Get().Sizer == cfg.Sizer { // Avoid situations where the queue is not able to hold any data. if cfg.Batch.Get().MinSize > cfg.QueueSize { return errors.New("`min_size` must be less than or equal to `queue_size`") } } return nil } // BatchConfig defines a configuration for batching requests based on a timeout and a minimum number of items. type BatchConfig struct { // FlushTimeout sets the time after which a batch will be sent regardless of its size. FlushTimeout time.Duration `mapstructure:"flush_timeout"` // Sizer determines the type of size measurement used by the batch. // If not configured, use the same configuration as the queue. // It accepts "requests", "items", or "bytes". Sizer request.SizerType `mapstructure:"sizer"` // MinSize defines the configuration for the minimum size of a batch. MinSize int64 `mapstructure:"min_size"` // MaxSize defines the configuration for the maximum size of a batch. MaxSize int64 `mapstructure:"max_size"` } func (cfg *BatchConfig) Validate() error { if cfg == nil { return nil } // Only support items or bytes sizer for batch at this moment. if cfg.Sizer != request.SizerTypeItems && cfg.Sizer != request.SizerTypeBytes { return fmt.Errorf("`batch` supports only `items` or `bytes` sizer, found %q", cfg.Sizer.String()) } if cfg.FlushTimeout <= 0 { return fmt.Errorf("`flush_timeout` must be positive, found %d", cfg.FlushTimeout) } if cfg.MinSize < 0 { return fmt.Errorf("`min_size` must be non-negative, found %d", cfg.MinSize) } if cfg.MaxSize < 0 { return fmt.Errorf("`max_size` must be non-negative, found %d", cfg.MaxSize) } if cfg.MaxSize > 0 && cfg.MaxSize < cfg.MinSize { return fmt.Errorf("`max_size` (%d) must be greater or equal to `min_size` (%d)", cfg.MaxSize, cfg.MinSize) } return nil } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/config_test.go000066400000000000000000000123221511331344600322530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch import ( "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) func TestConfig_Validate(t *testing.T) { cfg := newTestConfig() require.NoError(t, xconfmap.Validate(cfg)) cfg.NumConsumers = 0 require.EqualError(t, xconfmap.Validate(cfg), "`num_consumers` must be positive") cfg = newTestConfig() cfg.QueueSize = 0 require.EqualError(t, xconfmap.Validate(cfg), "`queue_size` must be positive") cfg = newTestConfig() cfg.QueueSize = 0 require.EqualError(t, xconfmap.Validate(cfg), "`queue_size` must be positive") storageID := component.MustNewID("test") cfg = newTestConfig() cfg.WaitForResult = true cfg.StorageID = &storageID require.EqualError(t, xconfmap.Validate(cfg), "`wait_for_result` is not supported with a persistent queue configured with `storage`") cfg = newTestConfig() cfg.QueueSize = cfg.Batch.Get().MinSize - 1 require.EqualError(t, xconfmap.Validate(cfg), "`min_size` must be less than or equal to `queue_size`") cfg = newTestConfig() cfg.Batch.Get().Sizer = request.SizerType{} require.EqualError(t, xconfmap.Validate(cfg), "batch: `batch` supports only `items` or `bytes` sizer, found \"\"") cfg = newTestConfig() cfg.Sizer = request.SizerTypeBytes require.NoError(t, xconfmap.Validate(cfg)) // Confirm Validate doesn't return error with invalid config when feature is disabled cfg.Enabled = false assert.NoError(t, xconfmap.Validate(cfg)) } func TestBatchConfig_Validate(t *testing.T) { cfg := newTestBatchConfig() require.NoError(t, xconfmap.Validate(cfg)) cfg = newTestBatchConfig() cfg.FlushTimeout = 0 require.EqualError(t, xconfmap.Validate(cfg), "`flush_timeout` must be positive, found 0") cfg = newTestBatchConfig() cfg.MinSize = -1 require.EqualError(t, xconfmap.Validate(cfg), "`min_size` must be non-negative, found -1") cfg = newTestBatchConfig() cfg.MaxSize = -1 require.EqualError(t, xconfmap.Validate(cfg), "`max_size` must be non-negative, found -1") cfg = newTestBatchConfig() cfg.Sizer = request.SizerTypeRequests require.EqualError(t, xconfmap.Validate(cfg), "`batch` supports only `items` or `bytes` sizer, found \"requests\"") cfg = newTestBatchConfig() cfg.Sizer = request.SizerType{} require.EqualError(t, xconfmap.Validate(cfg), "`batch` supports only `items` or `bytes` sizer, found \"\"") cfg = newTestBatchConfig() cfg.MinSize = 2048 cfg.MaxSize = 1024 require.EqualError(t, xconfmap.Validate(cfg), "`max_size` (1024) must be greater or equal to `min_size` (2048)") } func newTestBatchConfig() BatchConfig { return BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 2048, MaxSize: 0, } } func TestUnmarshal(t *testing.T) { newBaseCfg := func() Config { return Config{ Enabled: true, Sizer: request.SizerTypeRequests, NumConsumers: 10, QueueSize: 1_000, Batch: configoptional.Default(BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 8192, }), } } tests := []struct { path string expectedErr string expectedCfg func() Config }{ { path: "batch_set_empty_explicit_sizer.yaml", expectedCfg: func() Config { cfg := newBaseCfg() cfg.Sizer = request.SizerTypeBytes // Batch is set, sizer is not overridden cfg.Batch.GetOrInsertDefault() return cfg }, }, { path: "batch_set_empty_no_explicit_sizer.yaml", expectedCfg: func() Config { cfg := newBaseCfg() cfg.Batch.GetOrInsertDefault() return cfg }, }, { path: "batch_set_nonempty_explicit_sizer.yaml", expectedCfg: func() Config { cfg := newBaseCfg() cfg.Sizer = request.SizerTypeBytes cfg.QueueSize = 2000 cfg.Batch = configoptional.Some(BatchConfig{ FlushTimeout: 200 * time.Millisecond, // Sizer has been overridden by parent sizer Sizer: request.SizerTypeBytes, MinSize: 100, }) return cfg }, }, { path: "batch_set_nonempty_no_explicit_sizer.yaml", expectedCfg: func() Config { cfg := newBaseCfg() cfg.QueueSize = 2000 cfg.Batch = configoptional.Some(BatchConfig{ FlushTimeout: 200 * time.Millisecond, // Sizer has NOT been overridden by parent sizer Sizer: request.SizerTypeItems, MinSize: 100, }) return cfg }, }, { path: "batch_unset.yaml", // Batch remains unset, sizer override does not apply. expectedCfg: newBaseCfg, }, } for _, tt := range tests { t.Run(tt.path, func(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", tt.path)) require.NoError(t, err) cfg := newBaseCfg() err = cfg.Unmarshal(cm) if tt.expectedErr != "" { assert.ErrorContains(t, err, tt.expectedErr) return } require.NoError(t, err) assert.Equal(t, tt.expectedCfg(), cfg) assert.NoError(t, xconfmap.Validate(cfg)) }) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/disabled_batcher.go000066400000000000000000000017001511331344600332040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) // disabledBatcher is a special-case of Batcher that has no size limit for sending. Any items read from the queue will // be sent out (asynchronously) immediately regardless of the size. type disabledBatcher[T any] struct { component.StartFunc component.ShutdownFunc consumeFunc sender.SendFunc[T] } func (db *disabledBatcher[T]) Consume(ctx context.Context, req T, done queue.Done) { done.OnDone(db.consumeFunc(ctx, req)) } func newDisabledBatcher[T any](consumeFunc sender.SendFunc[T]) Batcher[T] { return &disabledBatcher[T]{consumeFunc: consumeFunc} } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/disabled_batcher_test.go000066400000000000000000000042061511331344600342470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch import ( "context" "errors" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" ) func TestDisabledBatcher(t *testing.T) { tests := []struct { name string maxWorkers int }{ { name: "one_worker", maxWorkers: 1, }, { name: "three_workers", maxWorkers: 3, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink := requesttest.NewSink() ba := newDisabledBatcher(sink.Export) q, err := queue.NewQueue(queue.Settings[request.Request]{ Capacity: 1000, BlockOnOverflow: true, NumConsumers: tt.maxWorkers, Telemetry: componenttest.NewNopTelemetrySettings(), }, ba.Consume) require.NoError(t, err) require.NoError(t, q.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, q.Shutdown(context.Background())) require.NoError(t, ba.Shutdown(context.Background())) }) require.NoError(t, q.Offer(context.Background(), &requesttest.FakeRequest{Items: 8})) sink.SetExportErr(errors.New("transient error")) require.NoError(t, q.Offer(context.Background(), &requesttest.FakeRequest{Items: 8})) require.NoError(t, q.Offer(context.Background(), &requesttest.FakeRequest{Items: 17})) require.NoError(t, q.Offer(context.Background(), &requesttest.FakeRequest{Items: 13})) require.NoError(t, q.Offer(context.Background(), &requesttest.FakeRequest{Items: 35})) require.NoError(t, q.Offer(context.Background(), &requesttest.FakeRequest{Items: 2})) assert.Eventually(t, func() bool { return sink.RequestsCount() == 5 && sink.ItemsCount() == 75 }, 1*time.Second, 10*time.Millisecond) }) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/doc.go000066400000000000000000000004641511331344600305200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package queuebatch provides helper functions for exporter's queueing and batching. package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/encoding.go000066400000000000000000000012641511331344600315400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import "context" // encoding defines the encoding to be used if persistent queue is configured. // Duplicate definition with exporterhelper.QueueBatchEncoding since aliasing generics is not supported by default. type encoding[T any] interface { // Marshal is a function that can marshal a request and its context into bytes. Marshal(context.Context, T) ([]byte, error) // Unmarshal is a function that can unmarshal bytes into a request and its context. Unmarshal([]byte) (context.Context, T, error) } generated_package_test.go000066400000000000000000000002511511331344600343360ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch// Code generated by mdatagen. DO NOT EDIT. package queuebatch import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/logs.go000066400000000000000000000076131511331344600307220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "errors" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/xpdata/pref" pdatareq "go.opentelemetry.io/collector/pdata/xpdata/request" ) var ( logsMarshaler = &plog.ProtoMarshaler{} logsUnmarshaler = &plog.ProtoUnmarshaler{} ) // NewLogsQueueBatchSettings returns a new QueueBatchSettings to configure to WithQueueBatch when using plog.Logs. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewLogsQueueBatchSettings() Settings[request.Request] { return Settings[request.Request]{ ReferenceCounter: logsReferenceCounter{}, Encoding: logsEncoding{}, } } var ( _ request.Request = (*logsRequest)(nil) _ request.ErrorHandler = (*logsRequest)(nil) ) type logsRequest struct { ld plog.Logs cachedSize int } func newLogsRequest(ld plog.Logs) request.Request { return &logsRequest{ ld: ld, cachedSize: -1, } } type logsEncoding struct{} var _ encoding[request.Request] = logsEncoding{} func (logsEncoding) Unmarshal(bytes []byte) (context.Context, request.Request, error) { if queue.PersistRequestContextOnRead() { ctx, logs, err := pdatareq.UnmarshalLogs(bytes) if errors.Is(err, pdatareq.ErrInvalidFormat) { // fall back to unmarshaling without context logs, err = logsUnmarshaler.UnmarshalLogs(bytes) } return ctx, newLogsRequest(logs), err } logs, err := logsUnmarshaler.UnmarshalLogs(bytes) if err != nil { var req request.Request return context.Background(), req, err } return context.Background(), newLogsRequest(logs), nil } func (logsEncoding) Marshal(ctx context.Context, req request.Request) ([]byte, error) { logs := req.(*logsRequest).ld if queue.PersistRequestContextOnWrite() { return pdatareq.MarshalLogs(ctx, logs) } return logsMarshaler.MarshalLogs(logs) } var _ queue.ReferenceCounter[request.Request] = logsReferenceCounter{} type logsReferenceCounter struct{} func (logsReferenceCounter) Ref(req request.Request) { pref.RefLogs(req.(*logsRequest).ld) } func (logsReferenceCounter) Unref(req request.Request) { pref.UnrefLogs(req.(*logsRequest).ld) } func (req *logsRequest) OnError(err error) request.Request { var logError consumererror.Logs if errors.As(err, &logError) { // TODO: Add logic to unref the new request created here. return newLogsRequest(logError.Data()) } return req } func (req *logsRequest) ItemsCount() int { return req.ld.LogRecordCount() } func (req *logsRequest) size(sizer sizer.LogsSizer) int { if req.cachedSize == -1 { req.cachedSize = sizer.LogsSize(req.ld) } return req.cachedSize } func (req *logsRequest) setCachedSize(size int) { req.cachedSize = size } func (req *logsRequest) BytesSize() int { return logsMarshaler.LogsSize(req.ld) } // RequestConsumeFromLogs returns a RequestConsumeFunc that consumes plog.Logs. func RequestConsumeFromLogs(pusher consumer.ConsumeLogsFunc) request.RequestConsumeFunc { return func(ctx context.Context, request request.Request) error { return pusher.ConsumeLogs(ctx, request.(*logsRequest).ld) } } // RequestFromLogs returns a RequestFromLogsFunc that converts plog.Logs into a Request. func RequestFromLogs() request.RequestConverterFunc[plog.Logs] { return func(_ context.Context, ld plog.Logs) (request.Request, error) { return newLogsRequest(ld), nil } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/logs_batch.go000066400000000000000000000140141511331344600320540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "errors" "fmt" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/plog" ) // MergeSplit splits and/or merges the provided logs request and the current request into one or more requests // conforming with the MaxSizeConfig. func (req *logsRequest) MergeSplit(_ context.Context, maxSize int, szt request.SizerType, r2 request.Request) ([]request.Request, error) { var sz sizer.LogsSizer switch szt { case request.SizerTypeItems: sz = &sizer.LogsCountSizer{} case request.SizerTypeBytes: sz = &sizer.LogsBytesSizer{} default: return nil, errors.New("unknown sizer type") } if r2 != nil { req2, ok := r2.(*logsRequest) if !ok { return nil, errors.New("invalid input type") } req2.mergeTo(req, sz) } // If no limit we can simply merge the new request into the current and return. if maxSize == 0 { return []request.Request{req}, nil } return req.split(maxSize, sz) } func (req *logsRequest) mergeTo(dst *logsRequest, sz sizer.LogsSizer) { if sz != nil { dst.setCachedSize(dst.size(sz) + req.size(sz)) req.setCachedSize(0) } req.ld.ResourceLogs().MoveAndAppendTo(dst.ld.ResourceLogs()) } func (req *logsRequest) split(maxSize int, sz sizer.LogsSizer) ([]request.Request, error) { var res []request.Request for req.size(sz) > maxSize { ld, removedSize := extractLogs(req.ld, maxSize, sz) if ld.LogRecordCount() == 0 { return res, fmt.Errorf("one log record size is greater than max size, dropping items: %d", req.ld.LogRecordCount()) } req.setCachedSize(req.size(sz) - removedSize) res = append(res, newLogsRequest(ld)) } res = append(res, req) return res, nil } // extractLogs extracts logs from the input logs and returns a new logs with the specified number of log records. func extractLogs(srcLogs plog.Logs, capacity int, sz sizer.LogsSizer) (plog.Logs, int) { destLogs := plog.NewLogs() capacityLeft := capacity - sz.LogsSize(destLogs) removedSize := 0 srcLogs.ResourceLogs().RemoveIf(func(srcRL plog.ResourceLogs) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawRlSize := sz.ResourceLogsSize(srcRL) rlSize := sz.DeltaSize(rawRlSize) if rlSize > capacityLeft { extSrcRL, extRlSize := extractResourceLogs(srcRL, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extRlSize // There represents the delta between the delta sizes. removedSize += rlSize - rawRlSize - (sz.DeltaSize(rawRlSize-extRlSize) - (rawRlSize - extRlSize)) // It is possible that for the bytes scenario, the extracted field contains no log records. // Do not add it to the destination if that is the case. if extSrcRL.ScopeLogs().Len() > 0 { extSrcRL.MoveTo(destLogs.ResourceLogs().AppendEmpty()) } return extSrcRL.ScopeLogs().Len() != 0 } capacityLeft -= rlSize removedSize += rlSize srcRL.MoveTo(destLogs.ResourceLogs().AppendEmpty()) return true }) return destLogs, removedSize } // extractResourceLogs extracts resource logs and returns a new resource logs with the specified number of log records. func extractResourceLogs(srcRL plog.ResourceLogs, capacity int, sz sizer.LogsSizer) (plog.ResourceLogs, int) { destRL := plog.NewResourceLogs() destRL.SetSchemaUrl(srcRL.SchemaUrl()) srcRL.Resource().CopyTo(destRL.Resource()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ResourceLogsSize(destRL) removedSize := 0 srcRL.ScopeLogs().RemoveIf(func(srcSL plog.ScopeLogs) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawSlSize := sz.ScopeLogsSize(srcSL) slSize := sz.DeltaSize(rawSlSize) if slSize > capacityLeft { extSrcSL, extSlSize := extractScopeLogs(srcSL, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extSlSize // There represents the delta between the delta sizes. removedSize += slSize - rawSlSize - (sz.DeltaSize(rawSlSize-extSlSize) - (rawSlSize - extSlSize)) // It is possible that for the bytes scenario, the extracted field contains no log records. // Do not add it to the destination if that is the case. if extSrcSL.LogRecords().Len() > 0 { extSrcSL.MoveTo(destRL.ScopeLogs().AppendEmpty()) } return extSrcSL.LogRecords().Len() != 0 } capacityLeft -= slSize removedSize += slSize srcSL.MoveTo(destRL.ScopeLogs().AppendEmpty()) return true }) return destRL, removedSize } // extractScopeLogs extracts scope logs and returns a new scope logs with the specified number of log records. func extractScopeLogs(srcSL plog.ScopeLogs, capacity int, sz sizer.LogsSizer) (plog.ScopeLogs, int) { destSL := plog.NewScopeLogs() destSL.SetSchemaUrl(srcSL.SchemaUrl()) srcSL.Scope().CopyTo(destSL.Scope()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ScopeLogsSize(destSL) removedSize := 0 srcSL.LogRecords().RemoveIf(func(srcLR plog.LogRecord) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rlSize := sz.DeltaSize(sz.LogRecordSize(srcLR)) if rlSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rlSize removedSize += rlSize srcLR.MoveTo(destSL.LogRecords().AppendEmpty()) return true }) return destSL, removedSize } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/logs_batch_test.go000066400000000000000000000336241511331344600331230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMergeLogs(t *testing.T) { lr1 := newLogsRequest(testdata.GenerateLogs(2)) lr2 := newLogsRequest(testdata.GenerateLogs(3)) res, err := lr1.MergeSplit(context.Background(), 0, request.SizerTypeItems, lr2) require.NoError(t, err) require.Equal(t, 5, res[0].ItemsCount()) } func TestMergeSplitLogs(t *testing.T) { tests := []struct { name string szt request.SizerType maxSize int lr1 request.Request lr2 request.Request expected []request.Request }{ { name: "both_requests_empty", szt: request.SizerTypeItems, maxSize: 10, lr1: newLogsRequest(plog.NewLogs()), lr2: newLogsRequest(plog.NewLogs()), expected: []request.Request{newLogsRequest(plog.NewLogs())}, }, { name: "first_request_empty", szt: request.SizerTypeItems, maxSize: 10, lr1: newLogsRequest(plog.NewLogs()), lr2: newLogsRequest(testdata.GenerateLogs(5)), expected: []request.Request{newLogsRequest(testdata.GenerateLogs(5))}, }, { name: "first_empty_second_nil", szt: request.SizerTypeItems, maxSize: 10, lr1: newLogsRequest(plog.NewLogs()), lr2: nil, expected: []request.Request{newLogsRequest(plog.NewLogs())}, }, { name: "merge_only", szt: request.SizerTypeItems, maxSize: 10, lr1: newLogsRequest(testdata.GenerateLogs(4)), lr2: newLogsRequest(testdata.GenerateLogs(6)), expected: []request.Request{newLogsRequest(func() plog.Logs { logs := testdata.GenerateLogs(4) testdata.GenerateLogs(6).ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) return logs }())}, }, { name: "split_only", szt: request.SizerTypeItems, maxSize: 4, lr1: newLogsRequest(plog.NewLogs()), lr2: newLogsRequest(testdata.GenerateLogs(10)), expected: []request.Request{ newLogsRequest(testdata.GenerateLogs(4)), newLogsRequest(testdata.GenerateLogs(4)), newLogsRequest(testdata.GenerateLogs(2)), }, }, { name: "merge_and_split", szt: request.SizerTypeItems, maxSize: 10, lr1: newLogsRequest(testdata.GenerateLogs(8)), lr2: newLogsRequest(testdata.GenerateLogs(20)), expected: []request.Request{ newLogsRequest(func() plog.Logs { logs := testdata.GenerateLogs(8) testdata.GenerateLogs(2).ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) return logs }()), newLogsRequest(testdata.GenerateLogs(10)), newLogsRequest(testdata.GenerateLogs(8)), }, }, { name: "scope_logs_split", szt: request.SizerTypeItems, maxSize: 4, lr1: newLogsRequest(func() plog.Logs { ld := testdata.GenerateLogs(4) ld.ResourceLogs().At(0).ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Body().SetStr("extra log") return ld }()), lr2: newLogsRequest(testdata.GenerateLogs(2)), expected: []request.Request{ newLogsRequest(testdata.GenerateLogs(4)), newLogsRequest(func() plog.Logs { ld := testdata.GenerateLogs(0) ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().AppendEmpty().Body().SetStr("extra log") testdata.GenerateLogs(2).ResourceLogs().MoveAndAppendTo(ld.ResourceLogs()) return ld }()), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.lr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.lr2) require.NoError(t, err) assert.Len(t, res, len(tt.expected)) for i := range res { assert.Equal(t, tt.expected[i].(*logsRequest).ld, res[i].(*logsRequest).ld) } }) } } func TestMergeSplitLogsBasedOnByteSize(t *testing.T) { tests := []struct { name string szt request.SizerType maxSize int lr1 request.Request lr2 request.Request expected []request.Request expectPartialError bool }{ { name: "both_requests_empty", szt: request.SizerTypeBytes, maxSize: logsMarshaler.LogsSize(testdata.GenerateLogs(10)), lr1: newLogsRequest(plog.NewLogs()), lr2: newLogsRequest(plog.NewLogs()), expected: []request.Request{newLogsRequest(plog.NewLogs())}, }, { name: "first_request_empty", szt: request.SizerTypeBytes, maxSize: logsMarshaler.LogsSize(testdata.GenerateLogs(10)), lr1: newLogsRequest(plog.NewLogs()), lr2: newLogsRequest(testdata.GenerateLogs(5)), expected: []request.Request{newLogsRequest(testdata.GenerateLogs(5))}, }, { name: "first_empty_second_nil", szt: request.SizerTypeBytes, maxSize: logsMarshaler.LogsSize(testdata.GenerateLogs(10)), lr1: newLogsRequest(plog.NewLogs()), lr2: nil, expected: []request.Request{newLogsRequest(plog.NewLogs())}, }, { name: "merge_only", szt: request.SizerTypeBytes, maxSize: logsMarshaler.LogsSize(testdata.GenerateLogs(11)), lr1: newLogsRequest(testdata.GenerateLogs(4)), lr2: newLogsRequest(testdata.GenerateLogs(6)), expected: []request.Request{newLogsRequest(func() plog.Logs { logs := testdata.GenerateLogs(4) testdata.GenerateLogs(6).ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) return logs }())}, }, { name: "split_only", szt: request.SizerTypeBytes, maxSize: logsMarshaler.LogsSize(testdata.GenerateLogs(4)), lr1: newLogsRequest(plog.NewLogs()), lr2: newLogsRequest(testdata.GenerateLogs(10)), expected: []request.Request{ newLogsRequest(testdata.GenerateLogs(4)), newLogsRequest(testdata.GenerateLogs(4)), newLogsRequest(testdata.GenerateLogs(2)), }, }, { name: "merge_and_split", szt: request.SizerTypeBytes, maxSize: logsMarshaler.LogsSize(testdata.GenerateLogs(10))/2 + logsMarshaler.LogsSize(testdata.GenerateLogs(11))/2, lr1: newLogsRequest(testdata.GenerateLogs(8)), lr2: newLogsRequest(testdata.GenerateLogs(20)), expected: []request.Request{ newLogsRequest(func() plog.Logs { logs := testdata.GenerateLogs(8) testdata.GenerateLogs(2).ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) return logs }()), newLogsRequest(testdata.GenerateLogs(10)), newLogsRequest(testdata.GenerateLogs(8)), }, }, { name: "scope_logs_split", szt: request.SizerTypeBytes, maxSize: logsMarshaler.LogsSize(testdata.GenerateLogs(4)), lr1: newLogsRequest(func() plog.Logs { ld := testdata.GenerateLogs(4) ld.ResourceLogs().At(0).ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Body().SetStr("extra log") return ld }()), lr2: newLogsRequest(testdata.GenerateLogs(2)), expected: []request.Request{ newLogsRequest(testdata.GenerateLogs(4)), newLogsRequest(func() plog.Logs { ld := testdata.GenerateLogs(0) ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().AppendEmpty().Body().SetStr("extra log") testdata.GenerateLogs(2).ResourceLogs().MoveAndAppendTo(ld.ResourceLogs()) return ld }()), }, }, { name: "unsplittable_large_log", szt: request.SizerTypeBytes, maxSize: 10, lr1: newLogsRequest(func() plog.Logs { ld := testdata.GenerateLogs(1) ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().SetStr(string(make([]byte, 100))) return ld }()), lr2: nil, expected: []request.Request{}, expectPartialError: true, }, { name: "splittable_then_unsplittable_log", szt: request.SizerTypeBytes, maxSize: 1000, lr1: newLogsRequest(func() plog.Logs { ld := testdata.GenerateLogs(2) ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().SetStr(string(make([]byte, 10))) ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(1).Body().SetStr(string(make([]byte, 1001))) return ld }()), lr2: nil, expected: []request.Request{newLogsRequest(func() plog.Logs { ld := testdata.GenerateLogs(1) ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().SetStr(string(make([]byte, 10))) return ld }())}, expectPartialError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.lr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.lr2) if tt.expectPartialError { require.ErrorContains(t, err, "one log record size is greater than max size, dropping") } else { require.NoError(t, err) } assert.Len(t, res, len(tt.expected)) for i := range res { assert.Equal(t, tt.expected[i].(*logsRequest).ld, res[i].(*logsRequest).ld) assert.Equal(t, logsMarshaler.LogsSize(tt.expected[i].(*logsRequest).ld), logsMarshaler.LogsSize(res[i].(*logsRequest).ld)) } }) } } func TestMergeSplitLogsInputNotModifiedIfErrorReturned(t *testing.T) { r1 := newLogsRequest(testdata.GenerateLogs(18)) r2 := newTracesRequest(testdata.GenerateTraces(3)) _, err := r1.MergeSplit(context.Background(), 10, request.SizerTypeItems, r2) require.Error(t, err) assert.Equal(t, 18, r1.ItemsCount()) } func TestExtractLogs(t *testing.T) { for i := range 10 { ld := testdata.GenerateLogs(10) extractedLogs, _ := extractLogs(ld, i, &sizer.LogsCountSizer{}) assert.Equal(t, i, extractedLogs.LogRecordCount()) assert.Equal(t, 10-i, ld.LogRecordCount()) } } func TestMergeSplitManySmallLogs(t *testing.T) { // All requests merge into a single batch. merged := []request.Request{newLogsRequest(testdata.GenerateLogs(1))} for range 1000 { lr2 := newLogsRequest(testdata.GenerateLogs(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(t, merged, 2) } func TestLogsMergeSplitExactBytes(t *testing.T) { pb := plog.ProtoMarshaler{} // Set max size off by 1, so forces every log to be it's own batch. lr := newLogsRequest(testdata.GenerateLogs(4)) merged, err := lr.MergeSplit(context.Background(), pb.LogsSize(testdata.GenerateLogs(2))-1, request.SizerTypeBytes, nil) require.NoError(t, err) assert.Len(t, merged, 4) } func TestLogsMergeSplitExactItems(t *testing.T) { // Set max size off by 1, so forces every log to be it's own batch. lr := newLogsRequest(testdata.GenerateLogs(4)) merged, err := lr.MergeSplit(context.Background(), 1, request.SizerTypeItems, nil) require.NoError(t, err) assert.Len(t, merged, 4) } func TestLogsMergeSplitUnknownSizerType(t *testing.T) { req := newLogsRequest(plog.NewLogs()) // Call MergeSplit with invalid sizer _, err := req.MergeSplit(context.Background(), 0, request.SizerType{}, nil) require.EqualError(t, err, "unknown sizer type") } func BenchmarkSplittingBasedOnItemCountManySmallLogs(b *testing.B) { // All requests merge into a single batch. b.ReportAllocs() for b.Loop() { merged := []request.Request{newLogsRequest(testdata.GenerateLogs(10))} for range 1000 { lr2 := newLogsRequest(testdata.GenerateLogs(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10010, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 1) } } func BenchmarkSplittingBasedOnByteSizeManySmallLogs(b *testing.B) { // All requests merge into a single batch. b.ReportAllocs() for b.Loop() { merged := []request.Request{newLogsRequest(testdata.GenerateLogs(10))} for range 1000 { lr2 := newLogsRequest(testdata.GenerateLogs(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), logsMarshaler.LogsSize(testdata.GenerateLogs(11000)), request.SizerTypeBytes, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 1) } } func BenchmarkSplittingBasedOnItemCountManyLogsSlightlyAboveLimit(b *testing.B) { // Every incoming request results in a split. b.ReportAllocs() for b.Loop() { merged := []request.Request{newLogsRequest(testdata.GenerateLogs(0))} for range 10 { lr2 := newLogsRequest(testdata.GenerateLogs(10001)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 11) } } func BenchmarkSplittingBasedOnByteSizeManyLogsSlightlyAboveLimit(b *testing.B) { // Every incoming request results in a split. b.ReportAllocs() for b.Loop() { merged := []request.Request{newLogsRequest(testdata.GenerateLogs(0))} for range 10 { lr2 := newLogsRequest(testdata.GenerateLogs(10001)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), logsMarshaler.LogsSize(testdata.GenerateLogs(10000)), request.SizerTypeBytes, lr2) assert.Len(b, res, 2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 11) } } func BenchmarkSplittingBasedOnItemCountHugeLogs(b *testing.B) { // One request splits into many batches. b.ReportAllocs() for b.Loop() { merged := []request.Request{newLogsRequest(testdata.GenerateLogs(0))} lr2 := newLogsRequest(testdata.GenerateLogs(100000)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) assert.Len(b, merged, 10) } } func BenchmarkSplittingBasedOnByteSizeHugeLogs(b *testing.B) { // One request splits into many batches. b.ReportAllocs() for b.Loop() { merged := []request.Request{newLogsRequest(testdata.GenerateLogs(0))} lr2 := newLogsRequest(testdata.GenerateLogs(100000)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), logsMarshaler.LogsSize(testdata.GenerateLogs(10010)), request.SizerTypeBytes, lr2) merged = append(merged[0:len(merged)-1], res...) assert.Len(b, merged, 10) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/logs_test.go000066400000000000000000000013511511331344600317520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "errors" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" ) func TestLogsRequest(t *testing.T) { lr := newLogsRequest(testdata.GenerateLogs(1)) logErr := consumererror.NewLogs(errors.New("some error"), plog.NewLogs()) assert.Equal( t, newLogsRequest(plog.NewLogs()), lr.(request.ErrorHandler).OnError(logErr), ) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/metadata.yaml000066400000000000000000000002531511331344600320640ustar00rootroot00000000000000type: queuebatch github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg stability: beta: [traces, metrics, logs] opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/metrics.go000066400000000000000000000074761511331344600314330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "errors" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/xpdata/pref" pdatareq "go.opentelemetry.io/collector/pdata/xpdata/request" ) var ( metricsMarshaler = &pmetric.ProtoMarshaler{} metricsUnmarshaler = &pmetric.ProtoUnmarshaler{} ) func NewMetricsQueueBatchSettings() Settings[request.Request] { return Settings[request.Request]{ ReferenceCounter: metricsReferenceCounter{}, Encoding: metricsEncoding{}, } } var ( _ request.Request = (*metricsRequest)(nil) _ request.ErrorHandler = (*metricsRequest)(nil) ) type metricsRequest struct { md pmetric.Metrics cachedSize int } func newMetricsRequest(md pmetric.Metrics) request.Request { return &metricsRequest{ md: md, cachedSize: -1, } } type metricsEncoding struct{} var _ encoding[request.Request] = metricsEncoding{} func (metricsEncoding) Unmarshal(bytes []byte) (context.Context, request.Request, error) { if queue.PersistRequestContextOnRead() { ctx, metrics, err := pdatareq.UnmarshalMetrics(bytes) if errors.Is(err, pdatareq.ErrInvalidFormat) { // fall back to unmarshaling without context metrics, err = metricsUnmarshaler.UnmarshalMetrics(bytes) } return ctx, newMetricsRequest(metrics), err } metrics, err := metricsUnmarshaler.UnmarshalMetrics(bytes) if err != nil { var req request.Request return context.Background(), req, err } return context.Background(), newMetricsRequest(metrics), nil } func (metricsEncoding) Marshal(ctx context.Context, req request.Request) ([]byte, error) { metrics := req.(*metricsRequest).md if queue.PersistRequestContextOnWrite() { return pdatareq.MarshalMetrics(ctx, metrics) } return metricsMarshaler.MarshalMetrics(metrics) } var _ queue.ReferenceCounter[request.Request] = metricsReferenceCounter{} type metricsReferenceCounter struct{} func (metricsReferenceCounter) Ref(req request.Request) { pref.RefMetrics(req.(*metricsRequest).md) } func (metricsReferenceCounter) Unref(req request.Request) { pref.UnrefMetrics(req.(*metricsRequest).md) } func (req *metricsRequest) OnError(err error) request.Request { var metricsError consumererror.Metrics if errors.As(err, &metricsError) { // TODO: Add logic to unref the new request created here. return newMetricsRequest(metricsError.Data()) } return req } func (req *metricsRequest) ItemsCount() int { return req.md.DataPointCount() } func (req *metricsRequest) size(sizer sizer.MetricsSizer) int { if req.cachedSize == -1 { req.cachedSize = sizer.MetricsSize(req.md) } return req.cachedSize } func (req *metricsRequest) setCachedSize(count int) { req.cachedSize = count } func (req *metricsRequest) BytesSize() int { return metricsMarshaler.MetricsSize(req.md) } // RequestFromMetrics returns a RequestFromMetricsFunc that converts pdata.Metrics into a Request. func RequestFromMetrics() request.RequestConverterFunc[pmetric.Metrics] { return func(_ context.Context, md pmetric.Metrics) (request.Request, error) { return newMetricsRequest(md), nil } } // RequestConsumeFromMetrics returns a RequestConsumeFunc that consumes pmetric.Metrics. func RequestConsumeFromMetrics(pusher consumer.ConsumeMetricsFunc) request.RequestConsumeFunc { return func(ctx context.Context, request request.Request) error { return pusher.ConsumeMetrics(ctx, request.(*metricsRequest).md) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/metrics_batch.go000066400000000000000000000325601511331344600325640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "errors" "fmt" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/pmetric" ) // MergeSplit splits and/or merges the provided metrics request and the current request into one or more requests // conforming with the MaxSizeConfig. func (req *metricsRequest) MergeSplit(_ context.Context, maxSize int, szt request.SizerType, r2 request.Request) ([]request.Request, error) { var sz sizer.MetricsSizer switch szt { case request.SizerTypeItems: sz = &sizer.MetricsCountSizer{} case request.SizerTypeBytes: sz = &sizer.MetricsBytesSizer{} default: return nil, errors.New("unknown sizer type") } if r2 != nil { req2, ok := r2.(*metricsRequest) if !ok { return nil, errors.New("invalid input type") } req2.mergeTo(req, sz) } // If no limit we can simply merge the new request into the current and return. if maxSize == 0 { return []request.Request{req}, nil } return req.split(maxSize, sz) } func (req *metricsRequest) mergeTo(dst *metricsRequest, sz sizer.MetricsSizer) { if sz != nil { dst.setCachedSize(dst.size(sz) + req.size(sz)) req.setCachedSize(0) } req.md.ResourceMetrics().MoveAndAppendTo(dst.md.ResourceMetrics()) } func (req *metricsRequest) split(maxSize int, sz sizer.MetricsSizer) ([]request.Request, error) { var res []request.Request for req.size(sz) > maxSize { md, rmSize := extractMetrics(req.md, maxSize, sz) if md.DataPointCount() == 0 { return res, fmt.Errorf("one datapoint size is greater than max size, dropping items: %d", req.md.DataPointCount()) } req.setCachedSize(req.size(sz) - rmSize) res = append(res, newMetricsRequest(md)) } res = append(res, req) return res, nil } // extractMetrics extracts metrics from srcMetrics until capacity is reached. func extractMetrics(srcMetrics pmetric.Metrics, capacity int, sz sizer.MetricsSizer) (pmetric.Metrics, int) { destMetrics := pmetric.NewMetrics() capacityLeft := capacity - sz.MetricsSize(destMetrics) removedSize := 0 srcMetrics.ResourceMetrics().RemoveIf(func(srcRM pmetric.ResourceMetrics) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawRlSize := sz.ResourceMetricsSize(srcRM) rlSize := sz.DeltaSize(rawRlSize) if rlSize > capacityLeft { extSrcRM, extRmSize := extractResourceMetrics(srcRM, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extRmSize // There represents the delta between the delta sizes. removedSize += rlSize - rawRlSize - (sz.DeltaSize(rawRlSize-extRmSize) - (rawRlSize - extRmSize)) // It is possible that for the bytes scenario, the extracted field contains no scope metrics. // Do not add it to the destination if that is the case. if extSrcRM.ScopeMetrics().Len() > 0 { extSrcRM.MoveTo(destMetrics.ResourceMetrics().AppendEmpty()) } return extSrcRM.ScopeMetrics().Len() != 0 } capacityLeft -= rlSize removedSize += rlSize srcRM.MoveTo(destMetrics.ResourceMetrics().AppendEmpty()) return true }) return destMetrics, removedSize } // extractResourceMetrics extracts resource metrics and returns a new resource metrics with the specified number of data points. func extractResourceMetrics(srcRM pmetric.ResourceMetrics, capacity int, sz sizer.MetricsSizer) (pmetric.ResourceMetrics, int) { destRM := pmetric.NewResourceMetrics() destRM.SetSchemaUrl(srcRM.SchemaUrl()) srcRM.Resource().CopyTo(destRM.Resource()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ResourceMetricsSize(destRM) removedSize := 0 srcRM.ScopeMetrics().RemoveIf(func(srcSM pmetric.ScopeMetrics) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawSmSize := sz.ScopeMetricsSize(srcSM) smSize := sz.DeltaSize(rawSmSize) if smSize > capacityLeft { extSrcSM, extSmSize := extractScopeMetrics(srcSM, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extSmSize // There represents the delta between the delta sizes. removedSize += smSize - rawSmSize - (sz.DeltaSize(rawSmSize-extSmSize) - (rawSmSize - extSmSize)) // It is possible that for the bytes scenario, the extracted field contains no scope metrics. // Do not add it to the destination if that is the case. if extSrcSM.Metrics().Len() > 0 { extSrcSM.MoveTo(destRM.ScopeMetrics().AppendEmpty()) } return extSrcSM.Metrics().Len() != 0 } capacityLeft -= smSize removedSize += smSize srcSM.MoveTo(destRM.ScopeMetrics().AppendEmpty()) return true }) return destRM, removedSize } // extractScopeMetrics extracts scope metrics and returns a new scope metrics with the specified number of data points. func extractScopeMetrics(srcSM pmetric.ScopeMetrics, capacity int, sz sizer.MetricsSizer) (pmetric.ScopeMetrics, int) { destSM := pmetric.NewScopeMetrics() destSM.SetSchemaUrl(srcSM.SchemaUrl()) srcSM.Scope().CopyTo(destSM.Scope()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ScopeMetricsSize(destSM) removedSize := 0 srcSM.Metrics().RemoveIf(func(srcSM pmetric.Metric) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawRmSize := sz.MetricSize(srcSM) rmSize := sz.DeltaSize(rawRmSize) if rmSize > capacityLeft { extSrcDP, extRmSize := extractMetricDataPoints(srcSM, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extRmSize // There represents the delta between the delta sizes. removedSize += rmSize - rawRmSize - (sz.DeltaSize(rawRmSize-extRmSize) - (rawRmSize - extRmSize)) // It is possible that for the bytes scenario, the extracted field contains no datapoints. // Do not add it to the destination if that is the case. if dataPointsLen(extSrcDP) > 0 { extSrcDP.MoveTo(destSM.Metrics().AppendEmpty()) } return dataPointsLen(extSrcDP) != 0 } capacityLeft -= rmSize removedSize += rmSize srcSM.MoveTo(destSM.Metrics().AppendEmpty()) return true }) return destSM, removedSize } func extractMetricDataPoints(srcMetric pmetric.Metric, capacity int, sz sizer.MetricsSizer) (pmetric.Metric, int) { destMetric := pmetric.NewMetric() destMetric.SetName(srcMetric.Name()) destMetric.SetDescription(srcMetric.Description()) destMetric.SetUnit(srcMetric.Unit()) srcMetric.Metadata().CopyTo(destMetric.Metadata()) var removedSize int switch srcMetric.Type() { case pmetric.MetricTypeGauge: removedSize = extractGaugeDataPoints(srcMetric.Gauge(), destMetric, capacity, sz) case pmetric.MetricTypeSum: removedSize = extractSumDataPoints(srcMetric.Sum(), destMetric, capacity, sz) destMetric.Sum().SetIsMonotonic(srcMetric.Sum().IsMonotonic()) destMetric.Sum().SetAggregationTemporality(srcMetric.Sum().AggregationTemporality()) case pmetric.MetricTypeHistogram: removedSize = extractHistogramDataPoints(srcMetric.Histogram(), destMetric, capacity, sz) destMetric.Histogram().SetAggregationTemporality(srcMetric.Histogram().AggregationTemporality()) case pmetric.MetricTypeExponentialHistogram: removedSize = extractExponentialHistogramDataPoints(srcMetric.ExponentialHistogram(), destMetric, capacity, sz) destMetric.ExponentialHistogram().SetAggregationTemporality(srcMetric.ExponentialHistogram().AggregationTemporality()) case pmetric.MetricTypeSummary: removedSize = extractSummaryDataPoints(srcMetric.Summary(), destMetric, capacity, sz) } return destMetric, removedSize } func dataPointsLen(m pmetric.Metric) int { switch m.Type() { case pmetric.MetricTypeGauge: return m.Gauge().DataPoints().Len() case pmetric.MetricTypeSum: return m.Sum().DataPoints().Len() case pmetric.MetricTypeHistogram: return m.Histogram().DataPoints().Len() case pmetric.MetricTypeExponentialHistogram: return m.ExponentialHistogram().DataPoints().Len() case pmetric.MetricTypeSummary: return m.Summary().DataPoints().Len() } return 0 } func extractGaugeDataPoints(srcGauge pmetric.Gauge, destMetric pmetric.Metric, capacity int, sz sizer.MetricsSizer) int { destGauge := destMetric.SetEmptyGauge() // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.MetricSize(destMetric) removedSize := 0 srcGauge.DataPoints().RemoveIf(func(srcDP pmetric.NumberDataPoint) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rdSize := sz.DeltaSize(sz.NumberDataPointSize(srcDP)) if rdSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rdSize removedSize += rdSize srcDP.MoveTo(destGauge.DataPoints().AppendEmpty()) return true }) return removedSize } func extractSumDataPoints(srcSum pmetric.Sum, destMetric pmetric.Metric, capacity int, sz sizer.MetricsSizer) int { destSum := destMetric.SetEmptySum() // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.MetricSize(destMetric) removedSize := 0 srcSum.DataPoints().RemoveIf(func(srcDP pmetric.NumberDataPoint) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rdSize := sz.DeltaSize(sz.NumberDataPointSize(srcDP)) if rdSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rdSize removedSize += rdSize srcDP.MoveTo(destSum.DataPoints().AppendEmpty()) return true }) return removedSize } func extractHistogramDataPoints(srcHistogram pmetric.Histogram, destMetric pmetric.Metric, capacity int, sz sizer.MetricsSizer) int { destHistogram := destMetric.SetEmptyHistogram() // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.MetricSize(destMetric) removedSize := 0 srcHistogram.DataPoints().RemoveIf(func(srcDP pmetric.HistogramDataPoint) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rdSize := sz.DeltaSize(sz.HistogramDataPointSize(srcDP)) if rdSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rdSize removedSize += rdSize srcDP.MoveTo(destHistogram.DataPoints().AppendEmpty()) return true }) return removedSize } func extractExponentialHistogramDataPoints(srcExponentialHistogram pmetric.ExponentialHistogram, destMetric pmetric.Metric, capacity int, sz sizer.MetricsSizer) int { destExponentialHistogram := destMetric.SetEmptyExponentialHistogram() // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.MetricSize(destMetric) removedSize := 0 srcExponentialHistogram.DataPoints().RemoveIf(func(srcDP pmetric.ExponentialHistogramDataPoint) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rdSize := sz.DeltaSize(sz.ExponentialHistogramDataPointSize(srcDP)) if rdSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rdSize removedSize += rdSize srcDP.MoveTo(destExponentialHistogram.DataPoints().AppendEmpty()) return true }) return removedSize } func extractSummaryDataPoints(srcSummary pmetric.Summary, destMetric pmetric.Metric, capacity int, sz sizer.MetricsSizer) int { destSummary := destMetric.SetEmptySummary() // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.MetricSize(destMetric) removedSize := 0 srcSummary.DataPoints().RemoveIf(func(srcDP pmetric.SummaryDataPoint) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rdSize := sz.DeltaSize(sz.SummaryDataPointSize(srcDP)) if rdSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rdSize removedSize += rdSize srcDP.MoveTo(destSummary.DataPoints().AppendEmpty()) return true }) return removedSize } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/metrics_batch_test.go000066400000000000000000000562721511331344600336310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMergeMetrics(t *testing.T) { mr1 := newMetricsRequest(testdata.GenerateMetrics(2)) mr2 := newMetricsRequest(testdata.GenerateMetrics(3)) res, err := mr1.MergeSplit(context.Background(), 0, request.SizerTypeItems, mr2) require.NoError(t, err) // Every metric has 2 data points. assert.Equal(t, 2*5, res[0].ItemsCount()) } func TestMergeSplitMetrics(t *testing.T) { s := sizer.MetricsCountSizer{} tests := []struct { name string szt request.SizerType maxSize int mr1 request.Request mr2 request.Request expected []request.Request }{ { name: "both_requests_empty", szt: request.SizerTypeItems, maxSize: 10, mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: newMetricsRequest(pmetric.NewMetrics()), expected: []request.Request{newMetricsRequest(pmetric.NewMetrics())}, }, { name: "first_request_empty", szt: request.SizerTypeItems, maxSize: 10, mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: newMetricsRequest(testdata.GenerateMetrics(5)), expected: []request.Request{newMetricsRequest(testdata.GenerateMetrics(5))}, }, { name: "first_empty_second_nil", szt: request.SizerTypeItems, maxSize: 10, mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: nil, expected: []request.Request{newMetricsRequest(pmetric.NewMetrics())}, }, { name: "merge_only", szt: request.SizerTypeItems, maxSize: 60, mr1: newMetricsRequest(testdata.GenerateMetrics(10)), mr2: newMetricsRequest(testdata.GenerateMetrics(14)), expected: []request.Request{newMetricsRequest(func() pmetric.Metrics { metrics := testdata.GenerateMetrics(10) testdata.GenerateMetrics(14).ResourceMetrics().MoveAndAppendTo(metrics.ResourceMetrics()) return metrics }())}, }, { name: "split_only", szt: request.SizerTypeItems, maxSize: 14, mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: newMetricsRequest(testdata.GenerateMetrics(15)), // 15 metrics, 30 data points expected: []request.Request{ newMetricsRequest(testdata.GenerateMetrics(7)), // 7 metrics, 14 data points newMetricsRequest(testdata.GenerateMetrics(7)), // 7 metrics, 14 data points newMetricsRequest(testdata.GenerateMetrics(1)), // 1 metric, 2 data points }, }, { name: "split_and_merge", szt: request.SizerTypeItems, maxSize: 28, mr1: newMetricsRequest(testdata.GenerateMetrics(7)), // 7 metrics, 14 data points mr2: newMetricsRequest(testdata.GenerateMetrics(25)), // 25 metrics, 50 data points expected: []request.Request{ newMetricsRequest(func() pmetric.Metrics { metrics := testdata.GenerateMetrics(7) testdata.GenerateMetrics(7).ResourceMetrics().MoveAndAppendTo(metrics.ResourceMetrics()) return metrics }()), newMetricsRequest(testdata.GenerateMetrics(14)), // 14 metrics, 28 data points newMetricsRequest(testdata.GenerateMetrics(4)), // 4 metrics, 8 data points }, }, { name: "scope_metrics_split", szt: request.SizerTypeItems, maxSize: 8, mr1: newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(4) extraScopeMetrics := md.ResourceMetrics().At(0).ScopeMetrics().AppendEmpty() testdata.GenerateMetrics(4).ResourceMetrics().At(0).ScopeMetrics().At(0).MoveTo(extraScopeMetrics) extraScopeMetrics.Scope().SetName("extra scope") return md }()), mr2: nil, expected: []request.Request{ newMetricsRequest(testdata.GenerateMetrics(4)), newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(4) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Scope().SetName("extra scope") return md }()), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.mr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.mr2) require.NoError(t, err) assert.Len(t, res, len(tt.expected)) for i := range res { expected := tt.expected[i].(*metricsRequest) actual := res[i].(*metricsRequest) assert.Equal(t, expected.size(&s), actual.size(&s)) } }) } } func TestSplitMetricsWithDataPointSplit(t *testing.T) { generateTestMetrics := func(metricType pmetric.MetricType) pmetric.Metrics { md := pmetric.NewMetrics() m := md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") m.SetDescription("test_description") m.SetUnit("test_unit") m.Metadata().PutStr("test_metadata_key", "test_metadata_value") const numDataPoints = 2 switch metricType { case pmetric.MetricTypeSum: sum := m.SetEmptySum() for i := range numDataPoints { sum.DataPoints().AppendEmpty().SetIntValue(int64(i + 1)) } case pmetric.MetricTypeGauge: gauge := m.SetEmptyGauge() for i := range numDataPoints { gauge.DataPoints().AppendEmpty().SetIntValue(int64(i + 1)) } case pmetric.MetricTypeHistogram: hist := m.SetEmptyHistogram() for i := range uint64(numDataPoints) { hist.DataPoints().AppendEmpty().SetCount(i + 1) } case pmetric.MetricTypeExponentialHistogram: expHist := m.SetEmptyExponentialHistogram() for i := range uint64(numDataPoints) { expHist.DataPoints().AppendEmpty().SetCount(i + 1) } case pmetric.MetricTypeSummary: summary := m.SetEmptySummary() for i := range uint64(numDataPoints) { summary.DataPoints().AppendEmpty().SetCount(i + 1) } } return md } tests := []struct { name string metricType pmetric.MetricType }{ { name: "sum", metricType: pmetric.MetricTypeSum, }, { name: "gauge", metricType: pmetric.MetricTypeGauge, }, { name: "histogram", metricType: pmetric.MetricTypeHistogram, }, { name: "exponential_histogram", metricType: pmetric.MetricTypeExponentialHistogram, }, { name: "summary", metricType: pmetric.MetricTypeSummary, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Generate metrics with 2 data points. mr1 := newMetricsRequest(generateTestMetrics(tt.metricType)) // Split by data point, so maxSize is 1. res, err := mr1.MergeSplit(context.Background(), 1, request.SizerTypeItems, nil) require.NoError(t, err) require.Len(t, res, 2) for _, req := range res { actualRequest := req.(*metricsRequest) // Each split request should contain one data point. assert.Equal(t, 1, actualRequest.ItemsCount()) m := actualRequest.md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) assert.Equal(t, "test_metric", m.Name()) assert.Equal(t, "test_description", m.Description()) assert.Equal(t, "test_unit", m.Unit()) assert.Equal(t, 1, m.Metadata().Len()) val, ok := m.Metadata().Get("test_metadata_key") assert.True(t, ok) assert.Equal(t, "test_metadata_value", val.AsString()) } }) } } func TestMergeSplitMetricsInputNotModifiedIfErrorReturned(t *testing.T) { r1 := newMetricsRequest(testdata.GenerateMetrics(18)) // 18 metrics, 36 data points r2 := newLogsRequest(testdata.GenerateLogs(3)) _, err := r1.MergeSplit(context.Background(), 10, request.SizerTypeItems, r2) require.Error(t, err) assert.Equal(t, 36, r1.ItemsCount()) } func TestExtractMetrics(t *testing.T) { for i := range 20 { md := testdata.GenerateMetrics(10) extractedMetrics, _ := extractMetrics(md, i, &sizer.MetricsCountSizer{}) assert.Equal(t, i, extractedMetrics.DataPointCount()) assert.Equal(t, 20-i, md.DataPointCount()) } } func TestExtractMetricsInvalidMetric(t *testing.T) { md := testdata.GenerateMetricsMetricTypeInvalid() extractedMetrics, _ := extractMetrics(md, 10, &sizer.MetricsCountSizer{}) assert.Equal(t, testdata.GenerateMetricsMetricTypeInvalid(), extractedMetrics) assert.Equal(t, 0, md.ResourceMetrics().Len()) } func TestMergeSplitManySmallMetrics(t *testing.T) { // All requests merge into a single batch. merged := []request.Request{newMetricsRequest(testdata.GenerateMetrics(1))} for range 1000 { lr2 := newMetricsRequest(testdata.GenerateMetrics(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 20000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(t, merged, 2) } func BenchmarkSplittingBasedOnItemCountManySmallMetrics(b *testing.B) { // All requests merge into a single batch. b.ReportAllocs() for b.Loop() { merged := []request.Request{newMetricsRequest(testdata.GenerateMetrics(10))} for range 1000 { lr2 := newMetricsRequest(testdata.GenerateMetrics(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 20020, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 1) } } func BenchmarkSplittingBasedOnItemCountManyMetricsSlightlyAboveLimit(b *testing.B) { // Every incoming request results in a split. b.ReportAllocs() for b.Loop() { merged := []request.Request{newMetricsRequest(testdata.GenerateMetrics(0))} for range 10 { lr2 := newMetricsRequest(testdata.GenerateMetrics(10001)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 20000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 11) } } func BenchmarkSplittingBasedOnItemCountHugeMetrics(b *testing.B) { // One request splits into many batches. b.ReportAllocs() for b.Loop() { merged := []request.Request{newMetricsRequest(testdata.GenerateMetrics(0))} lr2 := newMetricsRequest(testdata.GenerateMetrics(100000)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 20000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) assert.Len(b, merged, 10) } } func TestMergeSplitMetricsBasedOnByteSize(t *testing.T) { tests := []struct { name string szt request.SizerType maxSize int mr1 request.Request mr2 request.Request expected []request.Request expectSplitError bool }{ { name: "both_requests_empty", szt: request.SizerTypeBytes, maxSize: metricsMarshaler.MetricsSize(testdata.GenerateMetrics(10)), mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: newMetricsRequest(pmetric.NewMetrics()), expected: []request.Request{newMetricsRequest(pmetric.NewMetrics())}, }, { name: "first_request_empty", szt: request.SizerTypeBytes, maxSize: metricsMarshaler.MetricsSize(testdata.GenerateMetrics(10)), mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: newMetricsRequest(testdata.GenerateMetrics(5)), expected: []request.Request{newMetricsRequest(testdata.GenerateMetrics(5))}, }, { name: "first_empty_second_nil", szt: request.SizerTypeBytes, maxSize: metricsMarshaler.MetricsSize(testdata.GenerateMetrics(10)), mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: nil, expected: []request.Request{newMetricsRequest(pmetric.NewMetrics())}, }, { name: "merge_only", szt: request.SizerTypeBytes, maxSize: metricsMarshaler.MetricsSize(testdata.GenerateMetrics(15)) - 1, mr1: newMetricsRequest(testdata.GenerateMetrics(7)), mr2: newMetricsRequest(testdata.GenerateMetrics(7)), expected: []request.Request{newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(7) testdata.GenerateMetrics(7).ResourceMetrics().MoveAndAppendTo(md.ResourceMetrics()) return md }())}, }, { name: "split_only", szt: request.SizerTypeBytes, maxSize: metricsMarshaler.MetricsSize(testdata.GenerateMetrics(7)) + 1, mr1: newMetricsRequest(pmetric.NewMetrics()), mr2: newMetricsRequest(testdata.GenerateMetrics(17)), expected: []request.Request{ newMetricsRequest(testdata.GenerateMetrics(7)), newMetricsRequest(testdata.GenerateMetrics(7)), newMetricsRequest(testdata.GenerateMetrics(3)), }, }, { name: "merge_and_split", szt: request.SizerTypeBytes, maxSize: metricsMarshaler.MetricsSize(testdata.GenerateMetrics(7)) + 1, mr1: newMetricsRequest(testdata.GenerateMetrics(14)), mr2: newMetricsRequest(testdata.GenerateMetrics(11)), expected: []request.Request{ newMetricsRequest(testdata.GenerateMetrics(7)), newMetricsRequest(testdata.GenerateMetrics(7)), newMetricsRequest(testdata.GenerateMetrics(7)), newMetricsRequest(testdata.GenerateMetrics(4)), }, }, { name: "scope_metrics_split", szt: request.SizerTypeBytes, maxSize: metricsMarshaler.MetricsSize(testdata.GenerateMetrics(7)) + 1, mr1: newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(7) extraScopeMetrics := md.ResourceMetrics().At(0).ScopeMetrics().AppendEmpty() testdata.GenerateMetrics(7).ResourceMetrics().At(0).ScopeMetrics().At(0).MoveTo(extraScopeMetrics) extraScopeMetrics.Scope().SetName("extra scope") return md }()), mr2: nil, expected: []request.Request{ newMetricsRequest(testdata.GenerateMetrics(7)), newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(7) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Scope().SetName("extra scope") // Remove last data point. lastDP := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(6).Summary().DataPoints().Len() idx := 0 md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(6).Summary().DataPoints().RemoveIf(func(pmetric.SummaryDataPoint) bool { idx++ return idx == lastDP }) return md }()), newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(7) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Scope().SetName("extra scope") // Remove all metrics but last one lastM := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().Len() idx := 0 md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().RemoveIf(func(pmetric.Metric) bool { idx++ return idx != lastM }) // Remove all data points but last one lastDP := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Summary().DataPoints().Len() idx = 0 md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Summary().DataPoints().RemoveIf(func(pmetric.SummaryDataPoint) bool { idx++ return idx != lastDP }) return md }()), }, }, { name: "unsplittable_large_metric", szt: request.SizerTypeBytes, maxSize: 10, mr1: newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(1) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).SetDescription(string(make([]byte, 100))) return md }()), mr2: nil, expected: []request.Request{}, expectSplitError: true, }, { name: "splittable_then_unsplittable_metric", szt: request.SizerTypeBytes, maxSize: 1000, mr1: newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(2) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).SetDescription(string(make([]byte, 10))) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1).SetDescription(string(make([]byte, 1001))) return md }()), mr2: nil, expected: []request.Request{newMetricsRequest(func() pmetric.Metrics { md := testdata.GenerateMetrics(1) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).SetDescription(string(make([]byte, 10))) return md }())}, expectSplitError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.mr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.mr2) if tt.expectSplitError { require.ErrorContains(t, err, "one datapoint size is greater than max size, dropping items:") } else { require.NoError(t, err) } require.Len(t, res, len(tt.expected)) for i := range res { assert.Equal(t, tt.expected[i].(*metricsRequest).md, res[i].(*metricsRequest).md, i) assert.Equal(t, metricsMarshaler.MetricsSize(tt.expected[i].(*metricsRequest).md), metricsMarshaler.MetricsSize(res[i].(*metricsRequest).md)) } }) } } func TestExtractGaugeDataPoints(t *testing.T) { tests := []struct { name string capacity int numDataPoints int expectedPoints int }{ { name: "extract_all_points", capacity: 100, numDataPoints: 2, expectedPoints: 2, }, { name: "extract_partial_points", capacity: 1, numDataPoints: 2, expectedPoints: 1, }, { name: "no_capacity", capacity: 0, numDataPoints: 2, expectedPoints: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srcMetric := pmetric.NewMetric() gauge := srcMetric.SetEmptyGauge() for i := 0; i < tt.numDataPoints; i++ { dp := gauge.DataPoints().AppendEmpty() dp.SetIntValue(int64(i)) } sz := &mockMetricsSizer{dpSize: 1} destMetric := pmetric.NewMetric() removedSize := extractGaugeDataPoints(gauge, destMetric, tt.capacity, sz) assert.Equal(t, tt.expectedPoints, destMetric.Gauge().DataPoints().Len()) if tt.expectedPoints > 0 { assert.Equal(t, tt.expectedPoints, removedSize) } }) } } func TestExtractSumDataPoints(t *testing.T) { tests := []struct { name string capacity int numDataPoints int expectedPoints int }{ { name: "extract_all_points", capacity: 100, numDataPoints: 2, expectedPoints: 2, }, { name: "extract_partial_points", capacity: 1, numDataPoints: 2, expectedPoints: 1, }, { name: "no_capacity", capacity: 0, numDataPoints: 2, expectedPoints: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srcMetric := pmetric.NewMetric() sum := srcMetric.SetEmptySum() for i := 0; i < tt.numDataPoints; i++ { dp := sum.DataPoints().AppendEmpty() dp.SetIntValue(int64(i)) } sz := &mockMetricsSizer{dpSize: 1} destMetric := pmetric.NewMetric() removedSize := extractSumDataPoints(sum, destMetric, tt.capacity, sz) assert.Equal(t, tt.expectedPoints, destMetric.Sum().DataPoints().Len()) if tt.expectedPoints > 0 { assert.Equal(t, tt.expectedPoints, removedSize) } }) } } func TestExtractHistogramDataPoints(t *testing.T) { tests := []struct { name string capacity int numDataPoints int expectedPoints int }{ { name: "extract_all_points", capacity: 100, numDataPoints: 2, expectedPoints: 2, }, { name: "extract_partial_points", capacity: 1, numDataPoints: 2, expectedPoints: 1, }, { name: "no_capacity", capacity: 0, numDataPoints: 2, expectedPoints: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srcMetric := pmetric.NewMetric() histogram := srcMetric.SetEmptyHistogram() for i := 0; i < tt.numDataPoints; i++ { dp := histogram.DataPoints().AppendEmpty() dp.SetCount(uint64(i)) } sz := &mockMetricsSizer{dpSize: 1} destMetric := pmetric.NewMetric() removedSize := extractHistogramDataPoints(histogram, destMetric, tt.capacity, sz) assert.Equal(t, tt.expectedPoints, destMetric.Histogram().DataPoints().Len()) if tt.expectedPoints > 0 { assert.Equal(t, tt.expectedPoints, removedSize) } }) } } func TestExtractExponentialHistogramDataPoints(t *testing.T) { tests := []struct { name string capacity int numDataPoints int expectedPoints int }{ { name: "extract_all_points", capacity: 100, numDataPoints: 2, expectedPoints: 2, }, { name: "extract_partial_points", capacity: 1, numDataPoints: 2, expectedPoints: 1, }, { name: "no_capacity", capacity: 0, numDataPoints: 2, expectedPoints: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srcMetric := pmetric.NewMetric() expHistogram := srcMetric.SetEmptyExponentialHistogram() for i := 0; i < tt.numDataPoints; i++ { dp := expHistogram.DataPoints().AppendEmpty() dp.SetCount(uint64(i)) } sz := &mockMetricsSizer{dpSize: 1} destMetric := pmetric.NewMetric() removedSize := extractExponentialHistogramDataPoints(expHistogram, destMetric, tt.capacity, sz) assert.Equal(t, tt.expectedPoints, destMetric.ExponentialHistogram().DataPoints().Len()) if tt.expectedPoints > 0 { assert.Equal(t, tt.expectedPoints, removedSize) } }) } } func TestExtractSummaryDataPoints(t *testing.T) { tests := []struct { name string capacity int numDataPoints int expectedPoints int }{ { name: "extract_all_points", capacity: 100, numDataPoints: 2, expectedPoints: 2, }, { name: "extract_partial_points", capacity: 1, numDataPoints: 2, expectedPoints: 1, }, { name: "no_capacity", capacity: 0, numDataPoints: 2, expectedPoints: 0, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srcMetric := pmetric.NewMetric() summary := srcMetric.SetEmptySummary() for i := 0; i < tt.numDataPoints; i++ { dp := summary.DataPoints().AppendEmpty() dp.SetCount(uint64(i)) } sz := &mockMetricsSizer{dpSize: 1} destMetric := pmetric.NewMetric() removedSize := extractSummaryDataPoints(summary, destMetric, tt.capacity, sz) assert.Equal(t, tt.expectedPoints, destMetric.Summary().DataPoints().Len()) if tt.expectedPoints > 0 { assert.Equal(t, tt.expectedPoints, removedSize) } }) } } func TestMetricsMergeSplitUnknownSizerType(t *testing.T) { req := newMetricsRequest(pmetric.NewMetrics()) // Call MergeSplit with invalid sizer _, err := req.MergeSplit(context.Background(), 0, request.SizerType{}, nil) require.EqualError(t, err, "unknown sizer type") } // mockMetricsSizer implements sizer.MetricsSizer interface for testing type mockMetricsSizer struct { dpSize int } func (m *mockMetricsSizer) MetricsSize(_ pmetric.Metrics) int { return 0 } func (m *mockMetricsSizer) MetricSize(_ pmetric.Metric) int { return 0 } func (m *mockMetricsSizer) NumberDataPointSize(_ pmetric.NumberDataPoint) int { return m.dpSize } func (m *mockMetricsSizer) HistogramDataPointSize(_ pmetric.HistogramDataPoint) int { return m.dpSize } func (m *mockMetricsSizer) ExponentialHistogramDataPointSize(_ pmetric.ExponentialHistogramDataPoint) int { return m.dpSize } func (m *mockMetricsSizer) SummaryDataPointSize(_ pmetric.SummaryDataPoint) int { return m.dpSize } func (m *mockMetricsSizer) ResourceMetricsSize(_ pmetric.ResourceMetrics) int { return 0 } func (m *mockMetricsSizer) ScopeMetricsSize(_ pmetric.ScopeMetrics) int { return 0 } func (m *mockMetricsSizer) DeltaSize(size int) int { return size } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/metrics_test.go000066400000000000000000000014171511331344600324570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "errors" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMetricsRequest(t *testing.T) { mr := newMetricsRequest(testdata.GenerateMetrics(1)) metricsErr := consumererror.NewMetrics(errors.New("some error"), pmetric.NewMetrics()) assert.Equal( t, newMetricsRequest(pmetric.NewMetrics()), mr.(request.ErrorHandler).OnError(metricsErr), ) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/multi_batcher.go000066400000000000000000000045211511331344600325730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "sync" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) type multiBatcher struct { cfg BatchConfig wp *workerPool sizer request.Sizer partitioner Partitioner[request.Request] mergeCtx func(context.Context, context.Context) context.Context consumeFunc sender.SendFunc[request.Request] shards sync.Map logger *zap.Logger } func newMultiBatcher( bCfg BatchConfig, sizer request.Sizer, wp *workerPool, partitioner Partitioner[request.Request], mergeCtx func(context.Context, context.Context) context.Context, next sender.SendFunc[request.Request], logger *zap.Logger, ) *multiBatcher { return &multiBatcher{ cfg: bCfg, wp: wp, sizer: sizer, partitioner: partitioner, mergeCtx: mergeCtx, consumeFunc: next, logger: logger, } } func (mb *multiBatcher) getPartition(ctx context.Context, req request.Request) *partitionBatcher { key := mb.partitioner.GetKey(ctx, req) s, found := mb.shards.Load(key) // Fast path, shard already created. if found { return s.(*partitionBatcher) } newS := newPartitionBatcher(mb.cfg, mb.sizer, mb.mergeCtx, mb.wp, mb.consumeFunc, mb.logger) _ = newS.Start(ctx, nil) s, loaded := mb.shards.LoadOrStore(key, newS) // If not loaded, there was a race condition in adding the new shard. Shutdown the newly created shard. if loaded { _ = newS.Shutdown(ctx) } return s.(*partitionBatcher) } func (mb *multiBatcher) Start(context.Context, component.Host) error { return nil } func (mb *multiBatcher) Consume(ctx context.Context, req request.Request, done queue.Done) { shard := mb.getPartition(ctx, req) shard.Consume(ctx, req, done) } func (mb *multiBatcher) Shutdown(ctx context.Context) error { var wg sync.WaitGroup mb.shards.Range(func(_, shard any) bool { wg.Add(1) go func() { defer wg.Done() _ = shard.(*partitionBatcher).Shutdown(ctx) }() return true }) wg.Wait() return nil } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/multi_batcher_test.go000066400000000000000000000075221511331344600336360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" ) func TestMultiBatcher_NoTimeout(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, Sizer: request.SizerTypeItems, MinSize: 10, } sink := requesttest.NewSink() type partitionKey struct{} ba := newMultiBatcher(cfg, request.NewItemsSizer(), newWorkerPool(1), NewPartitioner(func(ctx context.Context, _ request.Request) string { return ctx.Value(partitionKey{}).(string) }), nil, sink.Export, zap.NewNop(), ) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, ba.Shutdown(context.Background())) }) done := newFakeDone() ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p1"), &requesttest.FakeRequest{Items: 8}, done) ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p2"), &requesttest.FakeRequest{Items: 6}, done) // Neither batch should be flushed since they haven't reached min threshold. assert.Equal(t, 0, sink.RequestsCount()) assert.Equal(t, 0, sink.ItemsCount()) ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p1"), &requesttest.FakeRequest{Items: 8}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 1 && sink.ItemsCount() == 16 }, 500*time.Millisecond, 10*time.Millisecond) ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p2"), &requesttest.FakeRequest{Items: 6}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 2 && sink.ItemsCount() == 28 }, 500*time.Millisecond, 10*time.Millisecond) // Check that done callback is called for the right amount of times. assert.EqualValues(t, 0, done.errors.Load()) assert.EqualValues(t, 4, done.success.Load()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) } func TestMultiBatcher_Timeout(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 100 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 100, } sink := requesttest.NewSink() type partitionKey struct{} ba := newMultiBatcher(cfg, request.NewItemsSizer(), newWorkerPool(1), NewPartitioner(func(ctx context.Context, _ request.Request) string { return ctx.Value(partitionKey{}).(string) }), nil, sink.Export, zap.NewNop(), ) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, ba.Shutdown(context.Background())) }) done := newFakeDone() ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p1"), &requesttest.FakeRequest{Items: 8}, done) ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p2"), &requesttest.FakeRequest{Items: 6}, done) // Neither batch should be flushed since they haven't reached min threshold. assert.Equal(t, 0, sink.RequestsCount()) assert.Equal(t, 0, sink.ItemsCount()) ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p1"), &requesttest.FakeRequest{Items: 8}, done) ba.Consume(context.WithValue(context.Background(), partitionKey{}, "p2"), &requesttest.FakeRequest{Items: 6}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 2 && sink.ItemsCount() == 28 }, 1*time.Second, 10*time.Millisecond) // Check that done callback is called for the right amount of times. assert.EqualValues(t, 0, done.errors.Load()) assert.EqualValues(t, 4, done.success.Load()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/partition_batcher.go000066400000000000000000000207631511331344600334600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "sync" "time" "go.uber.org/multierr" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) var _ Batcher[request.Request] = (*partitionBatcher)(nil) type batch struct { ctx context.Context req request.Request done multiDone } // partitionBatcher continuously batch incoming requests and flushes asynchronously if minimum size limit is met or on timeout. type partitionBatcher struct { cfg BatchConfig wp *workerPool sizer request.Sizer mergeCtx func(context.Context, context.Context) context.Context consumeFunc sender.SendFunc[request.Request] stopWG sync.WaitGroup currentBatchMu sync.Mutex currentBatch *batch timer *time.Timer shutdownCh chan struct{} logger *zap.Logger } func newPartitionBatcher( cfg BatchConfig, sizer request.Sizer, mergeCtx func(context.Context, context.Context) context.Context, wp *workerPool, next sender.SendFunc[request.Request], logger *zap.Logger, ) *partitionBatcher { return &partitionBatcher{ cfg: cfg, wp: wp, sizer: sizer, mergeCtx: mergeCtx, consumeFunc: next, shutdownCh: make(chan struct{}, 1), logger: logger, } } func (qb *partitionBatcher) resetTimer() { if qb.cfg.FlushTimeout > 0 { qb.timer.Reset(qb.cfg.FlushTimeout) } } func (qb *partitionBatcher) Consume(ctx context.Context, req request.Request, done queue.Done) { qb.currentBatchMu.Lock() if qb.currentBatch == nil { reqList, mergeSplitErr := req.MergeSplit(ctx, int(qb.cfg.MaxSize), qb.cfg.Sizer, nil) if mergeSplitErr != nil { // Do not return in case of error if there are data, try to export as much as possible. qb.logger.Warn("Failed to split request.", zap.Error(mergeSplitErr)) } if len(reqList) == 0 { done.OnDone(mergeSplitErr) qb.currentBatchMu.Unlock() return } // If more than one flush is required for this request, call done only when all flushes are done. numRefs := len(reqList) // Need to also inform about the mergeSplitErr, consider the errored data as 1 batch. if mergeSplitErr != nil { numRefs++ } if numRefs > 1 { done = newRefCountDone(done, int64(numRefs)) if mergeSplitErr != nil { done.OnDone(mergeSplitErr) } } // We have at least one result in the reqList. Last in the list may not have enough data to be flushed. // Find if it has at least MinSize, and if it does then move that as the current batch. lastReq := reqList[len(reqList)-1] if qb.sizer.Sizeof(lastReq) < qb.cfg.MinSize { // Do not flush the last item and add it to the current batch. reqList = reqList[:len(reqList)-1] qb.currentBatch = &batch{ ctx: ctx, req: lastReq, done: multiDone{done}, } qb.resetTimer() } qb.currentBatchMu.Unlock() for i := 0; i < len(reqList); i++ { qb.flush(ctx, reqList[i], done) } return } reqList, mergeSplitErr := qb.currentBatch.req.MergeSplit(ctx, int(qb.cfg.MaxSize), qb.cfg.Sizer, req) // If failed to merge signal all Done callbacks from the current batch as well as the current request and reset the current batch. if mergeSplitErr != nil { // Do not return in case of error if there are data, try to export as much as possible. qb.logger.Warn("Failed to split request.", zap.Error(mergeSplitErr)) } if len(reqList) == 0 { done.OnDone(mergeSplitErr) qb.currentBatchMu.Unlock() return } // If more than one flush is required for this request, call done only when all flushes are done. numRefs := len(reqList) // Need to also inform about the mergeSplitErr, consider the errored data as 1 batch. if mergeSplitErr != nil { numRefs++ } if numRefs > 1 { done = newRefCountDone(done, int64(len(reqList))) if mergeSplitErr != nil { done.OnDone(mergeSplitErr) } } // We have at least one result in the reqList, if more results here is what that means: // - First result will contain items from the current batch + some results from the current request. // - All other results except first will contain items only from the current request. // - Last result may not have enough data to be flushed. // Logic on how to deal with the current batch: qb.currentBatch.req = reqList[0] qb.currentBatch.done = append(qb.currentBatch.done, done) mergedCtx := context.Background() //nolint:contextcheck if qb.mergeCtx != nil { mergedCtx = qb.mergeCtx(qb.currentBatch.ctx, ctx) } qb.currentBatch.ctx = contextWithMergedLinks(mergedCtx, qb.currentBatch.ctx, ctx) // Save the "currentBatch" if we need to flush it, because we want to execute flush without holding the lock, and // cannot unlock and re-lock because we are not done processing all the responses. var firstBatch *batch // Need to check the currentBatch if more than 1 result returned or if 1 result return but larger than MinSize. if len(reqList) > 1 || qb.sizer.Sizeof(qb.currentBatch.req) >= qb.cfg.MinSize { firstBatch = qb.currentBatch qb.currentBatch = nil } // At this moment we dealt with the first result which is iter in the currentBatch or in the `firstBatch` we will flush. reqList = reqList[1:] // If we still have results to process, then we need to check if the last result has enough data to flush, or we add it to the currentBatch. if len(reqList) > 0 { lastReq := reqList[len(reqList)-1] if qb.sizer.Sizeof(lastReq) < qb.cfg.MinSize { // Do not flush the last item and add it to the current batch. reqList = reqList[:len(reqList)-1] qb.currentBatch = &batch{ ctx: ctx, req: lastReq, done: multiDone{done}, } qb.resetTimer() } } qb.currentBatchMu.Unlock() if firstBatch != nil { qb.flush(firstBatch.ctx, firstBatch.req, firstBatch.done) } for i := 0; i < len(reqList); i++ { qb.flush(ctx, reqList[i], done) } } // Start starts the goroutine that reads from the queue and flushes asynchronously. func (qb *partitionBatcher) Start(context.Context, component.Host) error { if qb.cfg.FlushTimeout <= 0 { return nil } qb.timer = time.NewTimer(qb.cfg.FlushTimeout) qb.stopWG.Add(1) go func() { defer qb.stopWG.Done() for { select { case <-qb.shutdownCh: return case <-qb.timer.C: qb.flushCurrentBatchIfNecessary() } } }() return nil } // Shutdown ensures that queue and all Batcher are stopped. func (qb *partitionBatcher) Shutdown(context.Context) error { close(qb.shutdownCh) // Make sure execute one last flush if necessary. qb.flushCurrentBatchIfNecessary() qb.stopWG.Wait() return nil } // flushCurrentBatchIfNecessary sends out the current request batch if it is not nil func (qb *partitionBatcher) flushCurrentBatchIfNecessary() { qb.currentBatchMu.Lock() if qb.currentBatch == nil { qb.currentBatchMu.Unlock() return } batchToFlush := qb.currentBatch qb.currentBatch = nil qb.currentBatchMu.Unlock() // flush() blocks until successfully started a goroutine for flushing. qb.flush(batchToFlush.ctx, batchToFlush.req, batchToFlush.done) qb.resetTimer() } // flush starts a goroutine that calls consumeFunc. It blocks until a worker is available if necessary. func (qb *partitionBatcher) flush(ctx context.Context, req request.Request, done queue.Done) { qb.stopWG.Add(1) qb.wp.execute(func() { defer qb.stopWG.Done() done.OnDone(qb.consumeFunc(ctx, req)) }) } type workerPool struct { workers chan struct{} } func newWorkerPool(maxWorkers int) *workerPool { workers := make(chan struct{}, maxWorkers) for range maxWorkers { workers <- struct{}{} } return &workerPool{workers: workers} } func (wp *workerPool) execute(f func()) { <-wp.workers go func() { defer func() { wp.workers <- struct{}{} }() f() }() } type multiDone []queue.Done func (mdc multiDone) OnDone(err error) { for _, d := range mdc { d.OnDone(err) } } type refCountDone struct { done queue.Done mu sync.Mutex refCount int64 err error } func newRefCountDone(done queue.Done, refCount int64) queue.Done { return &refCountDone{ done: done, refCount: refCount, } } func (rcd *refCountDone) OnDone(err error) { rcd.mu.Lock() defer rcd.mu.Unlock() rcd.err = multierr.Append(rcd.err, err) rcd.refCount-- if rcd.refCount == 0 { // No more references, call done. rcd.done.OnDone(rcd.err) } } partition_batcher_test.go000066400000000000000000000441631511331344600344400ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch import ( "context" "errors" "runtime" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" ) type testContextKey string const timestampKey testContextKey = "timestamp" func TestPartitionBatcher_NoSplit_MinThresholdZero_TimeoutDisabled(t *testing.T) { tests := []struct { name string sizerType request.SizerType sizer request.Sizer maxWorkers int }{ { name: "items/one_worker", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 1, }, { name: "items/three_workers", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 3, }, { name: "bytes/one_worker", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 1, }, { name: "bytes/three_workers", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 3, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, Sizer: tt.sizerType, MinSize: 0, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, tt.sizer, nil, newWorkerPool(tt.maxWorkers), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, ba.Shutdown(context.Background())) }) done := newFakeDone() ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) sink.SetExportErr(errors.New("transient error")) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) <-time.After(10 * time.Millisecond) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 17, Bytes: 17}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 13, Bytes: 13}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 35, Bytes: 35}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 2, Bytes: 2}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 5 && (sink.ItemsCount() == 75 || sink.BytesCount() == 75) }, 1*time.Second, 10*time.Millisecond) // Check that done callback is called for the right number of times. assert.EqualValues(t, 1, done.errors.Load()) assert.EqualValues(t, 5, done.success.Load()) }) } } func TestPartitionBatcher_NoSplit_TimeoutDisabled(t *testing.T) { tests := []struct { name string sizerType request.SizerType sizer request.Sizer maxWorkers int }{ { name: "items/one_worker", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 1, }, { name: "items/three_workers", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 3, }, { name: "bytes/one_worker", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 1, }, { name: "bytes/three_workers", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 3, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, Sizer: tt.sizerType, MinSize: 10, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, tt.sizer, nil, newWorkerPool(tt.maxWorkers), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) done := newFakeDone() // These two requests will be dropped because of export error. sink.SetExportErr(errors.New("transient error")) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) <-time.After(10 * time.Millisecond) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 7, Bytes: 7}, done) // This requests will be dropped because of merge error. ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8, MergeErr: errors.New("transient error")}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 13, Bytes: 13}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 35, Bytes: 35}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 2, Bytes: 2}, done) // Only the requests with 7+13 and 35 will be flushed. assert.Eventually(t, func() bool { return sink.RequestsCount() == 2 && (sink.ItemsCount() == 55 || sink.BytesCount() == 55) }, 1*time.Second, 10*time.Millisecond) require.NoError(t, ba.Shutdown(context.Background())) // After shutdown the pending "current batch" is also flushed. assert.Equal(t, 3, sink.RequestsCount()) assert.True(t, sink.ItemsCount() == 57 || sink.BytesCount() == 57) // Check that done callback is called for the right number of times. assert.EqualValues(t, 3, done.errors.Load()) assert.EqualValues(t, 4, done.success.Load()) }) } } func TestPartitionBatcher_NoSplit_WithTimeout(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("Skipping test on Windows, see https://github.com/open-telemetry/opentelemetry-collector/issues/11869") } tests := []struct { name string sizerType request.SizerType sizer request.Sizer maxWorkers int }{ { name: "items/one_worker", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 1, }, { name: "items/three_workers", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 3, }, { name: "bytes/one_worker", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 1, }, { name: "bytes/three_workers", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 3, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 50 * time.Millisecond, Sizer: tt.sizerType, MinSize: 100, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, tt.sizer, nil, newWorkerPool(tt.maxWorkers), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, ba.Shutdown(context.Background())) }) done := newFakeDone() ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 17, Bytes: 17}, done) // This requests will be dropped because of merge error. ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8, MergeErr: errors.New("transient error")}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 13, Bytes: 13}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 35, Bytes: 35}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 2, Bytes: 2}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 1 && (sink.ItemsCount() == 75 || sink.BytesCount() == 75) }, 1*time.Second, 10*time.Millisecond) // Check that done callback is called for the right number of times. assert.EqualValues(t, 1, done.errors.Load()) assert.EqualValues(t, 5, done.success.Load()) }) } } func TestPartitionBatcher_Split_TimeoutDisabled(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("Skipping test on Windows, see https://github.com/open-telemetry/opentelemetry-collector/issues/11847") } tests := []struct { name string sizerType request.SizerType sizer request.Sizer maxWorkers int }{ { name: "items/one_worker", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 1, }, { name: "items/three_workers", sizerType: request.SizerTypeItems, sizer: request.NewItemsSizer(), maxWorkers: 3, }, { name: "bytes/one_worker", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 1, }, { name: "bytes/three_workers", sizerType: request.SizerTypeBytes, sizer: request.NewBytesSizer(), maxWorkers: 3, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, Sizer: tt.sizerType, MinSize: 100, MaxSize: 100, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, tt.sizer, nil, newWorkerPool(tt.maxWorkers), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) done := newFakeDone() // This requests will be dropped because of merge error. ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8, MergeErr: errors.New("transient error")}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 17, Bytes: 17}, done) // This requests will be dropped because of merge error. ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8, MergeErr: errors.New("transient error")}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 13, Bytes: 13}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 35, Bytes: 35}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 2, Bytes: 2}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 30, Bytes: 30}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 1 && (sink.ItemsCount() == 100 || sink.BytesCount() == 100) }, 1*time.Second, 10*time.Millisecond) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 900, Bytes: 900}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 10 && (sink.ItemsCount() == 1000 || sink.BytesCount() == 1000) }, 1*time.Second, 10*time.Millisecond) // At this point the 7th not failing request is still pending. assert.EqualValues(t, 6, done.success.Load()) require.NoError(t, ba.Shutdown(context.Background())) // After shutdown the pending "current batch" is also flushed. assert.Equal(t, 11, sink.RequestsCount()) assert.True(t, sink.ItemsCount() == 1005 || sink.BytesCount() == 1005) // Check that done callback is called for the right number of times. assert.EqualValues(t, 2, done.errors.Load()) assert.EqualValues(t, 7, done.success.Load()) }) } } func TestPartitionBatcher_Shutdown(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 100 * time.Second, Sizer: request.SizerTypeItems, MinSize: 10, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, request.NewItemsSizer(), nil, newWorkerPool(2), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) done := newFakeDone() ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 1, Bytes: 1}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 2, Bytes: 2}, done) assert.Equal(t, 0, sink.RequestsCount()) assert.Equal(t, 0, sink.ItemsCount()) require.NoError(t, ba.Shutdown(context.Background())) assert.Equal(t, 1, sink.RequestsCount()) assert.Equal(t, 3, sink.ItemsCount()) // Check that done callback is called for the right number of times. assert.EqualValues(t, 0, done.errors.Load()) assert.EqualValues(t, 2, done.success.Load()) } func TestPartitionBatcher_MergeError(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 200 * time.Second, Sizer: request.SizerTypeItems, MinSize: 5, MaxSize: 7, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, request.NewItemsSizer(), nil, newWorkerPool(2), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, ba.Shutdown(context.Background())) }) done := newFakeDone() ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 9, Bytes: 9}, done) assert.Eventually(t, func() bool { return sink.RequestsCount() == 1 && sink.ItemsCount() == 7 }, 1*time.Second, 10*time.Millisecond) sink.SetExportErr(errors.New("transient error")) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 4, Bytes: 4}, done) assert.Eventually(t, func() bool { return done.errors.Load() == 2 }, 1*time.Second, 10*time.Millisecond) // Check that done callback is called for the right number of times. assert.EqualValues(t, 2, done.errors.Load()) assert.EqualValues(t, 0, done.success.Load()) } func TestPartitionBatcher_PartialSuccessError(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, Sizer: request.SizerTypeBytes, MinSize: 10, MaxSize: 15, } core, observed := observer.New(zap.WarnLevel) logger := zap.New(core) sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, request.NewItemsSizer(), nil, newWorkerPool(1), sink.Export, logger) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) done := newFakeDone() req := &requesttest.FakeRequest{ Items: 100, Bytes: 100, MergeErr: errors.New("split error"), MergeErrResult: []request.Request{&requesttest.FakeRequest{Items: 10, Bytes: 15}}, } ba.Consume(context.Background(), req, done) assert.Eventually(t, func() bool { logs := observed.All() if len(logs) == 0 { return false } log := logs[0] return log.Level == zap.WarnLevel && log.Message == "Failed to split request." }, time.Second, 10*time.Millisecond) require.NoError(t, ba.Shutdown(context.Background())) // Verify that done callback was called with the returned batch and error for the split. assert.Equal(t, int64(1), done.errors.Load()) assert.Equal(t, 1, sink.RequestsCount()) assert.Equal(t, 10, sink.ItemsCount()) assert.Equal(t, 15, sink.BytesCount()) } func TestSPartitionBatcher_PartialSuccessError_AfterOkRequest(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, Sizer: request.SizerTypeBytes, MinSize: 10, MaxSize: 15, } core, observed := observer.New(zap.WarnLevel) logger := zap.New(core) sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, request.NewItemsSizer(), nil, newWorkerPool(1), sink.Export, logger) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) done := newFakeDone() ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 5, Bytes: 5}, done) req := &requesttest.FakeRequest{ Items: 100, Bytes: 100, MergeErr: errors.New("split error"), MergeErrResult: []request.Request{&requesttest.FakeRequest{Items: 10, Bytes: 15}}, } ba.Consume(context.Background(), req, done) assert.Eventually(t, func() bool { logs := observed.All() if len(logs) == 0 { return false } log := logs[0] return log.Level == zap.WarnLevel && log.Message == "Failed to split request." }, time.Second, 10*time.Millisecond) require.NoError(t, ba.Shutdown(context.Background())) // Verify that done callback was called with the success for the returned batch and error for the split. assert.Equal(t, int64(1), done.errors.Load()) assert.Equal(t, int64(1), done.success.Load()) assert.Equal(t, 1, sink.RequestsCount()) assert.Equal(t, 10, sink.ItemsCount()) assert.Equal(t, 15, sink.BytesCount()) } type fakeDone struct { errors *atomic.Int64 success *atomic.Int64 } func newFakeDone() fakeDone { return fakeDone{ errors: &atomic.Int64{}, success: &atomic.Int64{}, } } func (fd fakeDone) OnDone(err error) { if err != nil { fd.errors.Add(1) } else { fd.success.Add(1) } } func TestShardBatcher_EmptyRequestList(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, MinSize: 0, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, request.NewItemsSizer(), nil, newWorkerPool(1), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, ba.Shutdown(context.Background())) }) done := newFakeDone() req := &requesttest.FakeRequest{ Items: 1, MergeErr: errors.New("force empty list"), } ba.Consume(context.Background(), req, done) assert.Eventually(t, func() bool { return done.errors.Load() == 1 }, time.Second, 10*time.Millisecond) assert.Equal(t, int64(0), done.success.Load()) assert.Equal(t, 0, sink.RequestsCount()) } func TestPartitionBatcher_ContextMerging(t *testing.T) { tests := []struct { name string mergeCtxFunc func(ctx1, ctx2 context.Context) context.Context }{ { name: "merge_context_with_timestamp", mergeCtxFunc: func(ctx1, _ context.Context) context.Context { return context.WithValue(ctx1, timestampKey, 1234) }, }, { name: "merge_context_returns_background", mergeCtxFunc: func(_, _ context.Context) context.Context { return context.Background() }, }, { name: "nil_merge_context", mergeCtxFunc: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cfg := BatchConfig{ FlushTimeout: 0, Sizer: request.SizerTypeItems, MinSize: 10, } sink := requesttest.NewSink() ba := newPartitionBatcher(cfg, request.NewItemsSizer(), tt.mergeCtxFunc, newWorkerPool(1), sink.Export, zap.NewNop()) require.NoError(t, ba.Start(context.Background(), componenttest.NewNopHost())) done := newFakeDone() ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) ba.Consume(context.Background(), &requesttest.FakeRequest{Items: 8, Bytes: 8}, done) <-time.After(10 * time.Millisecond) assert.Equal(t, 1, sink.RequestsCount()) assert.EqualValues(t, 2, done.success.Load()) }) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/partitioner.go000066400000000000000000000014411511331344600323070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) // Partitioner is an interface that returns the the partition key of the given element. type Partitioner[T any] interface { GetKey(context.Context, T) string } type GetKeyFunc[T any] func(context.Context, T) string func (f GetKeyFunc[T]) GetKey(ctx context.Context, t T) string { return f(ctx, t) } type basePartitioner struct { GetKeyFunc[request.Request] } func NewPartitioner( getKeyFunc GetKeyFunc[request.Request], ) Partitioner[request.Request] { return &basePartitioner{ GetKeyFunc: getKeyFunc, } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/partitioner_test.go000066400000000000000000000030761511331344600333540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch import ( "context" "strconv" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" ) func TestPartitioner_GetKeyFromRequest(t *testing.T) { partitioner := NewPartitioner(func(_ context.Context, req request.Request) string { return strconv.Itoa(req.(*requesttest.FakeRequest).ItemsCount()) }) require.Equal(t, "2", partitioner.GetKey(context.Background(), &requesttest.FakeRequest{Items: 2})) require.Equal(t, "3", partitioner.GetKey(context.Background(), &requesttest.FakeRequest{Items: 3})) require.Equal(t, "4", partitioner.GetKey(context.Background(), &requesttest.FakeRequest{Items: 4})) } func TestPartitioner_GetKeyFromContext(t *testing.T) { partitioner := NewPartitioner(func(ctx context.Context, _ request.Request) string { return client.FromContext(ctx).Metadata.Get("metadata_key")[0] }) ctx1 := client.NewContext(context.Background(), client.Info{ Metadata: client.NewMetadata(map[string][]string{"metadata_key": {"partition1"}}), }) require.Equal(t, "partition1", partitioner.GetKey(ctx1, &requesttest.FakeRequest{Items: 2})) ctx2 := client.NewContext(context.Background(), client.Info{ Metadata: client.NewMetadata(map[string][]string{"metadata_key": {"partition2"}}), }) require.Equal(t, "partition2", partitioner.GetKey(ctx2, &requesttest.FakeRequest{Items: 2})) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/queue_batch.go000066400000000000000000000061551511331344600322430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "errors" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" "go.opentelemetry.io/collector/pipeline" ) // Settings is a subset of the queuebatch.Settings that are needed when used within an Exporter. type Settings[T any] struct { ReferenceCounter queue.ReferenceCounter[T] Encoding queue.Encoding[T] Partitioner Partitioner[T] MergeCtx func(context.Context, context.Context) context.Context } // AllSettings defines settings for creating a QueueBatch. type AllSettings[T any] struct { Settings[T] Signal pipeline.Signal ID component.ID Telemetry component.TelemetrySettings } type QueueBatch struct { queue queue.Queue[request.Request] batcher Batcher[request.Request] } func NewQueueBatch( set AllSettings[request.Request], cfg Config, next sender.SendFunc[request.Request], ) (*QueueBatch, error) { b, err := NewBatcher(cfg.Batch, batcherSettings[request.Request]{ partitioner: set.Partitioner, mergeCtx: set.MergeCtx, next: next, maxWorkers: cfg.NumConsumers, logger: set.Telemetry.Logger, }) if err != nil { return nil, err } if cfg.Batch.HasValue() && set.Partitioner == nil { // If batching is enabled and partitioner is not defined then keep the number of queue consumers to 1. // see: https://github.com/open-telemetry/opentelemetry-collector/issues/12473 cfg.NumConsumers = 1 } q, err := queue.NewQueue(queue.Settings[request.Request]{ SizerType: cfg.Sizer, Capacity: cfg.QueueSize, NumConsumers: cfg.NumConsumers, WaitForResult: cfg.WaitForResult, BlockOnOverflow: cfg.BlockOnOverflow, Signal: set.Signal, StorageID: cfg.StorageID, ReferenceCounter: set.ReferenceCounter, Encoding: set.Encoding, ID: set.ID, Telemetry: set.Telemetry, }, b.Consume) if err != nil { return nil, err } return &QueueBatch{queue: q, batcher: b}, nil } // Start is invoked during service startup. func (qs *QueueBatch) Start(ctx context.Context, host component.Host) error { if err := qs.batcher.Start(ctx, host); err != nil { return err } if err := qs.queue.Start(ctx, host); err != nil { return errors.Join(err, qs.batcher.Shutdown(ctx)) } return nil } // Shutdown is invoked during service shutdown. func (qs *QueueBatch) Shutdown(ctx context.Context) error { // Stop the queue and batcher, this will drain the queue and will call the retry (which is stopped) that will only // try once every request. return errors.Join(qs.queue.Shutdown(ctx), qs.batcher.Shutdown(ctx)) } // Send implements the requestSender interface. It puts the request in the queue. func (qs *QueueBatch) Send(ctx context.Context, req request.Request) error { return qs.queue.Offer(ctx, req) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/queue_batch_test.go000066400000000000000000000535061511331344600333040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch import ( "context" "errors" "runtime" "sync" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/experr" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/hosttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sendertest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/storagetest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pipeline" ) func newFakeRequestSettings() AllSettings[request.Request] { return AllSettings[request.Request]{ Signal: pipeline.SignalMetrics, ID: component.NewID(exportertest.NopType), Telemetry: componenttest.NewNopTelemetrySettings(), Settings: Settings[request.Request]{ Encoding: newFakeEncoding(&requesttest.FakeRequest{}), }, } } type fakeEncoding struct { mr request.Request } func (f fakeEncoding) Marshal(context.Context, request.Request) ([]byte, error) { return []byte("mockRequest"), nil } func (f fakeEncoding) Unmarshal([]byte) (context.Context, request.Request, error) { return context.Background(), f.mr, nil } func newFakeEncoding(mr request.Request) queue.Encoding[request.Request] { return &fakeEncoding{mr: mr} } func TestQueueBatchStopWhileWaiting(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.NumConsumers = 1 cfg.Batch = configoptional.Optional[BatchConfig]{} qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) sink.SetExportErr(errors.New("transient error")) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) // Enqueue another request to ensure when calling shutdown we drain the queue. require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 3, Delay: 100 * time.Millisecond})) require.LessOrEqual(t, int64(1), qb.queue.Size()) require.NoError(t, qb.Shutdown(context.Background())) assert.Equal(t, 1, sink.RequestsCount()) assert.Equal(t, 3, sink.ItemsCount()) require.Zero(t, qb.queue.Size()) } func TestQueueBatchDoNotPreserveCancellation(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.NumConsumers = 1 qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) ctx, cancelFunc := context.WithCancel(context.Background()) cancelFunc() require.NoError(t, qb.Send(ctx, &requesttest.FakeRequest{Items: 4})) require.NoError(t, qb.Shutdown(context.Background())) assert.Equal(t, 1, sink.RequestsCount()) assert.Equal(t, 4, sink.ItemsCount()) require.Zero(t, qb.queue.Size()) } func TestQueueBatchHappyPath(t *testing.T) { cfg := newTestConfig() cfg.BlockOnOverflow = false cfg.QueueSize = 56 sink := requesttest.NewSink() qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) for i := range 10 { require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: i + 1})) } // expect queue to be full require.Error(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 2})) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) assert.Eventually(t, func() bool { // Because batching is used, cannot guarantee that will be 1 batch or multiple because of the flush interval. // Check only for total items count. return sink.ItemsCount() == 55 }, 1*time.Second, 10*time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatchDifferentSizers(t *testing.T) { // Set up the config so that the request is accepted in the queue // because the bytes size is used for the queue, // but split because the items size is used for batch. cfg := Config{ Enabled: true, WaitForResult: false, Sizer: request.SizerTypeBytes, QueueSize: 100, BlockOnOverflow: false, NumConsumers: 1, Batch: configoptional.Some(BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 100, MaxSize: 200, }), } sink := requesttest.NewSink() qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 1000, Bytes: 100})) assert.Eventually(t, func() bool { return sink.RequestsCount() == 5 && sink.ItemsCount() == 1000 }, 1*time.Second, 10*time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatchPersistenceEnabled(t *testing.T) { cfg := newTestConfig() storageID := component.MustNewIDWithName("file_storage", "storage") cfg.StorageID = &storageID qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) host := hosttest.NewHost(map[component.ID]component.Component{ storageID: storagetest.NewMockStorageExtension(nil), }) // we start correctly with a file storage extension require.NoError(t, qb.Start(context.Background(), host)) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatchPersistenceEnabledStorageError(t *testing.T) { storageError := errors.New("could not get storage client") cfg := newTestConfig() storageID := component.MustNewIDWithName("file_storage", "storage") cfg.StorageID = &storageID qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) host := hosttest.NewHost(map[component.ID]component.Component{ storageID: storagetest.NewMockStorageExtension(storageError), }) // we fail to start if we get an error creating the storage client require.Error(t, qb.Start(context.Background(), host), "could not get storage client") } func TestQueueBatchPersistentEnabled_NoDataLossOnShutdown(t *testing.T) { cfg := newTestConfig() cfg.NumConsumers = 1 storageID := component.MustNewIDWithName("file_storage", "storage") cfg.StorageID = &storageID mockReq := &requesttest.FakeRequest{Items: 2} qSet := newFakeRequestSettings() qSet.Encoding = newFakeEncoding(mockReq) consumed := &atomic.Bool{} done := make(chan struct{}) qb, err := NewQueueBatch(qSet, cfg, func(context.Context, request.Request) error { consumed.Store(true) <-done return experr.NewShutdownErr(errors.New("could not export data")) }) require.NoError(t, err) host := hosttest.NewHost(map[component.ID]component.Component{ storageID: storagetest.NewMockStorageExtension(nil), }) require.NoError(t, qb.Start(context.Background(), host)) // Invoke queuedRetrySender so the producer will put the item for consumer to poll require.NoError(t, qb.Send(context.Background(), mockReq)) // first wait for the item to be consumed from the queue assert.Eventually(t, func() bool { return consumed.Load() }, 1*time.Second, 10*time.Millisecond) // shuts down the exporter, unsent data should be preserved as in-flight data in the persistent queue. close(done) require.NoError(t, qb.Shutdown(context.Background())) // start the exporter again replacing the preserved mockRequest in the unmarshaler with a new one that doesn't fail. sink := requesttest.NewSink() replacedReq := &requesttest.FakeRequest{Items: 7} qSet.Encoding = newFakeEncoding(replacedReq) qb, err = NewQueueBatch(qSet, cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), host)) assert.Eventually(t, func() bool { return sink.ItemsCount() == 7 && sink.RequestsCount() == 1 }, 1*time.Second, 10*time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatchNoStartShutdown(t *testing.T) { qs, err := NewQueueBatch(newFakeRequestSettings(), newTestConfig(), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) assert.NoError(t, qs.Shutdown(context.Background())) } func TestQueueBatch_Merge(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping flaky test on Windows, see https://github.com/open-telemetry/opentelemetry-collector/issues/10758") } tests := []struct { name string batchCfg BatchConfig }{ { name: "split_disabled", batchCfg: BatchConfig{ FlushTimeout: 100 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 10, }, }, { name: "split_high_limit", batchCfg: BatchConfig{ FlushTimeout: 100 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 10, MaxSize: 1000, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.Batch = configoptional.Some(tt.batchCfg) qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, qb.Shutdown(context.Background())) }) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 8})) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 3})) // the first two requests should be merged into one and sent by reaching the minimum items size assert.Eventually(t, func() bool { return sink.RequestsCount() == 1 && sink.ItemsCount() == 11 }, 50*time.Millisecond, 10*time.Millisecond) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 3})) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 1})) // the third and fifth requests should be sent by reaching the timeout // the fourth request should be ignored because of the merge error. time.Sleep(50 * time.Millisecond) // should be ignored because of the merge error. require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{ Items: 3, MergeErr: errors.New("merge error"), })) assert.Equal(t, 1, sink.RequestsCount()) assert.Eventually(t, func() bool { return sink.RequestsCount() == 2 && sink.ItemsCount() == 15 }, 1*time.Second, 10*time.Millisecond) }) } } func TestQueueBatch_BatchExportError(t *testing.T) { tests := []struct { name string batchCfg BatchConfig expectedRequests int expectedItems int }{ { name: "merge_only", batchCfg: BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 10, }, }, { name: "merge_without_split_triggered", batchCfg: BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 10, MaxSize: 200, }, }, { name: "merge_with_split_triggered", batchCfg: BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 10, MaxSize: 20, }, expectedRequests: 1, expectedItems: 8, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.Batch = configoptional.Some(tt.batchCfg) qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) // the first two requests should be blocked by the batchSender. time.Sleep(50 * time.Millisecond) assert.Equal(t, 0, sink.RequestsCount()) // the third request should trigger the export and cause an error. sink.SetExportErr(errors.New("transient error")) errReq := &requesttest.FakeRequest{Items: 20} require.NoError(t, qb.Send(context.Background(), errReq)) // the batch should be dropped since the queue doesn't have re-queuing enabled. assert.Eventually(t, func() bool { return sink.RequestsCount() == tt.expectedRequests && sink.ItemsCount() == tt.expectedItems && qb.queue.Size() == 0 }, 1*time.Second, 10*time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) }) } } func TestQueueBatch_MergeOrSplit(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.Batch = configoptional.Some(BatchConfig{ FlushTimeout: 100 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 5, MaxSize: 10, }) qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) // should be sent right away by reaching the minimum items size. require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 8})) assert.Eventually(t, func() bool { return sink.RequestsCount() == 1 && sink.ItemsCount() == 8 }, 1*time.Second, 10*time.Millisecond) // big request should be broken down into two requests, both are sent right away. require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 17})) assert.Eventually(t, func() bool { return sink.RequestsCount() == 3 && sink.ItemsCount() == 25 }, 1*time.Second, 10*time.Millisecond) // request that cannot be split should be dropped. require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{ Items: 11, MergeErr: errors.New("split error"), })) // big request should be broken down into two requests, both are sent right away. require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 13})) assert.Eventually(t, func() bool { return sink.RequestsCount() == 5 && sink.ItemsCount() == 38 }, 1*time.Second, 10*time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatch_MergeOrSplit_Multibatch(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.Batch = configoptional.Some(BatchConfig{ FlushTimeout: 100 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 10, }) type partitionKey struct{} set := newFakeRequestSettings() set.Partitioner = NewPartitioner(func(ctx context.Context, _ request.Request) string { key := ctx.Value(partitionKey{}).(string) return key }) qb, err := NewQueueBatch(set, cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) // should be sent right away by reaching the minimum items size. require.NoError(t, qb.Send(context.WithValue(context.Background(), partitionKey{}, "p1"), &requesttest.FakeRequest{Items: 8})) require.NoError(t, qb.Send(context.WithValue(context.Background(), partitionKey{}, "p2"), &requesttest.FakeRequest{Items: 6})) // Neither batch should be flushed since they haven't reached min threshold. assert.Equal(t, 0, sink.RequestsCount()) assert.Equal(t, 0, sink.ItemsCount()) require.NoError(t, qb.Send(context.WithValue(context.Background(), partitionKey{}, "p1"), &requesttest.FakeRequest{Items: 8})) assert.Eventually(t, func() bool { return sink.RequestsCount() == 1 && sink.ItemsCount() == 16 }, 500*time.Millisecond, 10*time.Millisecond) require.NoError(t, qb.Send(context.WithValue(context.Background(), partitionKey{}, "p2"), &requesttest.FakeRequest{Items: 6})) assert.Eventually(t, func() bool { return sink.RequestsCount() == 2 && sink.ItemsCount() == 28 }, 500*time.Millisecond, 10*time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatch_Shutdown(t *testing.T) { sink := requesttest.NewSink() qb, err := NewQueueBatch(newFakeRequestSettings(), newTestConfig(), sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 3})) // To make the request reached the batchSender before shutdown. time.Sleep(50 * time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) // shutdown should force sending the batch assert.Equal(t, 1, sink.RequestsCount()) assert.Equal(t, 3, sink.ItemsCount()) } func TestQueueBatch_BatchBlocking(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.WaitForResult = true cfg.Batch = configoptional.Some(BatchConfig{Sizer: request.SizerTypeItems, MinSize: 3}) qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) // send 6 blockOnOverflow requests wg := sync.WaitGroup{} for range 6 { wg.Add(1) go func() { defer wg.Done() assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 1, Delay: 10 * time.Millisecond})) }() } wg.Wait() // should be sent in two batches since the batch size is 3 assert.Equal(t, 2, sink.RequestsCount()) assert.Equal(t, 6, sink.ItemsCount()) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatch_DrainActiveRequests(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.WaitForResult = true cfg.Batch = configoptional.Some(BatchConfig{Sizer: request.SizerTypeItems, MinSize: 2}) qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) // send 3 blockOnOverflow requests with a timeout go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 1, Delay: 40 * time.Millisecond})) }() go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 1, Delay: 40 * time.Millisecond})) }() go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 1, Delay: 40 * time.Millisecond})) }() // give time for the first two requests to be batched time.Sleep(20 * time.Millisecond) // Shutdown should force the active batch to be dispatched and wait for all batches to be delivered. // It should take 120 milliseconds to complete. require.NoError(t, qb.Shutdown(context.Background())) assert.Equal(t, 2, sink.RequestsCount()) assert.Equal(t, 3, sink.ItemsCount()) } func TestQueueBatchTimerResetNoConflict(t *testing.T) { sink := requesttest.NewSink() cfg := newTestConfig() cfg.WaitForResult = true cfg.Batch = configoptional.Some(BatchConfig{FlushTimeout: 100 * time.Millisecond, MinSize: 8}) qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) // Send 2 concurrent requests that should be merged in one batch in the same interval as the flush timer go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) }() time.Sleep(30 * time.Millisecond) go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) }() // The batch should be sent either with the flush interval or by reaching the minimum items size with no conflict assert.EventuallyWithT(t, func(c *assert.CollectT) { assert.LessOrEqual(c, 1, sink.RequestsCount()) assert.Equal(c, 8, sink.ItemsCount()) }, 1*time.Second, 10*time.Millisecond) require.NoError(t, qb.Shutdown(context.Background())) } func TestQueueBatchTimerFlush(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping flaky test on Windows, see https://github.com/open-telemetry/opentelemetry-collector/issues/10802") } sink := requesttest.NewSink() cfg := newTestConfig() cfg.WaitForResult = true cfg.Batch = configoptional.Some(BatchConfig{FlushTimeout: 100 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 8}) qb, err := NewQueueBatch(newFakeRequestSettings(), cfg, sink.Export) require.NoError(t, err) require.NoError(t, qb.Start(context.Background(), componenttest.NewNopHost())) time.Sleep(50 * time.Millisecond) // Send 2 concurrent requests that should be merged in one batch and sent immediately go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) }() go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) }() assert.EventuallyWithT(t, func(c *assert.CollectT) { assert.LessOrEqual(c, 1, sink.RequestsCount()) assert.Equal(c, 8, sink.ItemsCount()) }, 30*time.Millisecond, 5*time.Millisecond) // Send another request that should be flushed after 100ms instead of 50ms since last flush go func() { assert.NoError(t, qb.Send(context.Background(), &requesttest.FakeRequest{Items: 4})) }() // Confirm that it is not flushed in 50ms time.Sleep(60 * time.Millisecond) assert.LessOrEqual(t, 1, sink.RequestsCount()) assert.Equal(t, 8, sink.ItemsCount()) // Confirm that it is flushed after 100ms (using 60+50=110 here to be safe) time.Sleep(50 * time.Millisecond) assert.LessOrEqual(t, 2, sink.RequestsCount()) assert.Equal(t, 12, sink.ItemsCount()) require.NoError(t, qb.Shutdown(context.Background())) } func newTestConfig() Config { return Config{ Enabled: true, WaitForResult: false, Sizer: request.SizerTypeItems, NumConsumers: runtime.NumCPU(), QueueSize: 100_000, BlockOnOverflow: true, Batch: configoptional.Some(BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: request.SizerTypeItems, MinSize: 2048, }), } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/testdata/000077500000000000000000000000001511331344600312315ustar00rootroot00000000000000batch_set_empty_explicit_sizer.yaml000066400000000000000000000001041511331344600403200ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/testdatasizer: bytes # Batch is set but empty, do not override sizer batch: batch_set_empty_no_explicit_sizer.yaml000066400000000000000000000000251511331344600410160ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/testdataenabled: true batch: batch_set_nonempty_explicit_sizer.yaml000066400000000000000000000001621511331344600410370ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/testdataenabled: true sizer: bytes queue_size: 2000 batch: # sizer is overridden here by parent sizer min_size: 100 batch_set_nonempty_no_explicit_sizer.yaml000066400000000000000000000002101511331344600415250ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/testdataenabled: true queue_size: 2000 batch: # sizer is NOT overridden here by parent sizer, since parent sizer is not set min_size: 100 batch_unset.yaml000066400000000000000000000000161511331344600343320ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/testdataenabled: true opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/traces.go000066400000000000000000000100601511331344600312250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "errors" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/xpdata/pref" pdatareq "go.opentelemetry.io/collector/pdata/xpdata/request" ) var ( tracesMarshaler = &ptrace.ProtoMarshaler{} tracesUnmarshaler = &ptrace.ProtoUnmarshaler{} ) // NewTracesQueueBatchSettings returns a new QueueBatchSettings to configure to WithQueueBatch when using ptrace.Traces. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewTracesQueueBatchSettings() Settings[request.Request] { return Settings[request.Request]{ ReferenceCounter: tracesReferenceCounter{}, Encoding: tracesEncoding{}, } } var ( _ request.Request = (*tracesRequest)(nil) _ request.ErrorHandler = (*tracesRequest)(nil) ) type tracesRequest struct { td ptrace.Traces cachedSize int } func newTracesRequest(td ptrace.Traces) request.Request { return &tracesRequest{ td: td, cachedSize: -1, } } type tracesEncoding struct{} var _ encoding[request.Request] = tracesEncoding{} func (tracesEncoding) Unmarshal(bytes []byte) (context.Context, request.Request, error) { if queue.PersistRequestContextOnRead() { ctx, traces, err := pdatareq.UnmarshalTraces(bytes) if errors.Is(err, pdatareq.ErrInvalidFormat) { // fall back to unmarshaling without context traces, err = tracesUnmarshaler.UnmarshalTraces(bytes) } return ctx, newTracesRequest(traces), err } traces, err := tracesUnmarshaler.UnmarshalTraces(bytes) if err != nil { var req request.Request return context.Background(), req, err } return context.Background(), newTracesRequest(traces), nil } func (tracesEncoding) Marshal(ctx context.Context, req request.Request) ([]byte, error) { traces := req.(*tracesRequest).td if queue.PersistRequestContextOnWrite() { return pdatareq.MarshalTraces(ctx, traces) } return tracesMarshaler.MarshalTraces(traces) } var _ queue.ReferenceCounter[request.Request] = tracesReferenceCounter{} type tracesReferenceCounter struct{} func (tracesReferenceCounter) Ref(req request.Request) { pref.RefTraces(req.(*tracesRequest).td) } func (tracesReferenceCounter) Unref(req request.Request) { pref.UnrefTraces(req.(*tracesRequest).td) } func (req *tracesRequest) OnError(err error) request.Request { var traceError consumererror.Traces if errors.As(err, &traceError) { // TODO: Add logic to unref the new request created here. return newTracesRequest(traceError.Data()) } return req } func (req *tracesRequest) ItemsCount() int { return req.td.SpanCount() } func (req *tracesRequest) size(sizer sizer.TracesSizer) int { if req.cachedSize == -1 { req.cachedSize = sizer.TracesSize(req.td) } return req.cachedSize } func (req *tracesRequest) setCachedSize(size int) { req.cachedSize = size } func (req *tracesRequest) BytesSize() int { return tracesMarshaler.TracesSize(req.td) } // RequestConsumeFromTraces returns a RequestConsumeFunc that consumes ptrace.Traces. func RequestConsumeFromTraces(pusher consumer.ConsumeTracesFunc) request.RequestConsumeFunc { return func(ctx context.Context, request request.Request) error { return pusher.ConsumeTraces(ctx, request.(*tracesRequest).td) } } // RequestFromTraces returns a RequestConverterFunc that converts ptrace.Traces into a Request. func RequestFromTraces() request.RequestConverterFunc[ptrace.Traces] { return func(_ context.Context, traces ptrace.Traces) (request.Request, error) { return newTracesRequest(traces), nil } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/traces_batch.go000066400000000000000000000137771511331344600324100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "errors" "fmt" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/ptrace" ) // MergeSplit splits and/or merges the provided traces request and the current request into one or more requests // conforming with the MaxSizeConfig. func (req *tracesRequest) MergeSplit(_ context.Context, maxSize int, szt request.SizerType, r2 request.Request) ([]request.Request, error) { var sz sizer.TracesSizer switch szt { case request.SizerTypeItems: sz = &sizer.TracesCountSizer{} case request.SizerTypeBytes: sz = &sizer.TracesBytesSizer{} default: return nil, errors.New("unknown sizer type") } if r2 != nil { req2, ok := r2.(*tracesRequest) if !ok { return nil, errors.New("invalid input type") } req2.mergeTo(req, sz) } // If no limit we can simply merge the new request into the current and return. if maxSize == 0 { return []request.Request{req}, nil } return req.split(maxSize, sz) } func (req *tracesRequest) mergeTo(dst *tracesRequest, sz sizer.TracesSizer) { if sz != nil { dst.setCachedSize(dst.size(sz) + req.size(sz)) req.setCachedSize(0) } req.td.ResourceSpans().MoveAndAppendTo(dst.td.ResourceSpans()) } func (req *tracesRequest) split(maxSize int, sz sizer.TracesSizer) ([]request.Request, error) { var res []request.Request for req.size(sz) > maxSize { td, rmSize := extractTraces(req.td, maxSize, sz) if td.SpanCount() == 0 { return res, fmt.Errorf("one span size is greater than max size, dropping items: %d", req.td.SpanCount()) } req.setCachedSize(req.size(sz) - rmSize) res = append(res, newTracesRequest(td)) } res = append(res, req) return res, nil } // extractTraces extracts a new traces with a maximum number of spans. func extractTraces(srcTraces ptrace.Traces, capacity int, sz sizer.TracesSizer) (ptrace.Traces, int) { destTraces := ptrace.NewTraces() capacityLeft := capacity - sz.TracesSize(destTraces) removedSize := 0 srcTraces.ResourceSpans().RemoveIf(func(srcRS ptrace.ResourceSpans) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawRsSize := sz.ResourceSpansSize(srcRS) rsSize := sz.DeltaSize(rawRsSize) if rsSize > capacityLeft { extSrcRS, extRsSize := extractResourceSpans(srcRS, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extRsSize // There represents the delta between the delta sizes. removedSize += rsSize - rawRsSize - (sz.DeltaSize(rawRsSize-extRsSize) - (rawRsSize - extRsSize)) // It is possible that for the bytes scenario, the extracted field contains no spans. // Do not add it to the destination if that is the case. if extSrcRS.ScopeSpans().Len() > 0 { extSrcRS.MoveTo(destTraces.ResourceSpans().AppendEmpty()) } return extSrcRS.ScopeSpans().Len() != 0 } capacityLeft -= rsSize removedSize += rsSize srcRS.MoveTo(destTraces.ResourceSpans().AppendEmpty()) return true }) return destTraces, removedSize } // extractResourceSpans extracts spans and returns a new resource spans with the specified number of spans. func extractResourceSpans(srcRS ptrace.ResourceSpans, capacity int, sz sizer.TracesSizer) (ptrace.ResourceSpans, int) { destRS := ptrace.NewResourceSpans() destRS.SetSchemaUrl(srcRS.SchemaUrl()) srcRS.Resource().CopyTo(destRS.Resource()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ResourceSpansSize(destRS) removedSize := 0 srcRS.ScopeSpans().RemoveIf(func(srcSS ptrace.ScopeSpans) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawSlSize := sz.ScopeSpansSize(srcSS) ssSize := sz.DeltaSize(rawSlSize) if ssSize > capacityLeft { extSrcSS, extSsSize := extractScopeSpans(srcSS, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extSsSize // There represents the delta between the delta sizes. removedSize += ssSize - rawSlSize - (sz.DeltaSize(rawSlSize-extSsSize) - (rawSlSize - extSsSize)) // It is possible that for the bytes scenario, the extracted field contains no spans. // Do not add it to the destination if that is the case. if extSrcSS.Spans().Len() > 0 { extSrcSS.MoveTo(destRS.ScopeSpans().AppendEmpty()) } return extSrcSS.Spans().Len() != 0 } capacityLeft -= ssSize removedSize += ssSize srcSS.MoveTo(destRS.ScopeSpans().AppendEmpty()) return true }) return destRS, removedSize } // extractScopeSpans extracts spans and returns a new scope spans with the specified number of spans. func extractScopeSpans(srcSS ptrace.ScopeSpans, capacity int, sz sizer.TracesSizer) (ptrace.ScopeSpans, int) { destSS := ptrace.NewScopeSpans() destSS.SetSchemaUrl(srcSS.SchemaUrl()) srcSS.Scope().CopyTo(destSS.Scope()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ScopeSpansSize(destSS) removedSize := 0 srcSS.Spans().RemoveIf(func(srcSpan ptrace.Span) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rsSize := sz.DeltaSize(sz.SpanSize(srcSpan)) if rsSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rsSize removedSize += rsSize srcSpan.MoveTo(destSS.Spans().AppendEmpty()) return true }) return destSS, removedSize } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/traces_batch_test.go000066400000000000000000000322771511331344600334430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMergeTraces(t *testing.T) { tr1 := newTracesRequest(testdata.GenerateTraces(2)) tr2 := newTracesRequest(testdata.GenerateTraces(3)) res, err := tr1.MergeSplit(context.Background(), 0, request.SizerTypeItems, tr2) require.NoError(t, err) assert.Equal(t, 5, res[0].ItemsCount()) } func TestMergeSplitTraces(t *testing.T) { tests := []struct { name string szt request.SizerType maxSize int tr1 request.Request tr2 request.Request expected []request.Request }{ { name: "both_requests_empty", szt: request.SizerTypeItems, maxSize: 10, tr1: newTracesRequest(ptrace.NewTraces()), tr2: newTracesRequest(ptrace.NewTraces()), expected: []request.Request{newTracesRequest(ptrace.NewTraces())}, }, { name: "first_request_empty", szt: request.SizerTypeItems, maxSize: 10, tr1: newTracesRequest(ptrace.NewTraces()), tr2: newTracesRequest(testdata.GenerateTraces(5)), expected: []request.Request{newTracesRequest(testdata.GenerateTraces(5))}, }, { name: "second_request_empty", szt: request.SizerTypeItems, maxSize: 10, tr1: newTracesRequest(testdata.GenerateTraces(5)), tr2: newTracesRequest(ptrace.NewTraces()), expected: []request.Request{newTracesRequest(testdata.GenerateTraces(5))}, }, { name: "first_empty_second_nil", szt: request.SizerTypeItems, maxSize: 10, tr1: newTracesRequest(ptrace.NewTraces()), tr2: nil, expected: []request.Request{newTracesRequest(ptrace.NewTraces())}, }, { name: "merge_only", szt: request.SizerTypeItems, maxSize: 10, tr1: newTracesRequest(testdata.GenerateTraces(5)), tr2: newTracesRequest(testdata.GenerateTraces(5)), expected: []request.Request{newTracesRequest(func() ptrace.Traces { td := testdata.GenerateTraces(5) testdata.GenerateTraces(5).ResourceSpans().MoveAndAppendTo(td.ResourceSpans()) return td }())}, }, { name: "split_only", szt: request.SizerTypeItems, maxSize: 4, tr1: newTracesRequest(ptrace.NewTraces()), tr2: newTracesRequest(testdata.GenerateTraces(10)), expected: []request.Request{ newTracesRequest(testdata.GenerateTraces(4)), newTracesRequest(testdata.GenerateTraces(4)), newTracesRequest(testdata.GenerateTraces(2)), }, }, { name: "split_and_merge", szt: request.SizerTypeItems, maxSize: 10, tr1: newTracesRequest(testdata.GenerateTraces(4)), tr2: newTracesRequest(testdata.GenerateTraces(20)), expected: []request.Request{ newTracesRequest(func() ptrace.Traces { td := testdata.GenerateTraces(4) testdata.GenerateTraces(6).ResourceSpans().MoveAndAppendTo(td.ResourceSpans()) return td }()), newTracesRequest(testdata.GenerateTraces(10)), newTracesRequest(testdata.GenerateTraces(4)), }, }, { name: "scope_spans_split", szt: request.SizerTypeItems, maxSize: 10, tr1: newTracesRequest(func() ptrace.Traces { td := testdata.GenerateTraces(10) extraScopeTraces := testdata.GenerateTraces(5) extraScopeTraces.ResourceSpans().At(0).ScopeSpans().At(0).Scope().SetName("extra scope") extraScopeTraces.ResourceSpans().MoveAndAppendTo(td.ResourceSpans()) return td }()), tr2: nil, expected: []request.Request{ newTracesRequest(testdata.GenerateTraces(10)), newTracesRequest(func() ptrace.Traces { td := testdata.GenerateTraces(5) td.ResourceSpans().At(0).ScopeSpans().At(0).Scope().SetName("extra scope") return td }()), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.tr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.tr2) require.NoError(t, err) assert.Len(t, res, len(tt.expected)) for i := range res { assert.Equal(t, tt.expected[i].(*tracesRequest).td, res[i].(*tracesRequest).td) } }) } } func TestMergeSplitTracesBasedOnByteSize(t *testing.T) { tests := []struct { name string szt request.SizerType maxSize int lr1 request.Request lr2 request.Request expected []request.Request expectPartialError bool }{ { name: "both_requests_empty", szt: request.SizerTypeBytes, maxSize: tracesMarshaler.TracesSize(testdata.GenerateTraces(10)), lr1: newTracesRequest(ptrace.NewTraces()), lr2: newTracesRequest(ptrace.NewTraces()), expected: []request.Request{newTracesRequest(ptrace.NewTraces())}, }, { name: "first_request_empty", szt: request.SizerTypeBytes, maxSize: tracesMarshaler.TracesSize(testdata.GenerateTraces(10)), lr1: newTracesRequest(ptrace.NewTraces()), lr2: newTracesRequest(testdata.GenerateTraces(5)), expected: []request.Request{newTracesRequest(testdata.GenerateTraces(5))}, }, { name: "first_empty_second_nil", szt: request.SizerTypeBytes, maxSize: tracesMarshaler.TracesSize(testdata.GenerateTraces(10)), lr1: newTracesRequest(ptrace.NewTraces()), lr2: nil, expected: []request.Request{newTracesRequest(ptrace.NewTraces())}, }, { name: "merge_only", szt: request.SizerTypeBytes, maxSize: tracesMarshaler.TracesSize(testdata.GenerateTraces(10)), lr1: newTracesRequest(testdata.GenerateTraces(1)), lr2: newTracesRequest(testdata.GenerateTraces(6)), expected: []request.Request{newTracesRequest(func() ptrace.Traces { traces := testdata.GenerateTraces(1) testdata.GenerateTraces(6).ResourceSpans().MoveAndAppendTo(traces.ResourceSpans()) return traces }())}, }, { name: "split_only", szt: request.SizerTypeBytes, maxSize: tracesMarshaler.TracesSize(testdata.GenerateTraces(4)), lr1: newTracesRequest(ptrace.NewTraces()), lr2: newTracesRequest(testdata.GenerateTraces(10)), expected: []request.Request{ newTracesRequest(testdata.GenerateTraces(4)), newTracesRequest(testdata.GenerateTraces(4)), newTracesRequest(testdata.GenerateTraces(2)), }, }, { name: "merge_and_split", szt: request.SizerTypeBytes, maxSize: tracesMarshaler.TracesSize(testdata.GenerateTraces(10))/2 + tracesMarshaler.TracesSize(testdata.GenerateTraces(11))/2, lr1: newTracesRequest(testdata.GenerateTraces(8)), lr2: newTracesRequest(testdata.GenerateTraces(20)), expected: []request.Request{ newTracesRequest(func() ptrace.Traces { traces := testdata.GenerateTraces(8) testdata.GenerateTraces(2).ResourceSpans().MoveAndAppendTo(traces.ResourceSpans()) return traces }()), newTracesRequest(testdata.GenerateTraces(10)), newTracesRequest(testdata.GenerateTraces(8)), }, }, { name: "scope_spans_split", szt: request.SizerTypeBytes, maxSize: tracesMarshaler.TracesSize(testdata.GenerateTraces(4)), lr1: newTracesRequest(func() ptrace.Traces { ld := testdata.GenerateTraces(4) ld.ResourceSpans().At(0).ScopeSpans().AppendEmpty().Spans().AppendEmpty().Attributes().PutStr("attr", "attrvalue") return ld }()), lr2: newTracesRequest(testdata.GenerateTraces(2)), expected: []request.Request{ newTracesRequest(testdata.GenerateTraces(4)), newTracesRequest(func() ptrace.Traces { ld := testdata.GenerateTraces(0) ld.ResourceSpans().At(0).ScopeSpans().At(0).Spans().AppendEmpty().Attributes().PutStr("attr", "attrvalue") testdata.GenerateTraces(2).ResourceSpans().MoveAndAppendTo(ld.ResourceSpans()) return ld }()), }, expectPartialError: false, }, { name: "unsplittable_large_trace", szt: request.SizerTypeBytes, maxSize: 10, lr1: newTracesRequest(func() ptrace.Traces { ld := testdata.GenerateTraces(1) ld.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes().PutStr("large_attr", string(make([]byte, 100))) return ld }()), lr2: nil, expected: []request.Request{}, expectPartialError: true, }, { name: "splittable_then_unsplittable_trace", szt: request.SizerTypeBytes, maxSize: 1000, lr1: newTracesRequest(func() ptrace.Traces { ld := testdata.GenerateTraces(2) ld.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes().PutStr("large_attr", string(make([]byte, 10))) ld.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(1).Attributes().PutStr("large_attr", string(make([]byte, 1001))) return ld }()), lr2: nil, expected: []request.Request{newTracesRequest(func() ptrace.Traces { ld := testdata.GenerateTraces(1) ld.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Attributes().PutStr("large_attr", string(make([]byte, 10))) return ld }())}, expectPartialError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.lr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.lr2) if tt.expectPartialError { require.ErrorContains(t, err, "one span size is greater than max size, dropping items:") } else { require.NoError(t, err) } assert.Len(t, res, len(tt.expected)) for i := range res { assert.Equal(t, tt.expected[i].(*tracesRequest).td, res[i].(*tracesRequest).td) assert.Equal(t, tracesMarshaler.TracesSize(tt.expected[i].(*tracesRequest).td), tracesMarshaler.TracesSize(res[i].(*tracesRequest).td)) } }) } } func TestMergeSplitTracesInputNotModifiedIfErrorReturned(t *testing.T) { r1 := newTracesRequest(testdata.GenerateTraces(18)) r2 := newLogsRequest(testdata.GenerateLogs(3)) _, err := r1.MergeSplit(context.Background(), 10, request.SizerTypeItems, r2) require.Error(t, err) assert.Equal(t, 18, r1.ItemsCount()) } func TestExtractTraces(t *testing.T) { for i := range 10 { td := testdata.GenerateTraces(10) extractedTraces, removedSize := extractTraces(td, i, &sizer.TracesCountSizer{}) assert.Equal(t, i, extractedTraces.SpanCount()) assert.Equal(t, 10-i, td.SpanCount()) assert.Equal(t, i, removedSize) } } func TestMergeSplitManySmallTraces(t *testing.T) { merged := []request.Request{newTracesRequest(testdata.GenerateTraces(1))} for range 1000 { lr2 := newTracesRequest(testdata.GenerateTraces(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(t, merged, 2) } func TestTracesMergeSplitExactBytes(t *testing.T) { pb := ptrace.ProtoMarshaler{} // Set max size off by 1, so forces every log to be it's own batch. lr := newTracesRequest(testdata.GenerateTraces(4)) merged, err := lr.MergeSplit(context.Background(), pb.TracesSize(testdata.GenerateTraces(2))-1, request.SizerTypeBytes, nil) require.NoError(t, err) assert.Len(t, merged, 4) } func TestTracesMergeSplitExactItems(t *testing.T) { // Set max size off by 1, so forces every log to be it's own batch. lr := newTracesRequest(testdata.GenerateTraces(4)) merged, err := lr.MergeSplit(context.Background(), 1, request.SizerTypeItems, nil) require.NoError(t, err) assert.Len(t, merged, 4) } func TestTracesMergeSplitUnknownSizerType(t *testing.T) { req := newTracesRequest(ptrace.NewTraces()) // Call MergeSplit with invalid sizer _, err := req.MergeSplit(context.Background(), 0, request.SizerType{}, nil) require.EqualError(t, err, "unknown sizer type") } func BenchmarkSplittingBasedOnItemCountManySmallTraces(b *testing.B) { // All requests merge into a single batch. b.ReportAllocs() for b.Loop() { merged := []request.Request{newTracesRequest(testdata.GenerateTraces(10))} for range 1000 { lr2 := newTracesRequest(testdata.GenerateTraces(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10010, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 1) } } func BenchmarkSplittingBasedOnItemCountManyTracesSlightlyAboveLimit(b *testing.B) { // Every incoming request results in a split. b.ReportAllocs() for b.Loop() { merged := []request.Request{newTracesRequest(testdata.GenerateTraces(0))} for range 10 { lr2 := newTracesRequest(testdata.GenerateTraces(10001)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 11) } } func BenchmarkSplittingBasedOnItemCountHugeTraces(b *testing.B) { // One request splits into many batches. b.ReportAllocs() for b.Loop() { merged := []request.Request{newTracesRequest(testdata.GenerateTraces(0))} lr2 := newTracesRequest(testdata.GenerateTraces(100000)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10000, request.SizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) assert.Len(b, merged, 10) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/queuebatch/traces_test.go000066400000000000000000000013671511331344600322760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package queuebatch // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" import ( "errors" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) func TestTracesRequest(t *testing.T) { mr := newTracesRequest(testdata.GenerateTraces(1)) traceErr := consumererror.NewTraces(errors.New("some error"), ptrace.NewTraces()) assert.Equal(t, newTracesRequest(ptrace.NewTraces()), mr.(request.ErrorHandler).OnError(traceErr)) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/request/000077500000000000000000000000001511331344600267625ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/request/request.go000066400000000000000000000057001511331344600310030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" import ( "context" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) // Request represents a single request that can be sent to an external endpoint. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. type Request interface { // ItemsCount returns a number of basic items in the request where item is the smallest piece of data that can be // sent. For example, for OTLP exporter, this value represents the number of spans, // metric data points or log records. ItemsCount() int // MergeSplit is a function that merge and/or splits this request with another one into multiple requests based on the // configured limit provided in maxSize. // MergeSplit does not split if maxSize is zero. // All the returned requests MUST have a number of items that does not exceed the maximum number of items. // Size of the last returned request MUST be less or equal than the size of any other returned request. // The original request MUST not be mutated if error is returned after mutation or if the exporter is // marked as not mutable. The length of the returned slice MUST not be 0. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. MergeSplit(ctx context.Context, maxSize int, sizerType SizerType, req Request) ([]Request, error) // BytesSize returns the size of the request in bytes. BytesSize() int } // ErrorHandler is an optional interface that can be implemented by Request to provide a way handle partial // temporary failures. For example, if some items failed to process and can be retried, this interface allows to // return a new Request that contains the items left to be sent. Otherwise, the original Request should be returned. // If not implemented, the original Request will be returned assuming the error is applied to the whole Request. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. type ErrorHandler interface { Request // OnError returns a new Request may contain the items left to be sent if some items failed to process and can be retried. // Otherwise, it should return the original Request. OnError(error) Request } type RequestConverterFunc[T any] func(context.Context, T) (Request, error) // RequestConsumeFunc processes the request. After the function returns, the request is no longer accessible, // and accessing it is considered undefined behavior. type RequestConsumeFunc = sender.SendFunc[Request] opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/request/sizer.go000066400000000000000000000037411511331344600304520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" import ( "encoding" "fmt" ) // TODO: Move this back to queuebatch when remove the circular dependency. var ( _ encoding.TextMarshaler = (*SizerType)(nil) _ encoding.TextUnmarshaler = (*SizerType)(nil) ) type SizerType struct { val string } const ( sizerTypeBytes = "bytes" sizerTypeItems = "items" sizerTypeRequests = "requests" ) var ( SizerTypeBytes = SizerType{val: sizerTypeBytes} SizerTypeItems = SizerType{val: sizerTypeItems} SizerTypeRequests = SizerType{val: sizerTypeRequests} ) // UnmarshalText implements TextUnmarshaler interface. func (s *SizerType) UnmarshalText(text []byte) error { switch str := string(text); str { case sizerTypeItems: *s = SizerTypeItems case sizerTypeBytes: *s = SizerTypeBytes case sizerTypeRequests: *s = SizerTypeRequests default: return fmt.Errorf("invalid sizer: %q", str) } return nil } func (s *SizerType) MarshalText() ([]byte, error) { return []byte(s.val), nil } func (s *SizerType) String() string { return s.val } // Sizer is an interface that returns the size of the given element. type Sizer interface { Sizeof(Request) int64 } func NewSizer(sizerType SizerType) Sizer { switch sizerType { case SizerTypeBytes: return NewBytesSizer() case SizerTypeItems: return NewItemsSizer() default: return RequestsSizer{} } } // RequestsSizer is a Sizer implementation that returns the size of a queue element as one request. type RequestsSizer struct{} func (rs RequestsSizer) Sizeof(Request) int64 { return 1 } type itemsSizer struct{} func (itemsSizer) Sizeof(req Request) int64 { return int64(req.ItemsCount()) } type bytesSizer struct{} func (bytesSizer) Sizeof(req Request) int64 { return int64(req.BytesSize()) } func NewItemsSizer() Sizer { return itemsSizer{} } func NewBytesSizer() Sizer { return bytesSizer{} } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/request/sizer_test.go000066400000000000000000000022671511331344600315130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request_test import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" ) func TestItemsSizer(t *testing.T) { sz := request.NewItemsSizer() assert.EqualValues(t, 3, sz.Sizeof(&requesttest.FakeRequest{Items: 3})) } func TestSizeTypeUnmarshalText(t *testing.T) { var sizer request.SizerType require.NoError(t, sizer.UnmarshalText([]byte("bytes"))) require.NoError(t, sizer.UnmarshalText([]byte("items"))) require.NoError(t, sizer.UnmarshalText([]byte("requests"))) require.Error(t, sizer.UnmarshalText([]byte("invalid"))) } func TestSizeTypeMarshalText(t *testing.T) { val, err := request.SizerTypeBytes.MarshalText() require.NoError(t, err) assert.Equal(t, []byte("bytes"), val) val, err = request.SizerTypeItems.MarshalText() require.NoError(t, err) assert.Equal(t, []byte("items"), val) val, err = request.SizerTypeRequests.MarshalText() require.NoError(t, err) assert.Equal(t, []byte("requests"), val) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/requesttest/000077500000000000000000000000001511331344600276625ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/requesttest/request.go000066400000000000000000000053421511331344600317050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package requesttest // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" import ( "context" "errors" "fmt" "time" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) type errorPartial struct { fr *FakeRequest } func (e errorPartial) Error() string { return fmt.Sprintf("items: %d", e.fr.Items) } type FakeRequest struct { Items int Bytes int Partial int MergeErr error MergeErrResult []request.Request Delay time.Duration } func (r *FakeRequest) OnError(err error) request.Request { var pErr errorPartial if errors.As(err, &pErr) { return pErr.fr } return r } func (r *FakeRequest) ItemsCount() int { return r.Items } func (r *FakeRequest) BytesSize() int { return r.Bytes } func (r *FakeRequest) MergeSplit(_ context.Context, maxSize int, szt request.SizerType, r2 request.Request) ([]request.Request, error) { if r.MergeErr != nil { return r.MergeErrResult, r.MergeErr } if r2 != nil { fr2 := r2.(*FakeRequest) if fr2.MergeErr != nil { return fr2.MergeErrResult, fr2.MergeErr } fr2.mergeTo(r) } if maxSize == 0 { return []request.Request{r}, nil } var res []request.Request switch szt { case request.SizerTypeItems: for r.Items != 0 { if r.Items <= maxSize { res = append(res, r) break } res = append(res, &FakeRequest{Items: maxSize, Bytes: -1, Delay: r.Delay}) r.Items -= maxSize r.Bytes = -1 } case request.SizerTypeBytes: for r.Bytes != 0 { if r.Bytes <= maxSize { res = append(res, r) break } res = append(res, &FakeRequest{Items: -1, Bytes: maxSize, Delay: r.Delay}) r.Items = -1 r.Bytes -= maxSize } } return res, nil } func (r *FakeRequest) mergeTo(dst *FakeRequest) { dst.Items += r.Items dst.Bytes += r.Bytes dst.Delay += r.Delay } func RequestFromMetricsFunc(err error) func(context.Context, pmetric.Metrics) (request.Request, error) { return func(_ context.Context, md pmetric.Metrics) (request.Request, error) { return &FakeRequest{Items: md.DataPointCount()}, err } } func RequestFromTracesFunc(err error) func(context.Context, ptrace.Traces) (request.Request, error) { return func(_ context.Context, td ptrace.Traces) (request.Request, error) { return &FakeRequest{Items: td.SpanCount()}, err } } func RequestFromLogsFunc(err error) func(context.Context, plog.Logs) (request.Request, error) { return func(_ context.Context, ld plog.Logs) (request.Request, error) { return &FakeRequest{Items: ld.LogRecordCount()}, err } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/requesttest/sink.go000066400000000000000000000026361511331344600311640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package requesttest // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" import ( "context" "sync" "time" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) func NewSink() *Sink { return &Sink{} } type Sink struct { requestsCount int itemsCount int bytesCount int mu sync.Mutex exportErr error } func (s *Sink) Export(ctx context.Context, req request.Request) error { r := req.(*FakeRequest) select { case <-ctx.Done(): return ctx.Err() case <-time.After(r.Delay): } s.mu.Lock() defer s.mu.Unlock() if s.exportErr != nil { err := s.exportErr s.exportErr = nil return err } if r.Partial > 0 { s.requestsCount++ s.itemsCount += r.Items - r.Partial return errorPartial{fr: &FakeRequest{ Items: r.Partial, Partial: 0, MergeErr: r.MergeErr, Delay: r.Delay, }} } s.requestsCount++ s.itemsCount += r.Items s.bytesCount += r.Bytes return nil } func (s *Sink) SetExportErr(err error) { s.mu.Lock() defer s.mu.Unlock() s.exportErr = err } func (s *Sink) RequestsCount() int { s.mu.Lock() defer s.mu.Unlock() return s.requestsCount } func (s *Sink) ItemsCount() int { s.mu.Lock() defer s.mu.Unlock() return s.itemsCount } func (s *Sink) BytesCount() int { s.mu.Lock() defer s.mu.Unlock() return s.bytesCount } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/retry_sender.go000066400000000000000000000104241511331344600303270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import ( "context" "errors" "fmt" "time" "github.com/cenkalti/backoff/v5" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/experr" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) // TODO: Clean this by forcing all exporters to return an internal error type that always include the information about retries. type throttleRetry struct { err error delay time.Duration } func (t throttleRetry) Error() string { return "Throttle (" + t.delay.String() + "), error: " + t.err.Error() } func (t throttleRetry) Unwrap() error { return t.err } // NewThrottleRetry creates a new throttle retry error. func NewThrottleRetry(err error, delay time.Duration) error { return throttleRetry{ err: err, delay: delay, } } type retrySender struct { component.StartFunc cfg configretry.BackOffConfig stopCh chan struct{} logger *zap.Logger next sender.Sender[request.Request] } func newRetrySender(config configretry.BackOffConfig, set exporter.Settings, next sender.Sender[request.Request]) *retrySender { return &retrySender{ cfg: config, stopCh: make(chan struct{}), logger: set.Logger, next: next, } } func (rs *retrySender) Shutdown(context.Context) error { close(rs.stopCh) return nil } // Send implements the requestSender interface func (rs *retrySender) Send(ctx context.Context, req request.Request) error { // Do not use NewExponentialBackOff since it calls Reset and the code here must // call Reset after changing the InitialInterval (this saves an unnecessary call to Now). expBackoff := backoff.ExponentialBackOff{ InitialInterval: rs.cfg.InitialInterval, RandomizationFactor: rs.cfg.RandomizationFactor, Multiplier: rs.cfg.Multiplier, MaxInterval: rs.cfg.MaxInterval, } span := trace.SpanFromContext(ctx) retryNum := int64(0) var maxElapsedTime time.Time if rs.cfg.MaxElapsedTime > 0 { maxElapsedTime = time.Now().Add(rs.cfg.MaxElapsedTime) } for { span.AddEvent( "Sending request.", trace.WithAttributes(attribute.Int64("retry_num", retryNum))) err := rs.next.Send(ctx, req) if err == nil { return nil } // Immediately drop data on permanent errors. if consumererror.IsPermanent(err) { return fmt.Errorf("not retryable error: %w", err) } if errReq, ok := req.(request.ErrorHandler); ok { req = errReq.OnError(err) } backoffDelay := expBackoff.NextBackOff() if backoffDelay == backoff.Stop { return fmt.Errorf("no more retries left: %w", err) } throttleErr := throttleRetry{} if errors.As(err, &throttleErr) { backoffDelay = max(backoffDelay, throttleErr.delay) } nextRetryTime := time.Now().Add(backoffDelay) if !maxElapsedTime.IsZero() && maxElapsedTime.Before(nextRetryTime) { // The delay is longer than the maxElapsedTime. return fmt.Errorf("no more retries left: %w", err) } if deadline, has := ctx.Deadline(); has && deadline.Before(nextRetryTime) { // The delay is longer than the deadline. There is no point in // waiting for cancelation. return fmt.Errorf("request will be cancelled before next retry: %w", err) } backoffDelayStr := backoffDelay.String() span.AddEvent( "Exporting failed. Will retry the request after interval.", trace.WithAttributes( attribute.String("interval", backoffDelayStr), attribute.String("error", err.Error()))) rs.logger.Info( "Exporting failed. Will retry the request after interval.", zap.Error(err), zap.String("interval", backoffDelayStr), ) retryNum++ // back-off, but get interrupted when shutting down or request is cancelled or timed out. select { case <-ctx.Done(): return fmt.Errorf("request is cancelled or timed out: %w", err) case <-rs.stopCh: return experr.NewShutdownErr(err) case <-time.After(backoffDelay): } } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/retry_sender_test.go000066400000000000000000000143471511331344600313760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "context" "errors" "fmt" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" "go.opentelemetry.io/collector/exporter/exportertest" ) func TestRetrySenderDropOnPermanentError(t *testing.T) { rCfg := configretry.NewDefaultBackOffConfig() sink := requesttest.NewSink() expErr := consumererror.NewPermanent(errors.New("bad data")) rs := newRetrySender(rCfg, exportertest.NewNopSettings(exportertest.NopType), sender.NewSender(sink.Export)) require.NoError(t, rs.Start(context.Background(), componenttest.NewNopHost())) sink.SetExportErr(expErr) require.ErrorIs(t, rs.Send(context.Background(), &requesttest.FakeRequest{Items: 2}), expErr) sink.SetExportErr(expErr) require.ErrorIs(t, rs.Send(context.Background(), &requesttest.FakeRequest{Items: 3}), expErr) assert.Equal(t, 0, sink.ItemsCount()) assert.Equal(t, 0, sink.RequestsCount()) require.NoError(t, rs.Shutdown(context.Background())) } func TestRetrySenderSimpleRetry(t *testing.T) { rCfg := configretry.NewDefaultBackOffConfig() rCfg.InitialInterval = 0 sink := requesttest.NewSink() expErr := errors.New("transient error") rs := newRetrySender(rCfg, exportertest.NewNopSettings(exportertest.NopType), sender.NewSender(sink.Export)) require.NoError(t, rs.Start(context.Background(), componenttest.NewNopHost())) sink.SetExportErr(expErr) require.NoError(t, rs.Send(context.Background(), &requesttest.FakeRequest{Items: 2})) assert.Equal(t, 2, sink.ItemsCount()) assert.Equal(t, 1, sink.RequestsCount()) require.NoError(t, rs.Shutdown(context.Background())) } func TestRetrySenderRetryPartial(t *testing.T) { rCfg := configretry.NewDefaultBackOffConfig() rCfg.InitialInterval = 0 sink := requesttest.NewSink() rs := newRetrySender(rCfg, exportertest.NewNopSettings(exportertest.NopType), sender.NewSender(sink.Export)) require.NoError(t, rs.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, rs.Send(context.Background(), &requesttest.FakeRequest{Items: 5, Partial: 3})) assert.Equal(t, 5, sink.ItemsCount()) assert.Equal(t, 2, sink.RequestsCount()) require.NoError(t, rs.Shutdown(context.Background())) } func TestRetrySenderMaxElapsedTime(t *testing.T) { rCfg := configretry.NewDefaultBackOffConfig() rCfg.InitialInterval = time.Millisecond rCfg.MaxElapsedTime = 100 * time.Millisecond expErr := errors.New("transient error") rs := newRetrySender(rCfg, exportertest.NewNopSettings(exportertest.NopType), sender.NewSender(func(context.Context, request.Request) error { return expErr })) require.NoError(t, rs.Start(context.Background(), componenttest.NewNopHost())) require.ErrorIs(t, rs.Send(context.Background(), &requesttest.FakeRequest{Items: 2}), expErr) require.NoError(t, rs.Shutdown(context.Background())) } func TestRetrySenderThrottleError(t *testing.T) { rCfg := configretry.NewDefaultBackOffConfig() rCfg.InitialInterval = 10 * time.Millisecond sink := requesttest.NewSink() rs := newRetrySender(rCfg, exportertest.NewNopSettings(exportertest.NopType), sender.NewSender(sink.Export)) require.NoError(t, rs.Start(context.Background(), componenttest.NewNopHost())) retry := fmt.Errorf("wrappe error: %w", NewThrottleRetry(errors.New("throttle error"), 100*time.Millisecond)) start := time.Now() sink.SetExportErr(retry) require.NoError(t, rs.Send(context.Background(), &requesttest.FakeRequest{Items: 5})) // The initial backoff is 10ms, but because of the throttle this should wait at least 100ms. assert.Less(t, 100*time.Millisecond, time.Since(start)) assert.Equal(t, 5, sink.ItemsCount()) assert.Equal(t, 1, sink.RequestsCount()) require.NoError(t, rs.Shutdown(context.Background())) } func TestRetrySenderWithContextTimeout(t *testing.T) { const testTimeout = 10 * time.Second rCfg := configretry.NewDefaultBackOffConfig() rCfg.Enabled = true // First attempt after 100ms is attempted rCfg.InitialInterval = 100 * time.Millisecond rCfg.RandomizationFactor = 0 // Second attempt is at twice the testTimeout rCfg.Multiplier = float64(2 * testTimeout / rCfg.InitialInterval) set := exportertest.NewNopSettings(exportertest.NopType) logger, observed := observer.New(zap.InfoLevel) set.Logger = zap.New(logger) rs := newRetrySender(rCfg, set, sender.NewSender(func(context.Context, request.Request) error { return errors.New("transient error") })) require.NoError(t, rs.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() ctx, cancel := context.WithTimeout(context.Background(), testTimeout) defer cancel() require.ErrorContains(t, rs.Send(ctx, &requesttest.FakeRequest{Items: 2}), "request will be cancelled before next retry: transient error") assert.Len(t, observed.All(), 1) assert.Equal(t, "Exporting failed. Will retry the request after interval.", observed.All()[0].Message) require.Less(t, time.Since(start), testTimeout/2) require.NoError(t, rs.Shutdown(context.Background())) } func TestRetrySenderWithCancelledContext(t *testing.T) { rCfg := configretry.NewDefaultBackOffConfig() rCfg.Enabled = true // First attempt after 1s is attempted rCfg.InitialInterval = 1 * time.Second rs := newRetrySender(rCfg, exportertest.NewNopSettings(exportertest.NopType), sender.NewSender(func(context.Context, request.Request) error { return errors.New("transient error") })) require.NoError(t, rs.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() ctx, cancel := context.WithCancelCause(context.Background()) go func() { <-time.After(100 * time.Millisecond) cancel(errors.New("my reason")) }() require.ErrorContains(t, rs.Send(ctx, &requesttest.FakeRequest{Items: 2}), "request is cancelled or timed out: transient error") require.Less(t, time.Since(start), 1*time.Second) require.NoError(t, rs.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sender/000077500000000000000000000000001511331344600265525ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sender/sender.go000066400000000000000000000014001511331344600303540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sender // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" import ( "context" "go.opentelemetry.io/collector/component" ) type Sender[T any] interface { component.Component Send(context.Context, T) error } type SendFunc[T any] func(ctx context.Context, data T) error func NewSender[T any](consFunc SendFunc[T]) Sender[T] { return &sender[T]{consFunc: consFunc} } // sender is a Sender that emits the incoming request to the exporter consumer func. type sender[T any] struct { component.StartFunc component.ShutdownFunc consFunc SendFunc[T] } func (es *sender[T]) Send(ctx context.Context, req T) error { return es.consFunc(ctx, req) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sender/sender_test.go000066400000000000000000000013221511331344600314160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sender import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestExportSenderRightArguments(t *testing.T) { es := NewSender[int64](func(_ context.Context, data int64) error { assert.Equal(t, int64(1), data) return nil }) require.NoError(t, es.Send(context.Background(), int64(1))) } func TestExportSenderReturnsError(t *testing.T) { err := errors.New("test error") es := NewSender[int64](func(_ context.Context, data int64) error { assert.Equal(t, int64(1), data) return err }) require.ErrorIs(t, es.Send(context.Background(), int64(1)), err) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sendertest/000077500000000000000000000000001511331344600274525ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sendertest/sendertest.go000066400000000000000000000010021511331344600321520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sendertest // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sendertest" import ( "context" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) func NewNopSenderFunc[T any]() sender.SendFunc[T] { return func(context.Context, T) error { return nil } } func NewErrSenderFunc[T any](err error) sender.SendFunc[T] { return func(context.Context, T) error { return err } } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sendertest/sendertest_test.go000066400000000000000000000007431511331344600332240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sendertest import ( "context" "errors" "testing" "github.com/stretchr/testify/require" ) func TestNewNopSenderFunc(t *testing.T) { sender := NewNopSenderFunc[int]() require.NoError(t, sender(context.Background(), 1)) } func TestNewErrSenderFunc(t *testing.T) { err := errors.New("test") sender := NewErrSenderFunc[int](err) require.ErrorIs(t, sender(context.Background(), 1), err) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/000077500000000000000000000000001511331344600264265ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/logs_sizer.go000066400000000000000000000024041511331344600311350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" import ( "go.opentelemetry.io/collector/pdata/plog" ) type LogsSizer interface { LogsSize(ld plog.Logs) int ResourceLogsSize(rl plog.ResourceLogs) int ScopeLogsSize(sl plog.ScopeLogs) int LogRecordSize(lr plog.LogRecord) int // DeltaSize returns the delta size when a ResourceLog, ScopeLog or LogRecord is added. DeltaSize(newItemSize int) int } // LogsBytesSizer returns the byte size of serialized protos. type LogsBytesSizer struct { plog.ProtoMarshaler protoDeltaSizer } // LogsCountSizer returns the nunmber of logs entries. type LogsCountSizer struct{} func (s *LogsCountSizer) LogsSize(ld plog.Logs) int { return ld.LogRecordCount() } func (s *LogsCountSizer) ResourceLogsSize(rl plog.ResourceLogs) int { count := 0 for k := 0; k < rl.ScopeLogs().Len(); k++ { count += rl.ScopeLogs().At(k).LogRecords().Len() } return count } func (s *LogsCountSizer) ScopeLogsSize(sl plog.ScopeLogs) int { return sl.LogRecords().Len() } func (s *LogsCountSizer) LogRecordSize(_ plog.LogRecord) int { return 1 } func (s *LogsCountSizer) DeltaSize(newItemSize int) int { return newItemSize } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/logs_sizer_test.go000066400000000000000000000036431511331344600322020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/testdata" ) func TestLogsCountSizer(t *testing.T) { ld := testdata.GenerateLogs(5) sizer := LogsCountSizer{} require.Equal(t, 5, sizer.LogsSize(ld)) rl := ld.ResourceLogs().At(0) require.Equal(t, 5, sizer.ResourceLogsSize(rl)) sl := rl.ScopeLogs().At(0) require.Equal(t, 5, sizer.ScopeLogsSize(sl)) require.Equal(t, 1, sizer.LogRecordSize(sl.LogRecords().At(0))) require.Equal(t, 1, sizer.LogRecordSize(sl.LogRecords().At(1))) require.Equal(t, 1, sizer.LogRecordSize(sl.LogRecords().At(2))) require.Equal(t, 1, sizer.LogRecordSize(sl.LogRecords().At(3))) require.Equal(t, 1, sizer.LogRecordSize(sl.LogRecords().At(4))) prevSize := sizer.ScopeLogsSize(sl) lr := sl.LogRecords().At(2) lr.CopyTo(sl.LogRecords().AppendEmpty()) require.Equal(t, sizer.ScopeLogsSize(sl), prevSize+sizer.DeltaSize(sizer.LogRecordSize(lr))) } func TestLogsBytesSizer(t *testing.T) { ld := testdata.GenerateLogs(5) sizer := LogsBytesSizer{} require.Equal(t, 545, sizer.LogsSize(ld)) rl := ld.ResourceLogs().At(0) require.Equal(t, 542, sizer.ResourceLogsSize(rl)) sl := rl.ScopeLogs().At(0) require.Equal(t, 497, sizer.ScopeLogsSize(sl)) require.Equal(t, 109, sizer.LogRecordSize(sl.LogRecords().At(0))) require.Equal(t, 79, sizer.LogRecordSize(sl.LogRecords().At(1))) require.Equal(t, 109, sizer.LogRecordSize(sl.LogRecords().At(2))) require.Equal(t, 79, sizer.LogRecordSize(sl.LogRecords().At(3))) require.Equal(t, 109, sizer.LogRecordSize(sl.LogRecords().At(4))) prevSize := sizer.ScopeLogsSize(sl) lr := sl.LogRecords().At(2) lr.CopyTo(sl.LogRecords().AppendEmpty()) require.Equal(t, sizer.ScopeLogsSize(sl), prevSize+sizer.DeltaSize(sizer.LogRecordSize(lr))) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/metrics_sizer.go000066400000000000000000000046611511331344600316460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" import ( "go.opentelemetry.io/collector/pdata/pmetric" ) // MetricsCountSizer returns the nunmber of metrics entries. type MetricsSizer interface { MetricsSize(md pmetric.Metrics) (count int) ResourceMetricsSize(rm pmetric.ResourceMetrics) (count int) ScopeMetricsSize(sm pmetric.ScopeMetrics) (count int) MetricSize(m pmetric.Metric) int DeltaSize(newItemSize int) int NumberDataPointSize(ndp pmetric.NumberDataPoint) int HistogramDataPointSize(hdp pmetric.HistogramDataPoint) int ExponentialHistogramDataPointSize(ehdp pmetric.ExponentialHistogramDataPoint) int SummaryDataPointSize(sdps pmetric.SummaryDataPoint) int } type MetricsBytesSizer struct { pmetric.ProtoMarshaler protoDeltaSizer } var _ MetricsSizer = &MetricsBytesSizer{} type MetricsCountSizer struct{} var _ MetricsSizer = &MetricsCountSizer{} func (s *MetricsCountSizer) MetricsSize(md pmetric.Metrics) int { return md.DataPointCount() } func (s *MetricsCountSizer) ResourceMetricsSize(rm pmetric.ResourceMetrics) (count int) { for i := 0; i < rm.ScopeMetrics().Len(); i++ { count += s.ScopeMetricsSize(rm.ScopeMetrics().At(i)) } return count } func (s *MetricsCountSizer) ScopeMetricsSize(sm pmetric.ScopeMetrics) (count int) { for i := 0; i < sm.Metrics().Len(); i++ { count += s.MetricSize(sm.Metrics().At(i)) } return count } func (s *MetricsCountSizer) MetricSize(m pmetric.Metric) int { switch m.Type() { case pmetric.MetricTypeGauge: return m.Gauge().DataPoints().Len() case pmetric.MetricTypeSum: return m.Sum().DataPoints().Len() case pmetric.MetricTypeHistogram: return m.Histogram().DataPoints().Len() case pmetric.MetricTypeExponentialHistogram: return m.ExponentialHistogram().DataPoints().Len() case pmetric.MetricTypeSummary: return m.Summary().DataPoints().Len() } return 0 } func (s *MetricsCountSizer) DeltaSize(newItemSize int) int { return newItemSize } func (s *MetricsCountSizer) NumberDataPointSize(_ pmetric.NumberDataPoint) int { return 1 } func (s *MetricsCountSizer) HistogramDataPointSize(_ pmetric.HistogramDataPoint) int { return 1 } func (s *MetricsCountSizer) ExponentialHistogramDataPointSize(_ pmetric.ExponentialHistogramDataPoint) int { return 1 } func (s *MetricsCountSizer) SummaryDataPointSize(_ pmetric.SummaryDataPoint) int { return 1 } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/metrics_sizer_test.go000066400000000000000000000056731511331344600327110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMetricsCountSizer(t *testing.T) { md := testdata.GenerateMetrics(7) sizer := MetricsCountSizer{} require.Equal(t, 14, sizer.MetricsSize(md)) rm := md.ResourceMetrics().At(0) require.Equal(t, 14, sizer.ResourceMetricsSize(rm)) sm := rm.ScopeMetrics().At(0) require.Equal(t, 14, sizer.ScopeMetricsSize(sm)) // Test different metric types require.Equal(t, 2, sizer.MetricSize(sm.Metrics().At(0))) // Test data point sizes require.Equal(t, 1, sizer.NumberDataPointSize(sm.Metrics().At(0).Gauge().DataPoints().At(0))) require.Equal(t, 1, sizer.NumberDataPointSize(sm.Metrics().At(1).Gauge().DataPoints().At(0))) require.Equal(t, 1, sizer.NumberDataPointSize(sm.Metrics().At(2).Sum().DataPoints().At(0))) require.Equal(t, 1, sizer.NumberDataPointSize(sm.Metrics().At(3).Sum().DataPoints().At(0))) require.Equal(t, 1, sizer.HistogramDataPointSize(sm.Metrics().At(4).Histogram().DataPoints().At(0))) require.Equal(t, 1, sizer.ExponentialHistogramDataPointSize(sm.Metrics().At(5).ExponentialHistogram().DataPoints().At(0))) require.Equal(t, 1, sizer.SummaryDataPointSize(sm.Metrics().At(6).Summary().DataPoints().At(0))) prevSize := sizer.ScopeMetricsSize(sm) sm.Metrics().At(0).CopyTo(sm.Metrics().AppendEmpty()) require.Equal(t, sizer.ScopeMetricsSize(sm), prevSize+sizer.DeltaSize(sizer.MetricSize(sm.Metrics().At(0)))) } func TestMetricsBytesSizer(t *testing.T) { md := testdata.GenerateMetrics(7) sizer := MetricsBytesSizer{} require.Equal(t, 1594, sizer.MetricsSize(md)) rm := md.ResourceMetrics().At(0) require.Equal(t, 1591, sizer.ResourceMetricsSize(rm)) sm := rm.ScopeMetrics().At(0) require.Equal(t, 1546, sizer.ScopeMetricsSize(sm)) // Test different metric types require.Equal(t, 130, sizer.MetricSize(sm.Metrics().At(0))) // Test data point sizes require.Equal(t, 55, sizer.NumberDataPointSize(sm.Metrics().At(0).Gauge().DataPoints().At(0))) require.Equal(t, 83, sizer.NumberDataPointSize(sm.Metrics().At(1).Gauge().DataPoints().At(0))) require.Equal(t, 55, sizer.NumberDataPointSize(sm.Metrics().At(2).Sum().DataPoints().At(0))) require.Equal(t, 83, sizer.NumberDataPointSize(sm.Metrics().At(3).Sum().DataPoints().At(0))) require.Equal(t, 92, sizer.HistogramDataPointSize(sm.Metrics().At(4).Histogram().DataPoints().At(0))) require.Equal(t, 119, sizer.ExponentialHistogramDataPointSize(sm.Metrics().At(5).ExponentialHistogram().DataPoints().At(0))) require.Equal(t, 92, sizer.SummaryDataPointSize(sm.Metrics().At(6).Summary().DataPoints().At(0))) prevSize := sizer.ScopeMetricsSize(sm) sm.Metrics().At(0).CopyTo(sm.Metrics().AppendEmpty()) require.Equal(t, sizer.ScopeMetricsSize(sm), prevSize+sizer.DeltaSize(sizer.MetricSize(sm.Metrics().At(0)))) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/profiles_sizer.go000066400000000000000000000026171511331344600320220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" import ( "go.opentelemetry.io/collector/pdata/pprofile" ) type ProfilesSizer interface { ProfilesSize(pd pprofile.Profiles) int ResourceProfilesSize(rp pprofile.ResourceProfiles) int ScopeProfilesSize(sp pprofile.ScopeProfiles) int ProfileSize(p pprofile.Profile) int DeltaSize(newItemSize int) int } // TracesBytesSizer returns the byte size of serialized protos. type ProfilesBytesSizer struct { pprofile.ProtoMarshaler protoDeltaSizer } var _ ProfilesSizer = (*ProfilesBytesSizer)(nil) // ProfilesCountSizer returns the number of profiles in the profiles. type ProfilesCountSizer struct{} var _ ProfilesSizer = (*ProfilesCountSizer)(nil) func (s *ProfilesCountSizer) ProfilesSize(pd pprofile.Profiles) int { return pd.SampleCount() } func (s *ProfilesCountSizer) ResourceProfilesSize(rp pprofile.ResourceProfiles) int { count := 0 for k := 0; k < rp.ScopeProfiles().Len(); k++ { count += rp.ScopeProfiles().At(k).Profiles().Len() } return count } func (s *ProfilesCountSizer) ScopeProfilesSize(sp pprofile.ScopeProfiles) int { return sp.Profiles().Len() } func (s *ProfilesCountSizer) ProfileSize(_ pprofile.Profile) int { return 1 } func (s *ProfilesCountSizer) DeltaSize(newItemSize int) int { return newItemSize } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/proto_delta_sizer.go000066400000000000000000000021321511331344600325030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" import ( math_bits "math/bits" ) type protoDeltaSizer struct{} // DeltaSize() returns the delta size of a proto slice when a new item is added. // Example: // // prevSize := proto1.Size() // proto1.RepeatedField().AppendEmpty() = proto2 // // Then currSize of proto1 can be calculated as // // currSize := (prevSize + sizer.DeltaSize(proto2.Size())) // // This is derived from: // - opentelemetry-collector/pdata/internal/data/protogen/metrics/v1/metrics.pb.go // - opentelemetry-collector/pdata/internal/data/protogen/logs/v1/logs.pb.go // - opentelemetry-collector/pdata/internal/data/protogen/traces/v1/traces.pb.go // - opentelemetry-collector/pdata/internal/data/protogen/profiles/v1development/profiles.pb.go // which is generated with gogo/protobuf. func (s *protoDeltaSizer) DeltaSize(newItemSize int) int { return 1 + newItemSize + sov(uint64(newItemSize)) } func sov(x uint64) int { return (math_bits.Len64(x|1) + 6) / 7 } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/proto_delta_sizer_test.go000066400000000000000000000005611511331344600335460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer import ( "testing" "github.com/stretchr/testify/require" ) func TestMetricsBytesDeltaSize(t *testing.T) { sizer := protoDeltaSizer{} require.Equal(t, 129, sizer.DeltaSize(127)) require.Equal(t, 131, sizer.DeltaSize(128)) require.Equal(t, 242, sizer.DeltaSize(239)) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/traces_sizer.go000066400000000000000000000024061511331344600314540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" import ( "go.opentelemetry.io/collector/pdata/ptrace" ) type TracesSizer interface { TracesSize(ld ptrace.Traces) int ResourceSpansSize(rs ptrace.ResourceSpans) int ScopeSpansSize(ss ptrace.ScopeSpans) int SpanSize(span ptrace.Span) int // DeltaSize() returns the delta size when a span is added. DeltaSize(newItemSize int) int } // TracesBytesSizer returns the byte size of serialized protos. type TracesBytesSizer struct { ptrace.ProtoMarshaler protoDeltaSizer } // TracesCountSizer returns the number of spans in the traces. type TracesCountSizer struct{} func (s *TracesCountSizer) TracesSize(td ptrace.Traces) int { return td.SpanCount() } func (s *TracesCountSizer) ResourceSpansSize(rs ptrace.ResourceSpans) int { count := 0 for k := 0; k < rs.ScopeSpans().Len(); k++ { count += rs.ScopeSpans().At(k).Spans().Len() } return count } func (s *TracesCountSizer) ScopeSpansSize(ss ptrace.ScopeSpans) int { return ss.Spans().Len() } func (s *TracesCountSizer) SpanSize(_ ptrace.Span) int { return 1 } func (s *TracesCountSizer) DeltaSize(newItemSize int) int { return newItemSize } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/sizer/traces_sizer_test.go000066400000000000000000000031561511331344600325160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sizer import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/testdata" ) func TestTracesCountSizer(t *testing.T) { td := testdata.GenerateTraces(5) sizer := TracesCountSizer{} require.Equal(t, 5, sizer.TracesSize(td)) rs := td.ResourceSpans().At(0) require.Equal(t, 5, sizer.ResourceSpansSize(rs)) ss := rs.ScopeSpans().At(0) require.Equal(t, 5, sizer.ScopeSpansSize(ss)) require.Equal(t, 1, sizer.SpanSize(ss.Spans().At(0))) require.Equal(t, 1, sizer.SpanSize(ss.Spans().At(1))) require.Equal(t, 1, sizer.SpanSize(ss.Spans().At(2))) require.Equal(t, 1, sizer.SpanSize(ss.Spans().At(3))) require.Equal(t, 1, sizer.SpanSize(ss.Spans().At(4))) prevSize := sizer.ScopeSpansSize(ss) span := ss.Spans().At(2) span.CopyTo(ss.Spans().AppendEmpty()) require.Equal(t, sizer.ScopeSpansSize(ss), prevSize+sizer.DeltaSize(sizer.SpanSize(span))) } func TestTracesBytesSizer(t *testing.T) { td := testdata.GenerateTraces(2) sizer := TracesBytesSizer{} require.Equal(t, 338, sizer.TracesSize(td)) rs := td.ResourceSpans().At(0) require.Equal(t, 335, sizer.ResourceSpansSize(rs)) ss := rs.ScopeSpans().At(0) require.Equal(t, 290, sizer.ScopeSpansSize(ss)) require.Equal(t, 187, sizer.SpanSize(ss.Spans().At(0))) require.Equal(t, 96, sizer.SpanSize(ss.Spans().At(1))) prevSize := sizer.ScopeSpansSize(ss) span := ss.Spans().At(1) spanSize := sizer.SpanSize(span) span.CopyTo(ss.Spans().AppendEmpty()) ds := sizer.DeltaSize(spanSize) require.Equal(t, prevSize+ds, sizer.ScopeSpansSize(ss)) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/storagetest/000077500000000000000000000000001511331344600276365ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/storagetest/mock_storage.go000066400000000000000000000046331511331344600326500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package storagetest // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/storagetest" import ( "context" "errors" "sync" "sync/atomic" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension/xextension/storage" ) type mockStorageExtension struct { component.StartFunc component.ShutdownFunc st sync.Map getClientError error executionDelay time.Duration } func (m *mockStorageExtension) GetClient(context.Context, component.Kind, component.ID, string) (storage.Client, error) { if m.getClientError != nil { return nil, m.getClientError } return &MockStorageClient{st: &m.st, closed: &atomic.Bool{}, executionDelay: m.executionDelay}, nil } func NewMockStorageExtension(getClientError error) storage.Extension { return NewMockStorageExtensionWithDelay(getClientError, 0) } func NewMockStorageExtensionWithDelay(getClientError error, executionDelay time.Duration) storage.Extension { return &mockStorageExtension{ getClientError: getClientError, executionDelay: executionDelay, } } type MockStorageClient struct { st *sync.Map closed *atomic.Bool executionDelay time.Duration // simulate real storage client delay } func (m *MockStorageClient) Get(ctx context.Context, s string) ([]byte, error) { getOp := storage.GetOperation(s) err := m.Batch(ctx, getOp) return getOp.Value, err } func (m *MockStorageClient) Set(ctx context.Context, s string, bytes []byte) error { return m.Batch(ctx, storage.SetOperation(s, bytes)) } func (m *MockStorageClient) Delete(ctx context.Context, s string) error { return m.Batch(ctx, storage.DeleteOperation(s)) } func (m *MockStorageClient) Close(context.Context) error { m.closed.Store(true) return nil } func (m *MockStorageClient) Batch(_ context.Context, ops ...*storage.Operation) error { if m.IsClosed() { panic("client already closed") } if m.executionDelay != 0 { time.Sleep(m.executionDelay) } for _, op := range ops { switch op.Type { case storage.Get: val, found := m.st.Load(op.Key) if !found { break } op.Value = val.([]byte) case storage.Set: m.st.Store(op.Key, op.Value) case storage.Delete: m.st.Delete(op.Key) default: return errors.New("wrong operation type") } } return nil } func (m *MockStorageClient) IsClosed() bool { return m.closed.Load() } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/timeout_sender.go000066400000000000000000000033151511331344600306510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/exporter/exporterhelper/internal" import ( "context" "errors" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) // TimeoutConfig for timeout. The timeout applies to individual attempts to send data to the backend. type TimeoutConfig struct { // Timeout is the timeout for every attempt to send data to the backend. // A zero timeout means no timeout. Timeout time.Duration `mapstructure:"timeout"` } func (ts *TimeoutConfig) Validate() error { // Negative timeouts are not acceptable, since all sends will fail. if ts.Timeout < 0 { return errors.New("'timeout' must be non-negative") } return nil } // NewDefaultTimeoutConfig returns the default config for TimeoutConfig. func NewDefaultTimeoutConfig() TimeoutConfig { return TimeoutConfig{ Timeout: 5 * time.Second, } } // timeoutSender is a requestSender that adds a `timeout` to every request that passes this sender. type timeoutSender[T any] struct { component.StartFunc component.ShutdownFunc cfg TimeoutConfig next sender.Sender[T] } func newTimeoutSender[T any](cfg TimeoutConfig, next sender.Sender[T]) sender.Sender[T] { return &timeoutSender[T]{cfg: cfg, next: next} } func (ts *timeoutSender[T]) Send(ctx context.Context, req T) error { // Intentionally don't overwrite the context inside the request, because in case of retries deadline will not be // updated because this deadline most likely is before the next one. tCtx, cancelFunc := context.WithTimeout(ctx, ts.cfg.Timeout) defer cancelFunc() return ts.next.Send(tCtx, req) } opentelemetry-collector-0.141.0/exporter/exporterhelper/internal/timeout_sender_test.go000066400000000000000000000024351511331344600317120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sender" ) func TestNewDefaultTimeoutConfig(t *testing.T) { cfg := NewDefaultTimeoutConfig() require.NoError(t, cfg.Validate()) assert.Equal(t, TimeoutConfig{Timeout: 5 * time.Second}, cfg) } func TestInvalidTimeout(t *testing.T) { cfg := NewDefaultTimeoutConfig() require.NoError(t, cfg.Validate()) cfg.Timeout = -1 assert.Error(t, cfg.Validate()) } func TestNewTimeoutSender(t *testing.T) { cfg := TimeoutConfig{Timeout: 5 * time.Second} ts := newTimeoutSender(cfg, sender.NewSender(func(ctx context.Context, data int64) error { deadline, ok := ctx.Deadline() assert.True(t, ok) timeout := time.Since(deadline) assert.LessOrEqual(t, timeout, 5*time.Second) assert.GreaterOrEqual(t, 4*time.Second, timeout) assert.Equal(t, int64(7), data) return nil })) require.NoError(t, ts.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, ts.Send(context.Background(), 7)) require.NoError(t, ts.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/exporter/exporterhelper/logs.go000066400000000000000000000020401511331344600247450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" ) // NewLogs creates an exporter.Logs that records observability logs and wraps every request with a Span. func NewLogs( ctx context.Context, set exporter.Settings, cfg component.Config, pusher consumer.ConsumeLogsFunc, options ...Option, ) (exporter.Logs, error) { if cfg == nil { return nil, errNilConfig } if pusher == nil { return nil, errNilPushLogs } return internal.NewLogsRequest(ctx, set, queuebatch.RequestFromLogs(), queuebatch.RequestConsumeFromLogs(pusher), append([]Option{internal.WithQueueBatchSettings(queuebatch.NewLogsQueueBatchSettings())}, options...)...) } opentelemetry-collector-0.141.0/exporter/exporterhelper/logs_test.go000066400000000000000000000360661511331344600260230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper import ( "context" "errors" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/hosttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadatatest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/oteltest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sendertest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/storagetest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" ) const ( fakeLogsParentSpanName = "fake_logs_parent_span_name" ) var ( fakeLogsName = component.MustNewIDWithName("fake_logs_exporter", "with_name") fakeLogsConfig = struct{}{} ) func TestLogs_InvalidName(t *testing.T) { le, err := NewLogs(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, newPushLogsData(nil)) require.Nil(t, le) require.Equal(t, errNilConfig, err) } func TestLogs_NilLogger(t *testing.T) { le, err := NewLogs(context.Background(), exporter.Settings{}, &fakeLogsConfig, newPushLogsData(nil)) require.Nil(t, le) require.Equal(t, errNilLogger, err) } func TestLogs_NilPushLogsData(t *testing.T) { le, err := NewLogs(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeLogsConfig, nil) require.Nil(t, le) require.Equal(t, errNilPushLogs, err) } func TestLogs_Default(t *testing.T) { ld := plog.NewLogs() le, err := NewLogs(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeLogsConfig, newPushLogsData(nil)) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, le.Capabilities()) assert.NoError(t, le.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, le.ConsumeLogs(context.Background(), ld)) assert.NoError(t, le.Shutdown(context.Background())) } func TestLogs_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} le, err := NewLogs(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeLogsConfig, newPushLogsData(nil), WithCapabilities(capabilities)) require.NoError(t, err) require.NotNil(t, le) assert.Equal(t, capabilities, le.Capabilities()) } func TestLogs_Default_ReturnError(t *testing.T) { ld := plog.NewLogs() want := errors.New("my_error") le, err := NewLogs(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeLogsConfig, newPushLogsData(want)) require.NoError(t, err) require.NotNil(t, le) require.Equal(t, want, le.ConsumeLogs(context.Background(), ld)) } func TestLogs_WithPersistentQueue(t *testing.T) { fgOrigReadState := queue.PersistRequestContextOnRead fgOrigWriteState := queue.PersistRequestContextOnWrite qCfg := NewDefaultQueueConfig() storageID := component.MustNewIDWithName("file_storage", "storage") qCfg.StorageID = &storageID set := exportertest.NewNopSettings(exportertest.NopType) set.ID = component.MustNewIDWithName("test_logs", "with_persistent_queue") host := hosttest.NewHost(map[component.ID]component.Component{ storageID: storagetest.NewMockStorageExtension(nil), }) spanCtx := oteltest.FakeSpanContext(t) tests := []struct { name string fgEnabledOnWrite bool fgEnabledOnRead bool wantData bool wantSpanCtx bool }{ { name: "feature_gate_disabled_on_write_and_read", wantData: true, }, { name: "feature_gate_enabled_on_write_and_read", fgEnabledOnWrite: true, fgEnabledOnRead: true, wantData: true, wantSpanCtx: true, }, { name: "feature_gate_disabled_on_write_enabled_on_read", wantData: true, fgEnabledOnRead: true, }, { name: "feature_gate_enabled_on_write_disabled_on_read", fgEnabledOnWrite: true, wantData: false, // going back from enabled to disabled feature gate isn't supported }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { queue.PersistRequestContextOnRead = func() bool { return tt.fgEnabledOnRead } queue.PersistRequestContextOnWrite = func() bool { return tt.fgEnabledOnWrite } t.Cleanup(func() { queue.PersistRequestContextOnRead = fgOrigReadState queue.PersistRequestContextOnWrite = fgOrigWriteState }) ls := consumertest.LogsSink{} te, err := NewLogs(context.Background(), set, &fakeLogsConfig, ls.ConsumeLogs, WithQueue(qCfg)) require.NoError(t, err) require.NoError(t, te.Start(context.Background(), host)) t.Cleanup(func() { require.NoError(t, te.Shutdown(context.Background())) }) logs := testdata.GenerateLogs(2) require.NoError(t, te.ConsumeLogs(trace.ContextWithSpanContext(context.Background(), spanCtx), logs)) if tt.wantData { require.Eventually(t, func() bool { return len(ls.AllLogs()) == 1 && ls.LogRecordCount() == 2 }, 500*time.Millisecond, 10*time.Millisecond) } // check that the span context is persisted if the feature gate is enabled if tt.wantSpanCtx { assert.Len(t, ls.Contexts(), 1) assert.Equal(t, spanCtx, trace.SpanContextFromContext(ls.Contexts()[0])) } }) } } func TestLogs_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) le, err := NewLogs(context.Background(), exporter.Settings{ID: fakeLogsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeLogsConfig, newPushLogsData(nil)) require.NoError(t, err) require.NotNil(t, le) checkRecordedMetricsForLogs(t, tt, fakeLogsName, le, nil) } func TestLogs_pLogModifiedDownStream_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) le, err := NewLogs(context.Background(), exporter.Settings{ID: fakeLogsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeLogsConfig, newPushLogsDataModifiedDownstream(nil), WithCapabilities(consumer.Capabilities{MutatesData: true})) assert.NotNil(t, le) require.NoError(t, err) ld := testdata.GenerateLogs(2) require.NoError(t, le.ConsumeLogs(context.Background(), ld)) assert.Equal(t, 0, ld.LogRecordCount()) metadatatest.AssertEqualExporterSentLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", fakeLogsName.String())), Value: int64(2), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestLogsRequest_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) le, err := internal.NewLogsRequest(context.Background(), exporter.Settings{ID: fakeLogsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, requesttest.RequestFromLogsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, le) checkRecordedMetricsForLogs(t, tt, fakeLogsName, le, nil) } func TestLogs_WithRecordMetrics_ReturnError(t *testing.T) { want := errors.New("my_error") tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) le, err := NewLogs(context.Background(), exporter.Settings{ID: fakeLogsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeLogsConfig, newPushLogsData(want)) require.NoError(t, err) require.NotNil(t, le) checkRecordedMetricsForLogs(t, tt, fakeLogsName, le, want) } func TestLogsRequest_WithRecordMetrics_ExportError(t *testing.T) { want := errors.New("export_error") tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) le, err := internal.NewLogsRequest(context.Background(), exporter.Settings{ID: fakeLogsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, requesttest.RequestFromLogsFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, le) checkRecordedMetricsForLogs(t, tt, fakeLogsName, le, want) } func TestLogs_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) le, err := NewLogs(context.Background(), set, &fakeLogsConfig, newPushLogsData(nil)) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForLogs(t, sr, set.TracerProvider.Tracer("test"), le, nil) } func TestLogsRequest_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) le, err := internal.NewLogsRequest(context.Background(), set, requesttest.RequestFromLogsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForLogs(t, sr, set.TracerProvider.Tracer("test"), le, nil) } func TestLogs_WithSpan_ReturnError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("my_error") le, err := NewLogs(context.Background(), set, &fakeLogsConfig, newPushLogsData(want)) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForLogs(t, sr, set.TracerProvider.Tracer("test"), le, want) } func TestLogsRequest_WithSpan_ReturnError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("my_error") le, err := internal.NewLogsRequest(context.Background(), set, requesttest.RequestFromLogsFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForLogs(t, sr, set.TracerProvider.Tracer("test"), le, want) } func TestLogs_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } le, err := NewLogs(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeLogsConfig, newPushLogsData(nil), WithShutdown(shutdown)) assert.NotNil(t, le) assert.NoError(t, err) assert.NoError(t, le.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestLogs_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } le, err := NewLogs(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeLogsConfig, newPushLogsData(nil), WithShutdown(shutdownErr)) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, want, le.Shutdown(context.Background())) } func newPushLogsDataModifiedDownstream(retError error) consumer.ConsumeLogsFunc { return func(_ context.Context, log plog.Logs) error { log.ResourceLogs().MoveAndAppendTo(plog.NewResourceLogsSlice()) return retError } } func newPushLogsData(retError error) consumer.ConsumeLogsFunc { return func(_ context.Context, _ plog.Logs) error { return retError } } func checkRecordedMetricsForLogs(t *testing.T, tt *componenttest.Telemetry, id component.ID, le exporter.Logs, wantError error) { ld := testdata.GenerateLogs(2) const numBatches = 7 for range numBatches { require.Equal(t, wantError, le.ConsumeLogs(context.Background(), ld)) } // TODO: When the new metrics correctly count partial dropped fix this. if wantError != nil { metadatatest.AssertEqualExporterSendFailedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", id.String())), Value: int64(numBatches * ld.LogRecordCount()), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } else { metadatatest.AssertEqualExporterSentLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("exporter", id.String())), Value: int64(numBatches * ld.LogRecordCount()), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } } func generateLogsTraffic(t *testing.T, tracer trace.Tracer, le exporter.Logs, numRequests int, wantError error) { ld := testdata.GenerateLogs(1) ctx, span := tracer.Start(context.Background(), fakeLogsParentSpanName) defer span.End() for range numRequests { require.Equal(t, wantError, le.ConsumeLogs(ctx, ld)) } } func checkWrapSpanForLogs(t *testing.T, sr *tracetest.SpanRecorder, tracer trace.Tracer, le exporter.Logs, wantError error) { const numRequests = 5 generateLogsTraffic(t, tracer, le, numRequests, wantError) // Inspection time! gotSpanData := sr.Ended() require.Len(t, gotSpanData, numRequests+1) parentSpan := gotSpanData[numRequests] require.Equalf(t, fakeLogsParentSpanName, parentSpan.Name(), "SpanData %v", parentSpan) for _, sd := range gotSpanData[:numRequests] { require.Equalf(t, parentSpan.SpanContext(), sd.Parent(), "Exporter span not a child\nSpanData %v", sd) oteltest.CheckStatus(t, sd, wantError) sentLogRecords := int64(1) failedToSendLogRecords := int64(0) if wantError != nil { sentLogRecords = 0 failedToSendLogRecords = 1 } require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsSent, Value: attribute.Int64Value(sentLogRecords)}, "SpanData %v", sd) require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsFailed, Value: attribute.Int64Value(failedToSendLogRecords)}, "SpanData %v", sd) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/metadata.yaml000066400000000000000000000102131511331344600261170ustar00rootroot00000000000000type: exporterhelper github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true codeowners: active: - bogdandrutu - dmitryax class: pkg stability: beta: [traces, metrics, logs] telemetry: metrics: exporter_enqueue_failed_log_records: enabled: true stability: level: alpha description: Number of log records failed to be added to the sending queue. unit: "{records}" sum: value_type: int monotonic: true exporter_enqueue_failed_metric_points: enabled: true stability: level: alpha description: Number of metric points failed to be added to the sending queue. unit: "{datapoints}" sum: value_type: int monotonic: true exporter_enqueue_failed_spans: enabled: true stability: level: alpha description: Number of spans failed to be added to the sending queue. unit: "{spans}" sum: value_type: int monotonic: true exporter_queue_batch_send_size: enabled: true description: Number of units in the batch stability: level: development unit: "{units}" histogram: value_type: int bucket_boundaries: [ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000, ] exporter_queue_batch_send_size_bytes: enabled: true description: Number of bytes in batch that was sent. Only available on detailed level. stability: level: development unit: By histogram: value_type: int bucket_boundaries: [ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, ] exporter_queue_capacity: enabled: true stability: level: alpha description: Fixed capacity of the retry queue (in batches). unit: "{batches}" gauge: value_type: int async: true exporter_queue_size: enabled: true stability: level: alpha description: Current size of the retry queue (in batches). unit: "{batches}" gauge: value_type: int async: true exporter_send_failed_log_records: enabled: true stability: level: alpha description: Number of log records in failed attempts to send to destination. unit: "{records}" sum: value_type: int monotonic: true exporter_send_failed_metric_points: enabled: true stability: level: alpha description: Number of metric points in failed attempts to send to destination. unit: "{datapoints}" sum: value_type: int monotonic: true exporter_send_failed_spans: enabled: true stability: level: alpha description: Number of spans in failed attempts to send to destination. unit: "{spans}" sum: value_type: int monotonic: true exporter_sent_log_records: enabled: true stability: level: alpha description: Number of log record successfully sent to destination. unit: "{records}" sum: value_type: int monotonic: true exporter_sent_metric_points: enabled: true stability: level: alpha description: Number of metric points successfully sent to destination. unit: "{datapoints}" sum: value_type: int monotonic: true exporter_sent_spans: enabled: true stability: level: alpha description: Number of spans successfully sent to destination. unit: "{spans}" sum: value_type: int monotonic: true opentelemetry-collector-0.141.0/exporter/exporterhelper/metrics.go000066400000000000000000000021011511331344600254450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" ) // NewMetrics creates an exporter.Metrics that records observability metrics and wraps every request with a Span. func NewMetrics( ctx context.Context, set exporter.Settings, cfg component.Config, pusher consumer.ConsumeMetricsFunc, options ...Option, ) (exporter.Metrics, error) { if cfg == nil { return nil, errNilConfig } if pusher == nil { return nil, errNilPushMetrics } return internal.NewMetricsRequest(ctx, set, queuebatch.RequestFromMetrics(), queuebatch.RequestConsumeFromMetrics(pusher), append([]Option{internal.WithQueueBatchSettings(queuebatch.NewMetricsQueueBatchSettings())}, options...)...) } opentelemetry-collector-0.141.0/exporter/exporterhelper/metrics_test.go000066400000000000000000000372401511331344600265200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper import ( "context" "errors" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/hosttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadatatest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/oteltest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sendertest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/storagetest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" ) const ( fakeMetricsParentSpanName = "fake_metrics_parent_span_name" ) var ( fakeMetricsName = component.MustNewIDWithName("fake_metrics_exporter", "with_name") fakeMetricsConfig = struct{}{} ) func TestMetrics_NilConfig(t *testing.T) { me, err := NewMetrics(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, newPushMetricsData(nil)) require.Nil(t, me) require.Equal(t, errNilConfig, err) } func TestMetrics_NilLogger(t *testing.T) { me, err := NewMetrics(context.Background(), exporter.Settings{}, &fakeMetricsConfig, newPushMetricsData(nil)) require.Nil(t, me) require.Equal(t, errNilLogger, err) } func TestMetrics_NilPushMetricsData(t *testing.T) { me, err := NewMetrics(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeMetricsConfig, nil) require.Nil(t, me) require.Equal(t, errNilPushMetrics, err) } func TestMetrics_Default(t *testing.T) { md := pmetric.NewMetrics() me, err := NewMetrics(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeMetricsConfig, newPushMetricsData(nil)) require.NoError(t, err) assert.NotNil(t, me) assert.Equal(t, consumer.Capabilities{MutatesData: false}, me.Capabilities()) assert.NoError(t, me.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, me.ConsumeMetrics(context.Background(), md)) assert.NoError(t, me.Shutdown(context.Background())) } func TestMetrics_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} me, err := NewMetrics(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeMetricsConfig, newPushMetricsData(nil), WithCapabilities(capabilities)) require.NoError(t, err) assert.NotNil(t, me) assert.Equal(t, capabilities, me.Capabilities()) } func TestMetrics_Default_ReturnError(t *testing.T) { md := pmetric.NewMetrics() want := errors.New("my_error") me, err := NewMetrics(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeMetricsConfig, newPushMetricsData(want)) require.NoError(t, err) require.NotNil(t, me) require.Equal(t, want, me.ConsumeMetrics(context.Background(), md)) } func TestMetrics_WithPersistentQueue(t *testing.T) { fgOrigReadState := queue.PersistRequestContextOnRead fgOrigWriteState := queue.PersistRequestContextOnWrite qCfg := NewDefaultQueueConfig() storageID := component.MustNewIDWithName("file_storage", "storage") qCfg.StorageID = &storageID set := exportertest.NewNopSettings(exportertest.NopType) set.ID = component.MustNewIDWithName("test_metrics", "with_persistent_queue") host := hosttest.NewHost(map[component.ID]component.Component{ storageID: storagetest.NewMockStorageExtension(nil), }) spanCtx := oteltest.FakeSpanContext(t) tests := []struct { name string fgEnabledOnWrite bool fgEnabledOnRead bool wantData bool wantSpanCtx bool }{ { name: "feature_gate_disabled_on_write_and_read", wantData: true, }, { name: "feature_gate_enabled_on_write_and_read", fgEnabledOnWrite: true, fgEnabledOnRead: true, wantData: true, wantSpanCtx: true, }, { name: "feature_gate_disabled_on_write_enabled_on_read", wantData: true, fgEnabledOnRead: true, }, { name: "feature_gate_enabled_on_write_disabled_on_read", fgEnabledOnWrite: true, wantData: false, // going back from enabled to disabled feature gate isn't supported }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { queue.PersistRequestContextOnRead = func() bool { return tt.fgEnabledOnRead } queue.PersistRequestContextOnWrite = func() bool { return tt.fgEnabledOnWrite } t.Cleanup(func() { queue.PersistRequestContextOnRead = fgOrigReadState queue.PersistRequestContextOnWrite = fgOrigWriteState }) ms := consumertest.MetricsSink{} te, err := NewMetrics(context.Background(), set, &fakeMetricsConfig, ms.ConsumeMetrics, WithQueue(qCfg)) require.NoError(t, err) require.NoError(t, te.Start(context.Background(), host)) t.Cleanup(func() { require.NoError(t, te.Shutdown(context.Background())) }) traces := testdata.GenerateMetrics(2) require.NoError(t, te.ConsumeMetrics(trace.ContextWithSpanContext(context.Background(), spanCtx), traces)) if tt.wantData { require.Eventually(t, func() bool { return len(ms.AllMetrics()) == 1 && ms.DataPointCount() == 4 }, 500*time.Millisecond, 10*time.Millisecond) } // check that the span context is persisted if the feature gate is enabled if tt.wantSpanCtx { assert.Len(t, ms.Contexts(), 1) assert.Equal(t, spanCtx, trace.SpanContextFromContext(ms.Contexts()[0])) } }) } } func TestMetrics_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) me, err := NewMetrics(context.Background(), exporter.Settings{ID: fakeMetricsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeMetricsConfig, newPushMetricsData(nil)) require.NoError(t, err) require.NotNil(t, me) checkRecordedMetricsForMetrics(t, tt, fakeMetricsName, me, nil) } func TestMetrics_pMetricModifiedDownStream_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) me, err := NewMetrics(context.Background(), exporter.Settings{ID: fakeMetricsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeMetricsConfig, newPushMetricsDataModifiedDownstream(nil), WithCapabilities(consumer.Capabilities{MutatesData: true})) require.NoError(t, err) require.NotNil(t, me) md := testdata.GenerateMetrics(2) require.NoError(t, me.ConsumeMetrics(context.Background(), md)) assert.Equal(t, 0, md.MetricCount()) metadatatest.AssertEqualExporterSentMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ExporterKey, fakeMetricsName.String())), Value: int64(4), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestMetricsRequest_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) me, err := internal.NewMetricsRequest(context.Background(), exporter.Settings{ID: fakeMetricsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, requesttest.RequestFromMetricsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, me) checkRecordedMetricsForMetrics(t, tt, fakeMetricsName, me, nil) } func TestMetrics_WithRecordMetrics_ReturnError(t *testing.T) { want := errors.New("my_error") tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) me, err := NewMetrics(context.Background(), exporter.Settings{ID: fakeMetricsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeMetricsConfig, newPushMetricsData(want)) require.NoError(t, err) require.NotNil(t, me) checkRecordedMetricsForMetrics(t, tt, fakeMetricsName, me, want) } func TestMetricsRequest_WithRecordMetrics_ExportError(t *testing.T) { want := errors.New("my_error") tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) me, err := internal.NewMetricsRequest(context.Background(), exporter.Settings{ID: fakeMetricsName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, requesttest.RequestFromMetricsFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, me) checkRecordedMetricsForMetrics(t, tt, fakeMetricsName, me, want) } func TestMetrics_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) me, err := NewMetrics(context.Background(), set, &fakeMetricsConfig, newPushMetricsData(nil)) require.NoError(t, err) require.NotNil(t, me) checkWrapSpanForMetrics(t, sr, set.TracerProvider.Tracer("test"), me, nil) } func TestMetricsRequest_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) me, err := internal.NewMetricsRequest(context.Background(), set, requesttest.RequestFromMetricsFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, me) checkWrapSpanForMetrics(t, sr, set.TracerProvider.Tracer("test"), me, nil) } func TestMetrics_WithSpan_ReturnError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("my_error") me, err := NewMetrics(context.Background(), set, &fakeMetricsConfig, newPushMetricsData(want)) require.NoError(t, err) require.NotNil(t, me) checkWrapSpanForMetrics(t, sr, set.TracerProvider.Tracer("test"), me, want) } func TestMetricsRequest_WithSpan_ExportError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("my_error") me, err := internal.NewMetricsRequest(context.Background(), set, requesttest.RequestFromMetricsFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, me) checkWrapSpanForMetrics(t, sr, set.TracerProvider.Tracer("test"), me, want) } func TestMetrics_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } me, err := NewMetrics(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeMetricsConfig, newPushMetricsData(nil), WithShutdown(shutdown)) assert.NotNil(t, me) assert.NoError(t, err) assert.NoError(t, me.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, me.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestMetrics_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } me, err := NewMetrics(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeMetricsConfig, newPushMetricsData(nil), WithShutdown(shutdownErr)) assert.NotNil(t, me) assert.NoError(t, err) assert.NoError(t, me.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, me.Shutdown(context.Background())) } func newPushMetricsData(retError error) consumer.ConsumeMetricsFunc { return func(_ context.Context, _ pmetric.Metrics) error { return retError } } func newPushMetricsDataModifiedDownstream(retError error) consumer.ConsumeMetricsFunc { return func(_ context.Context, metric pmetric.Metrics) error { metric.ResourceMetrics().MoveAndAppendTo(pmetric.NewResourceMetricsSlice()) return retError } } func checkRecordedMetricsForMetrics(t *testing.T, tt *componenttest.Telemetry, id component.ID, me exporter.Metrics, wantError error) { md := testdata.GenerateMetrics(2) const numBatches = 7 for range numBatches { require.Equal(t, wantError, me.ConsumeMetrics(context.Background(), md)) } // TODO: When the new metrics correctly count partial dropped fix this. numPoints := int64(numBatches * md.MetricCount() * 2) /* 2 points per metric*/ if wantError != nil { metadatatest.AssertEqualExporterSendFailedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ExporterKey, id.String())), Value: numPoints, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } else { metadatatest.AssertEqualExporterSentMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ExporterKey, id.String())), Value: numPoints, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } } func generateMetricsTraffic(t *testing.T, tracer trace.Tracer, me exporter.Metrics, numRequests int, wantError error) { md := testdata.GenerateMetrics(1) ctx, span := tracer.Start(context.Background(), fakeMetricsParentSpanName) defer span.End() for range numRequests { require.Equal(t, wantError, me.ConsumeMetrics(ctx, md)) } } func checkWrapSpanForMetrics(t *testing.T, sr *tracetest.SpanRecorder, tracer trace.Tracer, me exporter.Metrics, wantError error) { const numRequests = 5 generateMetricsTraffic(t, tracer, me, numRequests, wantError) // Inspection time! gotSpanData := sr.Ended() require.Len(t, gotSpanData, numRequests+1) parentSpan := gotSpanData[numRequests] require.Equalf(t, fakeMetricsParentSpanName, parentSpan.Name(), "SpanData %v", parentSpan) for _, sd := range gotSpanData[:numRequests] { require.Equalf(t, parentSpan.SpanContext(), sd.Parent(), "Exporter span not a child\nSpanData %v", sd) oteltest.CheckStatus(t, sd, wantError) sentMetricPoints := int64(2) failedToSendMetricPoints := int64(0) if wantError != nil { sentMetricPoints = 0 failedToSendMetricPoints = 2 } require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsSent, Value: attribute.Int64Value(sentMetricPoints)}, "SpanData %v", sd) require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsFailed, Value: attribute.Int64Value(failedToSendMetricPoints)}, "SpanData %v", sd) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/queue_batch.go000066400000000000000000000033461511331344600263000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "context" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" ) // WithQueue overrides the default QueueBatchConfig for an exporter. // The default QueueBatchConfig is to disable queueing. // This option cannot be used with the new exporter helpers New[Traces|Metrics|Logs]RequestExporter. func WithQueue(config QueueBatchConfig) Option { return internal.WithQueue(config) } // QueueBatchConfig defines configuration for queueing and batching for the exporter. type QueueBatchConfig = queuebatch.Config // BatchConfig defines a configuration for batching requests based on a timeout and a minimum number of items. type BatchConfig = queuebatch.BatchConfig // QueueBatchEncoding defines the encoding to be used if persistent queue is configured. // Duplicate definition with queuebatch.Encoding since aliasing generics is not supported by default. type QueueBatchEncoding[T any] interface { // Marshal is a function that can marshal a request and its context into bytes. Marshal(context.Context, T) ([]byte, error) // Unmarshal is a function that can unmarshal bytes into a request and its context. Unmarshal([]byte) (context.Context, T, error) } var ErrQueueIsFull = queue.ErrQueueIsFull // NewDefaultQueueConfig returns the default config for QueueBatchConfig. // By default, the queue stores 1000 requests of telemetry and is non-blocking when full. var NewDefaultQueueConfig = internal.NewDefaultQueueConfig opentelemetry-collector-0.141.0/exporter/exporterhelper/request.go000066400000000000000000000007161511331344600255010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" ) type RequestSizerType = request.SizerType var ( RequestSizerTypeBytes = request.SizerTypeBytes RequestSizerTypeItems = request.SizerTypeItems RequestSizerTypeRequests = request.SizerTypeRequests ) opentelemetry-collector-0.141.0/exporter/exporterhelper/retry_sender.go000066400000000000000000000006461511331344600265200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "time" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" ) // NewThrottleRetry creates a new throttle retry error. func NewThrottleRetry(err error, delay time.Duration) error { return internal.NewThrottleRetry(err, delay) } opentelemetry-collector-0.141.0/exporter/exporterhelper/timeout_sender.go000066400000000000000000000007111511331344600270320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "go.opentelemetry.io/collector/exporter/exporterhelper/internal" ) type TimeoutConfig = internal.TimeoutConfig // NewDefaultTimeoutConfig returns the default config for TimeoutConfig. func NewDefaultTimeoutConfig() TimeoutConfig { return internal.NewDefaultTimeoutConfig() } opentelemetry-collector-0.141.0/exporter/exporterhelper/traces.go000066400000000000000000000020671511331344600252730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" ) // NewTraces creates an exporter.Traces that records observability metrics and wraps every request with a Span. func NewTraces( ctx context.Context, set exporter.Settings, cfg component.Config, pusher consumer.ConsumeTracesFunc, options ...Option, ) (exporter.Traces, error) { if cfg == nil { return nil, errNilConfig } if pusher == nil { return nil, errNilPushTraces } return internal.NewTracesRequest(ctx, set, queuebatch.RequestFromTraces(), queuebatch.RequestConsumeFromTraces(pusher), append([]Option{internal.WithQueueBatchSettings(queuebatch.NewTracesQueueBatchSettings())}, options...)...) } opentelemetry-collector-0.141.0/exporter/exporterhelper/traces_test.go000066400000000000000000000370411511331344600263320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporterhelper import ( "context" "errors" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/hosttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/metadatatest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/oteltest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sendertest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/storagetest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) const ( fakeTraceParentSpanName = "fake_trace_parent_span_name" ) var ( fakeTracesName = component.MustNewIDWithName("fake_traces_exporter", "with_name") fakeTracesConfig = struct{}{} ) func TestTraces_InvalidName(t *testing.T) { te, err := NewTraces(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, newTraceDataPusher(nil)) require.Nil(t, te) require.Equal(t, errNilConfig, err) } func TestTraces_NilLogger(t *testing.T) { te, err := NewTraces(context.Background(), exporter.Settings{}, &fakeTracesConfig, newTraceDataPusher(nil)) require.Nil(t, te) require.Equal(t, errNilLogger, err) } func TestTraces_NilPushTraceData(t *testing.T) { te, err := NewTraces(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeTracesConfig, nil) require.Nil(t, te) require.Equal(t, errNilPushTraces, err) } func TestTraces_Default(t *testing.T) { td := ptrace.NewTraces() te, err := NewTraces(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeTracesConfig, newTraceDataPusher(nil)) assert.NotNil(t, te) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, te.Capabilities()) assert.NoError(t, te.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, te.ConsumeTraces(context.Background(), td)) assert.NoError(t, te.Shutdown(context.Background())) } func TestTraces_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} te, err := NewTraces(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeTracesConfig, newTraceDataPusher(nil), WithCapabilities(capabilities)) assert.NotNil(t, te) require.NoError(t, err) assert.Equal(t, capabilities, te.Capabilities()) } func TestTraces_Default_ReturnError(t *testing.T) { td := ptrace.NewTraces() want := errors.New("my_error") te, err := NewTraces(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeTracesConfig, newTraceDataPusher(want)) require.NoError(t, err) require.NotNil(t, te) err = te.ConsumeTraces(context.Background(), td) require.Equal(t, want, err) } func TestTraces_WithPersistentQueue(t *testing.T) { fgOrigReadState := queue.PersistRequestContextOnRead fgOrigWriteState := queue.PersistRequestContextOnWrite qCfg := NewDefaultQueueConfig() storageID := component.MustNewIDWithName("file_storage", "storage") qCfg.StorageID = &storageID set := exportertest.NewNopSettings(exportertest.NopType) set.ID = component.MustNewIDWithName("test_logs", "with_persistent_queue") host := hosttest.NewHost(map[component.ID]component.Component{ storageID: storagetest.NewMockStorageExtension(nil), }) spanCtx := oteltest.FakeSpanContext(t) tests := []struct { name string fgEnabledOnWrite bool fgEnabledOnRead bool wantData bool wantSpanCtx bool }{ { name: "feature_gate_disabled_on_write_and_read", wantData: true, }, { name: "feature_gate_enabled_on_write_and_read", fgEnabledOnWrite: true, fgEnabledOnRead: true, wantData: true, wantSpanCtx: true, }, { name: "feature_gate_disabled_on_write_enabled_on_read", wantData: true, fgEnabledOnRead: true, }, { name: "feature_gate_enabled_on_write_disabled_on_read", fgEnabledOnWrite: true, wantData: false, // going back from enabled to disabled feature gate isn't supported }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { queue.PersistRequestContextOnRead = func() bool { return tt.fgEnabledOnRead } queue.PersistRequestContextOnWrite = func() bool { return tt.fgEnabledOnWrite } t.Cleanup(func() { queue.PersistRequestContextOnRead = fgOrigReadState queue.PersistRequestContextOnWrite = fgOrigWriteState }) ts := consumertest.TracesSink{} te, err := NewTraces(context.Background(), set, &fakeTracesConfig, ts.ConsumeTraces, WithQueue(qCfg)) require.NoError(t, err) require.NoError(t, te.Start(context.Background(), host)) t.Cleanup(func() { require.NoError(t, te.Shutdown(context.Background())) }) traces := testdata.GenerateTraces(2) require.NoError(t, te.ConsumeTraces(trace.ContextWithSpanContext(context.Background(), spanCtx), traces)) if tt.wantData { require.Eventually(t, func() bool { return len(ts.AllTraces()) == 1 && ts.SpanCount() == 2 }, 500*time.Millisecond, 10*time.Millisecond) } // check that the span context is persisted if the feature gate is enabled if tt.wantSpanCtx { assert.Len(t, ts.Contexts(), 1) assert.Equal(t, spanCtx, trace.SpanContextFromContext(ts.Contexts()[0])) } }) } } func TestTraces_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := NewTraces(context.Background(), exporter.Settings{ID: fakeTracesName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeTracesConfig, newTraceDataPusher(nil)) require.NoError(t, err) require.NotNil(t, te) checkRecordedMetricsForTraces(t, tt, fakeTracesName, te, nil) } func TestTraces_pLogModifiedDownStream_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := NewTraces(context.Background(), exporter.Settings{ID: fakeTracesName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeTracesConfig, newTraceDataPusherModifiedDownstream(nil), WithCapabilities(consumer.Capabilities{MutatesData: true})) assert.NotNil(t, te) require.NoError(t, err) td := testdata.GenerateTraces(2) require.NoError(t, te.ConsumeTraces(context.Background(), td)) assert.Equal(t, 0, td.SpanCount()) metadatatest.AssertEqualExporterSentSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ExporterKey, fakeTracesName.String())), Value: int64(2), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestTracesRequest_WithRecordMetrics(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := internal.NewTracesRequest(context.Background(), exporter.Settings{ID: fakeTracesName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, requesttest.RequestFromTracesFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, te) checkRecordedMetricsForTraces(t, tt, fakeTracesName, te, nil) } func TestTraces_WithRecordMetrics_ReturnError(t *testing.T) { want := errors.New("my_error") tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := NewTraces(context.Background(), exporter.Settings{ID: fakeTracesName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, &fakeTracesConfig, newTraceDataPusher(want)) require.NoError(t, err) require.NotNil(t, te) checkRecordedMetricsForTraces(t, tt, fakeTracesName, te, want) } func TestTracesRequest_WithRecordMetrics_RequestSenderError(t *testing.T) { want := errors.New("export_error") tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) te, err := internal.NewTracesRequest(context.Background(), exporter.Settings{ID: fakeTracesName, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, requesttest.RequestFromTracesFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, te) checkRecordedMetricsForTraces(t, tt, fakeTracesName, te, want) } func TestTraces_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) te, err := NewTraces(context.Background(), set, &fakeTracesConfig, newTraceDataPusher(nil)) require.NoError(t, err) require.NotNil(t, te) checkWrapSpanForTraces(t, sr, set.TracerProvider.Tracer("test"), te, nil) } func TestTracesRequest_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) te, err := internal.NewTracesRequest(context.Background(), set, requesttest.RequestFromTracesFunc(nil), sendertest.NewNopSenderFunc[request.Request]()) require.NoError(t, err) require.NotNil(t, te) checkWrapSpanForTraces(t, sr, set.TracerProvider.Tracer("test"), te, nil) } func TestTraces_WithSpan_ReturnError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("my_error") te, err := NewTraces(context.Background(), set, &fakeTracesConfig, newTraceDataPusher(want)) require.NoError(t, err) require.NotNil(t, te) checkWrapSpanForTraces(t, sr, set.TracerProvider.Tracer("test"), te, want) } func TestTracesRequest_WithSpan_ExportError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("export_error") te, err := internal.NewTracesRequest(context.Background(), set, requesttest.RequestFromTracesFunc(nil), sendertest.NewErrSenderFunc[request.Request](want)) require.NoError(t, err) require.NotNil(t, te) checkWrapSpanForTraces(t, sr, set.TracerProvider.Tracer("test"), te, want) } func TestTraces_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } te, err := NewTraces(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeTracesConfig, newTraceDataPusher(nil), WithShutdown(shutdown)) assert.NotNil(t, te) assert.NoError(t, err) assert.NoError(t, te.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, te.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestTraces_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } te, err := NewTraces(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeTracesConfig, newTraceDataPusher(nil), WithShutdown(shutdownErr)) assert.NotNil(t, te) assert.NoError(t, err) assert.NoError(t, te.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, te.Shutdown(context.Background())) } func newTraceDataPusher(retError error) consumer.ConsumeTracesFunc { return func(context.Context, ptrace.Traces) error { return retError } } func newTraceDataPusherModifiedDownstream(retError error) consumer.ConsumeTracesFunc { return func(_ context.Context, trace ptrace.Traces) error { trace.ResourceSpans().MoveAndAppendTo(ptrace.NewResourceSpansSlice()) return retError } } func checkRecordedMetricsForTraces(t *testing.T, tt *componenttest.Telemetry, id component.ID, te exporter.Traces, wantError error) { td := testdata.GenerateTraces(2) const numBatches = 7 for range numBatches { require.Equal(t, wantError, te.ConsumeTraces(context.Background(), td)) } // TODO: When the new metrics correctly count partial dropped fix this. if wantError != nil { metadatatest.AssertEqualExporterSendFailedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ExporterKey, id.String())), Value: int64(numBatches * td.SpanCount()), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } else { metadatatest.AssertEqualExporterSentSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ExporterKey, id.String())), Value: int64(numBatches * td.SpanCount()), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } } func generateTraceTraffic(t *testing.T, tracer trace.Tracer, te exporter.Traces, numRequests int, wantError error) { td := ptrace.NewTraces() td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() ctx, span := tracer.Start(context.Background(), fakeTraceParentSpanName) defer span.End() for range numRequests { require.Equal(t, wantError, te.ConsumeTraces(ctx, td)) } } func checkWrapSpanForTraces(t *testing.T, sr *tracetest.SpanRecorder, tracer trace.Tracer, te exporter.Traces, wantError error) { const numRequests = 5 generateTraceTraffic(t, tracer, te, numRequests, wantError) // Inspection time! gotSpanData := sr.Ended() require.Len(t, gotSpanData, numRequests+1) parentSpan := gotSpanData[numRequests] require.Equalf(t, fakeTraceParentSpanName, parentSpan.Name(), "SpanData %v", parentSpan) for _, sd := range gotSpanData[:numRequests] { require.Equalf(t, parentSpan.SpanContext(), sd.Parent(), "Exporter span not a child\nSpanData %v", sd) oteltest.CheckStatus(t, sd, wantError) sentSpans := int64(1) failedToSendSpans := int64(0) if wantError != nil { sentSpans = 0 failedToSendSpans = 1 } require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsSent, Value: attribute.Int64Value(sentSpans)}, "SpanData %v", sd) require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsFailed, Value: attribute.Int64Value(failedToSendSpans)}, "SpanData %v", sd) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/000077500000000000000000000000001511331344600267165ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/Makefile000066400000000000000000000000411511331344600303510ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/constants.go000066400000000000000000000014621511331344600312640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" import ( "errors" ) var ( // errNilConfig is returned when an empty name is given. errNilConfig = errors.New("nil config") // errNilLogger is returned when a logger is nil errNilLogger = errors.New("nil logger") // errNilConsumeRequest is returned when a nil PushTraces is given. errNilConsumeRequest = errors.New("nil RequestConsumeFunc") // errNilPushProfileData is returned when a nil PushProfiles is given. errNilPushProfileData = errors.New("nil PushProfiles") // errNilProfilesConverter is returned when a nil RequestFromProfilesFunc is given. errNilProfilesConverter = errors.New("nil RequestFromProfilesFunc") ) opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/go.mod000066400000000000000000000133641511331344600300330ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumererror/xconsumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/exporter/xexporter v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pdata/xpdata v0.141.0 go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/zap v1.27.1 ) require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configoptional v1.47.0 // indirect go.opentelemetry.io/collector/config/configretry v1.47.0 // indirect go.opentelemetry.io/collector/confmap v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/receiver v1.47.0 // indirect go.opentelemetry.io/collector/receiver/receivertest v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/consumer/consumertest => ../../../consumer/consumertest replace go.opentelemetry.io/collector/pdata/pprofile => ../../../pdata/pprofile replace go.opentelemetry.io/collector/pdata/testdata => ../../../pdata/testdata replace go.opentelemetry.io/collector/exporter => ../../ replace go.opentelemetry.io/collector/consumer => ../../../consumer replace go.opentelemetry.io/collector/consumer/consumererror/xconsumererror => ../../../consumer/consumererror/xconsumererror replace go.opentelemetry.io/collector/receiver => ../../../receiver replace go.opentelemetry.io/collector/consumer/xconsumer => ../../../consumer/xconsumer replace go.opentelemetry.io/collector/component => ../../../component replace go.opentelemetry.io/collector/component/componenttest => ../../../component/componenttest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../../receiver/receivertest replace go.opentelemetry.io/collector/extension => ../../../extension replace go.opentelemetry.io/collector/pdata => ../../../pdata replace go.opentelemetry.io/collector/exporter/xexporter => ../../xexporter replace go.opentelemetry.io/collector/config/configretry => ../../../config/configretry replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../../pipeline/xpipeline replace go.opentelemetry.io/collector/pipeline => ../../../pipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../../exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../../../consumer/consumererror replace go.opentelemetry.io/collector/extension/extensiontest => ../../../extension/extensiontest replace go.opentelemetry.io/collector/extension/xextension => ../../../extension/xextension replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/client => ../../../client replace go.opentelemetry.io/collector/pdata/xpdata => ../../../pdata/xpdata replace go.opentelemetry.io/collector/config/configoptional => ../../../config/configoptional replace go.opentelemetry.io/collector/confmap => ../../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../../confmap/xconfmap replace go.opentelemetry.io/collector/exporter/exporterhelper => ../ replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/go.sum000066400000000000000000000210431511331344600300510ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/metadata.yaml000066400000000000000000000003441511331344600313630ustar00rootroot00000000000000type: xexporterhelper github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg codeowners: active: - mx-psi - dmathieu stability: development: [profiles] opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/new_request.go000066400000000000000000000103701511331344600316070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" import ( "context" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queuebatch" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) // NewLogsRequest creates new logs exporter based on custom LogsConverter and Sender. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewLogsRequest( ctx context.Context, set exporter.Settings, converter RequestConverterFunc[plog.Logs], pusher RequestConsumeFunc, options ...exporterhelper.Option, ) (exporter.Logs, error) { return internal.NewLogsRequest(ctx, set, converter, pusher, options...) } // NewMetricsRequest creates new metrics exporter based on custom MetricsConverter and Sender. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewMetricsRequest( ctx context.Context, set exporter.Settings, converter RequestConverterFunc[pmetric.Metrics], pusher RequestConsumeFunc, options ...exporterhelper.Option, ) (exporter.Metrics, error) { return internal.NewMetricsRequest(ctx, set, converter, pusher, options...) } // NewTracesRequest creates new traces exporter based on custom TracesConverter and Sender. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewTracesRequest( ctx context.Context, set exporter.Settings, converter RequestConverterFunc[ptrace.Traces], pusher RequestConsumeFunc, options ...exporterhelper.Option, ) (exporter.Traces, error) { return internal.NewTracesRequest(ctx, set, converter, pusher, options...) } // QueueBatchSettings are settings for the QueueBatch component. // They include things line Encoding to be used with persistent queue, or the available Sizers, etc. type QueueBatchSettings = queuebatch.Settings[Request] // NewMetricsQueueBatchSettings returns a new QueueBatchSettings to configure to WithQueueBatch when using pmetric.Metrics. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewMetricsQueueBatchSettings() QueueBatchSettings { return queuebatch.NewMetricsQueueBatchSettings() } // NewLogsQueueBatchSettings returns a new QueueBatchSettings to configure to WithQueueBatch when using plog.Logs. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewLogsQueueBatchSettings() QueueBatchSettings { return queuebatch.NewLogsQueueBatchSettings() } // NewTracesQueueBatchSettings returns a new QueueBatchSettings to configure to WithQueueBatch when using ptrace.Traces. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewTracesQueueBatchSettings() QueueBatchSettings { return queuebatch.NewTracesQueueBatchSettings() } // WithQueueBatch enables queueing and batching for an exporter. // This option should be used with the new exporter helpers New[Traces|Metrics|Logs]RequestExporter. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func WithQueueBatch(cfg exporterhelper.QueueBatchConfig, set QueueBatchSettings) exporterhelper.Option { return internal.WithQueueBatch(cfg, set) } opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/profiles.go000066400000000000000000000154031511331344600310730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" import ( "context" "errors" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/xpdata/pref" pdatareq "go.opentelemetry.io/collector/pdata/xpdata/request" "go.opentelemetry.io/collector/pipeline/xpipeline" ) var ( profilesMarshaler = &pprofile.ProtoMarshaler{} profilesUnmarshaler = &pprofile.ProtoUnmarshaler{} ) // NewProfilesQueueBatchSettings returns a new QueueBatchSettings to configure to WithQueueBatch when using pprofile.Profiles. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewProfilesQueueBatchSettings() QueueBatchSettings { return QueueBatchSettings{ ReferenceCounter: profilesReferenceCounter{}, Encoding: profilesEncoding{}, } } var ( _ request.Request = (*profilesRequest)(nil) _ request.ErrorHandler = (*profilesRequest)(nil) ) type profilesRequest struct { pd pprofile.Profiles cachedSize int } func newProfilesRequest(pd pprofile.Profiles) Request { return &profilesRequest{ pd: pd, cachedSize: -1, } } type profilesEncoding struct{} var _ exporterhelper.QueueBatchEncoding[request.Request] = profilesEncoding{} func (profilesEncoding) Unmarshal(bytes []byte) (context.Context, request.Request, error) { if queue.PersistRequestContextOnRead() { ctx, profiles, err := pdatareq.UnmarshalProfiles(bytes) if errors.Is(err, pdatareq.ErrInvalidFormat) { // fall back to unmarshaling without context profiles, err = profilesUnmarshaler.UnmarshalProfiles(bytes) } return ctx, newProfilesRequest(profiles), err } profiles, err := profilesUnmarshaler.UnmarshalProfiles(bytes) if err != nil { var req request.Request return context.Background(), req, err } return context.Background(), newProfilesRequest(profiles), nil } func (profilesEncoding) Marshal(ctx context.Context, req request.Request) ([]byte, error) { profiles := req.(*profilesRequest).pd if queue.PersistRequestContextOnWrite() { return pdatareq.MarshalProfiles(ctx, profiles) } return profilesMarshaler.MarshalProfiles(profiles) } var _ queue.ReferenceCounter[request.Request] = profilesReferenceCounter{} type profilesReferenceCounter struct{} func (profilesReferenceCounter) Ref(req request.Request) { pref.RefProfiles(req.(*profilesRequest).pd) } func (profilesReferenceCounter) Unref(req request.Request) { pref.UnrefProfiles(req.(*profilesRequest).pd) } func (req *profilesRequest) OnError(err error) Request { var profileError xconsumererror.Profiles if errors.As(err, &profileError) { // TODO: Add logic to unref the new request created here. return newProfilesRequest(profileError.Data()) } return req } func (req *profilesRequest) ItemsCount() int { return req.pd.SampleCount() } func (req *profilesRequest) size(sizer sizer.ProfilesSizer) int { if req.cachedSize == -1 { req.cachedSize = sizer.ProfilesSize(req.pd) } return req.cachedSize } func (req *profilesRequest) setCachedSize(size int) { req.cachedSize = size } func (req *profilesRequest) BytesSize() int { return profilesMarshaler.ProfilesSize(req.pd) } type profileExporter struct { *internal.BaseExporter xconsumer.Profiles } // NewProfiles creates an xexporter.Profiles that records observability metrics and wraps every request with a Span. func NewProfiles( ctx context.Context, set exporter.Settings, cfg component.Config, pusher xconsumer.ConsumeProfilesFunc, options ...exporterhelper.Option, ) (xexporter.Profiles, error) { if cfg == nil { return nil, errNilConfig } if pusher == nil { return nil, errNilPushProfileData } return NewProfilesRequest(ctx, set, requestFromProfiles(), requestConsumeFromProfiles(pusher), append([]exporterhelper.Option{internal.WithQueueBatchSettings(NewProfilesQueueBatchSettings())}, options...)...) } // requestConsumeFromProfiles returns a RequestConsumeFunc that consumes pprofile.Profiles. func requestConsumeFromProfiles(pusher xconsumer.ConsumeProfilesFunc) RequestConsumeFunc { return func(ctx context.Context, request Request) error { return pusher.ConsumeProfiles(ctx, request.(*profilesRequest).pd) } } // requestFromProfiles returns a RequestFromProfilesFunc that converts pprofile.Profiles into a Request. func requestFromProfiles() RequestConverterFunc[pprofile.Profiles] { return func(_ context.Context, profiles pprofile.Profiles) (Request, error) { return newProfilesRequest(profiles), nil } } // NewProfilesRequest creates a new profiles exporter based on a custom ProfilesConverter and Sender. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. func NewProfilesRequest( _ context.Context, set exporter.Settings, converter RequestConverterFunc[pprofile.Profiles], pusher RequestConsumeFunc, options ...exporterhelper.Option, ) (xexporter.Profiles, error) { if set.Logger == nil { return nil, errNilLogger } if converter == nil { return nil, errNilProfilesConverter } if pusher == nil { return nil, errNilConsumeRequest } be, err := internal.NewBaseExporter(set, xpipeline.SignalProfiles, pusher, options...) if err != nil { return nil, err } tc, err := xconsumer.NewProfiles(newConsumeProfiles(converter, be, set.Logger), be.ConsumerOptions...) if err != nil { return nil, err } return &profileExporter{BaseExporter: be, Profiles: tc}, nil } func newConsumeProfiles(converter RequestConverterFunc[pprofile.Profiles], be *internal.BaseExporter, logger *zap.Logger) xconsumer.ConsumeProfilesFunc { return func(ctx context.Context, pd pprofile.Profiles) error { req, err := converter(ctx, pd) if err != nil { logger.Error("Failed to convert profiles. Dropping data.", zap.Int("dropped_samples", pd.SampleCount()), zap.Error(err)) return consumererror.NewPermanent(err) } return be.Send(ctx, req) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/profiles_batch.go000066400000000000000000000154461511331344600322430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" import ( "context" "errors" "fmt" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/pprofile" ) // MergeSplit splits and/or merges the profiles into multiple requests based on the MaxSizeConfig. // // Following the OTLP 1.7.0 upgrade, this is currently a noop. // See https://github.com/open-telemetry/opentelemetry-collector/issues/13106 func (req *profilesRequest) MergeSplit(_ context.Context, maxSize int, szt exporterhelper.RequestSizerType, r2 Request) ([]Request, error) { var sz sizer.ProfilesSizer switch szt { case exporterhelper.RequestSizerTypeItems: sz = &sizer.ProfilesCountSizer{} case exporterhelper.RequestSizerTypeBytes: sz = &sizer.ProfilesBytesSizer{} default: return nil, errors.New("unknown sizer type") } if r2 != nil && r2.ItemsCount() > 0 { req2, ok := r2.(*profilesRequest) if !ok { return nil, errors.New("invalid input type") } // TODO(13106): handle merging of profiles (and change the indice tables with their new indices) // req2.mergeTo(req, sz) // If no limit we can simply merge the new request into the current and return. if maxSize == 0 { return []Request{req, req2}, nil } sp1, err1 := req.split(maxSize, sz) sp2, err2 := req2.split(maxSize, sz) return append(sp1, sp2...), errors.Join(err1, err2) } // If no limit we can simply merge the new request into the current and return. if maxSize == 0 { return []Request{req}, nil } return req.split(maxSize, sz) } // TODO(13106): handle merging of profiles (and change the indice tables with their new indices) /*func (req *profilesRequest) mergeTo(dst *profilesRequest, sz sizer.ProfilesSizer) { if sz != nil { dst.setCachedSize(dst.size(sz) + req.size(sz)) req.setCachedSize(0) } req.pd.ResourceProfiles().MoveAndAppendTo(dst.pd.ResourceProfiles()) }*/ func (req *profilesRequest) split(maxSize int, sz sizer.ProfilesSizer) ([]Request, error) { var res []Request for req.size(sz) > maxSize { pd, rmSize := extractProfiles(req.pd, maxSize, sz) if pd.SampleCount() == 0 { return res, fmt.Errorf("one sample size is greater than max size, dropping items: %d", req.pd.SampleCount()) } req.setCachedSize(req.size(sz) - rmSize) res = append(res, newProfilesRequest(pd)) } res = append(res, req) return res, nil } // extractProfiles extracts a new profiles with a maximum number of samples. func extractProfiles(srcProfiles pprofile.Profiles, capacity int, sz sizer.ProfilesSizer) (pprofile.Profiles, int) { destProfiles := pprofile.NewProfiles() capacityLeft := capacity - sz.ProfilesSize(destProfiles) removedSize := 0 srcProfiles.ResourceProfiles().RemoveIf(func(srcRP pprofile.ResourceProfiles) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawRpSize := sz.ResourceProfilesSize(srcRP) rpSize := sz.DeltaSize(rawRpSize) if rpSize > capacityLeft { extSrcRP, extRpSize := extractResourceProfiles(srcRP, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extRpSize // There represents the delta between the delta sizes. removedSize += rpSize - rawRpSize - (sz.DeltaSize(rawRpSize-extRpSize) - (rawRpSize - extRpSize)) // It is possible that for the bytes scenario, the extracted field contains no profiles. // Do not add it to the destination if that is the case. if extSrcRP.ScopeProfiles().Len() > 0 { extSrcRP.MoveTo(destProfiles.ResourceProfiles().AppendEmpty()) } return extSrcRP.ScopeProfiles().Len() != 0 } capacityLeft -= rpSize removedSize += rpSize srcRP.MoveTo(destProfiles.ResourceProfiles().AppendEmpty()) return true }) return destProfiles, removedSize } // extractResourceProfiles extracts profiles and returns a new resource profiles with the specified number of profiles. func extractResourceProfiles(srcRP pprofile.ResourceProfiles, capacity int, sz sizer.ProfilesSizer) (pprofile.ResourceProfiles, int) { destRP := pprofile.NewResourceProfiles() destRP.SetSchemaUrl(srcRP.SchemaUrl()) srcRP.Resource().CopyTo(destRP.Resource()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ResourceProfilesSize(destRP) removedSize := 0 srcRP.ScopeProfiles().RemoveIf(func(srcSS pprofile.ScopeProfiles) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rawSlSize := sz.ScopeProfilesSize(srcSS) ssSize := sz.DeltaSize(rawSlSize) if ssSize > capacityLeft { extSrcSS, extSsSize := extractScopeProfiles(srcSS, capacityLeft, sz) // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 removedSize += extSsSize // There represents the delta between the delta sizes. removedSize += ssSize - rawSlSize - (sz.DeltaSize(rawSlSize-extSsSize) - (rawSlSize - extSsSize)) // It is possible that for the bytes scenario, the extracted field contains no profiles. // Do not add it to the destination if that is the case. if extSrcSS.Profiles().Len() > 0 { extSrcSS.MoveTo(destRP.ScopeProfiles().AppendEmpty()) } return extSrcSS.Profiles().Len() != 0 } capacityLeft -= ssSize removedSize += ssSize srcSS.MoveTo(destRP.ScopeProfiles().AppendEmpty()) return true }) return destRP, removedSize } // extractScopeProfiles extracts profiles and returns a new scope profiles with the specified number of profiles. func extractScopeProfiles(srcSS pprofile.ScopeProfiles, capacity int, sz sizer.ProfilesSizer) (pprofile.ScopeProfiles, int) { destSS := pprofile.NewScopeProfiles() destSS.SetSchemaUrl(srcSS.SchemaUrl()) srcSS.Scope().CopyTo(destSS.Scope()) // Take into account that this can have max "capacity", so when added to the parent will need space for the extra delta size. capacityLeft := capacity - (sz.DeltaSize(capacity) - capacity) - sz.ScopeProfilesSize(destSS) removedSize := 0 srcSS.Profiles().RemoveIf(func(srcProfile pprofile.Profile) bool { // If the no more capacity left just return. if capacityLeft == 0 { return false } rsSize := sz.DeltaSize(sz.ProfileSize(srcProfile)) if rsSize > capacityLeft { // This cannot make it to exactly 0 for the bytes, // force it to be 0 since that is the stopping condition. capacityLeft = 0 return false } capacityLeft -= rsSize removedSize += rsSize srcProfile.MoveTo(destSS.Profiles().AppendEmpty()) return true }) return destSS, removedSize } opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/profiles_batch_test.go000066400000000000000000000326201511331344600332730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporterhelper import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sizer" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMergeProfiles(t *testing.T) { pr1 := newProfilesRequest(testdata.GenerateProfiles(2)) pr2 := newProfilesRequest(testdata.GenerateProfiles(3)) res, err := pr1.MergeSplit(context.Background(), 0, exporterhelper.RequestSizerTypeItems, pr2) require.NoError(t, err) assert.Len(t, res, 2) assert.Equal(t, 2, res[0].ItemsCount()) assert.Equal(t, 3, res[1].ItemsCount()) } func TestMergeProfilesInvalidInput(t *testing.T) { pr2 := newProfilesRequest(testdata.GenerateProfiles(3)) _, err := pr2.MergeSplit(context.Background(), 0, exporterhelper.RequestSizerTypeItems, &requesttest.FakeRequest{Items: 1}) require.Error(t, err) } func TestMergeSplitProfiles(t *testing.T) { t.Skip("merging of profiles has been temporarily disabled (https://github.com/open-telemetry/opentelemetry-collector/issues/13106)") tests := []struct { name string szt exporterhelper.RequestSizerType maxSize int pr1 Request pr2 Request expected []Request }{ { name: "both_requests_empty", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: newProfilesRequest(pprofile.NewProfiles()), expected: []Request{newProfilesRequest(pprofile.NewProfiles())}, }, { name: "first_request_empty", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: newProfilesRequest(testdata.GenerateProfiles(5)), expected: []Request{newProfilesRequest(testdata.GenerateProfiles(5))}, }, { name: "first_empty_second_nil", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: nil, expected: []Request{newProfilesRequest(pprofile.NewProfiles())}, }, { name: "merge_only", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(testdata.GenerateProfiles(4)), pr2: newProfilesRequest(testdata.GenerateProfiles(6)), expected: []Request{newProfilesRequest(func() pprofile.Profiles { profiles := testdata.GenerateProfiles(4) testdata.GenerateProfiles(6).ResourceProfiles().MoveAndAppendTo(profiles.ResourceProfiles()) return profiles }())}, }, { name: "split_only", szt: exporterhelper.RequestSizerTypeItems, maxSize: 4, pr1: newProfilesRequest(testdata.GenerateProfiles(10)), pr2: nil, expected: []Request{ newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(testdata.GenerateProfiles(2)), }, }, { name: "merge_and_split", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(testdata.GenerateProfiles(8)), pr2: newProfilesRequest(testdata.GenerateProfiles(20)), expected: []Request{ newProfilesRequest(func() pprofile.Profiles { profiles := testdata.GenerateProfiles(8) testdata.GenerateProfiles(2).ResourceProfiles().MoveAndAppendTo(profiles.ResourceProfiles()) return profiles }()), newProfilesRequest(testdata.GenerateProfiles(10)), newProfilesRequest(testdata.GenerateProfiles(8)), }, }, { name: "scope_profiles_split", szt: exporterhelper.RequestSizerTypeItems, maxSize: 4, pr1: newProfilesRequest(func() pprofile.Profiles { return testdata.GenerateProfiles(6) }()), pr2: nil, expected: []Request{ newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(func() pprofile.Profiles { return testdata.GenerateProfiles(2) }()), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.pr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.pr2) require.NoError(t, err) require.Len(t, res, len(tt.expected)) for i, r := range res { assert.Equal(t, tt.expected[i].(*profilesRequest).pd, r.(*profilesRequest).pd) } }) } } func TestMergeSplitProfilesBasedOnByteSize(t *testing.T) { t.Skip("merging of profiles has been temporarily disabled (https://github.com/open-telemetry/opentelemetry-collector/issues/13106)") tests := []struct { name string szt exporterhelper.RequestSizerType maxSize int pr1 Request pr2 Request expected []Request }{ { name: "both_requests_empty", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: newProfilesRequest(pprofile.NewProfiles()), expected: []Request{newProfilesRequest(pprofile.NewProfiles())}, }, { name: "first_request_empty", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: newProfilesRequest(testdata.GenerateProfiles(5)), expected: []Request{newProfilesRequest(testdata.GenerateProfiles(5))}, }, { name: "first_empty_second_nil", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: nil, expected: []Request{newProfilesRequest(pprofile.NewProfiles())}, }, { name: "merge_only", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(testdata.GenerateProfiles(4)), pr2: newProfilesRequest(testdata.GenerateProfiles(6)), expected: []Request{newProfilesRequest(func() pprofile.Profiles { profiles := testdata.GenerateProfiles(4) testdata.GenerateProfiles(6).ResourceProfiles().MoveAndAppendTo(profiles.ResourceProfiles()) return profiles }())}, }, { name: "split_only", szt: exporterhelper.RequestSizerTypeItems, maxSize: 4, pr1: newProfilesRequest(testdata.GenerateProfiles(10)), pr2: nil, expected: []Request{ newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(testdata.GenerateProfiles(2)), }, }, { name: "merge_and_split", szt: exporterhelper.RequestSizerTypeItems, maxSize: 10, pr1: newProfilesRequest(testdata.GenerateProfiles(8)), pr2: newProfilesRequest(testdata.GenerateProfiles(20)), expected: []Request{ newProfilesRequest(func() pprofile.Profiles { profiles := testdata.GenerateProfiles(8) testdata.GenerateProfiles(2).ResourceProfiles().MoveAndAppendTo(profiles.ResourceProfiles()) return profiles }()), newProfilesRequest(testdata.GenerateProfiles(10)), newProfilesRequest(testdata.GenerateProfiles(8)), }, }, { name: "scope_profiles_split", szt: exporterhelper.RequestSizerTypeItems, maxSize: 4, pr1: newProfilesRequest(func() pprofile.Profiles { return testdata.GenerateProfiles(6) }()), pr2: nil, expected: []Request{ newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(func() pprofile.Profiles { return testdata.GenerateProfiles(2) }()), }, }, { name: "both_requests_empty", szt: exporterhelper.RequestSizerTypeBytes, maxSize: profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(10)), pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: newProfilesRequest(pprofile.NewProfiles()), expected: []Request{newProfilesRequest(pprofile.NewProfiles())}, }, { name: "first_request_empty", szt: exporterhelper.RequestSizerTypeBytes, maxSize: profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(10)), pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: newProfilesRequest(testdata.GenerateProfiles(5)), expected: []Request{newProfilesRequest(testdata.GenerateProfiles(5))}, }, { name: "first_empty_second_nil", szt: exporterhelper.RequestSizerTypeBytes, maxSize: profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(10)), pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: nil, expected: []Request{newProfilesRequest(pprofile.NewProfiles())}, }, { name: "merge_only", szt: exporterhelper.RequestSizerTypeBytes, maxSize: profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(11)), pr1: newProfilesRequest(testdata.GenerateProfiles(4)), pr2: newProfilesRequest(testdata.GenerateProfiles(6)), expected: []Request{newProfilesRequest(func() pprofile.Profiles { profiles := testdata.GenerateProfiles(4) testdata.GenerateProfiles(6).ResourceProfiles().MoveAndAppendTo(profiles.ResourceProfiles()) return profiles }())}, }, { name: "split_only", szt: exporterhelper.RequestSizerTypeBytes, maxSize: profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(4)), pr1: newProfilesRequest(pprofile.NewProfiles()), pr2: newProfilesRequest(testdata.GenerateProfiles(10)), expected: []Request{ newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(testdata.GenerateProfiles(4)), newProfilesRequest(testdata.GenerateProfiles(2)), }, }, { name: "merge_and_split", szt: exporterhelper.RequestSizerTypeBytes, maxSize: profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(10)), pr1: newProfilesRequest(testdata.GenerateProfiles(8)), pr2: newProfilesRequest(testdata.GenerateProfiles(20)), expected: []Request{ newProfilesRequest(func() pprofile.Profiles { profiles := testdata.GenerateProfiles(7) testdata.GenerateProfiles(2).ResourceProfiles().MoveAndAppendTo(profiles.ResourceProfiles()) return profiles }()), newProfilesRequest(testdata.GenerateProfiles(10)), newProfilesRequest(testdata.GenerateProfiles(9)), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res, err := tt.pr1.MergeSplit(context.Background(), tt.maxSize, tt.szt, tt.pr2) require.NoError(t, err) require.Len(t, res, len(tt.expected)) for i, r := range res { assert.Equal(t, tt.expected[i].(*profilesRequest).pd.SampleCount(), r.(*profilesRequest).pd.SampleCount(), i) } }) } } func TestExtractProfiles(t *testing.T) { for i := range 10 { ld := testdata.GenerateProfiles(10) extractedProfiles, _ := extractProfiles(ld, i, &sizer.ProfilesCountSizer{}) assert.Equal(t, i, extractedProfiles.SampleCount()) assert.Equal(t, 10-i, ld.SampleCount()) } } func TestMergeSplitManySmallLogs(t *testing.T) { t.Skip("merging of profiles has been temporarily disabled (https://github.com/open-telemetry/opentelemetry-collector/issues/13106)") // All requests merge into a single batch. merged := []Request{newProfilesRequest(testdata.GenerateProfiles(1))} for range 1000 { lr2 := newProfilesRequest(testdata.GenerateProfiles(10)) res, _ := merged[len(merged)-1].MergeSplit(context.Background(), 10000, exporterhelper.RequestSizerTypeItems, lr2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(t, merged, 2) } func BenchmarkSplittingBasedOnByteSizeManySmallProfiles(b *testing.B) { b.Skip("merging of profiles has been temporarily disabled (https://github.com/open-telemetry/opentelemetry-collector/issues/13106)") // All requests merge into a single batch. b.ReportAllocs() for b.Loop() { merged := []Request{newProfilesRequest(testdata.GenerateProfiles(10))} for range 1000 { pr2 := newProfilesRequest(testdata.GenerateProfiles(10)) res, _ := merged[len(merged)-1].MergeSplit( context.Background(), profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(11000)), exporterhelper.RequestSizerTypeBytes, pr2, ) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 1) } } func BenchmarkSplittingBasedOnByteSizeManyProfilesSlightlyAboveLimit(b *testing.B) { b.Skip("merging of profiles has been temporarily disabled (https://github.com/open-telemetry/opentelemetry-collector/issues/13106)") // Every incoming request results in a split. b.ReportAllocs() for b.Loop() { merged := []Request{newProfilesRequest(testdata.GenerateProfiles(0))} for range 10 { pr2 := newProfilesRequest(testdata.GenerateProfiles(10001)) res, _ := merged[len(merged)-1].MergeSplit( context.Background(), profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(10000)), exporterhelper.RequestSizerTypeBytes, pr2, ) assert.Len(b, res, 2) merged = append(merged[0:len(merged)-1], res...) } assert.Len(b, merged, 11) } } func BenchmarkSplittingBasedOnByteSizeHugeProfiles(b *testing.B) { b.Skip("merging of profiles has been temporarily disabled (https://github.com/open-telemetry/opentelemetry-collector/issues/13106)") // One request splits into many batches. b.ReportAllocs() for b.Loop() { merged := []Request{newProfilesRequest(testdata.GenerateProfiles(0))} pr2 := newProfilesRequest(testdata.GenerateProfiles(100000)) res, _ := merged[len(merged)-1].MergeSplit( context.Background(), profilesMarshaler.ProfilesSize(testdata.GenerateProfiles(10010)), exporterhelper.RequestSizerTypeBytes, pr2, ) merged = append(merged[0:len(merged)-1], res...) assert.Len(b, merged, 10) } } opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/profiles_test.go000066400000000000000000000370441511331344600321370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporterhelper import ( "context" "errors" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumererror/xconsumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/internal" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/hosttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/oteltest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/queue" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/requesttest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/sendertest" "go.opentelemetry.io/collector/exporter/exporterhelper/internal/storagetest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/testdata" ) const ( fakeProfilesParentSpanName = "fake_profiles_parent_span_name" ) var fakeProfilesExporterConfig = struct{}{} func TestProfilesRequest(t *testing.T) { lr := newProfilesRequest(testdata.GenerateProfiles(1)) profileErr := xconsumererror.NewProfiles(errors.New("some error"), pprofile.NewProfiles()) assert.Equal( t, newProfilesRequest(pprofile.NewProfiles()), lr.(RequestErrorHandler).OnError(profileErr), ) } func TestProfilesExporter_InvalidName(t *testing.T) { le, err := NewProfiles(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, newPushProfilesData(nil)) require.Nil(t, le) require.Equal(t, errNilConfig, err) } func TestProfilesExporter_NilLogger(t *testing.T) { le, err := NewProfiles(context.Background(), exporter.Settings{}, &fakeProfilesExporterConfig, newPushProfilesData(nil)) require.Nil(t, le) require.Equal(t, errNilLogger, err) } func TestProfilesRequestExporter_NilLogger(t *testing.T) { le, err := NewProfilesRequest(context.Background(), exporter.Settings{}, requestFromProfilesFunc(nil), sendertest.NewNopSenderFunc[Request]()) require.Nil(t, le) require.Equal(t, errNilLogger, err) } func TestProfilesExporter_NilPushProfilesData(t *testing.T) { le, err := NewProfiles(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeProfilesExporterConfig, nil) require.Nil(t, le) require.Equal(t, errNilPushProfileData, err) } func TestProfilesExporter_NilProfilesConverter(t *testing.T) { te, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), nil, sendertest.NewNopSenderFunc[Request]()) require.Nil(t, te) require.Equal(t, errNilProfilesConverter, err) } func TestProfilesRequestExporter_NilProfilesConverter(t *testing.T) { le, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requestFromProfilesFunc(nil), nil) require.Nil(t, le) require.Equal(t, errNilConsumeRequest, err) } func TestProfilesExporter_Default(t *testing.T) { ld := pprofile.NewProfiles() le, err := NewProfiles(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeProfilesExporterConfig, newPushProfilesData(nil)) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, le.Capabilities()) require.NoError(t, le.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, le.ConsumeProfiles(context.Background(), ld)) require.NoError(t, le.Shutdown(context.Background())) } func TestProfilesRequestExporter_Default(t *testing.T) { ld := pprofile.NewProfiles() le, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requestFromProfilesFunc(nil), sendertest.NewNopSenderFunc[Request]()) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, le.Capabilities()) require.NoError(t, le.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, le.ConsumeProfiles(context.Background(), ld)) require.NoError(t, le.Shutdown(context.Background())) } func TestProfilesExporter_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} le, err := NewProfiles(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeProfilesExporterConfig, newPushProfilesData(nil), exporterhelper.WithCapabilities(capabilities)) require.NoError(t, err) require.NotNil(t, le) assert.Equal(t, capabilities, le.Capabilities()) } func TestProfilesRequestExporter_WithCapabilities(t *testing.T) { capabilities := consumer.Capabilities{MutatesData: true} le, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requestFromProfilesFunc(nil), sendertest.NewNopSenderFunc[Request](), exporterhelper.WithCapabilities(capabilities)) require.NoError(t, err) require.NotNil(t, le) assert.Equal(t, capabilities, le.Capabilities()) } func TestProfilesExporter_Default_ReturnError(t *testing.T) { ld := pprofile.NewProfiles() want := errors.New("my_error") le, err := NewProfiles(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeProfilesExporterConfig, newPushProfilesData(want)) require.NoError(t, err) require.NotNil(t, le) require.Equal(t, want, le.ConsumeProfiles(context.Background(), ld)) } func TestProfilesRequestExporter_Default_ConvertError(t *testing.T) { ld := pprofile.NewProfiles() want := errors.New("convert_error") le, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requestFromProfilesFunc(want), sendertest.NewNopSenderFunc[Request]()) require.NoError(t, err) require.NotNil(t, le) require.Equal(t, consumererror.NewPermanent(want), le.ConsumeProfiles(context.Background(), ld)) } func TestProfilesRequestExporter_Default_ExportError(t *testing.T) { ld := pprofile.NewProfiles() want := errors.New("export_error") le, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requestFromProfilesFunc(nil), sendertest.NewErrSenderFunc[Request](want)) require.NoError(t, err) require.NotNil(t, le) require.Equal(t, want, le.ConsumeProfiles(context.Background(), ld)) } func TestProfiles_WithPersistentQueue(t *testing.T) { fgOrigReadState := queue.PersistRequestContextOnRead fgOrigWriteState := queue.PersistRequestContextOnWrite qCfg := exporterhelper.NewDefaultQueueConfig() storageID := component.MustNewIDWithName("file_storage", "storage") qCfg.StorageID = &storageID set := exportertest.NewNopSettings(exportertest.NopType) set.ID = component.MustNewIDWithName("test_logs", "with_persistent_queue") host := hosttest.NewHost(map[component.ID]component.Component{ storageID: storagetest.NewMockStorageExtension(nil), }) spanCtx := oteltest.FakeSpanContext(t) tests := []struct { name string fgEnabledOnWrite bool fgEnabledOnRead bool wantData bool wantSpanCtx bool }{ { name: "feature_gate_disabled_on_write_and_read", wantData: true, }, { name: "feature_gate_enabled_on_write_and_read", fgEnabledOnWrite: true, fgEnabledOnRead: true, wantData: true, wantSpanCtx: true, }, { name: "feature_gate_disabled_on_write_enabled_on_read", wantData: true, fgEnabledOnRead: true, }, { name: "feature_gate_enabled_on_write_disabled_on_read", fgEnabledOnWrite: true, wantData: false, // going back from enabled to disabled feature gate isn't supported }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { queue.PersistRequestContextOnRead = func() bool { return tt.fgEnabledOnRead } queue.PersistRequestContextOnWrite = func() bool { return tt.fgEnabledOnWrite } t.Cleanup(func() { queue.PersistRequestContextOnRead = fgOrigReadState queue.PersistRequestContextOnWrite = fgOrigWriteState }) ts := consumertest.ProfilesSink{} te, err := NewProfiles(context.Background(), set, &fakeProfilesExporterConfig, ts.ConsumeProfiles, exporterhelper.WithQueue(qCfg)) require.NoError(t, err) require.NoError(t, te.Start(context.Background(), host)) t.Cleanup(func() { require.NoError(t, te.Shutdown(context.Background())) }) profiles := testdata.GenerateProfiles(2) require.NoError(t, te.ConsumeProfiles(trace.ContextWithSpanContext(context.Background(), spanCtx), profiles)) if tt.wantData { require.Eventually(t, func() bool { return len(ts.AllProfiles()) == 1 && ts.SampleCount() == 2 }, 500*time.Millisecond, 10*time.Millisecond) } // check that the span context is persisted if the feature gate is enabled if tt.wantSpanCtx { assert.Len(t, ts.Contexts(), 1) assert.Equal(t, spanCtx, trace.SpanContextFromContext(ts.Contexts()[0])) } }) } } func TestProfilesExporter_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) le, err := NewProfiles(context.Background(), set, &fakeProfilesExporterConfig, newPushProfilesData(nil)) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForProfilesExporter(t, sr, set.TracerProvider.Tracer("test"), le, nil) } func TestProfilesRequestExporter_WithSpan(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) le, err := NewProfilesRequest(context.Background(), set, requestFromProfilesFunc(nil), sendertest.NewNopSenderFunc[Request]()) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForProfilesExporter(t, sr, set.TracerProvider.Tracer("test"), le, nil) } func TestProfilesExporter_WithSpan_ReturnError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("my_error") le, err := NewProfiles(context.Background(), set, &fakeProfilesExporterConfig, newPushProfilesData(want)) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForProfilesExporter(t, sr, set.TracerProvider.Tracer("test"), le, want) } func TestProfilesRequestExporter_WithSpan_ReturnError(t *testing.T) { set := exportertest.NewNopSettings(exportertest.NopType) sr := new(tracetest.SpanRecorder) set.TracerProvider = sdktrace.NewTracerProvider(sdktrace.WithSpanProcessor(sr)) otel.SetTracerProvider(set.TracerProvider) defer otel.SetTracerProvider(nooptrace.NewTracerProvider()) want := errors.New("my_error") le, err := NewProfilesRequest(context.Background(), set, requestFromProfilesFunc(nil), sendertest.NewErrSenderFunc[Request](want)) require.NoError(t, err) require.NotNil(t, le) checkWrapSpanForProfilesExporter(t, sr, set.TracerProvider.Tracer("test"), le, want) } func TestProfilesExporter_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } le, err := NewProfiles(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeProfilesExporterConfig, newPushProfilesData(nil), exporterhelper.WithShutdown(shutdown)) assert.NotNil(t, le) require.NoError(t, err) require.NoError(t, le.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestProfilesRequestExporter_WithShutdown(t *testing.T) { shutdownCalled := false shutdown := func(context.Context) error { shutdownCalled = true; return nil } le, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requestFromProfilesFunc(nil), sendertest.NewNopSenderFunc[Request](), exporterhelper.WithShutdown(shutdown)) assert.NotNil(t, le) require.NoError(t, err) require.NoError(t, le.Shutdown(context.Background())) assert.True(t, shutdownCalled) } func TestProfilesExporter_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } le, err := NewProfiles(context.Background(), exportertest.NewNopSettings(exportertest.NopType), &fakeProfilesExporterConfig, newPushProfilesData(nil), exporterhelper.WithShutdown(shutdownErr)) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, want, le.Shutdown(context.Background())) } func TestProfilesRequestExporter_WithShutdown_ReturnError(t *testing.T) { want := errors.New("my_error") shutdownErr := func(context.Context) error { return want } le, err := NewProfilesRequest(context.Background(), exportertest.NewNopSettings(exportertest.NopType), requestFromProfilesFunc(nil), sendertest.NewNopSenderFunc[Request](), exporterhelper.WithShutdown(shutdownErr)) assert.NotNil(t, le) require.NoError(t, err) assert.Equal(t, want, le.Shutdown(context.Background())) } func newPushProfilesData(retError error) xconsumer.ConsumeProfilesFunc { return func(_ context.Context, _ pprofile.Profiles) error { return retError } } func generateProfilesTraffic(t *testing.T, tracer trace.Tracer, le xexporter.Profiles, numRequests int, wantError error) { ld := testdata.GenerateProfiles(1) ctx, span := tracer.Start(context.Background(), fakeProfilesParentSpanName) defer span.End() for range numRequests { require.Equal(t, wantError, le.ConsumeProfiles(ctx, ld)) } } func checkWrapSpanForProfilesExporter(t *testing.T, sr *tracetest.SpanRecorder, tracer trace.Tracer, le xexporter.Profiles, wantError error) { const numRequests = 5 generateProfilesTraffic(t, tracer, le, numRequests, wantError) // Inspection time! gotSpanData := sr.Ended() require.Len(t, gotSpanData, numRequests+1) parentSpan := gotSpanData[numRequests] require.Equalf(t, fakeProfilesParentSpanName, parentSpan.Name(), "SpanData %v", parentSpan) for _, sd := range gotSpanData[:numRequests] { require.Equalf(t, parentSpan.SpanContext(), sd.Parent(), "Exporter span not a child\nSpanData %v", sd) oteltest.CheckStatus(t, sd, wantError) sentSampleRecords := int64(1) failedToSendSampleRecords := int64(0) if wantError != nil { sentSampleRecords = 0 failedToSendSampleRecords = 1 } require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsSent, Value: attribute.Int64Value(sentSampleRecords)}, "SpanData %v", sd) require.Containsf(t, sd.Attributes(), attribute.KeyValue{Key: internal.ItemsFailed, Value: attribute.Int64Value(failedToSendSampleRecords)}, "SpanData %v", sd) } } func requestFromProfilesFunc(err error) func(context.Context, pprofile.Profiles) (Request, error) { return func(_ context.Context, pd pprofile.Profiles) (Request, error) { return &requesttest.FakeRequest{Items: pd.SampleCount()}, err } } opentelemetry-collector-0.141.0/exporter/exporterhelper/xexporterhelper/request.go000066400000000000000000000036161511331344600307430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporterhelper // import "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" import "go.opentelemetry.io/collector/exporter/exporterhelper/internal/request" // Request represents a single request that can be sent to an external endpoint. // Request represents a single request that can be sent to an external endpoint. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. type Request = request.Request // RequestErrorHandler is an optional interface that can be implemented by Request to provide a way handle partial // temporary failures. For example, if some items failed to process and can be retried, this interface allows to // return a new Request that contains the items left to be sent. Otherwise, the original Request should be returned. // If not implemented, the original Request will be returned assuming the error is applied to the whole Request. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. type RequestErrorHandler = request.ErrorHandler // RequestConverterFunc converts pdata telemetry into a user-defined Request. // Experimental: This API is at the early stage of development and may change without backward compatibility // until https://github.com/open-telemetry/opentelemetry-collector/issues/8122 is resolved. type RequestConverterFunc[T any] = request.RequestConverterFunc[T] // RequestConsumeFunc processes the request. After the function returns, the request is no longer accessible, // and accessing it is considered undefined behavior. type RequestConsumeFunc = request.RequestConsumeFunc opentelemetry-collector-0.141.0/exporter/exportertest/000077500000000000000000000000001511331344600231565ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/exportertest/Makefile000066400000000000000000000000351511331344600246140ustar00rootroot00000000000000include ../../Makefile.Commonopentelemetry-collector-0.141.0/exporter/exportertest/contract_checker.go000066400000000000000000000254371511331344600270210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exportertest // import "go.opentelemetry.io/collector/exporter/exportertest" import ( "context" "fmt" "strconv" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" ) // uniqueIDAttrName is the attribute name that is used in log records/spans/datapoints as the unique identifier. const uniqueIDAttrName = "test_id" // uniqueIDAttrVal is the value type of the uniqueIDAttrName. type uniqueIDAttrVal string type CheckConsumeContractParams struct { T *testing.T NumberOfTestElements int Signal pipeline.Signal // ExporterFactory to create an exporter to be tested. ExporterFactory exporter.Factory ExporterConfig component.Config // ReceiverFactory to create a mock receiver. ReceiverFactory receiver.Factory ReceiverConfig component.Config } func CheckConsumeContract(params CheckConsumeContractParams) { // Different scenarios to test for. // The decision function defines the testing scenario (i.e. to test for // success case or for error case or a mix of both). See for example randomErrorsConsumeDecision. scenarios := []struct { name string decisionFunc func() error checkIfTestPassed func(*testing.T, int, requestCounter) }{ { name: "always_succeed", // Always succeed. We expect all data to be delivered as is. decisionFunc: func() error { return nil }, checkIfTestPassed: alwaysSucceedsPassed, }, { name: "random_non_permanent_error", decisionFunc: randomNonPermanentErrorConsumeDecision, checkIfTestPassed: randomNonPermanentErrorConsumeDecisionPassed, }, { name: "random_permanent_error", decisionFunc: randomPermanentErrorConsumeDecision, checkIfTestPassed: randomPermanentErrorConsumeDecisionPassed, }, { name: "random_error", decisionFunc: randomErrorsConsumeDecision, checkIfTestPassed: randomErrorConsumeDecisionPassed, }, } for _, scenario := range scenarios { params.T.Run( scenario.name, func(t *testing.T) { checkConsumeContractScenario(t, params, scenario.decisionFunc, scenario.checkIfTestPassed) }, ) } } func checkConsumeContractScenario(t *testing.T, params CheckConsumeContractParams, decisionFunc func() error, checkIfTestPassed func(*testing.T, int, requestCounter)) { mockConsumerInstance := newMockConsumer(decisionFunc) switch params.Signal { case pipeline.SignalLogs: r, err := params.ReceiverFactory.CreateLogs(context.Background(), receivertest.NewNopSettings(params.ReceiverFactory.Type()), params.ReceiverConfig, &mockConsumerInstance) require.NoError(t, err) require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost())) checkLogs(t, params, r, &mockConsumerInstance, checkIfTestPassed) case pipeline.SignalTraces: r, err := params.ReceiverFactory.CreateTraces(context.Background(), receivertest.NewNopSettings(params.ReceiverFactory.Type()), params.ReceiverConfig, &mockConsumerInstance) require.NoError(t, err) require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost())) checkTraces(t, params, r, &mockConsumerInstance, checkIfTestPassed) case pipeline.SignalMetrics: r, err := params.ReceiverFactory.CreateMetrics(context.Background(), receivertest.NewNopSettings(params.ReceiverFactory.Type()), params.ReceiverConfig, &mockConsumerInstance) require.NoError(t, err) require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost())) checkMetrics(t, params, r, &mockConsumerInstance, checkIfTestPassed) default: require.FailNow(t, "must specify a valid DataType to test for") } } func checkMetrics(t *testing.T, params CheckConsumeContractParams, mockReceiver component.Component, mockConsumer *mockConsumer, checkIfTestPassed func(*testing.T, int, requestCounter), ) { ctx := context.Background() var exp exporter.Metrics var err error exp, err = params.ExporterFactory.CreateMetrics(ctx, NewNopSettings(params.ExporterFactory.Type()), params.ExporterConfig) require.NoError(t, err) require.NotNil(t, exp) err = exp.Start(ctx, componenttest.NewNopHost()) require.NoError(t, err) defer func(exp exporter.Metrics, ctx context.Context) { err = exp.Shutdown(ctx) require.NoError(t, err) err = mockReceiver.Shutdown(ctx) require.NoError(t, err) mockConsumer.clear() }(exp, ctx) for i := 0; i < params.NumberOfTestElements; i++ { id := uniqueIDAttrVal(strconv.Itoa(i)) data := createOneMetricWithID(id) err = exp.ConsumeMetrics(ctx, data) } reqCounter := mockConsumer.getRequestCounter() // The overall number of requests sent by exporter fmt.Printf("Number of export tries: %d\n", reqCounter.total) // Successfully delivered items fmt.Printf("Total items received successfully: %d\n", reqCounter.success) // Number of errors that happened fmt.Printf("Number of permanent errors: %d\n", reqCounter.error.permanent) fmt.Printf("Number of non-permanent errors: %d\n", reqCounter.error.nonpermanent) assert.EventuallyWithT(t, func(*assert.CollectT) { checkIfTestPassed(t, params.NumberOfTestElements, *reqCounter) }, 2*time.Second, 100*time.Millisecond) } func checkTraces(t *testing.T, params CheckConsumeContractParams, mockReceiver component.Component, mockConsumer *mockConsumer, checkIfTestPassed func(*testing.T, int, requestCounter)) { ctx := context.Background() var exp exporter.Traces var err error exp, err = params.ExporterFactory.CreateTraces(ctx, NewNopSettings(params.ExporterFactory.Type()), params.ExporterConfig) require.NoError(t, err) require.NotNil(t, exp) err = exp.Start(ctx, componenttest.NewNopHost()) require.NoError(t, err) defer func(exp exporter.Traces, ctx context.Context) { err = exp.Shutdown(ctx) require.NoError(t, err) err = mockReceiver.Shutdown(ctx) require.NoError(t, err) mockConsumer.clear() }(exp, ctx) for i := 0; i < params.NumberOfTestElements; i++ { id := uniqueIDAttrVal(strconv.Itoa(i)) data := createOneTraceWithID(id) err = exp.ConsumeTraces(ctx, data) } reqCounter := mockConsumer.getRequestCounter() // The overall number of requests sent by exporter fmt.Printf("Number of export tries: %d\n", reqCounter.total) // Successfully delivered items fmt.Printf("Total items received successfully: %d\n", reqCounter.success) // Number of errors that happened fmt.Printf("Number of permanent errors: %d\n", reqCounter.error.permanent) fmt.Printf("Number of non-permanent errors: %d\n", reqCounter.error.nonpermanent) assert.EventuallyWithT(t, func(*assert.CollectT) { checkIfTestPassed(t, params.NumberOfTestElements, *reqCounter) }, 2*time.Second, 100*time.Millisecond) } func checkLogs(t *testing.T, params CheckConsumeContractParams, mockReceiver component.Component, mockConsumer *mockConsumer, checkIfTestPassed func(*testing.T, int, requestCounter)) { ctx := context.Background() var exp exporter.Logs var err error exp, err = params.ExporterFactory.CreateLogs(ctx, NewNopSettings(params.ExporterFactory.Type()), params.ExporterConfig) require.NoError(t, err) require.NotNil(t, exp) err = exp.Start(ctx, componenttest.NewNopHost()) require.NoError(t, err) defer func(exp exporter.Logs, ctx context.Context) { err = exp.Shutdown(ctx) require.NoError(t, err) err = mockReceiver.Shutdown(ctx) require.NoError(t, err) mockConsumer.clear() }(exp, ctx) for i := 0; i < params.NumberOfTestElements; i++ { id := uniqueIDAttrVal(strconv.Itoa(i)) data := createOneLogWithID(id) err = exp.ConsumeLogs(ctx, data) } reqCounter := mockConsumer.getRequestCounter() // The overall number of requests sent by exporter fmt.Printf("Number of export tries: %d\n", reqCounter.total) // Successfully delivered items fmt.Printf("Total items received successfully: %d\n", reqCounter.success) // Number of errors that happened fmt.Printf("Number of permanent errors: %d\n", reqCounter.error.permanent) fmt.Printf("Number of non-permanent errors: %d\n", reqCounter.error.nonpermanent) assert.EventuallyWithT(t, func(*assert.CollectT) { checkIfTestPassed(t, params.NumberOfTestElements, *reqCounter) }, 2*time.Second, 100*time.Millisecond) } // Test is successful if all the elements were received successfully and no error was returned func alwaysSucceedsPassed(t *testing.T, allRecordsNumber int, reqCounter requestCounter) { require.Equal(t, allRecordsNumber, reqCounter.success) require.Equal(t, allRecordsNumber, reqCounter.total) require.Equal(t, 0, reqCounter.error.nonpermanent) require.Equal(t, 0, reqCounter.error.permanent) } // Test is successful if all the elements were retried on non-permanent errors func randomNonPermanentErrorConsumeDecisionPassed(t *testing.T, allRecordsNumber int, reqCounter requestCounter) { // more or equal tries than successes require.GreaterOrEqual(t, reqCounter.total, reqCounter.success) // it is retried on every error require.Equal(t, reqCounter.total-reqCounter.error.nonpermanent, reqCounter.success) require.Equal(t, allRecordsNumber+reqCounter.error.nonpermanent, reqCounter.total) } // Test is successful if the calls are not retried on permanent errors func randomPermanentErrorConsumeDecisionPassed(t *testing.T, allRecordsNumber int, reqCounter requestCounter) { require.Equal(t, allRecordsNumber-reqCounter.error.permanent, reqCounter.success) require.Equal(t, reqCounter.total, allRecordsNumber) } // Test is successful if the calls are not retried on permanent errors func randomErrorConsumeDecisionPassed(t *testing.T, allRecordsNumber int, reqCounter requestCounter) { require.Equal(t, allRecordsNumber-reqCounter.error.permanent, reqCounter.success) require.Equal(t, reqCounter.total, allRecordsNumber+reqCounter.error.nonpermanent) } func createOneLogWithID(id uniqueIDAttrVal) plog.Logs { data := plog.NewLogs() data.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Attributes().PutStr( uniqueIDAttrName, string(id), ) return data } func createOneTraceWithID(id uniqueIDAttrVal) ptrace.Traces { data := ptrace.NewTraces() data.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty().Attributes().PutStr( uniqueIDAttrName, string(id), ) return data } func createOneMetricWithID(id uniqueIDAttrVal) pmetric.Metrics { data := pmetric.NewMetrics() data.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyHistogram(). DataPoints().AppendEmpty().Attributes().PutStr(uniqueIDAttrName, string(id)) return data } opentelemetry-collector-0.141.0/exporter/exportertest/contract_checker_test.go000066400000000000000000000105531511331344600300510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exportertest import ( "context" "testing" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" ) // retryConfig is a configuration to quickly retry failed exports. var retryConfig = func() configretry.BackOffConfig { c := configretry.NewDefaultBackOffConfig() c.InitialInterval = time.Millisecond return c }() // mockReceiver is a receiver with pass-through consumers. type mockReceiver struct { component.StartFunc component.ShutdownFunc consumer.Traces consumer.Metrics consumer.Logs } // mockFactory is a factory to create exporters sending data to the mockReceiver. type mockFactory struct { mr *mockReceiver component.StartFunc component.ShutdownFunc } func (mef *mockFactory) createMockTraces( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Traces, error) { return exporterhelper.NewTraces(ctx, set, cfg, mef.mr.ConsumeTraces, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithRetry(retryConfig), ) } func (mef *mockFactory) createMockMetrics( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Metrics, error) { return exporterhelper.NewMetrics(ctx, set, cfg, mef.mr.ConsumeMetrics, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithRetry(retryConfig), ) } func (mef *mockFactory) createMockLogs( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Logs, error) { return exporterhelper.NewLogs(ctx, set, cfg, mef.mr.ConsumeLogs, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithRetry(retryConfig), ) } func newMockFactory(mr *mockReceiver) exporter.Factory { mef := &mockFactory{mr: mr} return exporter.NewFactory( component.MustNewType("pass_through_exporter"), func() component.Config { return &nopConfig{} }, exporter.WithTraces(mef.createMockTraces, component.StabilityLevelBeta), exporter.WithMetrics(mef.createMockMetrics, component.StabilityLevelBeta), exporter.WithLogs(mef.createMockLogs, component.StabilityLevelBeta), ) } func newMockReceiverFactory(mr *mockReceiver) receiver.Factory { return receiver.NewFactory(component.MustNewType("pass_through_receiver"), func() component.Config { return &nopConfig{} }, receiver.WithTraces(func(_ context.Context, _ receiver.Settings, _ component.Config, c consumer.Traces) (receiver.Traces, error) { mr.Traces = c return mr, nil }, component.StabilityLevelStable), receiver.WithMetrics(func(_ context.Context, _ receiver.Settings, _ component.Config, c consumer.Metrics) (receiver.Metrics, error) { mr.Metrics = c return mr, nil }, component.StabilityLevelStable), receiver.WithLogs(func(_ context.Context, _ receiver.Settings, _ component.Config, c consumer.Logs) (receiver.Logs, error) { mr.Logs = c return mr, nil }, component.StabilityLevelStable), ) } func TestCheckConsumeContractLogs(t *testing.T) { mr := &mockReceiver{} params := CheckConsumeContractParams{ T: t, ExporterFactory: newMockFactory(mr), Signal: pipeline.SignalLogs, ExporterConfig: nopConfig{}, NumberOfTestElements: 10, ReceiverFactory: newMockReceiverFactory(mr), } CheckConsumeContract(params) } func TestCheckConsumeContractMetrics(t *testing.T) { mr := &mockReceiver{} CheckConsumeContract(CheckConsumeContractParams{ T: t, ExporterFactory: newMockFactory(mr), Signal: pipeline.SignalMetrics, // Change to the appropriate data type ExporterConfig: nopConfig{}, NumberOfTestElements: 10, ReceiverFactory: newMockReceiverFactory(mr), }) } func TestCheckConsumeContractTraces(t *testing.T) { mr := &mockReceiver{} CheckConsumeContract(CheckConsumeContractParams{ T: t, ExporterFactory: newMockFactory(mr), Signal: pipeline.SignalTraces, ExporterConfig: nopConfig{}, NumberOfTestElements: 10, ReceiverFactory: newMockReceiverFactory(mr), }) } opentelemetry-collector-0.141.0/exporter/exportertest/go.mod000066400000000000000000000122041511331344600242630ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/exportertest go 1.24.0 require ( github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configretry v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/xexporter v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 google.golang.org/grpc v1.77.0 ) require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configoptional v1.47.0 // indirect go.opentelemetry.io/collector/confmap v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.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/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/exporter => ../../exporter replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/exporter/xexporter => ../xexporter replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/exporter/exportertest/go.sum000066400000000000000000000210431511331344600243110ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/exportertest/mock_consumer.go000066400000000000000000000132731511331344600263570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exportertest // import "go.opentelemetry.io/collector/exporter/exportertest" import ( "context" "fmt" "math/rand/v2" "sync" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) var ( errNonPermanent = status.Error(codes.DeadlineExceeded, "non Permanent error") errPermanent = status.Error(codes.Internal, "Permanent error") ) // // randomNonPermanentErrorConsumeDecision is a decision function that succeeds approximately // // half of the time and fails with a non-permanent error the rest of the time. func randomNonPermanentErrorConsumeDecision() error { if rand.Float32() < 0.5 { return errNonPermanent } return nil } // randomPermanentErrorConsumeDecision is a decision function that succeeds approximately // half of the time and fails with a permanent error the rest of the time. func randomPermanentErrorConsumeDecision() error { if rand.Float32() < 0.5 { return consumererror.NewPermanent(errPermanent) } return nil } // randomErrorsConsumeDecision is a decision function that succeeds approximately // a third of the time, fails with a permanent error the third of the time and fails with // a non-permanent error the rest of the time. func randomErrorsConsumeDecision() error { r := rand.Float64() third := 1.0 / 3.0 if r < third { return consumererror.NewPermanent(errPermanent) } if r < 2*third { return errNonPermanent } return nil } type mockConsumer struct { consumer.Traces consumer.Logs consumer.Metrics reqCounter *requestCounter mux sync.Mutex exportErrorFunction func() error receivedTraces []ptrace.Traces receivedMetrics []pmetric.Metrics receivedLogs []plog.Logs } func newMockConsumer(decisionFunc func() error) mockConsumer { return mockConsumer{ reqCounter: newRequestCounter(), mux: sync.Mutex{}, exportErrorFunction: decisionFunc, receivedTraces: nil, receivedMetrics: nil, receivedLogs: nil, } } func (r *mockConsumer) ConsumeLogs(_ context.Context, ld plog.Logs) error { r.mux.Lock() defer r.mux.Unlock() r.reqCounter.total++ generatedError := r.exportErrorFunction() if generatedError != nil { r.processError(generatedError) return generatedError } r.reqCounter.success++ r.receivedLogs = append(r.receivedLogs, ld) return nil } func (r *mockConsumer) ConsumeTraces(_ context.Context, td ptrace.Traces) error { r.mux.Lock() defer r.mux.Unlock() r.reqCounter.total++ generatedError := r.exportErrorFunction() if generatedError != nil { r.processError(generatedError) return generatedError } r.reqCounter.success++ r.receivedTraces = append(r.receivedTraces, td) return nil } func (r *mockConsumer) ConsumeMetrics(_ context.Context, md pmetric.Metrics) error { r.mux.Lock() defer r.mux.Unlock() r.reqCounter.total++ generatedError := r.exportErrorFunction() if generatedError != nil { r.processError(generatedError) return generatedError } r.reqCounter.success++ r.receivedMetrics = append(r.receivedMetrics, md) return nil } func (r *mockConsumer) Capabilities() consumer.Capabilities { return consumer.Capabilities{} } func (r *mockConsumer) processError(err error) { if consumererror.IsPermanent(err) { r.reqCounter.error.permanent++ } else { r.reqCounter.error.nonpermanent++ } } func (r *mockConsumer) clear() { r.mux.Lock() defer r.mux.Unlock() r.reqCounter = newRequestCounter() } func (r *mockConsumer) getRequestCounter() *requestCounter { return r.reqCounter } type requestCounter struct { success int error errorCounter total int } type errorCounter struct { permanent int nonpermanent int } func newErrorCounter() errorCounter { return errorCounter{ permanent: 0, nonpermanent: 0, } } func newRequestCounter() *requestCounter { return &requestCounter{ success: 0, error: newErrorCounter(), total: 0, } } func idFromLogs(data plog.Logs) (string, error) { var logID string rss := data.ResourceLogs() key, exists := rss.At(0).ScopeLogs().At(0).LogRecords().At(0).Attributes().Get(uniqueIDAttrName) if !exists { return "", fmt.Errorf("invalid data element, attribute %q is missing", uniqueIDAttrName) } if key.Type() != pcommon.ValueTypeStr { return "", fmt.Errorf("invalid data element, attribute %q is wrong type %v", uniqueIDAttrName, key.Type()) } logID = key.Str() return logID, nil } func idFromTraces(data ptrace.Traces) (string, error) { var traceID string rss := data.ResourceSpans() key, exists := rss.At(0).ScopeSpans().At(0).Spans().At(0).Attributes().Get(uniqueIDAttrName) if !exists { return "", fmt.Errorf("invalid data element, attribute %q is missing", uniqueIDAttrName) } if key.Type() != pcommon.ValueTypeStr { return "", fmt.Errorf("invalid data element, attribute %q is wrong type %v", uniqueIDAttrName, key.Type()) } traceID = key.Str() return traceID, nil } func idFromMetrics(data pmetric.Metrics) (string, error) { var metricID string rss := data.ResourceMetrics() key, exists := rss.At(0).ScopeMetrics().At(0).Metrics().At(0).Histogram().DataPoints().At(0).Attributes().Get( uniqueIDAttrName) if !exists { return "", fmt.Errorf("invalid data element, attribute %q is missing", uniqueIDAttrName) } if key.Type() != pcommon.ValueTypeStr { return "", fmt.Errorf("invalid data element, attribute %q is wrong type %v", uniqueIDAttrName, key.Type()) } metricID = key.Str() return metricID, nil } opentelemetry-collector-0.141.0/exporter/exportertest/mock_consumer_test.go000066400000000000000000000200331511331344600274060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exportertest import ( "context" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) func createLog(id string) plog.Logs { validData := plog.NewLogs() validData.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Attributes().PutStr( uniqueIDAttrName, id, ) return validData } func createTrace(id string) ptrace.Traces { validData := ptrace.NewTraces() validData.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty().Attributes().PutStr( uniqueIDAttrName, id, ) return validData } func createMetric(id string) pmetric.Metrics { validData := pmetric.NewMetrics() validData.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyHistogram().DataPoints().AppendEmpty().Attributes().PutStr(uniqueIDAttrName, id) return validData } func TestIDFromMetrics(t *testing.T) { // Test case 1: Valid data id := "metric_id" validData := createMetric(id) metricID, err := idFromMetrics(validData) assert.Equal(t, metricID, id) require.NoError(t, err) // Test case 2: Missing uniqueIDAttrName attribute invalidData := pmetric.NewMetrics() // Create an invalid pmetric.Metrics object with missing attribute invalidData.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyHistogram().DataPoints().AppendEmpty().Attributes() _, err = idFromMetrics(invalidData) require.EqualError(t, err, fmt.Sprintf("invalid data element, attribute %q is missing", uniqueIDAttrName)) // Test case 3: Wrong attribute type var intID int64 = 12 wrongAttribute := pmetric.NewMetrics() // Create a valid pmetric.Metrics object wrongAttribute.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty(). SetEmptyHistogram().DataPoints().AppendEmpty().Attributes().PutInt(uniqueIDAttrName, intID) _, err = idFromMetrics(wrongAttribute) assert.EqualError(t, err, fmt.Sprintf("invalid data element, attribute %q is wrong type Int", uniqueIDAttrName)) } func TestIDFromTraces(t *testing.T) { // Test case 1: Valid data id := "trace_id" validData := createTrace(id) traceID, err := idFromTraces(validData) assert.Equal(t, traceID, id) require.NoError(t, err) // Test case 2: Missing uniqueIDAttrName attribute invalidData := ptrace.NewTraces() invalidData.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty().Attributes() _, err = idFromTraces(invalidData) require.EqualError(t, err, fmt.Sprintf("invalid data element, attribute %q is missing", uniqueIDAttrName)) // Test case 3: Wrong attribute type var intID int64 = 12 wrongAttribute := ptrace.NewTraces() wrongAttribute.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty().Attributes(). PutInt(uniqueIDAttrName, intID) _, err = idFromTraces(wrongAttribute) assert.EqualError(t, err, fmt.Sprintf("invalid data element, attribute %q is wrong type Int", uniqueIDAttrName)) } func TestIDFromLogs(t *testing.T) { // Test case 1: Valid data id := "log_id" validData := createLog(id) logID, err := idFromLogs(validData) assert.Equal(t, logID, id) require.NoError(t, err) // Test case 2: Missing uniqueIDAttrName attribute invalidData := plog.NewLogs() invalidData.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Attributes() _, err = idFromLogs(invalidData) require.EqualError(t, err, fmt.Sprintf("invalid data element, attribute %q is missing", uniqueIDAttrName)) // Test case 3: Wrong attribute type var intID int64 = 12 wrongAttribute := plog.NewLogs() // Create a valid plog.Metrics object wrongAttribute.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Attributes(). PutInt(uniqueIDAttrName, intID) _, err = idFromLogs(wrongAttribute) assert.EqualError(t, err, fmt.Sprintf("invalid data element, attribute %q is wrong type Int", uniqueIDAttrName)) } func returnNonPermanentError() error { return errNonPermanent } func returnPermanentError() error { return errPermanent } func TestConsumeLogsNonPermanent(t *testing.T) { mc := newMockConsumer(returnNonPermanentError) validData := createLog("logId") err := mc.ConsumeLogs(context.Background(), validData) if err != nil { return } assert.Equal(t, 1, mc.reqCounter.error.nonpermanent) assert.Equal(t, 0, mc.reqCounter.error.permanent) assert.Equal(t, 0, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeLogsPermanent(t *testing.T) { mc := newMockConsumer(returnPermanentError) validData := createLog("logId") err := mc.ConsumeLogs(context.Background(), validData) if err != nil { return } assert.Equal(t, 0, mc.reqCounter.error.nonpermanent) assert.Equal(t, 1, mc.reqCounter.error.permanent) assert.Equal(t, 0, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeLogsSuccess(t *testing.T) { mc := newMockConsumer(func() error { return nil }) validData := createLog("logId") err := mc.ConsumeLogs(context.Background(), validData) if err != nil { return } assert.Equal(t, 0, mc.reqCounter.error.nonpermanent) assert.Equal(t, 0, mc.reqCounter.error.permanent) assert.Equal(t, 1, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeTracesNonPermanent(t *testing.T) { mc := newMockConsumer(returnNonPermanentError) validData := createTrace("traceId") err := mc.ConsumeTraces(context.Background(), validData) if err != nil { return } assert.Equal(t, 1, mc.reqCounter.error.nonpermanent) assert.Equal(t, 0, mc.reqCounter.error.permanent) assert.Equal(t, 0, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeTracesPermanent(t *testing.T) { mc := newMockConsumer(returnPermanentError) validData := createTrace("traceId") err := mc.ConsumeTraces(context.Background(), validData) if err != nil { return } assert.Equal(t, 0, mc.reqCounter.error.nonpermanent) assert.Equal(t, 1, mc.reqCounter.error.permanent) assert.Equal(t, 0, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeTracesSuccess(t *testing.T) { mc := newMockConsumer(func() error { return nil }) validData := createTrace("traceId") err := mc.ConsumeTraces(context.Background(), validData) if err != nil { return } assert.Equal(t, 0, mc.reqCounter.error.nonpermanent) assert.Equal(t, 0, mc.reqCounter.error.permanent) assert.Equal(t, 1, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeMetricsNonPermanent(t *testing.T) { mc := newMockConsumer(returnNonPermanentError) validData := createMetric("metricId") err := mc.ConsumeMetrics(context.Background(), validData) if err != nil { return } assert.Equal(t, 1, mc.reqCounter.error.nonpermanent) assert.Equal(t, 0, mc.reqCounter.error.permanent) assert.Equal(t, 0, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeMetricsPermanent(t *testing.T) { mc := newMockConsumer(returnPermanentError) validData := createMetric("metricId") err := mc.ConsumeMetrics(context.Background(), validData) if err != nil { return } assert.Equal(t, 0, mc.reqCounter.error.nonpermanent) assert.Equal(t, 1, mc.reqCounter.error.permanent) assert.Equal(t, 0, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestConsumeMetricsSuccess(t *testing.T) { mc := newMockConsumer(func() error { return nil }) validData := createMetric("metricId") err := mc.ConsumeMetrics(context.Background(), validData) if err != nil { return } assert.Equal(t, 0, mc.reqCounter.error.nonpermanent) assert.Equal(t, 0, mc.reqCounter.error.permanent) assert.Equal(t, 1, mc.reqCounter.success) assert.Equal(t, 1, mc.reqCounter.total) } func TestCapabilities(t *testing.T) { mc := newMockConsumer(func() error { return nil }) assert.Equal(t, consumer.Capabilities{}, mc.Capabilities()) } opentelemetry-collector-0.141.0/exporter/exportertest/nop_exporter.go000066400000000000000000000041271511331344600262350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exportertest // import "go.opentelemetry.io/collector/exporter/exportertest" import ( "context" "github.com/google/uuid" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/xexporter" ) var NopType = component.MustNewType("nop") // NewNopSettings returns a new nop settings for Create* functions with the given type. func NewNopSettings(typ component.Type) exporter.Settings { return exporter.Settings{ ID: component.NewIDWithName(typ, uuid.NewString()), TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } // NewNopFactory returns an exporter.Factory that constructs nop exporters. func NewNopFactory() exporter.Factory { return xexporter.NewFactory( NopType, func() component.Config { return &nopConfig{} }, xexporter.WithTraces(createTraces, component.StabilityLevelStable), xexporter.WithMetrics(createMetrics, component.StabilityLevelStable), xexporter.WithLogs(createLogs, component.StabilityLevelStable), xexporter.WithProfiles(createProfiles, component.StabilityLevelAlpha), ) } func createTraces(context.Context, exporter.Settings, component.Config) (exporter.Traces, error) { return nopInstance, nil } func createMetrics(context.Context, exporter.Settings, component.Config) (exporter.Metrics, error) { return nopInstance, nil } func createLogs(context.Context, exporter.Settings, component.Config) (exporter.Logs, error) { return nopInstance, nil } func createProfiles(context.Context, exporter.Settings, component.Config) (xexporter.Profiles, error) { return nopInstance, nil } type nopConfig struct{} var nopInstance = &nop{ Consumer: consumertest.NewNop(), } // nop stores consumed traces, metrics, logs and profiles for testing purposes. type nop struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } opentelemetry-collector-0.141.0/exporter/exportertest/nop_exporter_test.go000066400000000000000000000041711511331344600272730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exportertest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestNewNopFactory(t *testing.T) { factory := NewNopFactory() require.NotNil(t, factory) assert.Equal(t, component.MustNewType("nop"), factory.Type()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &nopConfig{}, cfg) traces, err := factory.CreateTraces(context.Background(), NewNopSettings(NopType), cfg) require.NoError(t, err) assert.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, traces.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, traces.Shutdown(context.Background())) metrics, err := factory.CreateMetrics(context.Background(), NewNopSettings(NopType), cfg) require.NoError(t, err) assert.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metrics.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metrics.Shutdown(context.Background())) logs, err := factory.CreateLogs(context.Background(), NewNopSettings(NopType), cfg) require.NoError(t, err) assert.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logs.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logs.Shutdown(context.Background())) profiles, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), NewNopSettings(NopType), cfg) require.NoError(t, err) assert.NoError(t, profiles.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, profiles.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, profiles.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/exporter/go.mod000066400000000000000000000110741511331344600215170ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/config/configretry v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configoptional v1.47.0 // indirect go.opentelemetry.io/collector/confmap v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/component/componenttest => ../component/componenttest replace go.opentelemetry.io/collector/consumer => ../consumer replace go.opentelemetry.io/collector/extension => ../extension replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../pdata/pprofile replace go.opentelemetry.io/collector/pipeline => ../pipeline replace go.opentelemetry.io/collector/receiver => ../receiver retract v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module replace go.opentelemetry.io/collector/config/configretry => ../config/configretry replace go.opentelemetry.io/collector/consumer/xconsumer => ../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../receiver/receivertest replace go.opentelemetry.io/collector/exporter/xexporter => ./xexporter replace go.opentelemetry.io/collector/exporter/exportertest => ./exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../consumer/consumererror replace go.opentelemetry.io/collector/extension/extensiontest => ../extension/extensiontest replace go.opentelemetry.io/collector/extension/xextension => ../extension/xextension replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/client => ../client replace go.opentelemetry.io/collector/pdata/xpdata => ../pdata/xpdata replace go.opentelemetry.io/collector/confmap => ../confmap replace go.opentelemetry.io/collector/config/configoptional => ../config/configoptional replace go.opentelemetry.io/collector/confmap/xconfmap => ../confmap/xconfmap replace go.opentelemetry.io/collector/exporter/exporterhelper => ./exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/exporter/go.sum000066400000000000000000000207151511331344600215460ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/internal/000077500000000000000000000000001511331344600222225ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/internal/experr/000077500000000000000000000000001511331344600235275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/internal/experr/err.go000066400000000000000000000006011511331344600246430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package experr // import "go.opentelemetry.io/collector/exporter/internal/experr" import ( "fmt" "go.opentelemetry.io/collector/component" ) func ErrIDMismatch(id component.ID, typ component.Type) error { return fmt.Errorf("component type mismatch: component ID %q does not have type %q", id, typ) } opentelemetry-collector-0.141.0/exporter/nopexporter/000077500000000000000000000000001511331344600227735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/nopexporter/Makefile000066400000000000000000000000361511331344600244320ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/exporter/nopexporter/README.md000066400000000000000000000036101511331344600242520ustar00rootroot00000000000000# No-op Exporter | Status | | | ------------- |-----------| | Stability | [beta]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fnop%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fnop) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fnop%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fnop) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@evan-bradley](https://www.github.com/evan-bradley) | [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 Serves as a placeholder exporter in a pipeline. This can be useful if you want to e.g. start a Collector with only extensions enabled, or for testing Collector pipeline throughput without worrying about an exporter. ## Getting Started All that is required to enable the No-op exporter is to include it in the exporter definitions. It takes no configuration. ```yaml exporters: nop: ``` opentelemetry-collector-0.141.0/exporter/nopexporter/doc.go000066400000000000000000000004011511331344600240620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package nopexporter serves as a placeholder exporter. package nopexporter // import "go.opentelemetry.io/collector/exporter/nopexporter" opentelemetry-collector-0.141.0/exporter/nopexporter/generated_component_test.go000066400000000000000000000116221511331344600304030ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package nopexporter import ( "context" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) var typ = component.MustNewType("nop") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg) }, }, { name: "metrics", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg) }, }, { name: "traces", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(exporter.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(exporter.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(exporter.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) } } func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/exporter/nopexporter/generated_package_test.go000066400000000000000000000002521511331344600277710ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package nopexporter import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/nopexporter/go.mod000066400000000000000000000115051511331344600241030ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/nopexporter go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/consumer v1.47.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/exporter/xexporter v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/receiver v1.47.0 // indirect go.opentelemetry.io/collector/receiver/receivertest v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.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/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/exporter/xexporter => ../xexporter replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/exporter/nopexporter/go.sum000066400000000000000000000210431511331344600241260ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/nopexporter/internal/000077500000000000000000000000001511331344600246075ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/nopexporter/internal/metadata/000077500000000000000000000000001511331344600263675ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/nopexporter/internal/metadata/generated_status.go000066400000000000000000000006101511331344600322540ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("nop") ScopeName = "go.opentelemetry.io/collector/exporter/nopexporter" ) const ( TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelBeta LogsStability = component.StabilityLevelBeta ) opentelemetry-collector-0.141.0/exporter/nopexporter/metadata.yaml000066400000000000000000000003761511331344600254450ustar00rootroot00000000000000type: nop github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true codeowners: active: - evan-bradley class: exporter stability: beta: [traces, metrics, logs] distributions: [core, contrib, k8s] opentelemetry-collector-0.141.0/exporter/nopexporter/nop_exporter.go000066400000000000000000000024551511331344600260540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package nopexporter // import "go.opentelemetry.io/collector/exporter/nopexporter" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/nopexporter/internal/metadata" ) // NewFactory returns an exporter.Factory that constructs nop exporters. func NewFactory() exporter.Factory { return exporter.NewFactory( metadata.Type, func() component.Config { return &struct{}{} }, exporter.WithTraces(createTraces, metadata.TracesStability), exporter.WithMetrics(createMetrics, metadata.MetricsStability), exporter.WithLogs(createLogs, metadata.LogsStability), ) } func createTraces(context.Context, exporter.Settings, component.Config) (exporter.Traces, error) { return nopInstance, nil } func createMetrics(context.Context, exporter.Settings, component.Config) (exporter.Metrics, error) { return nopInstance, nil } func createLogs(context.Context, exporter.Settings, component.Config) (exporter.Logs, error) { return nopInstance, nil } var nopInstance = &nop{ Consumer: consumertest.NewNop(), } type nop struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } opentelemetry-collector-0.141.0/exporter/nopexporter/nop_exporter_test.go000066400000000000000000000034141511331344600271070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package nopexporter import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestNewNopFactory(t *testing.T) { factory := NewFactory() require.NotNil(t, factory) assert.Equal(t, component.MustNewType("nop"), factory.Type()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &struct{}{}, cfg) traces, err := factory.CreateTraces(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) assert.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, traces.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, traces.Shutdown(context.Background())) metrics, err := factory.CreateMetrics(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) assert.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metrics.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metrics.Shutdown(context.Background())) logs, err := factory.CreateLogs(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) assert.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logs.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logs.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/exporter/otlpexporter/000077500000000000000000000000001511331344600231555ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlpexporter/Makefile000066400000000000000000000000361511331344600246140ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/exporter/otlpexporter/README.md000066400000000000000000000071151511331344600244400ustar00rootroot00000000000000# OTLP gRPC Exporter | Status | | | ------------- |-----------| | Stability | [development]: profiles | | | [stable]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s], [otlp] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fotlp%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fotlp) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fotlp%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fotlp) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 [otlp]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp Export data via gRPC using [OTLP]( https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md) format. By default, this exporter requires TLS and offers queued retry capabilities. ## Getting Started The following settings are required: - `endpoint` (no default): host:port to which the exporter is going to send OTLP trace data, using the gRPC protocol. The valid syntax is described [here](https://github.com/grpc/grpc/blob/master/doc/naming.md). If a scheme of `https` is used then client transport security is enabled and overrides the `insecure` setting. - `tls`: see [TLS Configuration Settings](../../config/configtls/README.md) for the full set of available options. - `retry_on_failure`: see [Retry on Failure](../exporterhelper/README.md#retry-on-failure) for the full set of available options. - `sending_queue`: see [Sending Queue](../exporterhelper/README.md#sending-queue) for the full set of available options. - `timeout` (default = 5s): Time to wait per individual attempt to send data to a backend. Example: ```yaml exporters: otlp: endpoint: otelcol2:4317 tls: cert_file: file.cert key_file: file.key otlp/2: endpoint: otelcol2:4317 tls: insecure: true ``` By default, `gzip` compression is enabled. See [compression comparison](../../config/configgrpc/README.md#compression-comparison) for details benchmark information. To disable, configure as follows: ```yaml exporters: otlp: ... compression: none ``` ## Advanced Configuration Several helper files are leveraged to provide additional capabilities automatically: - [gRPC settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configgrpc/README.md) - [TLS and mTLS settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configtls/README.md) - [Queuing, batching, retry and timeout settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/exporter/exporterhelper/README.md) opentelemetry-collector-0.141.0/exporter/otlpexporter/cfg-schema.yaml000066400000000000000000000122061511331344600260370ustar00rootroot00000000000000type: '*otlpexporter.Config' fields: - name: timeout type: time.Duration kind: int64 default: 5s doc: | Timeout is the timeout for every attempt to send data to the backend. - name: sending_queue type: exporterhelper.QueueConfig kind: struct fields: - name: enabled kind: bool default: true doc: | Enabled indicates whether to not enqueue batches before sending to the consumerSender. - name: num_consumers kind: int default: 10 doc: | NumConsumers is the number of consumers from the queue. - name: queue_size kind: int default: 1000 doc: | QueueSize is the maximum number of batches allowed in queue at a given time. - name: retry_on_failure type: exporterhelper.RetrySettings kind: struct fields: - name: enabled kind: bool default: true doc: | Enabled indicates whether to not retry sending batches in case of export failure. - name: initial_interval type: time.Duration kind: int64 default: 5s doc: | InitialInterval the time to wait after the first failure before retrying. - name: randomization_factor kind: float64 default: 0.5 doc: | RandomizationFactor is a random factor used to calculate next backoffs. Randomized interval = RetryInterval * (1 ยฑ RandomizationFactor) - name: multiplier kind: float64 default: 1.5 doc: | Multiplier is the value multiplied by the backoff interval bounds - name: max_interval type: time.Duration kind: int64 default: 30s doc: | MaxInterval is the upper bound on backoff interval. Once this value is reached the delay between consecutive retries will always be `MaxInterval`. - name: max_elapsed_time type: time.Duration kind: int64 default: 5m0s doc: | MaxElapsedTime is the maximum amount of time (including retries) spent trying to send a request/batch. Once this value is reached, the data is discarded. - name: endpoint kind: string doc: | The target to which the exporter is going to send traces, metrics, logs or profiles using the gRPC protocol. The valid syntax is described at https://github.com/grpc/grpc/blob/master/doc/naming.md. - name: compression kind: string doc: | The compression key for supported compression types within collector. Supports `gzip`, `snappy` and `zstd`. - name: ca_file kind: string doc: | Path to the CA cert. For a client this verifies the server certificate. For a server this verifies client certificates. If empty uses system root CA. (optional) - name: cert_file kind: string doc: | Path to the TLS cert to use for TLS required connections. (optional) - name: key_file kind: string doc: | Path to the TLS key to use for TLS required connections. (optional) - name: insecure kind: bool doc: | In gRPC when set to true, this is used to disable the client transport security. See https://godoc.org/google.golang.org/grpc#WithInsecure. In HTTP, this disables verifying the server's certificate chain and host name (InsecureSkipVerify in the tls Config). Please refer to https://godoc.org/crypto/tls#Config for more information. (optional, default false) - name: server_name_override kind: string doc: | ServerName requested by client for virtual hosting. This sets the ServerName in the TLSConfig. Please refer to https://godoc.org/crypto/tls#Config for more information. (optional) - name: keepalive type: '*configgrpc.KeepaliveClientConfig' kind: ptr doc: | The keepalive parameters for gRPC client. See grpc.WithKeepaliveParams (https://godoc.org/google.golang.org/grpc#WithKeepaliveParams). fields: - name: time type: time.Duration kind: int64 - name: timeout type: time.Duration kind: int64 - name: permit_without_stream kind: bool - name: read_buffer_size kind: int doc: | ReadBufferSize for gRPC client. See grpc.WithReadBufferSize (https://godoc.org/google.golang.org/grpc#WithReadBufferSize). - name: write_buffer_size kind: int default: 524288 doc: | WriteBufferSize for gRPC gRPC. See grpc.WithWriteBufferSize (https://godoc.org/google.golang.org/grpc#WithWriteBufferSize). - name: wait_for_ready kind: bool doc: | WaitForReady parameter configures client to wait for ready state before sending data. (https://github.com/grpc/grpc/blob/master/doc/wait-for-ready.md) - name: headers type: map[string]string kind: map doc: | The headers associated with gRPC requests. - name: per_rpc_auth type: '*configgrpc.PerRPCAuthConfig' kind: ptr doc: | PerRPCAuth parameter configures the client to send authentication data on a per-RPC basis. fields: - name: type kind: string doc: | AuthType represents the authentication type to use. Currently, only 'bearer' is supported. - name: bearer_token kind: string doc: | BearerToken specifies the bearer token to use for every RPC. - name: balancer_name kind: string doc: | Sets the balancer in grpclb_policy to discover the servers. Default is pick_first https://github.com/grpc/grpc-go/blob/master/examples/features/load_balancing/README.md opentelemetry-collector-0.141.0/exporter/otlpexporter/config.go000066400000000000000000000041071511331344600247530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpexporter // import "go.opentelemetry.io/collector/exporter/otlpexporter" import ( "errors" "fmt" "net" "regexp" "strconv" "strings" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/exporter/exporterhelper" ) // Config defines configuration for OTLP exporter. type Config struct { TimeoutConfig exporterhelper.TimeoutConfig `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct. QueueConfig exporterhelper.QueueBatchConfig `mapstructure:"sending_queue"` RetryConfig configretry.BackOffConfig `mapstructure:"retry_on_failure"` ClientConfig configgrpc.ClientConfig `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct. // prevent unkeyed literal initialization _ struct{} } func (c *Config) Validate() error { if after, ok := strings.CutPrefix(c.ClientConfig.Endpoint, "unix://"); ok { if after == "" { return errors.New("unix socket path cannot be empty") } return nil } endpoint := c.sanitizedEndpoint() if endpoint == "" { return errors.New(`requires a non-empty "endpoint"`) } // Validate that the port is in the address _, port, err := net.SplitHostPort(endpoint) if err != nil { return err } if _, err := strconv.Atoi(port); err != nil { return fmt.Errorf(`invalid port "%s"`, port) } return nil } func (c *Config) sanitizedEndpoint() string { switch { case strings.HasPrefix(c.ClientConfig.Endpoint, "http://"): return strings.TrimPrefix(c.ClientConfig.Endpoint, "http://") case strings.HasPrefix(c.ClientConfig.Endpoint, "https://"): return strings.TrimPrefix(c.ClientConfig.Endpoint, "https://") case strings.HasPrefix(c.ClientConfig.Endpoint, "dns://"): r := regexp.MustCompile(`^dns:///?`) return r.ReplaceAllString(c.ClientConfig.Endpoint, "") default: return c.ClientConfig.Endpoint } } var _ component.Config = (*Config)(nil) opentelemetry-collector-0.141.0/exporter/otlpexporter/config_test.go000066400000000000000000000141121511331344600260070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpexporter import ( "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/exporter/exporterhelper" ) func TestUnmarshalDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) } func TestUnmarshalConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) require.NoError(t, xconfmap.Validate(&cfg)) assert.Equal(t, &Config{ TimeoutConfig: exporterhelper.TimeoutConfig{ Timeout: 10 * time.Second, }, RetryConfig: configretry.BackOffConfig{ Enabled: true, InitialInterval: 10 * time.Second, RandomizationFactor: 0.7, Multiplier: 1.3, MaxInterval: 1 * time.Minute, MaxElapsedTime: 10 * time.Minute, }, QueueConfig: exporterhelper.QueueBatchConfig{ Enabled: true, Sizer: exporterhelper.RequestSizerTypeItems, NumConsumers: 2, QueueSize: 100000, Batch: configoptional.Some(exporterhelper.BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: exporterhelper.RequestSizerTypeItems, MinSize: 1000, MaxSize: 10000, }), }, ClientConfig: configgrpc.ClientConfig{ Headers: configopaque.MapList{ {Name: "another", Value: "somevalue"}, {Name: "can you have a . here?", Value: "F0000000-0000-0000-0000-000000000000"}, {Name: "header1", Value: "234"}, }, Endpoint: "1.2.3.4:1234", Compression: "gzip", TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: "/var/lib/mycert.pem", }, Insecure: false, }, Keepalive: configoptional.Some(configgrpc.KeepaliveClientConfig{ Time: 20 * time.Second, PermitWithoutStream: true, Timeout: 30 * time.Second, }), WriteBufferSize: 512 * 1024, BalancerName: "round_robin", Auth: configoptional.Some(configauth.Config{AuthenticatorID: component.MustNewID("nop")}), }, }, cfg) } func TestUnmarshalDefaultBatchConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "default-batch.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) require.NoError(t, xconfmap.Validate(&cfg)) assert.Equal(t, &Config{ TimeoutConfig: exporterhelper.TimeoutConfig{ Timeout: 10 * time.Second, }, RetryConfig: configretry.NewDefaultBackOffConfig(), QueueConfig: exporterhelper.QueueBatchConfig{ Enabled: true, Sizer: exporterhelper.RequestSizerTypeRequests, QueueSize: 1000, NumConsumers: 10, Batch: configoptional.Some(exporterhelper.BatchConfig{ FlushTimeout: 200 * time.Millisecond, Sizer: exporterhelper.RequestSizerTypeItems, MinSize: 8192, }), }, ClientConfig: configgrpc.ClientConfig{ Endpoint: "1.2.3.4:1234", Compression: "gzip", WriteBufferSize: 512 * 1024, }, }, cfg) } func TestUnmarshalInvalidConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "invalid_configs.yaml")) require.NoError(t, err) factory := NewFactory() for _, tt := range []struct { name string errorMsg string }{ { name: "no_endpoint", errorMsg: `requires a non-empty "endpoint"`, }, { name: "https_endpoint", errorMsg: `requires a non-empty "endpoint"`, }, { name: "http_endpoint", errorMsg: `requires a non-empty "endpoint"`, }, { name: "invalid_timeout", errorMsg: `'timeout' must be non-negative`, }, { name: "invalid_retry", errorMsg: `'randomization_factor' must be within [0, 1]`, }, { name: "invalid_tls", errorMsg: `invalid TLS min_version: unsupported TLS version: "asd"`, }, { name: "missing_port", errorMsg: `missing port in address`, }, { name: "invalid_port", errorMsg: `invalid port "port"`, }, { name: "invalid_unix_socket", errorMsg: "unix socket path cannot be empty", }, } { t.Run(tt.name, func(t *testing.T) { cfg := factory.CreateDefaultConfig() sub, err := cm.Sub(tt.name) require.NoError(t, err) assert.NoError(t, sub.Unmarshal(&cfg)) assert.ErrorContains(t, xconfmap.Validate(cfg), tt.errorMsg) }) } } func TestValidDNSEndpoint(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = "dns://authority/backend.example.com:4317" assert.NoError(t, cfg.Validate()) } func TestValidUnixSocketEndpoint(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = "unix:///my/unix/socket.sock" assert.NoError(t, cfg.Validate()) } func TestSanitizeEndpoint(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = "dns://authority/backend.example.com:4317" assert.Equal(t, "authority/backend.example.com:4317", cfg.sanitizedEndpoint()) cfg.ClientConfig.Endpoint = "dns:///backend.example.com:4317" assert.Equal(t, "backend.example.com:4317", cfg.sanitizedEndpoint()) cfg.ClientConfig.Endpoint = "dns:////backend.example.com:4317" assert.Equal(t, "/backend.example.com:4317", cfg.sanitizedEndpoint()) } opentelemetry-collector-0.141.0/exporter/otlpexporter/doc.go000066400000000000000000000004341511331344600242520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package otlpexporter exports data by using the OTLP format to a gRPC endpoint. package otlpexporter // import "go.opentelemetry.io/collector/exporter/otlpexporter" opentelemetry-collector-0.141.0/exporter/otlpexporter/factory.go000066400000000000000000000077361511331344600251700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpexporter // import "go.opentelemetry.io/collector/exporter/otlpexporter" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" "go.opentelemetry.io/collector/exporter/otlpexporter/internal/metadata" "go.opentelemetry.io/collector/exporter/xexporter" ) // NewFactory creates a factory for OTLP exporter. func NewFactory() exporter.Factory { return xexporter.NewFactory( metadata.Type, createDefaultConfig, xexporter.WithTraces(createTraces, metadata.TracesStability), xexporter.WithMetrics(createMetrics, metadata.MetricsStability), xexporter.WithLogs(createLogs, metadata.LogsStability), xexporter.WithProfiles(createProfilesExporter, metadata.ProfilesStability), ) } func createDefaultConfig() component.Config { clientCfg := configgrpc.NewDefaultClientConfig() // Default to gzip compression clientCfg.Compression = configcompression.TypeGzip // We almost read 0 bytes, so no need to tune ReadBufferSize. clientCfg.WriteBufferSize = 512 * 1024 // For backward compatibility: clientCfg.Keepalive = configoptional.None[configgrpc.KeepaliveClientConfig]() clientCfg.BalancerName = "" return &Config{ TimeoutConfig: exporterhelper.NewDefaultTimeoutConfig(), RetryConfig: configretry.NewDefaultBackOffConfig(), QueueConfig: exporterhelper.NewDefaultQueueConfig(), ClientConfig: clientCfg, } } func createTraces( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Traces, error) { oce := newExporter(cfg, set) oCfg := cfg.(*Config) return exporterhelper.NewTraces(ctx, set, cfg, oce.pushTraces, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithTimeout(oCfg.TimeoutConfig), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig), exporterhelper.WithStart(oce.start), exporterhelper.WithShutdown(oce.shutdown), ) } func createMetrics( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Metrics, error) { oce := newExporter(cfg, set) oCfg := cfg.(*Config) return exporterhelper.NewMetrics(ctx, set, cfg, oce.pushMetrics, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithTimeout(oCfg.TimeoutConfig), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig), exporterhelper.WithStart(oce.start), exporterhelper.WithShutdown(oce.shutdown), ) } func createLogs( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Logs, error) { oce := newExporter(cfg, set) oCfg := cfg.(*Config) return exporterhelper.NewLogs(ctx, set, cfg, oce.pushLogs, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithTimeout(oCfg.TimeoutConfig), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig), exporterhelper.WithStart(oce.start), exporterhelper.WithShutdown(oce.shutdown), ) } func createProfilesExporter( ctx context.Context, set exporter.Settings, cfg component.Config, ) (xexporter.Profiles, error) { oce := newExporter(cfg, set) oCfg := cfg.(*Config) return xexporterhelper.NewProfiles(ctx, set, cfg, oce.pushProfiles, exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), exporterhelper.WithTimeout(oCfg.TimeoutConfig), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig), exporterhelper.WithStart(oce.start), exporterhelper.WithShutdown(oce.shutdown), ) } opentelemetry-collector-0.141.0/exporter/otlpexporter/factory_test.go000066400000000000000000000205711511331344600262170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpexporter import ( "context" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/internal/testutil" ) func TestCreateDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") require.NoError(t, componenttest.CheckConfigStruct(cfg)) ocfg, ok := factory.CreateDefaultConfig().(*Config) assert.True(t, ok) assert.Equal(t, configretry.NewDefaultBackOffConfig(), ocfg.RetryConfig) assert.Equal(t, exporterhelper.NewDefaultQueueConfig(), ocfg.QueueConfig) assert.Equal(t, exporterhelper.NewDefaultTimeoutConfig(), ocfg.TimeoutConfig) assert.Equal(t, configcompression.TypeGzip, ocfg.ClientConfig.Compression) } func TestCreateMetrics(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = testutil.GetAvailableLocalAddress(t) set := exportertest.NewNopSettings(factory.Type()) oexp, err := factory.CreateMetrics(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, oexp) } func TestCreateTraces(t *testing.T) { endpoint := testutil.GetAvailableLocalAddress(t) tests := []struct { name string config *Config mustFailOnStart bool }{ { name: "UseSecure", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, TLS: configtls.ClientConfig{ Insecure: false, }, }, }, }, { name: "Keepalive", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Keepalive: configoptional.Some(configgrpc.KeepaliveClientConfig{ Time: 30 * time.Second, Timeout: 25 * time.Second, PermitWithoutStream: true, }), }, }, }, { name: "NoneCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: "none", }, }, }, { name: "GzipCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: configcompression.TypeGzip, }, }, }, { name: "SnappyCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: configcompression.TypeSnappy, }, }, }, { name: "ZstdCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: configcompression.TypeZstd, }, }, }, { name: "Headers", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Headers: configopaque.MapList{ {Name: "hdr1", Value: "val1"}, {Name: "hdr2", Value: "val2"}, }, }, }, }, { name: "NumConsumers", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, }, }, }, { name: "CaCert", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "test_cert.pem"), }, }, }, }, }, { name: "CertPemFileError", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: "nosuchfile", }, }, }, }, mustFailOnStart: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { factory := NewFactory() set := exportertest.NewNopSettings(factory.Type()) consumer, err := factory.CreateTraces(context.Background(), set, tt.config) require.NoError(t, err) assert.NotNil(t, consumer) err = consumer.Start(context.Background(), componenttest.NewNopHost()) if tt.mustFailOnStart { require.Error(t, err) } else { require.NoError(t, err) } // Shutdown is called even when Start fails err = consumer.Shutdown(context.Background()) if err != nil { // Since the endpoint of OTLP exporter doesn't actually exist, // exporter may already stop because it cannot connect. assert.Equal(t, "rpc error: code = Canceled desc = grpc: the client connection is closing", err.Error()) } }) } } func TestCreateLogs(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = testutil.GetAvailableLocalAddress(t) set := exportertest.NewNopSettings(factory.Type()) oexp, err := factory.CreateLogs(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, oexp) } func TestCreateProfiles(t *testing.T) { endpoint := testutil.GetAvailableLocalAddress(t) tests := []struct { name string config *Config mustFailOnStart bool }{ { name: "UseSecure", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, TLS: configtls.ClientConfig{ Insecure: false, }, }, }, }, { name: "Keepalive", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Keepalive: configoptional.Some(configgrpc.KeepaliveClientConfig{ Time: 30 * time.Second, Timeout: 25 * time.Second, PermitWithoutStream: true, }), }, }, }, { name: "NoneCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: "none", }, }, }, { name: "GzipCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: configcompression.TypeGzip, }, }, }, { name: "SnappyCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: configcompression.TypeSnappy, }, }, }, { name: "ZstdCompression", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Compression: configcompression.TypeZstd, }, }, }, { name: "Headers", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, Headers: configopaque.MapList{ {Name: "hdr1", Value: "val1"}, {Name: "hdr2", Value: "val2"}, }, }, }, }, { name: "NumConsumers", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, }, }, }, { name: "CaCert", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "test_cert.pem"), }, }, }, }, }, { name: "CertPemFileError", config: &Config{ ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: "nosuchfile", }, }, }, }, mustFailOnStart: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { factory := NewFactory() set := exportertest.NewNopSettings(factory.Type()) consumer, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), set, tt.config) require.NoError(t, err) assert.NotNil(t, consumer) err = consumer.Start(context.Background(), componenttest.NewNopHost()) if tt.mustFailOnStart { require.Error(t, err) } else { require.NoError(t, err) } // Shutdown is called even when Start fails err = consumer.Shutdown(context.Background()) if err != nil { // Since the endpoint of OTLP exporter doesn't actually exist, // exporter may already stop because it cannot connect. assert.Equal(t, "rpc error: code = Canceled desc = grpc: the client connection is closing", err.Error()) } }) } } opentelemetry-collector-0.141.0/exporter/otlpexporter/generated_component_test.go000066400000000000000000000116241511331344600305670ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package otlpexporter import ( "context" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) var typ = component.MustNewType("otlp") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg) }, }, { name: "metrics", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg) }, }, { name: "traces", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(exporter.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(exporter.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(exporter.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) } } func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/exporter/otlpexporter/generated_package_test.go000066400000000000000000000002531511331344600301540ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package otlpexporter import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/otlpexporter/go.mod000066400000000000000000000205331511331344600242660ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/otlpexporter go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector v0.141.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configauth v1.47.0 go.opentelemetry.io/collector/config/configcompression v1.47.0 go.opentelemetry.io/collector/config/configgrpc v0.141.0 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/config/configretry v1.47.0 go.opentelemetry.io/collector/config/configtls v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/exporter/xexporter v0.141.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.10 ) require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v0.0.4 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.11 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/mostynb/go-grpc-compression v1.2.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/config/confignet v1.47.0 // indirect go.opentelemetry.io/collector/consumer/consumererror/xconsumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumertest v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/receiver v1.47.0 // indirect go.opentelemetry.io/collector/receiver/receivertest v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/config/configgrpc => ../../config/configgrpc replace go.opentelemetry.io/collector/config/confignet => ../../config/confignet replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/exporter/xexporter => ../xexporter replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector => ../.. replace go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper => ../exporterhelper/xexporterhelper replace go.opentelemetry.io/collector/consumer/consumererror/xconsumererror => ../../consumer/consumererror/xconsumererror replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/exporter/exportertest => ../exportertest replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/exporter/otlpexporter/go.sum000066400000000000000000000250721511331344600243160ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/otlpexporter/internal/000077500000000000000000000000001511331344600247715ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlpexporter/internal/metadata/000077500000000000000000000000001511331344600265515ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlpexporter/internal/metadata/generated_status.go000066400000000000000000000007141511331344600324430ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("otlp") ScopeName = "go.opentelemetry.io/collector/exporter/otlpexporter" ) const ( ProfilesStability = component.StabilityLevelDevelopment TracesStability = component.StabilityLevelStable MetricsStability = component.StabilityLevelStable LogsStability = component.StabilityLevelStable ) opentelemetry-collector-0.141.0/exporter/otlpexporter/metadata.yaml000066400000000000000000000004411511331344600256200ustar00rootroot00000000000000type: otlp github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: exporter stability: stable: [traces, metrics, logs] development: [profiles] distributions: [core, contrib, k8s, otlp] tests: config: endpoint: otelcol:4317 opentelemetry-collector-0.141.0/exporter/otlpexporter/otlp.go000066400000000000000000000151531511331344600244670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpexporter // import "go.opentelemetry.io/collector/exporter/otlpexporter" import ( "context" "fmt" "runtime" "go.uber.org/zap" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/internal/statusutil" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" ) type baseExporter struct { // Input configuration. config *Config // gRPC clients and connection. traceExporter ptraceotlp.GRPCClient metricExporter pmetricotlp.GRPCClient logExporter plogotlp.GRPCClient profileExporter pprofileotlp.GRPCClient clientConn *grpc.ClientConn metadata metadata.MD callOptions []grpc.CallOption settings component.TelemetrySettings // Default user-agent header. userAgent string } func newExporter(cfg component.Config, set exporter.Settings) *baseExporter { oCfg := cfg.(*Config) userAgent := fmt.Sprintf("%s/%s (%s/%s)", set.BuildInfo.Description, set.BuildInfo.Version, runtime.GOOS, runtime.GOARCH) return &baseExporter{config: oCfg, settings: set.TelemetrySettings, userAgent: userAgent} } // start actually creates the gRPC connection. The client construction is deferred till this point as this // is the only place we get hold of Extensions which are required to construct auth round tripper. func (e *baseExporter) start(ctx context.Context, host component.Host) (err error) { agentOpt := configgrpc.WithGrpcDialOption(grpc.WithUserAgent(e.userAgent)) if e.clientConn, err = e.config.ClientConfig.ToClientConn(ctx, host.GetExtensions(), e.settings, agentOpt); err != nil { return err } e.traceExporter = ptraceotlp.NewGRPCClient(e.clientConn) e.metricExporter = pmetricotlp.NewGRPCClient(e.clientConn) e.logExporter = plogotlp.NewGRPCClient(e.clientConn) e.profileExporter = pprofileotlp.NewGRPCClient(e.clientConn) headers := map[string]string{} for k, v := range e.config.ClientConfig.Headers.Iter { headers[k] = string(v) } e.metadata = metadata.New(headers) e.callOptions = []grpc.CallOption{ grpc.WaitForReady(e.config.ClientConfig.WaitForReady), } return err } func (e *baseExporter) shutdown(context.Context) error { if e.clientConn != nil { return e.clientConn.Close() } return nil } func (e *baseExporter) pushTraces(ctx context.Context, td ptrace.Traces) error { req := ptraceotlp.NewExportRequestFromTraces(td) resp, respErr := e.traceExporter.Export(ctx, req, e.callOptions...) if err := processError(respErr); err != nil { return err } partialSuccess := resp.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedSpans() != 0 { e.settings.Logger.Warn("Partial success response", zap.String("message", resp.PartialSuccess().ErrorMessage()), zap.Int64("dropped_spans", resp.PartialSuccess().RejectedSpans()), ) } return nil } func (e *baseExporter) pushMetrics(ctx context.Context, md pmetric.Metrics) error { req := pmetricotlp.NewExportRequestFromMetrics(md) resp, respErr := e.metricExporter.Export(ctx, req, e.callOptions...) if err := processError(respErr); err != nil { return err } partialSuccess := resp.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedDataPoints() != 0 { e.settings.Logger.Warn("Partial success response", zap.String("message", resp.PartialSuccess().ErrorMessage()), zap.Int64("dropped_data_points", resp.PartialSuccess().RejectedDataPoints()), ) } return nil } func (e *baseExporter) pushLogs(ctx context.Context, ld plog.Logs) error { req := plogotlp.NewExportRequestFromLogs(ld) resp, respErr := e.logExporter.Export(ctx, req, e.callOptions...) if err := processError(respErr); err != nil { return err } partialSuccess := resp.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedLogRecords() != 0 { e.settings.Logger.Warn("Partial success response", zap.String("message", resp.PartialSuccess().ErrorMessage()), zap.Int64("dropped_log_records", resp.PartialSuccess().RejectedLogRecords()), ) } return nil } func (e *baseExporter) pushProfiles(ctx context.Context, td pprofile.Profiles) error { req := pprofileotlp.NewExportRequestFromProfiles(td) resp, respErr := e.profileExporter.Export(ctx, req, e.callOptions...) if err := processError(respErr); err != nil { return err } partialSuccess := resp.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedProfiles() != 0 { e.settings.Logger.Warn("Partial success response", zap.String("message", resp.PartialSuccess().ErrorMessage()), zap.Int64("dropped_profiles", resp.PartialSuccess().RejectedProfiles()), ) } return nil } func processError(err error) error { if err == nil { // Request is successful, we are done. return nil } // We have an error, check gRPC status code. st := status.Convert(err) if st.Code() == codes.OK { // Not really an error, still success. return nil } // Now, this is a real error. retryInfo := statusutil.GetRetryInfo(st) if !shouldRetry(st.Code(), retryInfo) { // It is not a retryable error, we should not retry. return consumererror.NewPermanent(err) } // Check if server returned throttling information. throttleDuration := retryInfo.GetRetryDelay().AsDuration() if throttleDuration != 0 { // We are throttled. Wait before retrying as requested by the server. return exporterhelper.NewThrottleRetry(err, throttleDuration) } // Need to retry. return err } func shouldRetry(code codes.Code, retryInfo *errdetails.RetryInfo) bool { switch code { case codes.Canceled, codes.DeadlineExceeded, codes.Aborted, codes.OutOfRange, codes.Unavailable, codes.DataLoss: // These are retryable errors. return true case codes.ResourceExhausted: // Retry only if RetryInfo was supplied by the server. // This indicates that the server can still recover from resource exhaustion. return retryInfo != nil } // Don't retry on any other code. return false } opentelemetry-collector-0.141.0/exporter/otlpexporter/otlp_test.go000066400000000000000000000755651511331344600255430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpexporter import ( "context" "net" "path/filepath" "runtime" "sync" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/durationpb" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/pdata/testdata" ) type mockReceiver struct { srv *grpc.Server requestCount *atomic.Int64 totalItems *atomic.Int64 mux sync.Mutex metadata metadata.MD exportError error } func (r *mockReceiver) getMetadata() metadata.MD { r.mux.Lock() defer r.mux.Unlock() return r.metadata } func (r *mockReceiver) setExportError(err error) { r.mux.Lock() defer r.mux.Unlock() r.exportError = err } var _ ptraceotlp.GRPCServer = &mockTracesReceiver{} type mockTracesReceiver struct { ptraceotlp.UnimplementedGRPCServer mockReceiver exportResponse func() ptraceotlp.ExportResponse lastRequest ptrace.Traces } func (r *mockTracesReceiver) Export(ctx context.Context, req ptraceotlp.ExportRequest) (ptraceotlp.ExportResponse, error) { r.requestCount.Add(1) td := req.Traces() r.totalItems.Add(int64(td.SpanCount())) r.mux.Lock() defer r.mux.Unlock() r.lastRequest = td r.metadata, _ = metadata.FromIncomingContext(ctx) return r.exportResponse(), r.exportError } func (r *mockTracesReceiver) getLastRequest() ptrace.Traces { r.mux.Lock() defer r.mux.Unlock() return r.lastRequest } func (r *mockTracesReceiver) setExportResponse(fn func() ptraceotlp.ExportResponse) { r.mux.Lock() defer r.mux.Unlock() r.exportResponse = fn } func otlpTracesReceiverOnGRPCServer(ln net.Listener, useTLS bool) (*mockTracesReceiver, error) { sopts := []grpc.ServerOption{} if useTLS { _, currentFile, _, _ := runtime.Caller(0) basepath := filepath.Dir(currentFile) certpath := filepath.Join(basepath, filepath.Join("testdata", "test_cert.pem")) keypath := filepath.Join(basepath, filepath.Join("testdata", "test_key.pem")) creds, err := credentials.NewServerTLSFromFile(certpath, keypath) if err != nil { return nil, err } sopts = append(sopts, grpc.Creds(creds)) } rcv := &mockTracesReceiver{ mockReceiver: mockReceiver{ srv: grpc.NewServer(sopts...), requestCount: new(atomic.Int64), totalItems: new(atomic.Int64), }, exportResponse: ptraceotlp.NewExportResponse, } // Now run it as a gRPC server ptraceotlp.RegisterGRPCServer(rcv.srv, rcv) go func() { _ = rcv.srv.Serve(ln) }() return rcv, nil } var _ plogotlp.GRPCServer = &mockLogsReceiver{} type mockLogsReceiver struct { plogotlp.UnimplementedGRPCServer mockReceiver exportResponse func() plogotlp.ExportResponse lastRequest plog.Logs } func (r *mockLogsReceiver) Export(ctx context.Context, req plogotlp.ExportRequest) (plogotlp.ExportResponse, error) { r.requestCount.Add(1) ld := req.Logs() r.totalItems.Add(int64(ld.LogRecordCount())) r.mux.Lock() defer r.mux.Unlock() r.lastRequest = ld r.metadata, _ = metadata.FromIncomingContext(ctx) return r.exportResponse(), r.exportError } func (r *mockLogsReceiver) getLastRequest() plog.Logs { r.mux.Lock() defer r.mux.Unlock() return r.lastRequest } func (r *mockLogsReceiver) setExportResponse(fn func() plogotlp.ExportResponse) { r.mux.Lock() defer r.mux.Unlock() r.exportResponse = fn } func otlpLogsReceiverOnGRPCServer(ln net.Listener) *mockLogsReceiver { rcv := &mockLogsReceiver{ mockReceiver: mockReceiver{ srv: grpc.NewServer(), requestCount: new(atomic.Int64), totalItems: new(atomic.Int64), }, exportResponse: plogotlp.NewExportResponse, } // Now run it as a gRPC server plogotlp.RegisterGRPCServer(rcv.srv, rcv) go func() { _ = rcv.srv.Serve(ln) }() return rcv } var _ pmetricotlp.GRPCServer = &mockMetricsReceiver{} type mockMetricsReceiver struct { pmetricotlp.UnimplementedGRPCServer mockReceiver exportResponse func() pmetricotlp.ExportResponse lastRequest pmetric.Metrics } func (r *mockMetricsReceiver) Export(ctx context.Context, req pmetricotlp.ExportRequest) (pmetricotlp.ExportResponse, error) { md := req.Metrics() r.requestCount.Add(1) r.totalItems.Add(int64(md.DataPointCount())) r.mux.Lock() defer r.mux.Unlock() r.lastRequest = md r.metadata, _ = metadata.FromIncomingContext(ctx) return r.exportResponse(), r.exportError } func (r *mockMetricsReceiver) getLastRequest() pmetric.Metrics { r.mux.Lock() defer r.mux.Unlock() return r.lastRequest } func (r *mockMetricsReceiver) setExportResponse(fn func() pmetricotlp.ExportResponse) { r.mux.Lock() defer r.mux.Unlock() r.exportResponse = fn } func otlpMetricsReceiverOnGRPCServer(ln net.Listener) *mockMetricsReceiver { rcv := &mockMetricsReceiver{ mockReceiver: mockReceiver{ srv: grpc.NewServer(), requestCount: new(atomic.Int64), totalItems: new(atomic.Int64), }, exportResponse: pmetricotlp.NewExportResponse, } // Now run it as a gRPC server pmetricotlp.RegisterGRPCServer(rcv.srv, rcv) go func() { _ = rcv.srv.Serve(ln) }() return rcv } type mockProfilesReceiver struct { pprofileotlp.UnimplementedGRPCServer mockReceiver exportResponse func() pprofileotlp.ExportResponse lastRequest pprofile.Profiles } func (r *mockProfilesReceiver) Export(ctx context.Context, req pprofileotlp.ExportRequest) (pprofileotlp.ExportResponse, error) { r.requestCount.Add(1) td := req.Profiles() r.totalItems.Add(int64(td.SampleCount())) r.mux.Lock() defer r.mux.Unlock() r.lastRequest = td r.metadata, _ = metadata.FromIncomingContext(ctx) return r.exportResponse(), r.exportError } func (r *mockProfilesReceiver) getLastRequest() pprofile.Profiles { r.mux.Lock() defer r.mux.Unlock() return r.lastRequest } func (r *mockProfilesReceiver) setExportResponse(fn func() pprofileotlp.ExportResponse) { r.mux.Lock() defer r.mux.Unlock() r.exportResponse = fn } func otlpProfilesReceiverOnGRPCServer(ln net.Listener, useTLS bool) (*mockProfilesReceiver, error) { sopts := []grpc.ServerOption{} if useTLS { _, currentFile, _, _ := runtime.Caller(0) basepath := filepath.Dir(currentFile) certpath := filepath.Join(basepath, filepath.Join("testdata", "test_cert.pem")) keypath := filepath.Join(basepath, filepath.Join("testdata", "test_key.pem")) creds, err := credentials.NewServerTLSFromFile(certpath, keypath) if err != nil { return nil, err } sopts = append(sopts, grpc.Creds(creds)) } rcv := &mockProfilesReceiver{ mockReceiver: mockReceiver{ requestCount: &atomic.Int64{}, totalItems: &atomic.Int64{}, srv: grpc.NewServer(sopts...), }, exportResponse: pprofileotlp.NewExportResponse, } // Now run it as a gRPC server pprofileotlp.RegisterGRPCServer(rcv.srv, rcv) go func() { _ = rcv.srv.Serve(ln) }() return rcv, nil } func TestSendTraces(t *testing.T) { // Start an OTLP-compatible receiver. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) rcv, _ := otlpTracesReceiverOnGRPCServer(ln, false) // Also closes the connection. defer rcv.srv.GracefulStop() // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) // Disable queuing to ensure that we execute the request when calling ConsumeTraces // otherwise we will not see any errors. cfg.QueueConfig.Enabled = false cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, Headers: configopaque.MapList{ {Name: "header", Value: "header-value"}, }, } set := exportertest.NewNopSettings(factory.Type()) set.BuildInfo.Description = "Collector" set.BuildInfo.Version = "1.2.3test" // For testing the "Partial success" warning. logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := factory.CreateTraces(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { assert.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // Ensure that initially there is no data in the receiver. assert.EqualValues(t, 0, rcv.requestCount.Load()) // Send empty trace. td := ptrace.NewTraces() require.NoError(t, exp.ConsumeTraces(context.Background(), td)) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 0 }, 10*time.Second, 5*time.Millisecond) // Ensure it was received empty. assert.EqualValues(t, 0, rcv.totalItems.Load()) // A trace with 2 spans. td = testdata.GenerateTraces(2) err = exp.ConsumeTraces(context.Background(), td) require.NoError(t, err) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 1 }, 10*time.Second, 5*time.Millisecond) expectedHeader := []string{"header-value"} // Verify received span. assert.EqualValues(t, 2, rcv.totalItems.Load()) assert.EqualValues(t, 2, rcv.requestCount.Load()) assert.Equal(t, td, rcv.getLastRequest()) md := rcv.getMetadata() require.Equal(t, expectedHeader, md.Get("header")) require.Len(t, md.Get("User-Agent"), 1) require.Contains(t, md.Get("User-Agent")[0], "Collector/1.2.3test") // Return partial success rcv.setExportResponse(func() ptraceotlp.ExportResponse { response := ptraceotlp.NewExportResponse() partialSuccess := response.PartialSuccess() partialSuccess.SetErrorMessage("Some spans were not ingested") partialSuccess.SetRejectedSpans(1) return response }) // A request with 2 Trace entries. td = testdata.GenerateTraces(2) err = exp.ConsumeTraces(context.Background(), td) require.NoError(t, err) assert.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) assert.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestSendTracesWhenEndpointHasHttpScheme(t *testing.T) { tests := []struct { name string useTLS bool scheme string gRPCClientSettings configgrpc.ClientConfig }{ { name: "Use https scheme", useTLS: true, scheme: "https://", gRPCClientSettings: configgrpc.ClientConfig{}, }, { name: "Use http scheme", useTLS: false, scheme: "http://", gRPCClientSettings: configgrpc.ClientConfig{ TLS: configtls.ClientConfig{ Insecure: true, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { // Start an OTLP-compatible receiver. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) rcv, err := otlpTracesReceiverOnGRPCServer(ln, test.useTLS) require.NoError(t, err, "Failed to start mock OTLP receiver") // Also closes the connection. defer rcv.srv.GracefulStop() // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig = test.gRPCClientSettings cfg.ClientConfig.Endpoint = test.scheme + ln.Addr().String() if test.useTLS { cfg.ClientConfig.TLS.InsecureSkipVerify = true } set := exportertest.NewNopSettings(factory.Type()) exp, err := factory.CreateTraces(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { assert.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // Ensure that initially there is no data in the receiver. assert.EqualValues(t, 0, rcv.requestCount.Load()) // Send empty trace. td := ptrace.NewTraces() require.NoError(t, exp.ConsumeTraces(context.Background(), td)) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 0 }, 10*time.Second, 5*time.Millisecond) // Ensure it was received empty. assert.EqualValues(t, 0, rcv.totalItems.Load()) }) } } func TestSendMetrics(t *testing.T) { // Start an OTLP-compatible receiver. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) rcv := otlpMetricsReceiverOnGRPCServer(ln) // Also closes the connection. defer rcv.srv.GracefulStop() // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) // Disable queuing to ensure that we execute the request when calling ConsumeMetrics // otherwise we will not see any errors. cfg.QueueConfig.Enabled = false cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, Headers: configopaque.MapList{ {Name: "header", Value: "header-value"}, }, } set := exportertest.NewNopSettings(factory.Type()) set.BuildInfo.Description = "Collector" set.BuildInfo.Version = "1.2.3test" // For testing the "Partial success" warning. logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := factory.CreateMetrics(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { assert.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // Ensure that initially there is no data in the receiver. assert.EqualValues(t, 0, rcv.requestCount.Load()) // Send empty metric. md := pmetric.NewMetrics() require.NoError(t, exp.ConsumeMetrics(context.Background(), md)) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 0 }, 10*time.Second, 5*time.Millisecond) // Ensure it was received empty. assert.EqualValues(t, 0, rcv.totalItems.Load()) // Send two metrics. md = testdata.GenerateMetrics(2) err = exp.ConsumeMetrics(context.Background(), md) require.NoError(t, err) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 1 }, 10*time.Second, 5*time.Millisecond) expectedHeader := []string{"header-value"} // Verify received metrics. assert.EqualValues(t, 2, rcv.requestCount.Load()) assert.EqualValues(t, 4, rcv.totalItems.Load()) assert.Equal(t, md, rcv.getLastRequest()) mdata := rcv.getMetadata() require.Equal(t, expectedHeader, mdata.Get("header")) require.Len(t, mdata.Get("User-Agent"), 1) require.Contains(t, mdata.Get("User-Agent")[0], "Collector/1.2.3test") st := status.New(codes.InvalidArgument, "Invalid argument") rcv.setExportError(st.Err()) // Send two metrics.. md = testdata.GenerateMetrics(2) err = exp.ConsumeMetrics(context.Background(), md) require.Error(t, err) rcv.setExportError(nil) // Return partial success rcv.setExportResponse(func() pmetricotlp.ExportResponse { response := pmetricotlp.NewExportResponse() partialSuccess := response.PartialSuccess() partialSuccess.SetErrorMessage("Some data points were not ingested") partialSuccess.SetRejectedDataPoints(1) return response }) // Send two metrics. md = testdata.GenerateMetrics(2) require.NoError(t, exp.ConsumeMetrics(context.Background(), md)) assert.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) assert.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestSendTraceDataServerDownAndUp(t *testing.T) { // Find the addr, but don't start the server. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) // Disable queuing to ensure that we execute the request when calling ConsumeTraces // otherwise we will not see the error. cfg.QueueConfig.Enabled = false cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, // Need to wait for every request blocking until either request timeouts or succeed. // Do not rely on external retry logic here, if that is intended set InitialInterval to 100ms. WaitForReady: true, } set := exportertest.NewNopSettings(factory.Type()) exp, err := factory.CreateTraces(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { assert.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // A trace with 2 spans. td := testdata.GenerateTraces(2) ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second) require.Error(t, exp.ConsumeTraces(ctx, td)) assert.Equal(t, context.DeadlineExceeded, ctx.Err()) cancel() ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) require.Error(t, exp.ConsumeTraces(ctx, td)) assert.Equal(t, context.DeadlineExceeded, ctx.Err()) cancel() startServerAndMakeRequest(t, exp, td, ln) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) require.Error(t, exp.ConsumeTraces(ctx, td)) assert.Equal(t, context.DeadlineExceeded, ctx.Err()) cancel() // First call to startServerAndMakeRequest closed the connection. There is a race condition here that the // port may be reused, if this gets flaky rethink what to do. ln, err = net.Listen("tcp", ln.Addr().String()) require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) startServerAndMakeRequest(t, exp, td, ln) ctx, cancel = context.WithTimeout(context.Background(), 1*time.Second) require.Error(t, exp.ConsumeTraces(ctx, td)) assert.Equal(t, context.DeadlineExceeded, ctx.Err()) cancel() } func TestSendTraceDataServerStartWhileRequest(t *testing.T) { // Find the addr, but don't start the server. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, } set := exportertest.NewNopSettings(factory.Type()) exp, err := factory.CreateTraces(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { assert.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // A trace with 2 spans. td := testdata.GenerateTraces(2) done := make(chan bool, 1) defer close(done) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) go func() { assert.NoError(t, exp.ConsumeTraces(ctx, td)) done <- true }() time.Sleep(2 * time.Second) rcv, _ := otlpTracesReceiverOnGRPCServer(ln, false) defer rcv.srv.GracefulStop() // Wait until one of the conditions below triggers. select { case <-ctx.Done(): t.Fail() case <-done: require.NoError(t, ctx.Err()) } cancel() } func TestSendTracesOnResourceExhaustion(t *testing.T) { ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err) rcv, _ := otlpTracesReceiverOnGRPCServer(ln, false) rcv.setExportError(status.Error(codes.ResourceExhausted, "resource exhausted")) defer rcv.srv.GracefulStop() factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.RetryConfig.InitialInterval = 0 cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, } set := exportertest.NewNopSettings(factory.Type()) exp, err := factory.CreateTraces(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { assert.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) assert.EqualValues(t, 0, rcv.requestCount.Load()) td := ptrace.NewTraces() require.NoError(t, exp.ConsumeTraces(context.Background(), td)) assert.Never(t, func() bool { return rcv.requestCount.Load() > 1 }, 1*time.Second, 5*time.Millisecond, "Should not retry if RetryInfo is not included into status details by the server.") rcv.requestCount.Swap(0) st := status.New(codes.ResourceExhausted, "resource exhausted") st, _ = st.WithDetails(&errdetails.RetryInfo{ RetryDelay: durationpb.New(100 * time.Millisecond), }) rcv.setExportError(st.Err()) require.NoError(t, exp.ConsumeTraces(context.Background(), td)) assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 1 }, 10*time.Second, 5*time.Millisecond, "Should retry if RetryInfo is included into status details by the server.") } func startServerAndMakeRequest(t *testing.T, exp exporter.Traces, td ptrace.Traces, ln net.Listener) { rcv, _ := otlpTracesReceiverOnGRPCServer(ln, false) defer rcv.srv.GracefulStop() // Ensure that initially there is no data in the receiver. assert.EqualValues(t, 0, rcv.requestCount.Load()) // Clone the request and store as expected. expectedData := ptrace.NewTraces() td.CopyTo(expectedData) // Resend the request, this should succeed. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) require.NoError(t, exp.ConsumeTraces(ctx, td)) cancel() // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 0 }, 10*time.Second, 5*time.Millisecond) // Verify received span. assert.EqualValues(t, 2, rcv.totalItems.Load()) assert.Equal(t, expectedData, rcv.getLastRequest()) } func TestSendLogData(t *testing.T) { // Start an OTLP-compatible receiver. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) rcv := otlpLogsReceiverOnGRPCServer(ln) // Also closes the connection. defer rcv.srv.GracefulStop() // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) // Disable queuing to ensure that we execute the request when calling ConsumeLogs // otherwise we will not see any errors. cfg.QueueConfig.Enabled = false cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, } set := exportertest.NewNopSettings(factory.Type()) set.BuildInfo.Description = "Collector" set.BuildInfo.Version = "1.2.3test" // For testing the "Partial success" warning. logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := factory.CreateLogs(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { assert.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // Ensure that initially there is no data in the receiver. assert.EqualValues(t, 0, rcv.requestCount.Load()) // Send empty request. ld := plog.NewLogs() require.NoError(t, exp.ConsumeLogs(context.Background(), ld)) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 0 }, 10*time.Second, 5*time.Millisecond) // Ensure it was received empty. assert.EqualValues(t, 0, rcv.totalItems.Load()) // A request with 2 log entries. ld = testdata.GenerateLogs(2) err = exp.ConsumeLogs(context.Background(), ld) require.NoError(t, err) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 1 }, 10*time.Second, 5*time.Millisecond) // Verify received logs. assert.EqualValues(t, 2, rcv.requestCount.Load()) assert.EqualValues(t, 2, rcv.totalItems.Load()) assert.Equal(t, ld, rcv.getLastRequest()) md := rcv.getMetadata() require.Len(t, md.Get("User-Agent"), 1) require.Contains(t, md.Get("User-Agent")[0], "Collector/1.2.3test") st := status.New(codes.InvalidArgument, "Invalid argument") rcv.setExportError(st.Err()) // A request with 2 log entries. ld = testdata.GenerateLogs(2) err = exp.ConsumeLogs(context.Background(), ld) require.Error(t, err) rcv.setExportError(nil) // Return partial success rcv.setExportResponse(func() plogotlp.ExportResponse { response := plogotlp.NewExportResponse() partialSuccess := response.PartialSuccess() partialSuccess.SetErrorMessage("Some log records were not ingested") partialSuccess.SetRejectedLogRecords(1) return response }) // A request with 2 log entries. ld = testdata.GenerateLogs(2) err = exp.ConsumeLogs(context.Background(), ld) require.NoError(t, err) assert.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) assert.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestSendProfiles(t *testing.T) { // Start an OTLP-compatible receiver. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) rcv, _ := otlpProfilesReceiverOnGRPCServer(ln, false) // Also closes the connection. defer rcv.srv.GracefulStop() // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) // Disable queuing to ensure that we execute the request when calling ConsumeProfiles // otherwise we will not see any errors. cfg.QueueConfig.Enabled = false cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, Headers: configopaque.MapList{ {Name: "header", Value: "header-value"}, }, } set := exportertest.NewNopSettings(factory.Type()) set.BuildInfo.Description = "Collector" set.BuildInfo.Version = "1.2.3test" // For testing the "Partial success" warning. logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { require.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // Ensure that initially there is no data in the receiver. assert.EqualValues(t, 0, rcv.requestCount.Load()) // Send empty profile. td := pprofile.NewProfiles() require.NoError(t, exp.ConsumeProfiles(context.Background(), td)) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 0 }, 10*time.Second, 5*time.Millisecond) // Ensure it was received empty. assert.EqualValues(t, 0, rcv.totalItems.Load()) // A request with 2 profiles. td = testdata.GenerateProfiles(2) err = exp.ConsumeProfiles(context.Background(), td) require.NoError(t, err) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 1 }, 10*time.Second, 5*time.Millisecond) expectedHeader := []string{"header-value"} // Verify received span. assert.EqualValues(t, 2, rcv.totalItems.Load()) assert.EqualValues(t, 2, rcv.requestCount.Load()) assert.Equal(t, td, rcv.getLastRequest()) md := rcv.getMetadata() require.Equal(t, expectedHeader, md.Get("header")) require.Len(t, md.Get("User-Agent"), 1) require.Contains(t, md.Get("User-Agent")[0], "Collector/1.2.3test") // Return partial success rcv.setExportResponse(func() pprofileotlp.ExportResponse { response := pprofileotlp.NewExportResponse() partialSuccess := response.PartialSuccess() partialSuccess.SetErrorMessage("Some spans were not ingested") partialSuccess.SetRejectedProfiles(1) return response }) // A request with 2 Profile entries. td = testdata.GenerateProfiles(2) err = exp.ConsumeProfiles(context.Background(), td) require.NoError(t, err) assert.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) assert.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestSendProfilesWhenEndpointHasHttpScheme(t *testing.T) { tests := []struct { name string useTLS bool scheme string gRPCClientSettings configgrpc.ClientConfig }{ { name: "Use https scheme", useTLS: true, scheme: "https://", gRPCClientSettings: configgrpc.ClientConfig{}, }, { name: "Use http scheme", useTLS: false, scheme: "http://", gRPCClientSettings: configgrpc.ClientConfig{ TLS: configtls.ClientConfig{ Insecure: true, }, }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { // Start an OTLP-compatible receiver. ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) rcv, err := otlpProfilesReceiverOnGRPCServer(ln, test.useTLS) require.NoError(t, err, "Failed to start mock OTLP receiver") // Also closes the connection. defer rcv.srv.GracefulStop() // Start an OTLP exporter and point to the receiver. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig = test.gRPCClientSettings cfg.ClientConfig.Endpoint = test.scheme + ln.Addr().String() if test.useTLS { cfg.ClientConfig.TLS.InsecureSkipVerify = true } set := exportertest.NewNopSettings(factory.Type()) exp, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, exp) defer func() { require.NoError(t, exp.Shutdown(context.Background())) }() host := componenttest.NewNopHost() require.NoError(t, exp.Start(context.Background(), host)) // Ensure that initially there is no data in the receiver. assert.EqualValues(t, 0, rcv.requestCount.Load()) // Send empty profile. td := pprofile.NewProfiles() require.NoError(t, exp.ConsumeProfiles(context.Background(), td)) // Wait until it is received. assert.Eventually(t, func() bool { return rcv.requestCount.Load() > 0 }, 10*time.Second, 5*time.Millisecond) // Ensure it was received empty. assert.EqualValues(t, 0, rcv.totalItems.Load()) }) } } opentelemetry-collector-0.141.0/exporter/otlpexporter/testdata/000077500000000000000000000000001511331344600247665ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlpexporter/testdata/config.yaml000066400000000000000000000012031511331344600271130ustar00rootroot00000000000000endpoint: "1.2.3.4:1234" compression: "gzip" tls: ca_file: /var/lib/mycert.pem timeout: 10s sending_queue: enabled: true sizer: "items" num_consumers: 2 queue_size: 100000 batch: flush_timeout: 200ms min_size: 1000 max_size: 10000 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m auth: authenticator: nop headers: "can you have a . here?": "F0000000-0000-0000-0000-000000000000" header1: "234" another: "somevalue" keepalive: time: 20s timeout: 30s permit_without_stream: true balancer_name: "round_robin" opentelemetry-collector-0.141.0/exporter/otlpexporter/testdata/default-batch.yaml000066400000000000000000000000761511331344600303600ustar00rootroot00000000000000endpoint: "1.2.3.4:1234" timeout: 10s sending_queue: batch: opentelemetry-collector-0.141.0/exporter/otlpexporter/testdata/invalid_configs.yaml000066400000000000000000000045121511331344600310120ustar00rootroot00000000000000no_endpoint: timeout: 10s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m https_endpoint: endpoint: https:// http_endpoint: endpoint: http:// timeout: 10s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m invalid_timeout: endpoint: example.com:443 timeout: -5s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m invalid_retry: endpoint: example.com:443 timeout: 30s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: -5 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m invalid_tls: tls: min_version: asd endpoint: example.com:443 timeout: 10s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m missing_port: endpoint: example.com timeout: 10s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m invalid_port: endpoint: example.com:port timeout: 10s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m invalid_unix_socket: endpoint: unix:// timeout: 10s sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10mopentelemetry-collector-0.141.0/exporter/otlpexporter/testdata/test_cert.pem000066400000000000000000000017211511331344600274660ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICpDCCAYwCCQC5oaFsqLW3GTANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAls b2NhbGhvc3QwHhcNMjEwNzE0MDAxMzU2WhcNMzEwNzEyMDAxMzU2WjAUMRIwEAYD VQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDO mKaE1qg5VLMwaUnSzufT23rRJFbuy/HDXwsH63yZVSsISQkGjkBYBgrqAMtVnsI/ l4gXtBWkZtJFs68Sbo9ps3W0PdB5+d12R5NUNA1rkZtx3jtEN33dpGhifug/TIZe 7Zr0G1z6gNoaEezk0Jpg4KsH7QpIeHPRhIZMyWeqddgD/qL4/ukaU4NOORuF3WoT oo2LpI3jUq66mz2N2Inq0V/OX7BYB4Ur6EtjWh2baiUuw9fq+oLUlgZd6ypnugC/ +YfgYqvWtRntmEr0Z+O4Kz81P2IpH/0h1RFhWyK6thVGa9cx6aseCp3V2cMXfGfc z4n3Uvz87v+bZvGbcse/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAAlvNBNoqXUQ ohR0eozIHGeJ94U7WK5zXf2NSvmRlwHzHXvUq6GKd+8Bv1foMjI6OpSOZmjtRGsc rWET1WjSyQddRfqYazhWp1IyYu5LfATwPS+RXJAkWixKVfG+Ta2x6u+aT/bSZwEg NwRerc6pyqv5UG8Z7Pe1kAxbgOwZv5KXAewIgTSbEkmIp1Dg8GhGeWD5pjYNCkJV Na2KMAUWP3PeQzdSBKmBNpsRUALuSTxb5u7pl+PA7FLInTtDeyZn8xpO1GPBhbJE trDbmTbj5YexOXEaQtGtZ6fwRw2jnUm8nqtXozxIomnVTBO8vLmZAUgyJ71trRw0 gE9tH5Ndlug= -----END CERTIFICATE----- opentelemetry-collector-0.141.0/exporter/otlpexporter/testdata/test_key.pem000066400000000000000000000032501511331344600273200ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDOmKaE1qg5VLMw aUnSzufT23rRJFbuy/HDXwsH63yZVSsISQkGjkBYBgrqAMtVnsI/l4gXtBWkZtJF s68Sbo9ps3W0PdB5+d12R5NUNA1rkZtx3jtEN33dpGhifug/TIZe7Zr0G1z6gNoa Eezk0Jpg4KsH7QpIeHPRhIZMyWeqddgD/qL4/ukaU4NOORuF3WoToo2LpI3jUq66 mz2N2Inq0V/OX7BYB4Ur6EtjWh2baiUuw9fq+oLUlgZd6ypnugC/+YfgYqvWtRnt mEr0Z+O4Kz81P2IpH/0h1RFhWyK6thVGa9cx6aseCp3V2cMXfGfcz4n3Uvz87v+b ZvGbcse/AgMBAAECggEADeR39iDVKR3H+u5pl3JwZm+w35V4/w/ZzxB6FmtAcrMm dKUspTM1onWtkDTDd5t4ZnxTG3zxo5+Cbkt571xd6na16Ivrk/g4aza+8n+Zk200 LcEK7ThqD1h56H2uMmt78bA6pkWcx/+YKv6flndsmi0hcyP+eAcZirJFsa4teWna P6rhI9zThc9OcecqGZIlmzJQ4cLbIO86QqkWW6yjKYg6riOb2g+i3e97ZngMCTcV lni+sksLlXBNKPqh1AkiUFe4pInRBh4LGQ5rNSYswEqlQY0iW0u4Hs3HNou0On+8 1T8m5wzKQ+23AN+vVRJ/MHssQiB/TPK92jXVgEz6eQKBgQD2GEb7NzDIxsAQZBQo tt3jYitNcAEqMWeT7wxCMMue4wIrT6Fp6NuG5NMVqLglzx72m6TXg7YzZxPrAnlH jblWI4sxwVC8BjjYyGud7qMuhUIZmI8aS9HuYW0ODSxkcpVVXd4HDUYKg7PafAkl cj745E5KGD+qW44KASTTQ1SwRQKBgQDW6WLp/nPVPO5YEK4nzS7b1RRC8ypHiKd6 LzhA2izgcsmO3F3Y5ZZ5rzeFbjgZiGFTUB/r1mgomI8kZyIGP1AN6o8oY9I89gHY /DEEagIsFK5jAEoMeN0qbgqasOXpi+uUHCNidWa7OWOL9Rsh7dyVT54xcqMC2Qak Vpoy5miiMwKBgQDuOHH9nF9M+5fQRhB9mQcRpWXlgBagkVKCkVR8fl+dXoIrCtpl e1OGMNtki/42G1kNv3zCYm1tNMrDI5HjAf32tFF5yHguipdcwiXqq6aq0bQ6ssNT 4TFGYGkAwR/H3GNST5stmFvEsdjYFlmENiNfKyHd97spXZcReCn9l5/TQQKBgDRG PpYWG4zBrmPjYskxonU8ZhpG1YDi34Hb3H4B06qgoSBLv9QTPD/K++FLxv+G6c1/ DtSpqVo+iYrcPy1v1wQbisjTRv8nA5oI9c9SDcc1HJneJyTTfVBlxdSMtM/TBfFX ys+XKO7fbbRMYVYmamIzJJJ4hOgba/8rRYSeANN7AoGBAMDdrT+ig3aDMratbAvY lqsfN3AtxoZ+ZVQYyUbzTSZPZ/to9eNuBzhRKcQ3QfG95nrHb7OnWHa7+1kc4p/Q jMgzJgRpajlES+F3CCMPgJIJg7Ev+yiSCJLP9ZOsC+E96bK265hUcDyCXwb3Wzmg 4L9sc1QsQW80QO/RnaEzGO51 -----END PRIVATE KEY----- opentelemetry-collector-0.141.0/exporter/otlphttpexporter/000077500000000000000000000000001511331344600240555ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlphttpexporter/Makefile000066400000000000000000000000361511331344600255140ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/exporter/otlphttpexporter/README.md000066400000000000000000000103321511331344600253330ustar00rootroot00000000000000# OTLP/HTTP Exporter | Status | | | ------------- |-----------| | Stability | [development]: profiles | | | [stable]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s], [otlp] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aexporter%2Fotlphttp%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aexporter%2Fotlphttp) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aexporter%2Fotlphttp%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aexporter%2Fotlphttp) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 [otlp]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp Export traces and/or metrics via HTTP using [OTLP]( https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md) format. The following settings are required: - `endpoint` (no default): The target base URL to send data to (e.g.: https://example.com:4318). To send each signal a corresponding path will be added to this base URL, i.e. for traces "/v1/traces" will appended, for metrics "/v1/metrics" will be appended, for logs "/v1/logs" will be appended. The following settings can be optionally configured: - `traces_endpoint` (no default): The target URL to send trace data to (e.g.: https://example.com:4318/v1/traces). If this setting is present the `endpoint` setting is ignored for traces. - `metrics_endpoint` (no default): The target URL to send metric data to (e.g.: https://example.com:4318/v1/metrics). If this setting is present the `endpoint` setting is ignored for metrics. - `logs_endpoint` (no default): The target URL to send log data to (e.g.: https://example.com:4318/v1/logs). - `profiles_endpoint` (no default): The target URL to send profile data to (e.g.: https://example.com:4318/v1development/profiles). If this setting is present the `endpoint` setting is ignored for logs. - `tls`: see [TLS Configuration Settings](../../config/configtls/README.md) for the full set of available options. - `timeout` (default = 30s): HTTP request time limit. For details see https://golang.org/pkg/net/http/#Client - `read_buffer_size` (default = 0): ReadBufferSize for HTTP client. - `write_buffer_size` (default = 512 * 1024): WriteBufferSize for HTTP client. - `encoding` (default = proto): The encoding to use for the messages (valid options: `proto`, `json`) - `retry_on_failure`: see [Retry on Failure](../exporterhelper/README.md#retry-on-failure) for the full set of available options. - `sending_queue`: see [Sending Queue](../exporterhelper/README.md#sending-queue) for the full set of available options. Example: ```yaml exporters: otlphttp: endpoint: https://example.com:4318 ``` By default `gzip` compression is enabled. See [compression comparison](../../config/configgrpc/README.md#compression-comparison) for details benchmark information. To disable, configure as follows: ```yaml exporters: otlphttp: ... compression: none ``` By default `proto` encoding is used, to change the content encoding of the message configure it as follows: ```yaml exporters: otlphttp: ... encoding: json ``` The full list of settings exposed for this exporter are documented [here](./config.go) with detailed sample configurations [here](./testdata/config.yaml). opentelemetry-collector-0.141.0/exporter/otlphttpexporter/config.go000066400000000000000000000046551511331344600256630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlphttpexporter // import "go.opentelemetry.io/collector/exporter/otlphttpexporter" import ( "encoding" "errors" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/exporter/exporterhelper" ) // EncodingType defines the type for content encoding type EncodingType string const ( EncodingProto EncodingType = "proto" EncodingJSON EncodingType = "json" ) var _ encoding.TextUnmarshaler = (*EncodingType)(nil) // UnmarshalText unmarshalls text to an EncodingType. func (e *EncodingType) UnmarshalText(text []byte) error { if e == nil { return errors.New("cannot unmarshal to a nil *EncodingType") } str := string(text) switch str { case string(EncodingProto): *e = EncodingProto case string(EncodingJSON): *e = EncodingJSON default: return fmt.Errorf("invalid encoding type: %s", str) } return nil } // Config defines configuration for OTLP/HTTP exporter. type Config struct { ClientConfig confighttp.ClientConfig `mapstructure:",squash"` // squash ensures fields are correctly decoded in embedded struct. QueueConfig exporterhelper.QueueBatchConfig `mapstructure:"sending_queue"` RetryConfig configretry.BackOffConfig `mapstructure:"retry_on_failure"` // The URL to send traces to. If omitted the Endpoint + "/v1/traces" will be used. TracesEndpoint string `mapstructure:"traces_endpoint"` // The URL to send metrics to. If omitted the Endpoint + "/v1/metrics" will be used. MetricsEndpoint string `mapstructure:"metrics_endpoint"` // The URL to send logs to. If omitted the Endpoint + "/v1/logs" will be used. LogsEndpoint string `mapstructure:"logs_endpoint"` // The URL to send profiles to. If omitted the Endpoint + "/v1development/profiles" will be used. ProfilesEndpoint string `mapstructure:"profiles_endpoint"` // The encoding to export telemetry (default: "proto") Encoding EncodingType `mapstructure:"encoding"` } var _ component.Config = (*Config)(nil) // Validate checks if the exporter configuration is valid func (cfg *Config) Validate() error { if cfg.ClientConfig.Endpoint == "" && cfg.TracesEndpoint == "" && cfg.MetricsEndpoint == "" && cfg.LogsEndpoint == "" && cfg.ProfilesEndpoint == "" { return errors.New("at least one endpoint must be specified") } return nil } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/config_test.go000066400000000000000000000135221511331344600267130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlphttpexporter import ( "net/http" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/exporter/exporterhelper" ) func TestUnmarshalDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) // Default/Empty config is invalid. assert.Error(t, xconfmap.Validate(cfg)) } func TestUnmarshalConfig(t *testing.T) { defaultMaxIdleConns := http.DefaultTransport.(*http.Transport).MaxIdleConns defaultMaxIdleConnsPerHost := http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost defaultMaxConnsPerHost := http.DefaultTransport.(*http.Transport).MaxConnsPerHost defaultIdleConnTimeout := http.DefaultTransport.(*http.Transport).IdleConnTimeout cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) assert.Equal(t, &Config{ RetryConfig: configretry.BackOffConfig{ Enabled: true, InitialInterval: 10 * time.Second, RandomizationFactor: 0.7, Multiplier: 1.3, MaxInterval: 1 * time.Minute, MaxElapsedTime: 10 * time.Minute, }, QueueConfig: exporterhelper.QueueBatchConfig{ Enabled: true, Sizer: exporterhelper.RequestSizerTypeRequests, NumConsumers: 2, QueueSize: 10, Batch: configoptional.Default(exporterhelper.BatchConfig{ Sizer: exporterhelper.RequestSizerTypeItems, FlushTimeout: 200 * time.Millisecond, MinSize: 8192, }), }, Encoding: EncodingProto, ClientConfig: confighttp.ClientConfig{ Headers: configopaque.MapList{ {Name: "another", Value: "somevalue"}, {Name: "can you have a . here?", Value: "F0000000-0000-0000-0000-000000000000"}, {Name: "header1", Value: "234"}, }, Endpoint: "https://1.2.3.4:1234", TLS: configtls.ClientConfig{ Config: configtls.Config{ CAFile: "/var/lib/mycert.pem", CertFile: "certfile", KeyFile: "keyfile", }, Insecure: true, }, ReadBufferSize: 123, WriteBufferSize: 345, Timeout: time.Second * 10, Compression: "gzip", MaxIdleConns: defaultMaxIdleConns, MaxIdleConnsPerHost: defaultMaxIdleConnsPerHost, MaxConnsPerHost: defaultMaxConnsPerHost, IdleConnTimeout: defaultIdleConnTimeout, ForceAttemptHTTP2: true, }, ProfilesEndpoint: "https://custom.profiles.endpoint:8080/v1development/profiles", }, cfg) } func TestUnmarshalConfigInvalidEncoding(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "bad_invalid_encoding.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.Error(t, cm.Unmarshal(&cfg)) } func TestUnmarshalEncoding(t *testing.T) { tests := []struct { name string encodingBytes []byte expected EncodingType shouldError bool }{ { name: "UnmarshalEncodingProto", encodingBytes: []byte("proto"), expected: EncodingProto, shouldError: false, }, { name: "UnmarshalEncodingJson", encodingBytes: []byte("json"), expected: EncodingJSON, shouldError: false, }, { name: "UnmarshalEmptyEncoding", encodingBytes: []byte(""), shouldError: true, }, { name: "UnmarshalInvalidEncoding", encodingBytes: []byte("invalid"), shouldError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { var encoding EncodingType err := encoding.UnmarshalText(tt.encodingBytes) if tt.shouldError { assert.Error(t, err) } else { require.NoError(t, err) assert.Equal(t, tt.expected, encoding) } }) } } func TestConfigValidate(t *testing.T) { tests := []struct { name string cfg *Config wantErr bool }{ { name: "no endpoints specified", cfg: &Config{ ClientConfig: confighttp.ClientConfig{}, }, wantErr: true, }, { name: "main endpoint specified", cfg: &Config{ ClientConfig: confighttp.ClientConfig{ Endpoint: "http://localhost:4318", }, }, wantErr: false, }, { name: "only traces endpoint specified", cfg: &Config{ ClientConfig: confighttp.ClientConfig{}, TracesEndpoint: "http://localhost:4318/v1/traces", }, wantErr: false, }, { name: "only profiles endpoint specified", cfg: &Config{ ClientConfig: confighttp.ClientConfig{}, ProfilesEndpoint: "http://localhost:4318/v1development/profiles", }, wantErr: false, }, { name: "multiple endpoints specified", cfg: &Config{ ClientConfig: confighttp.ClientConfig{}, TracesEndpoint: "http://localhost:4318/v1/traces", MetricsEndpoint: "http://localhost:4318/v1/metrics", LogsEndpoint: "http://localhost:4318/v1/logs", ProfilesEndpoint: "http://localhost:4318/v1development/profiles", }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.cfg.Validate() if tt.wantErr { require.Error(t, err) assert.Contains(t, err.Error(), "at least one endpoint must be specified") } else { assert.NoError(t, err) } }) } } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/doc.go000066400000000000000000000004511511331344600251510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package otlphttpexporter exports data by using the OTLP format to an HTTP endpoint. package otlphttpexporter // import "go.opentelemetry.io/collector/exporter/otlphttpexporter" opentelemetry-collector-0.141.0/exporter/otlphttpexporter/factory.go000066400000000000000000000133401511331344600260540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlphttpexporter // import "go.opentelemetry.io/collector/exporter/otlphttpexporter" import ( "context" "fmt" "net/url" "strings" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper" "go.opentelemetry.io/collector/exporter/otlphttpexporter/internal/metadata" "go.opentelemetry.io/collector/exporter/xexporter" ) // NewFactory creates a factory for OTLP exporter. func NewFactory() exporter.Factory { return xexporter.NewFactory( metadata.Type, createDefaultConfig, xexporter.WithTraces(createTraces, metadata.TracesStability), xexporter.WithMetrics(createMetrics, metadata.MetricsStability), xexporter.WithLogs(createLogs, metadata.LogsStability), xexporter.WithProfiles(createProfiles, metadata.ProfilesStability), ) } func createDefaultConfig() component.Config { clientConfig := confighttp.NewDefaultClientConfig() clientConfig.Timeout = 30 * time.Second // Default to gzip compression clientConfig.Compression = configcompression.TypeGzip // We almost read 0 bytes, so no need to tune ReadBufferSize. clientConfig.WriteBufferSize = 512 * 1024 return &Config{ RetryConfig: configretry.NewDefaultBackOffConfig(), QueueConfig: exporterhelper.NewDefaultQueueConfig(), Encoding: EncodingProto, ClientConfig: clientConfig, } } // composeSignalURL composes the final URL for the signal (traces, metrics, logs) based on the configuration. // oCfg is the configuration of the exporter. // signalOverrideURL is the URL specified in the signal specific configuration (empty if not specified). // signalName is the name of the signal, e.g. "traces", "metrics", "logs". // signalVersion is the version of the signal, e.g. "v1" or "v1development". func composeSignalURL(oCfg *Config, signalOverrideURL, signalName, signalVersion string) (string, error) { switch { case signalOverrideURL != "": _, err := url.Parse(signalOverrideURL) if err != nil { return "", fmt.Errorf("%s_endpoint must be a valid URL", signalName) } return signalOverrideURL, nil case oCfg.ClientConfig.Endpoint == "": return "", fmt.Errorf("either endpoint or %s_endpoint must be specified", signalName) default: if strings.HasSuffix(oCfg.ClientConfig.Endpoint, "/") { return oCfg.ClientConfig.Endpoint + signalVersion + "/" + signalName, nil } return oCfg.ClientConfig.Endpoint + "/" + signalVersion + "/" + signalName, nil } } func createTraces( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Traces, error) { oce, err := newExporter(cfg, set) if err != nil { return nil, err } oCfg := cfg.(*Config) oce.tracesURL, err = composeSignalURL(oCfg, oCfg.TracesEndpoint, "traces", "v1") if err != nil { return nil, err } return exporterhelper.NewTraces(ctx, set, cfg, oce.pushTraces, exporterhelper.WithStart(oce.start), exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), // explicitly disable since we rely on http.Client timeout logic. exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig)) } func createMetrics( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Metrics, error) { oce, err := newExporter(cfg, set) if err != nil { return nil, err } oCfg := cfg.(*Config) oce.metricsURL, err = composeSignalURL(oCfg, oCfg.MetricsEndpoint, "metrics", "v1") if err != nil { return nil, err } return exporterhelper.NewMetrics(ctx, set, cfg, oce.pushMetrics, exporterhelper.WithStart(oce.start), exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), // explicitly disable since we rely on http.Client timeout logic. exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig)) } func createLogs( ctx context.Context, set exporter.Settings, cfg component.Config, ) (exporter.Logs, error) { oce, err := newExporter(cfg, set) if err != nil { return nil, err } oCfg := cfg.(*Config) oce.logsURL, err = composeSignalURL(oCfg, oCfg.LogsEndpoint, "logs", "v1") if err != nil { return nil, err } return exporterhelper.NewLogs(ctx, set, cfg, oce.pushLogs, exporterhelper.WithStart(oce.start), exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), // explicitly disable since we rely on http.Client timeout logic. exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig)) } func createProfiles( ctx context.Context, set exporter.Settings, cfg component.Config, ) (xexporter.Profiles, error) { oce, err := newExporter(cfg, set) if err != nil { return nil, err } oCfg := cfg.(*Config) oce.profilesURL, err = composeSignalURL(oCfg, oCfg.ProfilesEndpoint, "profiles", "v1development") if err != nil { return nil, err } return xexporterhelper.NewProfiles(ctx, set, cfg, oce.pushProfiles, exporterhelper.WithStart(oce.start), exporterhelper.WithCapabilities(consumer.Capabilities{MutatesData: false}), // explicitly disable since we rely on http.Client timeout logic. exporterhelper.WithTimeout(exporterhelper.TimeoutConfig{Timeout: 0}), exporterhelper.WithRetry(oCfg.RetryConfig), exporterhelper.WithQueue(oCfg.QueueConfig)) } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/factory_test.go000066400000000000000000000177011511331344600271200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlphttpexporter import ( "context" "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configcompression" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/internal/testutil" ) func TestCreateDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") require.NoError(t, componenttest.CheckConfigStruct(cfg)) ocfg, ok := factory.CreateDefaultConfig().(*Config) assert.True(t, ok) assert.Empty(t, ocfg.ClientConfig.Endpoint) assert.Equal(t, 30*time.Second, ocfg.ClientConfig.Timeout, "default timeout is 30 second") assert.True(t, ocfg.RetryConfig.Enabled, "default retry is enabled") assert.Equal(t, 300*time.Second, ocfg.RetryConfig.MaxElapsedTime, "default retry MaxElapsedTime") assert.Equal(t, 5*time.Second, ocfg.RetryConfig.InitialInterval, "default retry InitialInterval") assert.Equal(t, 30*time.Second, ocfg.RetryConfig.MaxInterval, "default retry MaxInterval") assert.True(t, ocfg.QueueConfig.Enabled, "default sending queue is enabled") assert.Equal(t, EncodingProto, ocfg.Encoding) assert.Equal(t, configcompression.TypeGzip, ocfg.ClientConfig.Compression) } func TestCreateMetrics(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = "http://" + testutil.GetAvailableLocalAddress(t) set := exportertest.NewNopSettings(factory.Type()) oexp, err := factory.CreateMetrics(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, oexp) } func clientConfig(endpoint string, headers configopaque.MapList, tlsSetting configtls.ClientConfig, compression configcompression.Type) confighttp.ClientConfig { clientConfig := confighttp.NewDefaultClientConfig() clientConfig.TLS = tlsSetting clientConfig.Compression = compression if endpoint != "" { clientConfig.Endpoint = endpoint } if headers != nil { clientConfig.Headers = headers } return clientConfig } func TestCreateTraces(t *testing.T) { var configCompression configcompression.Type endpoint := "http://" + testutil.GetAvailableLocalAddress(t) tests := []struct { name string config *Config mustFailOnCreate bool mustFailOnStart bool }{ { name: "NoEndpoint", config: &Config{ ClientConfig: clientConfig("", nil, configtls.ClientConfig{}, configCompression), }, mustFailOnCreate: true, }, { name: "UseSecure", config: &Config{ ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{ Insecure: false, }, configCompression), }, }, { name: "Headers", config: &Config{ ClientConfig: clientConfig(endpoint, configopaque.MapList{ {Name: "hdr1", Value: "val1"}, {Name: "hdr2", Value: "val2"}, }, configtls.ClientConfig{}, configCompression), }, }, { name: "CaCert", config: &Config{ ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{ Config: configtls.Config{ CAFile: filepath.Join("testdata", "test_cert.pem"), }, }, configCompression), }, }, { name: "CertPemFileError", config: &Config{ ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{ Config: configtls.Config{ CAFile: "nosuchfile", }, }, configCompression), }, mustFailOnCreate: false, mustFailOnStart: true, }, { name: "NoneCompression", config: &Config{ ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{}, "none"), }, }, { name: "GzipCompression", config: &Config{ ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{}, configcompression.TypeGzip), }, }, { name: "SnappyCompression", config: &Config{ ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{}, configcompression.TypeSnappy), }, }, { name: "ZstdCompression", config: &Config{ ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{}, configcompression.TypeZstd), }, }, { name: "ProtoEncoding", config: &Config{ Encoding: EncodingProto, ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{}, configCompression), }, }, { name: "JSONEncoding", config: &Config{ Encoding: EncodingJSON, ClientConfig: clientConfig(endpoint, nil, configtls.ClientConfig{}, configCompression), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { factory := NewFactory() set := exportertest.NewNopSettings(factory.Type()) consumer, err := factory.CreateTraces(context.Background(), set, tt.config) if tt.mustFailOnCreate { assert.Error(t, err) return } require.NoError(t, err) assert.NotNil(t, consumer) err = consumer.Start(context.Background(), componenttest.NewNopHost()) if tt.mustFailOnStart { require.Error(t, err) } err = consumer.Shutdown(context.Background()) if err != nil { // Since the endpoint of OTLP exporter doesn't actually exist, // exporter may already stop because it cannot connect. assert.Equal(t, "rpc error: code = Canceled desc = grpc: the client connection is closing", err.Error()) } }) } } func TestCreateLogs(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = "http://" + testutil.GetAvailableLocalAddress(t) set := exportertest.NewNopSettings(factory.Type()) oexp, err := factory.CreateLogs(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, oexp) } func TestCreateProfiles(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ClientConfig.Endpoint = "http://" + testutil.GetAvailableLocalAddress(t) set := exportertest.NewNopSettings(factory.Type()) oexp, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, oexp) } func TestCreateProfilesWithCustomEndpoint(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.ProfilesEndpoint = "http://" + testutil.GetAvailableLocalAddress(t) + "/custom/profiles" set := exportertest.NewNopSettings(factory.Type()) oexp, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, oexp) } func TestComposeSignalURL(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) // Has slash at end cfg.ClientConfig.Endpoint = "http://localhost:4318/" url, err := composeSignalURL(cfg, "", "traces", "v1") require.NoError(t, err) assert.Equal(t, "http://localhost:4318/v1/traces", url) // No slash at end cfg.ClientConfig.Endpoint = "http://localhost:4318" url, err = composeSignalURL(cfg, "", "traces", "v1") require.NoError(t, err) assert.Equal(t, "http://localhost:4318/v1/traces", url) // Different version cfg.ClientConfig.Endpoint = "http://localhost:4318" url, err = composeSignalURL(cfg, "", "traces", "v2") require.NoError(t, err) assert.Equal(t, "http://localhost:4318/v2/traces", url) // Test profiles endpoint with v1development cfg.ClientConfig.Endpoint = "http://localhost:4318" url, err = composeSignalURL(cfg, "", "profiles", "v1development") require.NoError(t, err) assert.Equal(t, "http://localhost:4318/v1development/profiles", url) // Test with custom profiles endpoint override cfg.ClientConfig.Endpoint = "http://localhost:4318" url, err = composeSignalURL(cfg, "http://custom:9090/profiles", "profiles", "v1development") require.NoError(t, err) assert.Equal(t, "http://custom:9090/profiles", url) } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/generated_component_test.go000066400000000000000000000116341511331344600314700ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package otlphttpexporter import ( "context" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) var typ = component.MustNewType("otlphttp") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg) }, }, { name: "metrics", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg) }, }, { name: "traces", createFn: func(ctx context.Context, set exporter.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), exportertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(exporter.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(exporter.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(exporter.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) } } func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/generated_package_test.go000066400000000000000000000002571511331344600310600ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package otlphttpexporter import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/go.mod000066400000000000000000000203351511331344600251660ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/otlphttpexporter go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector v0.141.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configcompression v1.47.0 go.opentelemetry.io/collector/config/confighttp v0.141.0 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/config/configretry v1.47.0 go.opentelemetry.io/collector/config/configtls v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/exporter/xexporter v0.141.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.10 ) require ( github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.1 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/cors v1.11.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configauth v1.47.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/consumer/consumererror/xconsumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumertest v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/receiver v1.47.0 // indirect go.opentelemetry.io/collector/receiver/receivertest v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector => ../../ replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/consumer/consumererror/xconsumererror => ../../consumer/consumererror/xconsumererror replace go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper => ../exporterhelper/xexporterhelper replace go.opentelemetry.io/collector/exporter/xexporter => ../xexporter replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/exporter/exportertest => ../exportertest replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/exporter/otlphttpexporter/go.sum000066400000000000000000000255201511331344600252140ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/otlphttpexporter/internal/000077500000000000000000000000001511331344600256715ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlphttpexporter/internal/metadata/000077500000000000000000000000001511331344600274515ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlphttpexporter/internal/metadata/generated_status.go000066400000000000000000000007241511331344600333440ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("otlphttp") ScopeName = "go.opentelemetry.io/collector/exporter/otlphttpexporter" ) const ( ProfilesStability = component.StabilityLevelDevelopment TracesStability = component.StabilityLevelStable MetricsStability = component.StabilityLevelStable LogsStability = component.StabilityLevelStable ) opentelemetry-collector-0.141.0/exporter/otlphttpexporter/metadata.yaml000066400000000000000000000004601511331344600265210ustar00rootroot00000000000000type: otlphttp github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: exporter stability: stable: [traces, metrics, logs] development: [profiles] distributions: [core, contrib, k8s, otlp] tests: config: endpoint: "https://1.2.3.4:1234" opentelemetry-collector-0.141.0/exporter/otlphttpexporter/otlp.go000066400000000000000000000335241511331344600253710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlphttpexporter // import "go.opentelemetry.io/collector/exporter/otlphttpexporter" import ( "bytes" "context" "errors" "fmt" "io" "net/http" "net/url" "runtime" "strconv" "time" "go.uber.org/zap" "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/internal/statusutil" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" ) type baseExporter struct { // Input configuration. config *Config client *http.Client tracesURL string metricsURL string logsURL string profilesURL string logger *zap.Logger settings component.TelemetrySettings // Default user-agent header. userAgent string } const ( headerRetryAfter = "Retry-After" maxHTTPResponseReadBytes = 64 * 1024 jsonContentType = "application/json" protobufContentType = "application/x-protobuf" ) // Create new exporter. func newExporter(cfg component.Config, set exporter.Settings) (*baseExporter, error) { oCfg := cfg.(*Config) if oCfg.ClientConfig.Endpoint != "" { _, err := url.Parse(oCfg.ClientConfig.Endpoint) if err != nil { return nil, errors.New("endpoint must be a valid URL") } } userAgent := fmt.Sprintf("%s/%s (%s/%s)", set.BuildInfo.Description, set.BuildInfo.Version, runtime.GOOS, runtime.GOARCH) // client construction is deferred to start return &baseExporter{ config: oCfg, logger: set.Logger, userAgent: userAgent, settings: set.TelemetrySettings, }, nil } // start actually creates the HTTP client. The client construction is deferred till this point as this // is the only place we get hold of Extensions which are required to construct auth round tripper. func (e *baseExporter) start(ctx context.Context, host component.Host) error { client, err := e.config.ClientConfig.ToClient(ctx, host.GetExtensions(), e.settings) if err != nil { return err } e.client = client return nil } func (e *baseExporter) pushTraces(ctx context.Context, td ptrace.Traces) error { tr := ptraceotlp.NewExportRequestFromTraces(td) var err error var request []byte switch e.config.Encoding { case EncodingJSON: request, err = tr.MarshalJSON() case EncodingProto: request, err = tr.MarshalProto() default: err = fmt.Errorf("invalid encoding: %s", e.config.Encoding) } if err != nil { return consumererror.NewPermanent(err) } return e.export(ctx, e.tracesURL, request, e.tracesPartialSuccessHandler) } func (e *baseExporter) pushMetrics(ctx context.Context, md pmetric.Metrics) error { tr := pmetricotlp.NewExportRequestFromMetrics(md) var err error var request []byte switch e.config.Encoding { case EncodingJSON: request, err = tr.MarshalJSON() case EncodingProto: request, err = tr.MarshalProto() default: err = fmt.Errorf("invalid encoding: %s", e.config.Encoding) } if err != nil { return consumererror.NewPermanent(err) } return e.export(ctx, e.metricsURL, request, e.metricsPartialSuccessHandler) } func (e *baseExporter) pushLogs(ctx context.Context, ld plog.Logs) error { tr := plogotlp.NewExportRequestFromLogs(ld) var err error var request []byte switch e.config.Encoding { case EncodingJSON: request, err = tr.MarshalJSON() case EncodingProto: request, err = tr.MarshalProto() default: err = fmt.Errorf("invalid encoding: %s", e.config.Encoding) } if err != nil { return consumererror.NewPermanent(err) } return e.export(ctx, e.logsURL, request, e.logsPartialSuccessHandler) } func (e *baseExporter) pushProfiles(ctx context.Context, td pprofile.Profiles) error { tr := pprofileotlp.NewExportRequestFromProfiles(td) var err error var request []byte switch e.config.Encoding { case EncodingJSON: request, err = tr.MarshalJSON() case EncodingProto: request, err = tr.MarshalProto() default: err = fmt.Errorf("invalid encoding: %s", e.config.Encoding) } if err != nil { return consumererror.NewPermanent(err) } return e.export(ctx, e.profilesURL, request, e.profilesPartialSuccessHandler) } func (e *baseExporter) export(ctx context.Context, url string, request []byte, partialSuccessHandler partialSuccessHandler) error { e.logger.Debug("Preparing to make HTTP request", zap.String("url", url)) req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(request)) if err != nil { return consumererror.NewPermanent(err) } switch e.config.Encoding { case EncodingJSON: req.Header.Set("Content-Type", jsonContentType) case EncodingProto: req.Header.Set("Content-Type", protobufContentType) default: return fmt.Errorf("invalid encoding: %s", e.config.Encoding) } req.Header.Set("User-Agent", e.userAgent) resp, err := e.client.Do(req) if err != nil { return fmt.Errorf("failed to make an HTTP request: %w", err) } defer func() { // Discard any remaining response body when we are done reading. _, _ = io.CopyN(io.Discard, resp.Body, maxHTTPResponseReadBytes) resp.Body.Close() }() if resp.StatusCode >= 200 && resp.StatusCode <= 299 { return handlePartialSuccessResponse(resp, partialSuccessHandler) } respStatus := readResponseStatus(resp) // Format the error message. Use the status if it is present in the response. var errString string var formattedErr error if respStatus != nil { errString = fmt.Sprintf( "error exporting items, request to %s responded with HTTP Status Code %d, Message=%s, Details=%v", url, resp.StatusCode, respStatus.Message, respStatus.Details) } else { errString = fmt.Sprintf( "error exporting items, request to %s responded with HTTP Status Code %d", url, resp.StatusCode) } formattedErr = statusutil.NewStatusFromMsgAndHTTPCode(errString, resp.StatusCode).Err() if !isRetryableStatusCode(resp.StatusCode) { return consumererror.NewPermanent(formattedErr) } // Check if the server is overwhelmed. // See spec https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#otlphttp-throttling isThrottleError := resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode == http.StatusServiceUnavailable if isThrottleError { // Use Values to check if the header is present, and if present even if it is empty return ThrottleRetry. values := resp.Header.Values(headerRetryAfter) if len(values) == 0 { return formattedErr } // The value of Retry-After field can be either an HTTP-date or a number of // seconds to delay after the response is received. See https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3 // // Retry-After = HTTP-date / delay-seconds // // First try to parse delay-seconds, since that is what the receiver will send. if seconds, err := strconv.Atoi(values[0]); err == nil { return exporterhelper.NewThrottleRetry(formattedErr, time.Duration(seconds)*time.Second) } if date, err := time.Parse(time.RFC1123, values[0]); err == nil { return exporterhelper.NewThrottleRetry(formattedErr, time.Until(date)) } } return formattedErr } // Determine if the status code is retryable according to the specification. // For more, see https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#failures-1 func isRetryableStatusCode(code int) bool { switch code { case http.StatusTooManyRequests: return true case http.StatusBadGateway: return true case http.StatusServiceUnavailable: return true case http.StatusGatewayTimeout: return true default: return false } } func readResponseBody(resp *http.Response) ([]byte, error) { if resp.ContentLength == 0 { return nil, nil } maxRead := resp.ContentLength // if maxRead == -1, the ContentLength header has not been sent, so read up to // the maximum permitted body size. If it is larger than the permitted body // size, still try to read from the body in case the value is an error. If the // body is larger than the maximum size, proto unmarshaling will likely fail. if maxRead == -1 || maxRead > maxHTTPResponseReadBytes { maxRead = maxHTTPResponseReadBytes } protoBytes := make([]byte, maxRead) n, err := io.ReadFull(resp.Body, protoBytes) // No bytes read and an EOF error indicates there is no body to read. if n == 0 && (err == nil || errors.Is(err, io.EOF)) { return nil, nil } // io.ReadFull will return io.ErrorUnexpectedEOF if the Content-Length header // wasn't set, since we will try to read past the length of the body. If this // is the case, the body will still have the full message in it, so we want to // ignore the error and parse the message. if err != nil && !errors.Is(err, io.ErrUnexpectedEOF) { return nil, err } return protoBytes[:n], nil } // Read the response and decode the status.Status from the body. // Returns nil if the response is empty or cannot be decoded. func readResponseStatus(resp *http.Response) *status.Status { var respStatus *status.Status if resp.StatusCode >= 400 && resp.StatusCode <= 599 { // Request failed. Read the body. OTLP spec says: // "Response body for all HTTP 4xx and HTTP 5xx responses MUST be a // Protobuf-encoded Status message that describes the problem." respBytes, err := readResponseBody(resp) if err != nil { return nil } // Decode it as Status struct. See https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md#failures respStatus = &status.Status{} err = proto.Unmarshal(respBytes, respStatus) if err != nil { return nil } } return respStatus } func handlePartialSuccessResponse(resp *http.Response, partialSuccessHandler partialSuccessHandler) error { bodyBytes, err := readResponseBody(resp) if err != nil { return err } return partialSuccessHandler(bodyBytes, resp.Header.Get("Content-Type")) } type partialSuccessHandler func(bytes []byte, contentType string) error func (e *baseExporter) tracesPartialSuccessHandler(protoBytes []byte, contentType string) error { if protoBytes == nil { return nil } exportResponse := ptraceotlp.NewExportResponse() switch contentType { case protobufContentType: err := exportResponse.UnmarshalProto(protoBytes) if err != nil { return fmt.Errorf("error parsing protobuf response: %w", err) } case jsonContentType: err := exportResponse.UnmarshalJSON(protoBytes) if err != nil { return fmt.Errorf("error parsing json response: %w", err) } default: return nil } partialSuccess := exportResponse.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedSpans() != 0 { e.logger.Warn("Partial success response", zap.String("message", exportResponse.PartialSuccess().ErrorMessage()), zap.Int64("dropped_spans", exportResponse.PartialSuccess().RejectedSpans()), ) } return nil } func (e *baseExporter) metricsPartialSuccessHandler(protoBytes []byte, contentType string) error { if protoBytes == nil { return nil } exportResponse := pmetricotlp.NewExportResponse() switch contentType { case protobufContentType: err := exportResponse.UnmarshalProto(protoBytes) if err != nil { return fmt.Errorf("error parsing protobuf response: %w", err) } case jsonContentType: err := exportResponse.UnmarshalJSON(protoBytes) if err != nil { return fmt.Errorf("error parsing json response: %w", err) } default: return nil } partialSuccess := exportResponse.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedDataPoints() != 0 { e.logger.Warn("Partial success response", zap.String("message", exportResponse.PartialSuccess().ErrorMessage()), zap.Int64("dropped_data_points", exportResponse.PartialSuccess().RejectedDataPoints()), ) } return nil } func (e *baseExporter) logsPartialSuccessHandler(protoBytes []byte, contentType string) error { if protoBytes == nil { return nil } exportResponse := plogotlp.NewExportResponse() switch contentType { case protobufContentType: err := exportResponse.UnmarshalProto(protoBytes) if err != nil { return fmt.Errorf("error parsing protobuf response: %w", err) } case jsonContentType: err := exportResponse.UnmarshalJSON(protoBytes) if err != nil { return fmt.Errorf("error parsing json response: %w", err) } default: return nil } partialSuccess := exportResponse.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedLogRecords() != 0 { e.logger.Warn("Partial success response", zap.String("message", exportResponse.PartialSuccess().ErrorMessage()), zap.Int64("dropped_log_records", exportResponse.PartialSuccess().RejectedLogRecords()), ) } return nil } func (e *baseExporter) profilesPartialSuccessHandler(protoBytes []byte, contentType string) error { if protoBytes == nil { return nil } exportResponse := pprofileotlp.NewExportResponse() switch contentType { case protobufContentType: err := exportResponse.UnmarshalProto(protoBytes) if err != nil { return fmt.Errorf("error parsing protobuf response: %w", err) } case jsonContentType: err := exportResponse.UnmarshalJSON(protoBytes) if err != nil { return fmt.Errorf("error parsing json response: %w", err) } default: return nil } partialSuccess := exportResponse.PartialSuccess() if partialSuccess.ErrorMessage() != "" || partialSuccess.RejectedProfiles() != 0 { e.logger.Warn("Partial success response", zap.String("message", exportResponse.PartialSuccess().ErrorMessage()), zap.Int64("dropped_samples", exportResponse.PartialSuccess().RejectedProfiles()), ) } return nil } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/otlp_test.go000066400000000000000000001056021511331344600264250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlphttpexporter import ( "bytes" "context" "errors" "fmt" "io" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/otlphttpexporter/internal/metadata" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" ) const ( tracesTelemetryType = "traces" metricsTelemetryType = "metrics" logsTelemetryType = "logs" profilesTelemetryType = "profiles" ) type responseSerializer interface { MarshalJSON() ([]byte, error) MarshalProto() ([]byte, error) } type responseSerializerProvider = func() responseSerializer func provideTracesResponseSerializer() responseSerializer { response := ptraceotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedSpans(1) return response } func provideMetricsResponseSerializer() responseSerializer { response := pmetricotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedDataPoints(1) return response } func provideLogsResponseSerializer() responseSerializer { response := plogotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedLogRecords(1) return response } func provideProfilesResponseSerializer() responseSerializer { response := pprofileotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedProfiles(1) return response } func TestErrorResponses(t *testing.T) { errMsgPrefix := func(srv *httptest.Server) string { return fmt.Sprintf("error exporting items, request to %s/v1/traces responded with HTTP Status Code ", srv.URL) } tests := []struct { name string responseStatus int responseBody *status.Status checkErr func(t *testing.T, err error, srv *httptest.Server) headers map[string]string }{ { name: "400", responseStatus: http.StatusBadRequest, responseBody: status.New(codes.InvalidArgument, "Bad field"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "402", responseStatus: http.StatusPaymentRequired, responseBody: status.New(codes.InvalidArgument, "Bad field"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "404", responseStatus: http.StatusNotFound, responseBody: status.New(codes.InvalidArgument, "Bad field"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "405", responseStatus: http.StatusMethodNotAllowed, responseBody: status.New(codes.InvalidArgument, "Bad field"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "413", responseStatus: http.StatusRequestEntityTooLarge, responseBody: status.New(codes.InvalidArgument, "Bad field"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "414", responseStatus: http.StatusRequestURITooLong, responseBody: status.New(codes.InvalidArgument, "Bad field"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "431", responseStatus: http.StatusRequestHeaderFieldsTooLarge, responseBody: status.New(codes.InvalidArgument, "Bad field"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "429", responseStatus: http.StatusTooManyRequests, responseBody: status.New(codes.ResourceExhausted, "Quota exceeded"), checkErr: func(t *testing.T, err error, srv *httptest.Server) { require.EqualError(t, err, status.New(codes.ResourceExhausted, errMsgPrefix(srv)+"429, Message=Quota exceeded, Details=[]").String()) }, }, { name: "429-Retry-After", responseStatus: http.StatusTooManyRequests, responseBody: status.New(codes.InvalidArgument, "Quota exceeded"), headers: map[string]string{"Retry-After": "Mon, 09 Feb 2025 15:04:05 GMT"}, checkErr: func(t *testing.T, err error, srv *httptest.Server) { // Cannot test for the delay part since it depends on now. Check first part (which has a negative duration) and last part: require.ErrorContains(t, err, "Throttle (-") require.ErrorContains(t, err, "), error: "+status.New(codes.ResourceExhausted, errMsgPrefix(srv)+"429, Message=Quota exceeded, Details=[]").String()) }, }, { name: "429-Retry-After-Malformed", responseStatus: http.StatusTooManyRequests, responseBody: status.New(codes.InvalidArgument, "Quota exceeded"), headers: map[string]string{"Retry-After": "Malformed"}, checkErr: func(t *testing.T, err error, srv *httptest.Server) { // Cannot test for the delay part since it depends on now. Check first part (which has a negative duration) and last part: require.EqualError(t, err, status.New(codes.ResourceExhausted, errMsgPrefix(srv)+"429, Message=Quota exceeded, Details=[]").String()) }, }, { name: "500", responseStatus: http.StatusInternalServerError, responseBody: status.New(codes.InvalidArgument, "Internal server error"), checkErr: func(t *testing.T, err error, _ *httptest.Server) { assert.True(t, consumererror.IsPermanent(err)) }, }, { name: "502", responseStatus: http.StatusBadGateway, responseBody: status.New(codes.InvalidArgument, "Bad gateway"), checkErr: func(t *testing.T, err error, srv *httptest.Server) { require.EqualError(t, err, status.New(codes.Unavailable, errMsgPrefix(srv)+"502, Message=Bad gateway, Details=[]").String()) }, }, { name: "503", responseStatus: http.StatusServiceUnavailable, responseBody: status.New(codes.InvalidArgument, "Server overloaded"), checkErr: func(t *testing.T, err error, srv *httptest.Server) { require.EqualError(t, err, status.New(codes.Unavailable, errMsgPrefix(srv)+"503, Message=Server overloaded, Details=[]").String()) }, }, { name: "503-Retry-After", responseStatus: http.StatusServiceUnavailable, responseBody: status.New(codes.InvalidArgument, "Server overloaded"), headers: map[string]string{"Retry-After": "30"}, checkErr: func(t *testing.T, err error, srv *httptest.Server) { require.EqualError(t, err, exporterhelper.NewThrottleRetry( status.New(codes.Unavailable, errMsgPrefix(srv)+"503, Message=Server overloaded, Details=[]").Err(), time.Duration(30)*time.Second).Error()) }, }, { name: "504", responseStatus: http.StatusGatewayTimeout, responseBody: status.New(codes.InvalidArgument, "Gateway timeout"), checkErr: func(t *testing.T, err error, srv *httptest.Server) { require.EqualError(t, err, status.New(codes.Unavailable, errMsgPrefix(srv)+"504, Message=Gateway timeout, Details=[]").String()) }, }, { name: "Bad response payload", responseStatus: http.StatusServiceUnavailable, responseBody: status.New(codes.InvalidArgument, strings.Repeat("a", maxHTTPResponseReadBytes+1)), checkErr: func(t *testing.T, err error, srv *httptest.Server) { require.EqualError(t, err, status.New(codes.Unavailable, errMsgPrefix(srv)+"503").String()) }, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { srv := createBackend("/v1/traces", func(writer http.ResponseWriter, _ *http.Request) { for k, v := range test.headers { writer.Header().Add(k, v) } writer.WriteHeader(test.responseStatus) if test.responseBody != nil { msg, err := proto.Marshal(test.responseBody.Proto()) assert.NoError(t, err) _, err = writer.Write(msg) assert.NoError(t, err) } }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, TracesEndpoint: srv.URL + "/v1/traces", // Create without QueueConfig and RetryConfig so that ConsumeTraces // returns the errors that we want to check immediately. } exp, err := createTraces(context.Background(), exportertest.NewNopSettings(metadata.Type), cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate traces traces := ptrace.NewTraces() err = exp.ConsumeTraces(context.Background(), traces) require.Error(t, err) test.checkErr(t, err, srv) }) } } func TestErrorResponseInvalidResponseBody(t *testing.T) { resp := &http.Response{ StatusCode: http.StatusBadRequest, Body: io.NopCloser(badReader{}), ContentLength: 100, } assert.Nil(t, readResponseStatus(resp)) } func TestUserAgent(t *testing.T) { set := exportertest.NewNopSettings(metadata.Type) set.BuildInfo.Description = "Collector" set.BuildInfo.Version = "1.2.3test" tests := []struct { name string headers configopaque.MapList expectedUA string }{ { name: "default_user_agent", expectedUA: "Collector/1.2.3test", }, { name: "custom_user_agent", headers: configopaque.MapList{{Name: "User-Agent", Value: "My Custom Agent"}}, expectedUA: "My Custom Agent", }, { name: "custom_user_agent_lowercase", headers: configopaque.MapList{{Name: "user-agent", Value: "My Custom Agent"}}, expectedUA: "My Custom Agent", }, } t.Run("traces", func(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srv := createBackend("/v1/traces", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("user-agent"), tt.expectedUA) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, TracesEndpoint: srv.URL + "/v1/traces", ClientConfig: confighttp.ClientConfig{ Headers: tt.headers, }, } exp, err := createTraces(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data traces := ptrace.NewTraces() err = exp.ConsumeTraces(context.Background(), traces) require.NoError(t, err) }) } }) t.Run("metrics", func(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srv := createBackend("/v1/metrics", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("user-agent"), tt.expectedUA) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, MetricsEndpoint: srv.URL + "/v1/metrics", ClientConfig: confighttp.ClientConfig{ Headers: tt.headers, }, } exp, err := createMetrics(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data metrics := pmetric.NewMetrics() err = exp.ConsumeMetrics(context.Background(), metrics) require.NoError(t, err) }) } }) t.Run("logs", func(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srv := createBackend("/v1/logs", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("user-agent"), tt.expectedUA) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, LogsEndpoint: srv.URL + "/v1/logs", ClientConfig: confighttp.ClientConfig{ Headers: tt.headers, }, } exp, err := createLogs(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data logs := plog.NewLogs() err = exp.ConsumeLogs(context.Background(), logs) require.NoError(t, err) srv.Close() }) } }) t.Run("profiles", func(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { srv := createBackend("/v1development/profiles", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("user-agent"), test.expectedUA) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, ClientConfig: confighttp.ClientConfig{ Endpoint: srv.URL, Headers: test.headers, }, } exp, err := createProfiles(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data profiles := pprofile.NewProfiles() err = exp.ConsumeProfiles(context.Background(), profiles) require.NoError(t, err) }) } }) } func TestPartialSuccessInvalidBody(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) exp, err := newExporter(cfg, set) require.NoError(t, err) invalidBodyCases := []struct { telemetryType string handler partialSuccessHandler }{ { telemetryType: "traces", handler: exp.tracesPartialSuccessHandler, }, { telemetryType: "metrics", handler: exp.metricsPartialSuccessHandler, }, { telemetryType: "logs", handler: exp.logsPartialSuccessHandler, }, { telemetryType: "profiles", handler: exp.profilesPartialSuccessHandler, }, } for _, tt := range invalidBodyCases { t.Run("Invalid response body_"+tt.telemetryType, func(t *testing.T) { err := tt.handler([]byte{1}, "application/x-protobuf") assert.ErrorContains(t, err, "error parsing protobuf response:") }) } } func TestPartialSuccessUnsupportedContentType(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) exp, err := newExporter(cfg, set) require.NoError(t, err) unsupportedContentTypeCases := []struct { contentType string }{ { contentType: "text/plain", }, { contentType: "application/octet-stream", }, } for _, telemetryType := range []string{"logs", "metrics", "traces", "profiles"} { for _, tt := range unsupportedContentTypeCases { t.Run("Unsupported content type "+tt.contentType+" "+telemetryType, func(t *testing.T) { var handler func(b []byte, contentType string) error switch telemetryType { case "logs": handler = exp.logsPartialSuccessHandler case "metrics": handler = exp.metricsPartialSuccessHandler case "traces": handler = exp.tracesPartialSuccessHandler case "profiles": handler = exp.profilesPartialSuccessHandler default: panic(telemetryType) } exportResponse := ptraceotlp.NewExportResponse() exportResponse.PartialSuccess().SetErrorMessage("foo") exportResponse.PartialSuccess().SetRejectedSpans(42) b, err := exportResponse.MarshalProto() require.NoError(t, err) err = handler(b, tt.contentType) assert.NoError(t, err) }) } } } func TestPartialSuccess_logs(t *testing.T) { srv := createBackend("/v1/logs", func(writer http.ResponseWriter, _ *http.Request) { response := plogotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedLogRecords(1) b, err := response.MarshalProto() assert.NoError(t, err) writer.Header().Set("Content-Type", "application/x-protobuf") _, err = writer.Write(b) assert.NoError(t, err) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, LogsEndpoint: srv.URL + "/v1/logs", ClientConfig: confighttp.ClientConfig{}, } set := exportertest.NewNopSettings(metadata.Type) logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := createLogs(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data logs := plog.NewLogs() err = exp.ConsumeLogs(context.Background(), logs) require.NoError(t, err) require.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) require.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestPartialResponse_missingHeaderButHasBody(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) exp, err := newExporter(cfg, set) require.NoError(t, err) contentTypes := []struct { contentType string }{ {contentType: protobufContentType}, {contentType: jsonContentType}, } telemetryTypes := []struct { telemetryType string handler partialSuccessHandler serializer responseSerializerProvider }{ { telemetryType: tracesTelemetryType, handler: exp.tracesPartialSuccessHandler, serializer: provideTracesResponseSerializer, }, { telemetryType: metricsTelemetryType, handler: exp.metricsPartialSuccessHandler, serializer: provideMetricsResponseSerializer, }, { telemetryType: logsTelemetryType, handler: exp.logsPartialSuccessHandler, serializer: provideLogsResponseSerializer, }, { telemetryType: profilesTelemetryType, handler: exp.profilesPartialSuccessHandler, serializer: provideProfilesResponseSerializer, }, } for _, ct := range contentTypes { for _, tt := range telemetryTypes { t.Run(tt.telemetryType+" "+ct.contentType, func(t *testing.T) { serializer := tt.serializer() var data []byte var err error switch ct.contentType { case jsonContentType: data, err = serializer.MarshalJSON() case protobufContentType: data, err = serializer.MarshalProto() default: require.Failf(t, "unsupported content type: %s", ct.contentType) } require.NoError(t, err) resp := &http.Response{ // `-1` indicates a missing Content-Length header in the Go http standard library ContentLength: -1, Body: io.NopCloser(bytes.NewReader(data)), Header: map[string][]string{ "Content-Type": {ct.contentType}, }, } err = handlePartialSuccessResponse(resp, tt.handler) assert.NoError(t, err) }) } } } func TestPartialResponse_missingHeaderAndBody(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) exp, err := newExporter(cfg, set) require.NoError(t, err) contentTypes := []struct { contentType string }{ {contentType: protobufContentType}, {contentType: jsonContentType}, } telemetryTypes := []struct { telemetryType string handler partialSuccessHandler }{ { telemetryType: tracesTelemetryType, handler: exp.tracesPartialSuccessHandler, }, { telemetryType: metricsTelemetryType, handler: exp.metricsPartialSuccessHandler, }, { telemetryType: logsTelemetryType, handler: exp.logsPartialSuccessHandler, }, { telemetryType: profilesTelemetryType, handler: exp.profilesPartialSuccessHandler, }, } for _, ct := range contentTypes { for _, tt := range telemetryTypes { t.Run(tt.telemetryType+" "+ct.contentType, func(t *testing.T) { resp := &http.Response{ // `-1` indicates a missing Content-Length header in the Go http standard library ContentLength: -1, Body: io.NopCloser(bytes.NewReader([]byte{})), Header: map[string][]string{ "Content-Type": {ct.contentType}, }, } err = handlePartialSuccessResponse(resp, tt.handler) assert.NoError(t, err) }) } } } func TestPartialResponse_nonErrUnexpectedEOFError(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) exp, err := newExporter(cfg, set) require.NoError(t, err) resp := &http.Response{ // `-1` indicates a missing Content-Length header in the Go http standard library ContentLength: -1, Body: io.NopCloser(badReader{}), } err = handlePartialSuccessResponse(resp, exp.tracesPartialSuccessHandler) assert.Error(t, err) } func TestPartialSuccess_shortContentLengthHeader(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) exp, err := newExporter(cfg, set) require.NoError(t, err) contentTypes := []struct { contentType string }{ {contentType: protobufContentType}, {contentType: jsonContentType}, } telemetryTypes := []struct { telemetryType string handler partialSuccessHandler serializer responseSerializerProvider }{ { telemetryType: tracesTelemetryType, handler: exp.tracesPartialSuccessHandler, serializer: provideTracesResponseSerializer, }, { telemetryType: metricsTelemetryType, handler: exp.metricsPartialSuccessHandler, serializer: provideMetricsResponseSerializer, }, { telemetryType: logsTelemetryType, handler: exp.logsPartialSuccessHandler, serializer: provideLogsResponseSerializer, }, { telemetryType: profilesTelemetryType, handler: exp.profilesPartialSuccessHandler, serializer: provideProfilesResponseSerializer, }, } for _, ct := range contentTypes { for _, tt := range telemetryTypes { t.Run(tt.telemetryType+" "+ct.contentType, func(t *testing.T) { serializer := tt.serializer() var data []byte var err error switch ct.contentType { case jsonContentType: data, err = serializer.MarshalJSON() case protobufContentType: data, err = serializer.MarshalProto() default: require.Failf(t, "unsupported content type: %s", ct.contentType) } require.NoError(t, err) resp := &http.Response{ ContentLength: 3, Body: io.NopCloser(bytes.NewReader(data)), Header: map[string][]string{ "Content-Type": {ct.contentType}, }, } // For short content-length, a real error happens. err = handlePartialSuccessResponse(resp, tt.handler) assert.Error(t, err) }) } } } func TestPartialSuccess_longContentLengthHeader(t *testing.T) { contentTypes := []struct { contentType string }{ {contentType: protobufContentType}, {contentType: jsonContentType}, } telemetryTypes := []struct { telemetryType string serializer responseSerializerProvider }{ { telemetryType: tracesTelemetryType, serializer: provideTracesResponseSerializer, }, { telemetryType: metricsTelemetryType, serializer: provideMetricsResponseSerializer, }, { telemetryType: logsTelemetryType, serializer: provideLogsResponseSerializer, }, { telemetryType: profilesTelemetryType, serializer: provideProfilesResponseSerializer, }, } for _, ct := range contentTypes { for _, tt := range telemetryTypes { t.Run(tt.telemetryType+" "+ct.contentType, func(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := newExporter(cfg, set) require.NoError(t, err) serializer := tt.serializer() var handler partialSuccessHandler switch tt.telemetryType { case tracesTelemetryType: handler = exp.tracesPartialSuccessHandler case metricsTelemetryType: handler = exp.metricsPartialSuccessHandler case logsTelemetryType: handler = exp.logsPartialSuccessHandler case profilesTelemetryType: handler = exp.profilesPartialSuccessHandler default: require.Failf(t, "unsupported telemetry type: %s", ct.contentType) } var data []byte switch ct.contentType { case jsonContentType: data, err = serializer.MarshalJSON() case protobufContentType: data, err = serializer.MarshalProto() default: require.Failf(t, "unsupported content type: %s", ct.contentType) } require.NoError(t, err) resp := &http.Response{ ContentLength: 4096, Body: io.NopCloser(bytes.NewReader(data)), Header: map[string][]string{ "Content-Type": {ct.contentType}, }, } // No real error happens for long content length, so the partial // success is handled as success with a warning. err = handlePartialSuccessResponse(resp, handler) require.NoError(t, err) assert.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) assert.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") }) } } } func TestPartialSuccessInvalidResponseBody(t *testing.T) { cfg := createDefaultConfig() set := exportertest.NewNopSettings(metadata.Type) exp, err := newExporter(cfg, set) require.NoError(t, err) resp := &http.Response{ Body: io.NopCloser(badReader{}), ContentLength: 100, Header: map[string][]string{ "Content-Type": {protobufContentType}, }, } err = handlePartialSuccessResponse(resp, exp.tracesPartialSuccessHandler) assert.Error(t, err) } func TestPartialSuccess_traces(t *testing.T) { srv := createBackend("/v1/traces", func(writer http.ResponseWriter, _ *http.Request) { response := ptraceotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedSpans(1) bytes, err := response.MarshalProto() assert.NoError(t, err) writer.Header().Set("Content-Type", "application/x-protobuf") _, err = writer.Write(bytes) assert.NoError(t, err) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, TracesEndpoint: srv.URL + "/v1/traces", ClientConfig: confighttp.ClientConfig{}, } set := exportertest.NewNopSettings(metadata.Type) logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := createTraces(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data traces := ptrace.NewTraces() err = exp.ConsumeTraces(context.Background(), traces) require.NoError(t, err) require.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) require.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestPartialSuccess_metrics(t *testing.T) { srv := createBackend("/v1/metrics", func(writer http.ResponseWriter, _ *http.Request) { response := pmetricotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedDataPoints(1) bytes, err := response.MarshalProto() assert.NoError(t, err) writer.Header().Set("Content-Type", "application/x-protobuf") _, err = writer.Write(bytes) assert.NoError(t, err) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, MetricsEndpoint: srv.URL + "/v1/metrics", ClientConfig: confighttp.ClientConfig{}, } set := exportertest.NewNopSettings(metadata.Type) logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := createMetrics(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data metrics := pmetric.NewMetrics() err = exp.ConsumeMetrics(context.Background(), metrics) require.NoError(t, err) require.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) require.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestPartialSuccess_profiles(t *testing.T) { srv := createBackend("/v1development/profiles", func(writer http.ResponseWriter, _ *http.Request) { response := pprofileotlp.NewExportResponse() partial := response.PartialSuccess() partial.SetErrorMessage("hello") partial.SetRejectedProfiles(1) bytes, err := response.MarshalProto() assert.NoError(t, err) writer.Header().Set("Content-Type", "application/x-protobuf") _, err = writer.Write(bytes) assert.NoError(t, err) }) defer srv.Close() cfg := &Config{ Encoding: EncodingProto, ClientConfig: confighttp.ClientConfig{ Endpoint: srv.URL, }, } set := exportertest.NewNopSettings(metadata.Type) logger, observed := observer.New(zap.DebugLevel) set.Logger = zap.New(logger) exp, err := createProfiles(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data profiles := pprofile.NewProfiles() err = exp.ConsumeProfiles(context.Background(), profiles) require.NoError(t, err) require.Len(t, observed.FilterLevelExact(zap.WarnLevel).All(), 1) require.Contains(t, observed.FilterLevelExact(zap.WarnLevel).All()[0].Message, "Partial success") } func TestEncoding(t *testing.T) { set := exportertest.NewNopSettings(metadata.Type) set.BuildInfo.Description = "Collector" set.BuildInfo.Version = "1.2.3test" tests := []struct { name string encoding EncodingType expectedEncoding EncodingType }{ { name: "proto_encoding", encoding: EncodingProto, expectedEncoding: "application/x-protobuf", }, { name: "json_encoding", encoding: EncodingJSON, expectedEncoding: "application/json", }, } t.Run("traces", func(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srv := createBackend("/v1/traces", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("content-type"), tt.expectedEncoding) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ TracesEndpoint: srv.URL + "/v1/traces", Encoding: tt.encoding, } exp, err := createTraces(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data traces := ptrace.NewTraces() err = exp.ConsumeTraces(context.Background(), traces) require.NoError(t, err) }) } }) t.Run("metrics", func(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srv := createBackend("/v1/metrics", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("content-type"), tt.expectedEncoding) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ MetricsEndpoint: srv.URL + "/v1/metrics", Encoding: tt.encoding, } exp, err := createMetrics(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data metrics := pmetric.NewMetrics() err = exp.ConsumeMetrics(context.Background(), metrics) require.NoError(t, err) }) } }) t.Run("logs", func(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { srv := createBackend("/v1/logs", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("content-type"), tt.expectedEncoding) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ LogsEndpoint: srv.URL + "/v1/logs", Encoding: tt.encoding, } exp, err := createLogs(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data logs := plog.NewLogs() err = exp.ConsumeLogs(context.Background(), logs) require.NoError(t, err) srv.Close() }) } }) t.Run("profiles", func(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { srv := createBackend("/v1development/profiles", func(writer http.ResponseWriter, request *http.Request) { assert.Contains(t, request.Header.Get("content-type"), test.expectedEncoding) writer.WriteHeader(http.StatusOK) }) defer srv.Close() cfg := &Config{ ClientConfig: confighttp.ClientConfig{ Endpoint: srv.URL, }, Encoding: test.encoding, } exp, err := createProfiles(context.Background(), set, cfg) require.NoError(t, err) // start the exporter err = exp.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, exp.Shutdown(context.Background())) }) // generate data profiles := pprofile.NewProfiles() err = exp.ConsumeProfiles(context.Background(), profiles) require.NoError(t, err) }) } }) } func createBackend(endpoint string, handler func(writer http.ResponseWriter, request *http.Request)) *httptest.Server { mux := http.NewServeMux() mux.HandleFunc(endpoint, handler) srv := httptest.NewServer(mux) return srv } type badReader struct{} func (b badReader) Read([]byte) (int, error) { return 0, errors.New("Bad read") } opentelemetry-collector-0.141.0/exporter/otlphttpexporter/testdata/000077500000000000000000000000001511331344600256665ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/otlphttpexporter/testdata/bad_empty_config.yaml000066400000000000000000000002541511331344600320440ustar00rootroot00000000000000receivers: nop: processors: nop: exporters: otlphttp: service: pipelines: traces: receivers: [nop] processors: [nop] exporters: [otlphttp] opentelemetry-collector-0.141.0/exporter/otlphttpexporter/testdata/bad_invalid_encoding.yaml000066400000000000000000000000221511331344600326460ustar00rootroot00000000000000encoding: invalid opentelemetry-collector-0.141.0/exporter/otlphttpexporter/testdata/config.yaml000066400000000000000000000011511511331344600300150ustar00rootroot00000000000000endpoint: "https://1.2.3.4:1234" tls: ca_file: /var/lib/mycert.pem cert_file: certfile key_file: keyfile insecure: true timeout: 10s read_buffer_size: 123 write_buffer_size: 345 sending_queue: enabled: true num_consumers: 2 queue_size: 10 retry_on_failure: enabled: true initial_interval: 10s randomization_factor: 0.7 multiplier: 1.3 max_interval: 60s max_elapsed_time: 10m headers: "can you have a . here?": "F0000000-0000-0000-0000-000000000000" header1: "234" another: "somevalue" compression: gzip profiles_endpoint: "https://custom.profiles.endpoint:8080/v1development/profiles" opentelemetry-collector-0.141.0/exporter/otlphttpexporter/testdata/test_cert.pem000066400000000000000000000033451511331344600303720ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIE6jCCAtICCQDVU4PtqpqADTANBgkqhkiG9w0BAQsFADA3MQswCQYDVQQGEwJV UzETMBEGA1UECAwKY2FsaWZvcm5pYTETMBEGA1UECgwKb3BlbmNlbnN1czAeFw0x OTAzMDQxODA3MjZaFw0yMDAzMDMxODA3MjZaMDcxCzAJBgNVBAYTAlVTMRMwEQYD VQQIDApjYWxpZm9ybmlhMRMwEQYDVQQKDApvcGVuY2Vuc3VzMIICIjANBgkqhkiG 9w0BAQEFAAOCAg8AMIICCgKCAgEAy9JQiAOMzArcdiS4szbTuzg5yYijSSY6SvGj XMs4/LEFLxgGmFfyHXxoVQzV26lTu/AiUFlZi4JY2qlkZyPwmmmSg4fmzikpVPiC Vv9pvSIojs8gs0sHaOt40Q8ym43bNt3Mh8rYrs+XMERi6Ol9//j4LnfePkNU5uEo qC8KQamckaMR6UEHFNunyOwvNBsipgTPldQUPGVnCsNKk8olYGAXS7DR25bgbPli 4T9VCSElsSPAODmyo+2MEDagVXa1vVYxKyO2k6oeBS0lsvdRqRTmGggcg0B/dk+a H1CL9ful0cu9P3dQif+hfGay8udPkwDLPEq1+WnjJFut3Pmbk3SqUCas5iWt76kK eKFh4k8fCy4yiaZxzvSbm9+bEBHAl0ZXd8pjvAsBfCKe6G9SBzE1DK4FjWiiEGCb 5dGsyTKr33q3DekLvT3LF8ZeON/13d9toucX9PqG2HDwMP/Fb4WjQIzOc/H9wIak pf7u6QBDGUiCMmoDrp1d8RsI1RPbEhoywH0YlLmwgf+cr1dU7vlISf576EsGxFz4 +/sZjIBvZBHn/x0MH+bs4J8V3vMujfDoRdhL07bK7q/AkEALUxljKEfoWeqiuVzK F9BVv3xNhiua2kgPVbMNWPrQ5uotkNp8IykJ3QOuQ3p5pzxdGfpLd6f8gmJDmcbi AI9dWTcCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAVVi4t/Sumre+AGTaU7np9dl2 tpllbES5ixe6m2uezt5wAzYNNyuQ2mMG2XrSkMy5gvBZRT9nRNSmLV8VEcxZihG0 YHS5soXnLL3Jdlwxp98WTDPvM1ntxcHyEyqrrg9YDfKn4sOrr5vo2yZzoKwtxtc7 lue9JormVx7GxMi7NwaUtCbnwAIcqJJpFjt1EhmJOxGqTJPgUvTBdeGvRj30c6fk pqpUdPbZ7RKPEtbLoMoCBujKnErv+H0G6Vp9WyCHN+Mi9uTMsGwH14cmJjmfwGDC 8/WF4LdlawFnf/arIp9YcVwcP91d4ywyvbuuo2M7qdosQ7k4uRZ3tyggLYShS3RW BMEhMRDz9dM0oKGF+HnaS824BIh6O6Hn82Vt8uCKS7IbEX99/kkN1KcqqQe6Lwjq tG/lm4K5yf+FJVDivpZ9mYTvqTBjhTaOp6m3HYSNJfS0hLQVvEuBNXd8bHiXkcLp rmFOYUWsjxV1Qku3U5Rner0UpB2Fuw9nJcXuDgWG0gjwzAZ83y3du1VIZp0Ad8Vv IYpaucbImGJszMtNXn3l72K1wvQVIhm9eRwYc3QteJzweHaDsbytZEoS/GhTrZIT wRe5ZGrjJBJngRANRSm1BH8j6PjLem9mzPb2eytwJJA0lLhUk4vYproVvXcx0vow 5F+5VB1YB8/tbWePmpo= -----END CERTIFICATE----- opentelemetry-collector-0.141.0/exporter/package_test.go000066400000000000000000000003111511331344600233620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package exporter import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/exporter/xexporter/000077500000000000000000000000001511331344600224465ustar00rootroot00000000000000opentelemetry-collector-0.141.0/exporter/xexporter/Makefile000066400000000000000000000000361511331344600241050ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/exporter/xexporter/exporter.go000066400000000000000000000075621511331344600246570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporter // import "go.opentelemetry.io/collector/exporter/xexporter" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/internal/experr" "go.opentelemetry.io/collector/pipeline" ) // Profiles is an exporter that can consume profiles. type Profiles interface { component.Component xconsumer.Profiles } type Factory interface { exporter.Factory // CreateProfiles creates a Profiles exporter based on this config. // If the exporter type does not support tracing, // this function returns the error [pipeline.ErrSignalNotSupported]. CreateProfiles(ctx context.Context, set exporter.Settings, cfg component.Config) (Profiles, error) // ProfilesStability gets the stability level of the Profiles exporter. ProfilesStability() component.StabilityLevel } // FactoryOption apply changes to ReceiverOptions. type FactoryOption interface { // applyOption applies the option. applyOption(o *factoryOpts) } // factoryOptionFunc is an ReceiverFactoryOption created through a function. type factoryOptionFunc func(*factoryOpts) func (f factoryOptionFunc) applyOption(o *factoryOpts) { f(o) } type factoryOpts struct { opts []exporter.FactoryOption *factory } // CreateProfilesFunc is the equivalent of Factory.CreateProfiles. type CreateProfilesFunc func(context.Context, exporter.Settings, component.Config) (Profiles, error) // WithTraces overrides the default "error not supported" implementation for CreateTraces and the default "undefined" stability level. func WithTraces(createTraces exporter.CreateTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, exporter.WithTraces(createTraces, sl)) }) } // WithMetrics overrides the default "error not supported" implementation for CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics exporter.CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, exporter.WithMetrics(createMetrics, sl)) }) } // WithLogs overrides the default "error not supported" implementation for CreateLogs and the default "undefined" stability level. func WithLogs(createLogs exporter.CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, exporter.WithLogs(createLogs, sl)) }) } // WithProfiles overrides the default "error not supported" implementation for CreateProfilesExporter and the default "undefined" stability level. func WithProfiles(createProfiles CreateProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesStabilityLevel = sl o.createProfilesFunc = createProfiles }) } type factory struct { exporter.Factory createProfilesFunc CreateProfilesFunc profilesStabilityLevel component.StabilityLevel } func (f *factory) ProfilesStability() component.StabilityLevel { return f.profilesStabilityLevel } func (f *factory) CreateProfiles(ctx context.Context, set exporter.Settings, cfg component.Config) (Profiles, error) { if f.createProfilesFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, experr.ErrIDMismatch(set.ID, f.Type()) } return f.createProfilesFunc(ctx, set, cfg) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { opts := factoryOpts{factory: &factory{}} for _, opt := range options { opt.applyOption(&opts) } opts.Factory = exporter.NewFactory(cfgType, createDefaultConfig, opts.opts...) return opts.factory } opentelemetry-collector-0.141.0/exporter/xexporter/exporter_test.go000066400000000000000000000031271511331344600257070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xexporter import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/internal/experr" ) var testID = component.MustNewID("test") func TestNewFactoryWithProfiles(t *testing.T) { testType := component.MustNewType("test") defaultCfg := struct{}{} factory := NewFactory( testType, func() component.Config { return &defaultCfg }, WithProfiles(createProfiles, component.StabilityLevelDevelopment), ) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelDevelopment, factory.ProfilesStability()) _, err := factory.CreateProfiles(context.Background(), exporter.Settings{ID: testID}, &defaultCfg) require.NoError(t, err) wrongID := component.MustNewID("wrong") wrongIDErrStr := experr.ErrIDMismatch(wrongID, testType).Error() _, err = factory.CreateProfiles(context.Background(), exporter.Settings{ID: wrongID}, &defaultCfg) assert.EqualError(t, err, wrongIDErrStr) } var nopInstance = &nop{ Consumer: consumertest.NewNop(), } // nop stores consumed profiles for testing purposes. type nop struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createProfiles(context.Context, exporter.Settings, component.Config) (Profiles, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/exporter/xexporter/go.mod000066400000000000000000000064711511331344600235640ustar00rootroot00000000000000module go.opentelemetry.io/collector/exporter/xexporter go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/consumer v1.47.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/exporter => ../ replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/exporter/xexporter/go.sum000066400000000000000000000166371511331344600236160ustar00rootroot00000000000000github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/exporter/xexporter/metadata.yaml000066400000000000000000000003361511331344600251140ustar00rootroot00000000000000type: xexporter github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg codeowners: active: - mx-psi - dmathieu stability: development: [profiles] opentelemetry-collector-0.141.0/extension/000077500000000000000000000000001511331344600205525ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/Makefile000066400000000000000000000000331511331344600222060ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/extension/README.md000066400000000000000000000024701511331344600220340ustar00rootroot00000000000000# General Information Extensions provide capabilities on top of the primary functionality of the collector. Generally, extensions are used for implementing components that can be added to the Collector, but which do not require direct access to telemetry data and are not part of the pipelines (like receivers, processors or exporters). Example extensions are: Memory Limiter extension that prevents out of memory situations or zPages extension that provides live data for debugging different components. Supported service extensions (sorted alphabetically): - [Memory Limiter](memorylimiterextension/README.md) - [zPages](zpagesextension/README.md) The [contributors repository](https://github.com/open-telemetry/opentelemetry-collector-contrib) may have more extensions that can be added to custom builds of the Collector. ## Ordering Extensions The order extensions are specified for the service is important as this is the order in which each extension will be started and the reverse order in which they will be shutdown. The ordering is determined in the `extensions` tag under the `service` tag in the configuration file, example: ```yaml service: # Extensions specified below are going to be loaded by the service in the # order given below, and shutdown on reverse order. extensions: [extension1, extension2] ``` opentelemetry-collector-0.141.0/extension/extension.go000066400000000000000000000045171511331344600231240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extension // import "go.opentelemetry.io/collector/extension" import ( "context" "fmt" "go.opentelemetry.io/collector/component" ) // Extension is the interface for objects hosted by the OpenTelemetry Collector that // don't participate directly on data pipelines but provide some functionality // to the service, examples: health check endpoint, z-pages, etc. type Extension interface { component.Component } // Settings is passed to Factory.Create(...) function. type Settings struct { // ID returns the ID of the component that will be created. ID component.ID component.TelemetrySettings // BuildInfo can be used by components for informational purposes BuildInfo component.BuildInfo // prevent unkeyed literal initialization _ struct{} } // CreateFunc is the equivalent of Factory.Create(...) function. type CreateFunc func(context.Context, Settings, component.Config) (Extension, error) type Factory interface { component.Factory // Create an extension based on the given config. Create(ctx context.Context, set Settings, cfg component.Config) (Extension, error) // Stability gets the stability level of the Extension. Stability() component.StabilityLevel unexportedFactoryFunc() } type factory struct { cfgType component.Type component.CreateDefaultConfigFunc createFunc CreateFunc extensionStability component.StabilityLevel } func (f *factory) Type() component.Type { return f.cfgType } func (f *factory) unexportedFactoryFunc() {} func (f *factory) Stability() component.StabilityLevel { return f.extensionStability } func (f *factory) Create(ctx context.Context, set Settings, cfg component.Config) (Extension, error) { if set.ID.Type() != f.cfgType { return nil, fmt.Errorf("component type mismatch: component ID %q does not have type %q", set.ID, f.cfgType) } return f.createFunc(ctx, set, cfg) } // NewFactory returns a new Factory based on this configuration. func NewFactory( cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, createServiceExtension CreateFunc, sl component.StabilityLevel, ) Factory { return &factory{ cfgType: cfgType, CreateDefaultConfigFunc: createDefaultConfig, createFunc: createServiceExtension, extensionStability: sl, } } opentelemetry-collector-0.141.0/extension/extension_test.go000066400000000000000000000023251511331344600241560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extension import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" ) type nopExtension struct { component.StartFunc component.ShutdownFunc Settings } func TestNewFactory(t *testing.T) { testType := component.MustNewType("test") defaultCfg := struct{}{} nopExtensionInstance := new(nopExtension) factory := NewFactory( testType, func() component.Config { return &defaultCfg }, func(context.Context, Settings, component.Config) (Extension, error) { return nopExtensionInstance, nil }, component.StabilityLevelDevelopment) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelDevelopment, factory.Stability()) ext, err := factory.Create(context.Background(), Settings{ID: component.NewID(testType)}, &defaultCfg) require.NoError(t, err) assert.Same(t, nopExtensionInstance, ext) _, err = factory.Create(context.Background(), Settings{ID: component.NewID(component.MustNewType("mismatch"))}, &defaultCfg) require.Error(t, err) } opentelemetry-collector-0.141.0/extension/extensionauth/000077500000000000000000000000001511331344600234505ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/extensionauth/Makefile000066400000000000000000000000361511331344600251070ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/extension/extensionauth/client.go000066400000000000000000000037331511331344600252630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauth // import "go.opentelemetry.io/collector/extension/extensionauth" import ( "net/http" "google.golang.org/grpc/credentials" ) // HTTPClient is an optional Extension interface that can be used as an HTTP authenticator for the configauth.Config option. // Authenticators are then included as part of OpenTelemetry Collector builds and can be referenced by their // names from the [configauth.Config] configuration. type HTTPClient interface { // RoundTripper returns a RoundTripper that can be used to authenticate HTTP requests. RoundTripper(base http.RoundTripper) (http.RoundTripper, error) } // GRPCClient is an optional Extension interface that can be used as a gRPC authenticator for the configauth.Config option. // Authenticators are then included as part of OpenTelemetry Collector builds and can be referenced by their // names from the [configauth.Config] configuration. type GRPCClient interface { // PerRPCCredentials returns a PerRPCCredentials that can be used to authenticate gRPC requests. PerRPCCredentials() (credentials.PerRPCCredentials, error) } var _ HTTPClient = (*ClientRoundTripperFunc)(nil) // ClientRoundTripperFunc specifies the function that returns a RoundTripper that can be used to authenticate HTTP requests. type ClientRoundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error) func (f ClientRoundTripperFunc) RoundTripper(base http.RoundTripper) (http.RoundTripper, error) { if f == nil { return base, nil } return f(base) } var _ GRPCClient = (*ClientPerRPCCredentialsFunc)(nil) // ClientPerRPCCredentialsFunc specifies the function that returns a PerRPCCredentials that can be used to authenticate gRPC requests. type ClientPerRPCCredentialsFunc func() (credentials.PerRPCCredentials, error) func (f ClientPerRPCCredentialsFunc) PerRPCCredentials() (credentials.PerRPCCredentials, error) { if f == nil { return nil, nil } return f() } opentelemetry-collector-0.141.0/extension/extensionauth/client_test.go000066400000000000000000000024351511331344600263200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauth import ( "context" "net/http" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc/credentials" ) func TestRoundTripperFunc(t *testing.T) { var called bool var httpClient HTTPClient = ClientRoundTripperFunc(func(base http.RoundTripper) (http.RoundTripper, error) { called = true return base, nil }) rt, err := httpClient.RoundTripper(http.DefaultTransport) require.NoError(t, err) assert.True(t, called) assert.Equal(t, http.DefaultTransport, rt) } type customPerRPCCredentials struct{} var _ credentials.PerRPCCredentials = (*customPerRPCCredentials)(nil) func (c *customPerRPCCredentials) GetRequestMetadata(context.Context, ...string) (map[string]string, error) { return nil, nil } func (c *customPerRPCCredentials) RequireTransportSecurity() bool { return true } func TestWithPerRPCCredentialsFunc(t *testing.T) { var called bool var grpcClient GRPCClient = ClientPerRPCCredentialsFunc(func() (credentials.PerRPCCredentials, error) { called = true return &customPerRPCCredentials{}, nil }) creds, err := grpcClient.PerRPCCredentials() require.NoError(t, err) assert.True(t, called) assert.NotNil(t, creds) } opentelemetry-collector-0.141.0/extension/extensionauth/doc.go000066400000000000000000000005231511331344600245440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package auth implements the configuration settings to // ensure authentication on incoming requests, and allows // exporters to add authentication on outgoing requests. package extensionauth // import "go.opentelemetry.io/collector/extension/extensionauth" opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/000077500000000000000000000000001511331344600272465ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/Makefile000066400000000000000000000000411511331344600307010ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/err.go000066400000000000000000000023671511331344600303750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauthtest // import "go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest" import ( "context" "net/http" "google.golang.org/grpc/credentials" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionauth" ) var ( _ extension.Extension = (*errClient)(nil) _ extensionauth.HTTPClient = (*errClient)(nil) _ extensionauth.GRPCClient = (*errClient)(nil) ) type errClient struct { component.StartFunc component.ShutdownFunc extensionauth.ClientPerRPCCredentialsFunc extensionauth.ClientRoundTripperFunc extensionauth.ServerAuthenticateFunc } // NewErr returns a new [extension.Extension] that implements all // extensionauth interface and always returns an error. func NewErr(err error) extension.Extension { return &errClient{ ClientRoundTripperFunc: func(http.RoundTripper) (http.RoundTripper, error) { return nil, err }, ClientPerRPCCredentialsFunc: func() (credentials.PerRPCCredentials, error) { return nil, err }, ServerAuthenticateFunc: func(ctx context.Context, _ map[string][]string) (context.Context, error) { return ctx, err }, } } opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/err_test.go000066400000000000000000000014001511331344600314170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauthtest import ( "context" "errors" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/extension/extensionauth" ) func TestErrorClient(t *testing.T) { client := NewErr(errors.New("error")) httpClient, ok := client.(extensionauth.HTTPClient) require.True(t, ok) _, err := httpClient.RoundTripper(nil) require.Error(t, err) grpcClient, ok := client.(extensionauth.GRPCClient) require.True(t, ok) _, err = grpcClient.PerRPCCredentials() require.Error(t, err) server, ok := client.(extensionauth.Server) require.True(t, ok) _, err = server.Authenticate(context.Background(), map[string][]string{}) require.Error(t, err) } opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/go.mod000066400000000000000000000030661511331344600303610ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensionauth v1.47.0 go.uber.org/goleak v1.3.0 google.golang.org/grpc v1.77.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/extension/extensionauth => .. replace go.opentelemetry.io/collector/component => ../../../component replace go.opentelemetry.io/collector/pdata => ../../../pdata replace go.opentelemetry.io/collector/extension => ../.. replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/go.sum000066400000000000000000000143221511331344600304030ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/nop_client.go000066400000000000000000000017151511331344600317330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauthtest // import "go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest" import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionauth" ) var ( _ extension.Extension = (*nopClient)(nil) _ extensionauth.HTTPClient = (*nopClient)(nil) _ extensionauth.GRPCClient = (*nopClient)(nil) ) type nopClient struct { component.StartFunc component.ShutdownFunc extensionauth.ClientRoundTripperFunc extensionauth.ClientPerRPCCredentialsFunc } // NewNopClient returns a new [extension.Extension] that implements the [extensionauth.HTTPClient] and [extensionauth.GRPCClient]. // For HTTP requests it returns the base RoundTripper and for gRPC requests it returns a nil [credentials.PerRPCCredentials]. func NewNopClient() extension.Extension { return &nopClient{} } opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/nop_client_test.go000066400000000000000000000012261511331344600327670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauthtest import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/extension/extensionauth" ) func TestNopClient(t *testing.T) { client := NewNopClient() httpClient, ok := client.(extensionauth.HTTPClient) require.True(t, ok) rt, err := httpClient.RoundTripper(nil) require.NoError(t, err) assert.Nil(t, rt) grpcClient, ok := client.(extensionauth.GRPCClient) require.True(t, ok) grpcAuth, err := grpcClient.PerRPCCredentials() require.NoError(t, err) assert.Nil(t, grpcAuth) } opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/nop_server.go000066400000000000000000000015301511331344600317560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauthtest // import "go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionauth" ) var ( _ extension.Extension = (*nopServer)(nil) _ extensionauth.Server = (*nopServer)(nil) ) type nopServer struct { component.StartFunc component.ShutdownFunc } // Authenticate implements extensionauth.Server. func (n *nopServer) Authenticate(ctx context.Context, _ map[string][]string) (context.Context, error) { return ctx, nil } // NewNopServer returns a new extension.Extension that implements the extensionauth.Server. func NewNopServer() extension.Extension { return &nopServer{} } opentelemetry-collector-0.141.0/extension/extensionauth/extensionauthtest/package_test.go000066400000000000000000000003221511331344600322240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauthtest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/extension/extensionauth/go.mod000066400000000000000000000010311511331344600245510ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/extensionauth go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 google.golang.org/grpc v1.77.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/extension/extensionauth/go.sum000066400000000000000000000066041511331344600246110ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/extensionauth/package_test.go000066400000000000000000000003161511331344600264310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauth import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/extension/extensionauth/server.go000066400000000000000000000044461511331344600253150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauth // import "go.opentelemetry.io/collector/extension/extensionauth" import ( "context" ) // Server is an optional Extension interface that can be used as an authenticator for the configauth.Config option. // Authenticators are then included as part of OpenTelemetry Collector builds and can be referenced by their // names from the [configauth.Config] configuration. Each Server is free to define its own behavior and configuration options, // but note that the expectations that come as part of Extensions exist here as well. For instance, multiple instances of the same // authenticator should be possible to exist under different names. type Server interface { // Authenticate checks whether the given map contains valid auth data. Successfully authenticated calls will always return a nil error. // When the authentication fails, an error must be returned and the caller must not retry. This function is typically called from interceptors, // on behalf of receivers, but receivers can still call this directly if the usage of interceptors isn't suitable. // The deadline and cancellation given to this function must be respected, but note that authentication data has to be part of the map, not context. // The resulting context should contain the authentication data, such as the principal/username, group membership (if available), and the raw // authentication data (if possible). This will allow other components in the pipeline to make decisions based on that data, such as routing based // on tenancy as determined by the group membership, or passing through the authentication data to the next collector/backend. // The context keys to be used are not defined yet. Authenticate(ctx context.Context, sources map[string][]string) (context.Context, error) } // ServerAuthenticateFunc defines the signature for the function responsible for performing the authentication based // on the given sources map. See Server.Authenticate. type ServerAuthenticateFunc func(ctx context.Context, sources map[string][]string) (context.Context, error) func (f ServerAuthenticateFunc) Authenticate(ctx context.Context, sources map[string][]string) (context.Context, error) { if f == nil { return ctx, nil } return f(ctx, sources) } opentelemetry-collector-0.141.0/extension/extensionauth/server_test.go000066400000000000000000000010741511331344600263460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionauth import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestServerAuthenticateFunc(t *testing.T) { var called bool var server Server = ServerAuthenticateFunc(func(ctx context.Context, _ map[string][]string) (context.Context, error) { called = true return ctx, nil }) ctx, err := server.Authenticate(context.Background(), nil) require.NoError(t, err) assert.True(t, called) assert.NotNil(t, ctx) } opentelemetry-collector-0.141.0/extension/extensioncapabilities/000077500000000000000000000000001511331344600251405ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/extensioncapabilities/Makefile000066400000000000000000000000361511331344600265770ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/extension/extensioncapabilities/go.mod000066400000000000000000000032031511331344600262440ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/extensioncapabilities go 1.24.0 require ( go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 ) require ( github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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 go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.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 ) replace go.opentelemetry.io/collector/extension => ../ replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/extension/extensioncapabilities/go.sum000066400000000000000000000152551511331344600263030ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/extensioncapabilities/interfaces.go000066400000000000000000000042121511331344600276110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package extensioncapabilities provides interfaces that can be implemented by extensions // to provide additional capabilities. package extensioncapabilities // import "go.opentelemetry.io/collector/extension/extensioncapabilities" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/extension" ) // Dependent is an optional interface that can be implemented by extensions // that depend on other extensions and must be started only after their dependencies. // See https://github.com/open-telemetry/opentelemetry-collector/pull/8768 for examples. type Dependent interface { extension.Extension Dependencies() []component.ID } // PipelineWatcher is an extra interface for Extension hosted by the OpenTelemetry // Collector that is to be implemented by extensions interested in changes to pipeline // states. Typically this will be used by extensions that change their behavior if data is // being ingested or not, e.g.: a k8s readiness probe. type PipelineWatcher interface { // Ready notifies the Extension that all pipelines were built and the // receivers were started, i.e.: the service is ready to receive data // (note that it may already have received data when this method is called). Ready() error // NotReady notifies the Extension that all receivers are about to be stopped, // i.e.: pipeline receivers will not accept new data. // This is sent before receivers are stopped, so the Extension can take any // appropriate actions before that happens. NotReady() error } // ConfigWatcher is an interface that should be implemented by an extension that // wishes to be notified of the Collector's effective configuration. type ConfigWatcher interface { // NotifyConfig notifies the extension of the Collector's current effective configuration. // The extension owns the `confmap.Conf`. Callers must ensure that it's safe for // extensions to store the `conf` pointer and use it concurrently with any other // instances of `conf`. NotifyConfig(ctx context.Context, conf *confmap.Conf) error } opentelemetry-collector-0.141.0/extension/extensionmiddleware/000077500000000000000000000000001511331344600246245ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/extensionmiddleware/Makefile000066400000000000000000000000361511331344600262630ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/extension/extensionmiddleware/README.md000066400000000000000000000043101511331344600261010ustar00rootroot00000000000000# OpenTelemetry Collector Middleware Extension API This package implements interfaces for injecting middleware behavior in OpenTelemetry Collector exporters and receivers. See the [associated `configmiddleware` package](../../config/configmiddleware/README.md) for referring to middleware extensions in component configurations. ## Overview Middleware extensions can be configured on gRPC and HTTP connections, on both the client and server side. The term "middleware" is defined broadly to cover many ways of intercepting, acting on, and observing requests as they enter and exit and RPC system. Middleware details and capabilities are specific to each protocol. In some cases, these interfaces permit configuring behavior other than middleware. Users have to place a trust in the extensions they configure, since they are capable of subverting security and other RPC configuration. Middleware is generally configured at a level in the code where: 1. the identity of the calling component is not known, because `confighttp` and `configgrpc` interfaces likewise are not configured with the identify of the calling component. 2. the signal type in use is not known, because a single connection serves multiple signals. ## Interfaces Each interface has a single function to configure middleware for a protocol on the client or server side. An error is returned if the extension cannot be configured. New protocols and new ways to configure middleware can be introduced by adding new interfaces. Note that for each interface, there is a corresponding method to locate a named middleware extension that satisfies the interface in [the `configmiddleware` package](../../config/configmiddleware/README.md) . ### HTTP Interface methods are called once per request to construct a client- or server-side middleware object. - **HTTPClient**: The extension returns a function to create new `http.RoundTripper`s. - **HTTPServer**: The extension returns a function to create new `http.Handler`s. ### GRPC Interface methods are called once at setup to configure the client- or server-side middleware object. - **GRPCClient**: The extension returns `[]grpc.DialOption`. - **GRPCServer**: The extension returns `[]grpc.ServerOption`. opentelemetry-collector-0.141.0/extension/extensionmiddleware/client.go000066400000000000000000000025601511331344600264340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddleware // import "go.opentelemetry.io/collector/extension/extensionmiddleware" import ( "net/http" "google.golang.org/grpc" ) // HTTPClient is an interface for HTTP client middleware extensions. type HTTPClient interface { // GetHTTPRoundTripper wraps the provided client RoundTripper. GetHTTPRoundTripper(http.RoundTripper) (http.RoundTripper, error) } // GRPCClient is an interface for gRPC client middleware extensions. type GRPCClient interface { // GetGRPCClientOptions returns the gRPC dial options to use for client connections. GetGRPCClientOptions() ([]grpc.DialOption, error) } var _ HTTPClient = (*GetHTTPRoundTripperFunc)(nil) // GetHTTPRoundTripperFunc is a function that implements HTTPClient. type GetHTTPRoundTripperFunc func(base http.RoundTripper) (http.RoundTripper, error) func (f GetHTTPRoundTripperFunc) GetHTTPRoundTripper(base http.RoundTripper) (http.RoundTripper, error) { if f == nil { return base, nil } return f(base) } var _ GRPCClient = (*GetGRPCClientOptionsFunc)(nil) // GetGRPCClientOptionsFunc is a function that implements GRPCClient. type GetGRPCClientOptionsFunc func() ([]grpc.DialOption, error) func (f GetGRPCClientOptionsFunc) GetGRPCClientOptions() ([]grpc.DialOption, error) { if f == nil { return nil, nil } return f() } opentelemetry-collector-0.141.0/extension/extensionmiddleware/client_test.go000066400000000000000000000046651511331344600275030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddleware import ( "errors" "net/http" "testing" "github.com/stretchr/testify/require" "google.golang.org/grpc" ) func TestGetHTTPRoundTripperFunc(t *testing.T) { // Create a base round tripper for testing baseRT := http.DefaultTransport t.Run("nil function", func(t *testing.T) { var nilFunc GetHTTPRoundTripperFunc rt, err := nilFunc.GetHTTPRoundTripper(baseRT) require.NoError(t, err) require.Equal(t, baseRT, rt) }) t.Run("identity function", func(t *testing.T) { identityFunc := GetHTTPRoundTripperFunc(func(base http.RoundTripper) (http.RoundTripper, error) { return base, nil }) rt, err := identityFunc.GetHTTPRoundTripper(baseRT) require.NoError(t, err) require.Equal(t, baseRT, rt) }) t.Run("error function", func(t *testing.T) { expectedErr := errors.New("round tripper error") errorFunc := GetHTTPRoundTripperFunc(func(_ http.RoundTripper) (http.RoundTripper, error) { return nil, expectedErr }) rt, err := errorFunc.GetHTTPRoundTripper(baseRT) require.Error(t, err) require.Equal(t, expectedErr, err) require.Nil(t, rt) }) } func TestGetGRPCClientOptionsFunc(t *testing.T) { t.Run("nil function", func(t *testing.T) { var nilFunc GetGRPCClientOptionsFunc options, err := nilFunc.GetGRPCClientOptions() require.NoError(t, err) require.Nil(t, options) }) t.Run("empty options function", func(t *testing.T) { emptyFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { return []grpc.DialOption{}, nil }) options, err := emptyFunc.GetGRPCClientOptions() require.NoError(t, err) require.Empty(t, options) }) t.Run("options function", func(t *testing.T) { // Create some test dial options dialOpt1 := grpc.WithAuthority("test-authority") dialOpt2 := grpc.WithDisableRetry() optionsFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { return []grpc.DialOption{dialOpt1, dialOpt2}, nil }) options, err := optionsFunc.GetGRPCClientOptions() require.NoError(t, err) require.Len(t, options, 2) }) t.Run("error function", func(t *testing.T) { expectedErr := errors.New("grpc options error") errorFunc := GetGRPCClientOptionsFunc(func() ([]grpc.DialOption, error) { return nil, expectedErr }) options, err := errorFunc.GetGRPCClientOptions() require.Error(t, err) require.Equal(t, expectedErr, err) require.Nil(t, options) }) } opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/000077500000000000000000000000001511331344600315765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/Makefile000066400000000000000000000000411511331344600332310ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/err.go000066400000000000000000000027761511331344600327310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddlewaretest // import "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" import ( "net/http" "google.golang.org/grpc" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensionmiddleware" ) var ( _ extension.Extension = (*baseExtension)(nil) _ extensionmiddleware.HTTPClient = (*baseExtension)(nil) _ extensionmiddleware.GRPCClient = (*baseExtension)(nil) _ extensionmiddleware.HTTPServer = (*baseExtension)(nil) _ extensionmiddleware.GRPCServer = (*baseExtension)(nil) ) type baseExtension struct { component.StartFunc component.ShutdownFunc extensionmiddleware.GetHTTPHandlerFunc extensionmiddleware.GetGRPCServerOptionsFunc extensionmiddleware.GetHTTPRoundTripperFunc extensionmiddleware.GetGRPCClientOptionsFunc } // NewErr returns a new [extension.Extension] that implements all // extensionmiddleware interface and always returns an error. func NewErr(err error) extension.Extension { return &baseExtension{ GetHTTPRoundTripperFunc: func(http.RoundTripper) (http.RoundTripper, error) { return nil, err }, GetGRPCClientOptionsFunc: func() ([]grpc.DialOption, error) { return nil, err }, GetHTTPHandlerFunc: func(http.Handler) (http.Handler, error) { return nil, err }, GetGRPCServerOptionsFunc: func() ([]grpc.ServerOption, error) { return nil, err }, } } opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/err_test.go000066400000000000000000000017431511331344600337610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddlewaretest import ( "errors" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/extension/extensionmiddleware" ) func TestErrClient(t *testing.T) { client := NewErr(errors.New("error")) httpClient, ok := client.(extensionmiddleware.HTTPClient) require.True(t, ok) _, err := httpClient.GetHTTPRoundTripper(nil) require.Error(t, err) grpcClient, ok := client.(extensionmiddleware.GRPCClient) require.True(t, ok) _, err = grpcClient.GetGRPCClientOptions() require.Error(t, err) } func TestErrServer(t *testing.T) { server := NewErr(errors.New("error")) httpServer, ok := server.(extensionmiddleware.HTTPServer) require.True(t, ok) _, err := httpServer.GetHTTPHandler(nil) require.Error(t, err) grpcServer, ok := server.(extensionmiddleware.GRPCServer) require.True(t, ok) _, err = grpcServer.GetGRPCServerOptions() require.Error(t, err) } opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/go.mod000066400000000000000000000034371511331344600327130ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 google.golang.org/grpc v1.77.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/extension/extensionmiddleware => .. replace go.opentelemetry.io/collector/component => ../../../component replace go.opentelemetry.io/collector/pdata => ../../../pdata replace go.opentelemetry.io/collector/extension => ../.. replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/go.sum000066400000000000000000000160551511331344600327400ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/nop.go000066400000000000000000000016131511331344600327220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddlewaretest // import "go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest" import ( "net/http" "go.opentelemetry.io/collector/extension" ) // NewNop returns a new [extension.Extension] that implements // the all the extensionmiddleware interfaces. For HTTP requests it // returns the base RoundTripper and for gRPC requests it returns an // empty slice of options. func NewNop() extension.Extension { return &baseExtension{} } // RoundTripperFunc implements an HTTP client middleware function. This // is the equivalent of net/http.HandlerFunc for creating a // net/http.RoundTripper from a function. type RoundTripperFunc func(*http.Request) (*http.Response, error) func (f RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) { return f(req) } opentelemetry-collector-0.141.0/extension/extensionmiddleware/extensionmiddlewaretest/nop_test.go000066400000000000000000000026101511331344600337570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddlewaretest import ( "net/http" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/extension/extensionmiddleware" ) func TestNopClient(t *testing.T) { client := NewNop() httpClient, ok := client.(extensionmiddleware.HTTPClient) require.True(t, ok) rt, err := httpClient.GetHTTPRoundTripper(nil) require.NoError(t, err) require.Nil(t, rt) grpcClient, ok := client.(extensionmiddleware.GRPCClient) require.True(t, ok) grpcOpts, err := grpcClient.GetGRPCClientOptions() require.NoError(t, err) require.Nil(t, grpcOpts) } func TestNopServer(t *testing.T) { client := NewNop() httpServer, ok := client.(extensionmiddleware.HTTPServer) require.True(t, ok) rt, err := httpServer.GetHTTPHandler(nil) require.NoError(t, err) require.Nil(t, rt) grpcServer, ok := client.(extensionmiddleware.GRPCServer) require.True(t, ok) grpcOpts, err := grpcServer.GetGRPCServerOptions() require.NoError(t, err) require.Nil(t, grpcOpts) } func TestRoundTripperFunc(t *testing.T) { called := false req := &http.Request{} resp := &http.Response{} f := RoundTripperFunc(func(r *http.Request) (*http.Response, error) { require.Equal(t, r, req) called = true return resp, nil }) result, _ := f.RoundTrip(req) require.True(t, called) require.Equal(t, resp, result) } opentelemetry-collector-0.141.0/extension/extensionmiddleware/go.mod000066400000000000000000000011171511331344600257320ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/extensionmiddleware go 1.24.0 require ( github.com/stretchr/testify v1.11.1 google.golang.org/grpc v1.77.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/extension/extensionmiddleware/go.sum000066400000000000000000000077411511331344600257700ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/extensionmiddleware/server.go000066400000000000000000000024521511331344600264640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddleware // import "go.opentelemetry.io/collector/extension/extensionmiddleware" import ( "net/http" "google.golang.org/grpc" ) // HTTPServer defines the interface for HTTP server middleware extensions. type HTTPServer interface { // GetHTTPHandler wraps the provided base http.Handler. GetHTTPHandler(base http.Handler) (http.Handler, error) } // GRPCServer defines the interface for gRPC server middleware extensions. type GRPCServer interface { // GetGRPCServerOptions returns options for a gRPC server. GetGRPCServerOptions() ([]grpc.ServerOption, error) } var _ HTTPServer = (*GetHTTPHandlerFunc)(nil) // GetHTTPHandlerFunc is a function that implements HTTPServer. type GetHTTPHandlerFunc func(base http.Handler) (http.Handler, error) func (f GetHTTPHandlerFunc) GetHTTPHandler(base http.Handler) (http.Handler, error) { if f == nil { return base, nil } return f(base) } var _ GRPCServer = (*GetGRPCServerOptionsFunc)(nil) // GetGRPCServerOptionsFunc is a function that implements GRPCServer. type GetGRPCServerOptionsFunc func() ([]grpc.ServerOption, error) func (f GetGRPCServerOptionsFunc) GetGRPCServerOptions() ([]grpc.ServerOption, error) { if f == nil { return nil, nil } return f() } opentelemetry-collector-0.141.0/extension/extensionmiddleware/server_test.go000066400000000000000000000054371511331344600275310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensionmiddleware import ( "context" "errors" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/require" "google.golang.org/grpc" ) func TestGetHTTPHandlerFunc(t *testing.T) { t.Run("nil_function", func(t *testing.T) { var f GetHTTPHandlerFunc baseHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) }) handler, err := f.GetHTTPHandler(baseHandler) require.NoError(t, err) rr := httptest.NewRecorder() handler.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/", http.NoBody)) require.Equal(t, http.StatusNoContent, rr.Code) }) t.Run("returns_wrapped_handler", func(t *testing.T) { called := false baseHandler := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusOK) }) f := GetHTTPHandlerFunc(func(base http.Handler) (http.Handler, error) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { called = true base.ServeHTTP(w, r) }), nil }) handler, err := f.GetHTTPHandler(baseHandler) require.NoError(t, err) require.NotNil(t, handler) rr := httptest.NewRecorder() handler.ServeHTTP(rr, httptest.NewRequest(http.MethodGet, "/", http.NoBody)) require.True(t, called) require.Equal(t, http.StatusOK, rr.Code) }) t.Run("returns_error", func(t *testing.T) { expectedErr := errors.New("test error") f := GetHTTPHandlerFunc(func(http.Handler) (http.Handler, error) { return nil, expectedErr }) baseHandler := http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}) handler, err := f.GetHTTPHandler(baseHandler) require.Equal(t, expectedErr, err) require.Nil(t, handler) }) } func TestGetGRPCServerOptionsFunc(t *testing.T) { t.Run("nil_function", func(t *testing.T) { var f GetGRPCServerOptionsFunc opts, err := f.GetGRPCServerOptions() require.NoError(t, err) require.Nil(t, opts) }) t.Run("returns_server_options", func(t *testing.T) { var interceptor grpc.UnaryServerInterceptor = func( context.Context, any, *grpc.UnaryServerInfo, grpc.UnaryHandler, ) (resp any, err error) { return nil, nil } expectedOpts := []grpc.ServerOption{grpc.UnaryInterceptor(interceptor)} f := GetGRPCServerOptionsFunc(func() ([]grpc.ServerOption, error) { return expectedOpts, nil }) opts, err := f.GetGRPCServerOptions() require.NoError(t, err) require.Equal(t, expectedOpts, opts) }) t.Run("returns_error", func(t *testing.T) { expectedErr := errors.New("test error") f := GetGRPCServerOptionsFunc(func() ([]grpc.ServerOption, error) { return nil, expectedErr }) opts, err := f.GetGRPCServerOptions() require.Equal(t, expectedErr, err) require.Nil(t, opts) }) } opentelemetry-collector-0.141.0/extension/extensiontest/000077500000000000000000000000001511331344600234665ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/extensiontest/Makefile000066400000000000000000000000361511331344600251250ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/extension/extensiontest/go.mod000066400000000000000000000033761511331344600246050ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/extensiontest go 1.24.0 replace go.opentelemetry.io/collector/extension => .. require ( github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/extension v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/extension/extensiontest/go.sum000066400000000000000000000140451511331344600246250ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/extensiontest/nop_extension.go000066400000000000000000000026001511331344600267030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensiontest // import "go.opentelemetry.io/collector/extension/extensiontest" import ( "context" "github.com/google/uuid" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/extension" ) // NopType is the type of the nop extension. var NopType = component.MustNewType("nop") // NewNopSettings returns a new nop settings for extension.Factory Create* functions with the given type. func NewNopSettings(typ component.Type) extension.Settings { return extension.Settings{ ID: component.NewIDWithName(typ, uuid.NewString()), TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } // NewNopFactory returns an extension.Factory that constructs nop extensions. func NewNopFactory() extension.Factory { return extension.NewFactory( NopType, func() component.Config { return &nopConfig{} }, func(context.Context, extension.Settings, component.Config) (extension.Extension, error) { return nopInstance, nil }, component.StabilityLevelStable) } type nopConfig struct{} var nopInstance = &nopExtension{} // nopExtension acts as an extension for testing purposes. type nopExtension struct { component.StartFunc component.ShutdownFunc } opentelemetry-collector-0.141.0/extension/extensiontest/nop_extension_test.go000066400000000000000000000014371511331344600277510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensiontest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) func TestNewNopFactory(t *testing.T) { factory := NewNopFactory() require.NotNil(t, factory) assert.Equal(t, component.MustNewType("nop"), factory.Type()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &nopConfig{}, cfg) traces, err := factory.Create(context.Background(), NewNopSettings(NopType), cfg) require.NoError(t, err) assert.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, traces.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/extension/go.mod000066400000000000000000000022761511331344600216670ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/extension/go.sum000066400000000000000000000124431511331344600217110ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/memorylimiterextension/000077500000000000000000000000001511331344600254055ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/memorylimiterextension/Makefile000066400000000000000000000000361511331344600270440ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/extension/memorylimiterextension/README.md000066400000000000000000000030421511331344600266630ustar00rootroot00000000000000# Memory Limiter Extension | Status | | | ------------- |-----------| | Stability | [development] | | Distributions | [] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Fmemorylimiter%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Fmemorylimiter) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Fmemorylimiter%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Fmemorylimiter) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development The memory limiter extension is used to prevent out of memory situations on the collector. The extension will potentially replace the Memory Limiter Processor. It provides better guarantees from running out of memory as it will be used by the receivers to reject requests before converting them into OTLP. All the configurations are the same as Memory Limiter Processor. The extension is under development and does nothing. see [memorylimiterprocessor](../../processor/memorylimiterprocessor/README.md) for additional details opentelemetry-collector-0.141.0/extension/memorylimiterextension/config.go000066400000000000000000000004411511331344600272000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterextension // import "go.opentelemetry.io/collector/extension/memorylimiterextension" import ( "go.opentelemetry.io/collector/internal/memorylimiter" ) type Config = memorylimiter.Config opentelemetry-collector-0.141.0/extension/memorylimiterextension/factory.go000066400000000000000000000021151511331344600274020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterextension // import "go.opentelemetry.io/collector/extension/memorylimiterextension" //go:generate mdatagen metadata.yaml import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/memorylimiterextension/internal/metadata" "go.opentelemetry.io/collector/internal/memorylimiter" ) // NewFactory returns a new factory for the Memory Limiter extension. func NewFactory() extension.Factory { return extension.NewFactory( metadata.Type, createDefaultConfig, create, metadata.ExtensionStability) } // CreateDefaultConfig creates the default configuration for extension. Notice // that the default configuration is expected to fail for this extension. func createDefaultConfig() component.Config { return memorylimiter.NewDefaultConfig() } func create(_ context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) { return newMemoryLimiter(cfg.(*Config), set.Logger) } opentelemetry-collector-0.141.0/extension/memorylimiterextension/factory_test.go000066400000000000000000000027301511331344600304440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterextension import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/extension/extensiontest" ) func TestCreateDefaultConfig(t *testing.T) { factory := NewFactory() require.NotNil(t, factory) cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") assert.NoError(t, componenttest.CheckConfigStruct(cfg)) } func TestCreate(t *testing.T) { factory := NewFactory() require.NotNil(t, factory) cfg := factory.CreateDefaultConfig() // Create extension with a valid config. pCfg := cfg.(*Config) pCfg.MemoryLimitMiB = 5722 pCfg.MemorySpikeLimitMiB = 1907 pCfg.CheckInterval = 100 * time.Millisecond set := extensiontest.NewNopSettings(factory.Type()) set.ID = component.NewID(factory.Type()) tp, err := factory.Create(context.Background(), set, cfg) require.NoError(t, err) assert.NotNil(t, tp) // test if we can shutdown a monitoring routine that has not started require.NoError(t, tp.Shutdown(context.Background())) assert.NoError(t, tp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tp.Shutdown(context.Background())) // verify that shutdown twice works: assert.NoError(t, tp.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/extension/memorylimiterextension/generated_component_test.go000066400000000000000000000040621511331344600330150ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package memorylimiterextension import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/extension/extensiontest" ) var typ = component.MustNewType("memory_limiter") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) t.Run("shutdown", func(t *testing.T) { e, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) err = e.Shutdown(context.Background()) require.NoError(t, err) }) t.Run("lifecycle", func(t *testing.T) { firstExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, firstExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, firstExt.Shutdown(context.Background())) secondExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, secondExt.Shutdown(context.Background())) }) } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/extension/memorylimiterextension/generated_package_test.go000066400000000000000000000002651511331344600324070ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package memorylimiterextension import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/extension/memorylimiterextension/go.mod000066400000000000000000000060601511331344600265150ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/memorylimiterextension go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensiontest v0.141.0 go.opentelemetry.io/collector/internal/memorylimiter v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // 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-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/shirou/gopsutil/v4 v4.25.10 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/internal/memorylimiter => ../../internal/memorylimiter replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/extension/memorylimiterextension/go.sum000066400000000000000000000224731511331344600265500ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/memorylimiterextension/internal/000077500000000000000000000000001511331344600272215ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/memorylimiterextension/internal/metadata/000077500000000000000000000000001511331344600310015ustar00rootroot00000000000000generated_status.go000066400000000000000000000005061511331344600346130ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/memorylimiterextension/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("memory_limiter") ScopeName = "go.opentelemetry.io/collector/extension/memorylimiterextension" ) const ( ExtensionStability = component.StabilityLevelDevelopment ) opentelemetry-collector-0.141.0/extension/memorylimiterextension/memorylimiter.go000066400000000000000000000021661511331344600306370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterextension // import "go.opentelemetry.io/collector/extension/memorylimiterextension" import ( "context" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/internal/memorylimiter" ) type memoryLimiterExtension struct { memLimiter *memorylimiter.MemoryLimiter } // newMemoryLimiter returns a new memorylimiter extension. func newMemoryLimiter(cfg *Config, logger *zap.Logger) (*memoryLimiterExtension, error) { ml, err := memorylimiter.NewMemoryLimiter(cfg, logger) if err != nil { return nil, err } return &memoryLimiterExtension{memLimiter: ml}, nil } func (ml *memoryLimiterExtension) Start(ctx context.Context, host component.Host) error { return ml.memLimiter.Start(ctx, host) } func (ml *memoryLimiterExtension) Shutdown(ctx context.Context) error { return ml.memLimiter.Shutdown(ctx) } // MustRefuse returns if the caller should deny because memory has reached it's configured limits func (ml *memoryLimiterExtension) MustRefuse() bool { return ml.memLimiter.MustRefuse() } opentelemetry-collector-0.141.0/extension/memorylimiterextension/memorylimiter_test.go000066400000000000000000000042571511331344600317010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterextension import ( "context" "runtime" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/internal/memorylimiter" "go.opentelemetry.io/collector/internal/memorylimiter/iruntime" ) func TestMemoryPressureResponse(t *testing.T) { ctx := context.Background() tests := []struct { name string mlCfg *Config memAlloc uint64 expectError bool }{ { name: "Below memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 800, expectError: false, }, { name: "Above memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 1800, expectError: true, }, { name: "Below memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 10, }, memAlloc: 800, expectError: false, }, { name: "Above memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 11, }, memAlloc: 800, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { memorylimiter.GetMemoryFn = func() (uint64, error) { return uint64(2048), nil } memorylimiter.ReadMemStatsFn = func(ms *runtime.MemStats) { ms.Alloc = tt.memAlloc } t.Cleanup(func() { memorylimiter.GetMemoryFn = iruntime.TotalMemory memorylimiter.ReadMemStatsFn = runtime.ReadMemStats }) ml, err := newMemoryLimiter(tt.mlCfg, zap.NewNop()) assert.NoError(t, err) assert.NoError(t, ml.Start(ctx, componenttest.NewNopHost())) ml.memLimiter.CheckMemLimits() mustRefuse := ml.MustRefuse() if tt.expectError { assert.True(t, mustRefuse) } else { require.NoError(t, err) } assert.NoError(t, ml.Shutdown(ctx)) }) } } opentelemetry-collector-0.141.0/extension/memorylimiterextension/metadata.yaml000066400000000000000000000004301511331344600300460ustar00rootroot00000000000000type: memory_limiter github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: extension stability: development: [extension] distributions: [] tests: config: check_interval: 5s limit_mib: 400 spike_limit_mib: 50 opentelemetry-collector-0.141.0/extension/memorylimiterextension/testdata/000077500000000000000000000000001511331344600272165ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/memorylimiterextension/testdata/config.yaml000066400000000000000000000014711511331344600313520ustar00rootroot00000000000000# check_interval is the time between measurements of memory usage for the # purposes of avoiding going over the limits. Defaults to zero, so no # checks will be performed. Values below 1 second are not recommended since # it can result in unnecessary CPU consumption. check_interval: 5s # Maximum amount of memory, in MiB, targeted to be allocated by the process heap. # Note that typically the total memory usage of process will be about 50MiB higher # than this value. limit_mib: 4000 # The maximum, in MiB, spike expected between the measurements of memory usage. spike_limit_mib: 500 # the maximum amount of memory, in %, targeted to be allocated by the process limit_percentage: 0 # the maximum, in percents against the total memory, spike expected between the measurements of memory usage. spike_limit_percentage: 0opentelemetry-collector-0.141.0/extension/package_test.go000066400000000000000000000003121511331344600235270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extension import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/extension/xextension/000077500000000000000000000000001511331344600227565ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/xextension/Makefile000066400000000000000000000000361511331344600244150ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/extension/xextension/go.mod000066400000000000000000000021701511331344600240640ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/xextension go 1.24.0 require ( go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 ) require ( github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect ) replace go.opentelemetry.io/collector/extension => ../ replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/extension/xextension/go.sum000066400000000000000000000107651511331344600241220ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/xextension/metadata.yaml000066400000000000000000000002711511331344600254220ustar00rootroot00000000000000type: xextension github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: extension codeowners: stability: development: [profiles] opentelemetry-collector-0.141.0/extension/xextension/storage/000077500000000000000000000000001511331344600244225ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/xextension/storage/README.md000066400000000000000000000026421511331344600257050ustar00rootroot00000000000000# Storage **Status: under development; This is currently just the interface** A storage extension persists state beyond the collector process. Other components can request a storage client from the storage extension and use it to manage state. The `storage.Extension` interface extends `component.Extension` by adding the following method: ``` GetClient(context.Context, component.Kind, component.ID, string) (Client, error) ``` The `storage.Client` interface contains the following methods: ``` Get(context.Context, string) ([]byte, error) Set(context.Context, string, []byte) error Delete(context.Context, string) error Close(context.Context) error ``` It is possible to execute several operations in a single transaction via `Batch`. The method takes a collection of `Operation` arguments (each of which contains `Key`, `Value` and `Type` properties): ``` Batch(context.Context, ...Operation) error ``` The elements itself can be created using: ``` SetOperation(string, []byte) Operation GetOperation(string) Operation DeleteOperation(string) Operation ``` Get operation results are stored in-place into the given Operation and can be retrieved using its `Value` property. Note: All methods should return error only if a problem occurred. (For example, if a file is no longer accessible, or if a remote service is unavailable.) Note: It is the responsibility of each component to `Close` a storage client that it has requested. opentelemetry-collector-0.141.0/extension/xextension/storage/doc.go000066400000000000000000000004111511331344600255120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package storage implements an extension that can // persist state beyond the collector process. package storage // import "go.opentelemetry.io/collector/extension/xextension/storage" opentelemetry-collector-0.141.0/extension/xextension/storage/metadata.yaml000066400000000000000000000003261511331344600270670ustar00rootroot00000000000000type: xextension github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: extension codeowners: active: - swiatekm stability: development: [profiles] opentelemetry-collector-0.141.0/extension/xextension/storage/nop_client.go000066400000000000000000000017721511331344600271120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package storage // import "go.opentelemetry.io/collector/extension/xextension/storage" import "context" type nopClient struct{} var nopClientInstance Client = &nopClient{} // NewNopClient returns a nop client func NewNopClient() Client { return nopClientInstance } // Get does nothing, and returns nil, nil func (c nopClient) Get(context.Context, string) ([]byte, error) { return nil, nil // no result, but no problem } // Set does nothing and returns nil func (c nopClient) Set(context.Context, string, []byte) error { return nil // no problem } // Delete does nothing and returns nil func (c nopClient) Delete(context.Context, string) error { return nil // no problem } // Close does nothing and returns nil func (c nopClient) Close(context.Context) error { return nil } // Batch does nothing, and returns nil, nil func (c nopClient) Batch(context.Context, ...*Operation) error { return nil // no result, but no problem } opentelemetry-collector-0.141.0/extension/xextension/storage/storage.go000066400000000000000000000054301511331344600264170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package storage // import "go.opentelemetry.io/collector/extension/xextension/storage" import ( "context" "errors" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" ) // Extension is the interface that storage extensions must implement type Extension interface { extension.Extension // GetClient will create a client for use by the specified component. // Each component can have multiple storages (e.g. one for each signal), // which can be identified using storageName parameter. // The component can use the client to manage state GetClient(ctx context.Context, kind component.Kind, id component.ID, storageName string) (Client, error) } // Client is the interface that storage clients must implement // All methods should return error only if a problem occurred. // This mirrors the behavior of a golang map: // - Set doesn't error if a key already exists - it just overwrites the value. // - Get doesn't error if a key is not found - it just returns nil. // - Delete doesn't error if the key doesn't exist - it just no-ops. // // Similarly: // - Batch doesn't error if any of the above happens for either retrieved or updated keys // // This also provides a way to differentiate data operations // // [overwrite | not-found | no-op] from "real" problems type Client interface { // Get will retrieve data from storage that corresponds to the // specified key. It should return (nil, nil) if not found Get(ctx context.Context, key string) ([]byte, error) // Set will store data. The data can be retrieved by the same // component after a process restart, using the same key Set(ctx context.Context, key string, value []byte) error // Delete will delete data associated with the specified key Delete(ctx context.Context, key string) error // Batch handles specified operations in batch. Get operation results are put in-place Batch(ctx context.Context, ops ...*Operation) error // Close will release any resources held by the client Close(ctx context.Context) error } type OpType int const ( Get OpType = iota Set Delete ) type Operation struct { // Key specifies key which is going to be get/set/deleted Key string // Value specifies value that is going to be set or holds result of get operation Value []byte // Type describes the operation type Type OpType } func SetOperation(key string, value []byte) *Operation { return &Operation{ Key: key, Value: value, Type: Set, } } func GetOperation(key string) *Operation { return &Operation{ Key: key, Type: Get, } } func DeleteOperation(key string) *Operation { return &Operation{ Key: key, Type: Delete, } } var ErrStorageFull = errors.New("the storage extension has run out of available space") opentelemetry-collector-0.141.0/extension/zpagesextension/000077500000000000000000000000001511331344600240005ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/zpagesextension/Makefile000066400000000000000000000000361511331344600254370ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/extension/zpagesextension/README.md000066400000000000000000000101551511331344600252610ustar00rootroot00000000000000# zPages | Status | | | ------------- |-----------| | Stability | [beta] | | Distributions | [core], [contrib], [k8s] | | Warnings | [The zPages extension is incompatible with `service::telemetry::traces::level` set to `none`](#warnings) | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aextension%2Fzpages%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aextension%2Fzpages) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aextension%2Fzpages%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aextension%2Fzpages) | [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 Enables an extension that serves zPages, an HTTP endpoint that provides live data for debugging different components that were properly instrumented for such. All core exporters and receivers provide some zPage instrumentation. zPages are useful for in-process diagnostics without having to depend on any backend to examine traces or metrics. The following settings are required: - `endpoint` (default = localhost:55679): Specifies the HTTP endpoint that serves zPages. Use localhost: to make it available only locally, or ":" to make it available on all network interfaces. The following settings can be optionally configured: - `expvar` - `enabled` (default = false): Enable the expvar services. For detail see [ExpvarZ](#expvarz). Example: ```yaml extensions: zpages: ``` The full list of settings exposed for this extension are documented [here](./config.go) with detailed sample configurations [here](./testdata/config.yaml). ## Exposed zPages routes The collector exposes the following zPage routes: ### ServiceZ ServiceZ gives an overview of the collector services and quick access to the `pipelinez`, `extensionz`, and `featurez` zPages. The page also provides build and runtime information. Example URL: http://localhost:55679/debug/servicez ### PipelineZ PipelineZ brings insight on the running pipelines running in the collector. You can find information on type, if data is mutated and the receivers, processors and exporters that are used for each pipeline. Example URL: http://localhost:55679/debug/pipelinez ### ExtensionZ ExtensionZ shows the extensions that are active in the collector. Example URL: http://localhost:55679/debug/extensionz ### FeatureZ FeatureZ lists the feature gates available along with their current status and description. Example URL: http://localhost:55679/debug/featurez ### TraceZ The TraceZ route is available to examine and bucketize spans by latency buckets for example (0us, 10us, 100us, 1ms, 10ms, 100ms, 1s, 10s, 1m] They also allow you to quickly examine error samples Example URL: http://localhost:55679/debug/tracez ### ExpvarZ The ExpvarZ exposes the useful information about Go runtime, OTel components could leverage [expvar](https://pkg.go.dev/expvar) library to expose their own state. Example URL: http://localhost:55679/debug/expvarz ## Warnings This extension registers a SpanProcessor to record all the spans created inside the Collector. This depends on a TracerProvider that supports the SDK methods RegisterSpanProcessor and UnregisterSpanProcessor. Setting `service::telemetry::traces::level` to `none` configures a No-Op TracerProvider that does not support these methods, and therefore the zPages extension cannot work in this mode. opentelemetry-collector-0.141.0/extension/zpagesextension/config.go000066400000000000000000000020611511331344600255730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpagesextension // import "go.opentelemetry.io/collector/extension/zpagesextension" import ( "errors" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/confighttp" ) // Config has the configuration for the extension enabling the zPages extension. type Config struct { confighttp.ServerConfig `mapstructure:",squash"` Expvar ExpvarConfig `mapstructure:"expvar"` // prevent unkeyed literal initialization _ struct{} } // ExpvarConfig has the configuration for the expvar service. type ExpvarConfig struct { // Enabled indicates whether to enable expvar service. // (default = false) Enabled bool `mapstructure:"enabled"` // prevent unkeyed literal initialization _ struct{} } var _ component.Config = (*Config)(nil) // Validate checks if the extension configuration is valid func (cfg *Config) Validate() error { if cfg.Endpoint == "" { return errors.New("\"endpoint\" is required when using the \"zpages\" extension") } return nil } opentelemetry-collector-0.141.0/extension/zpagesextension/config_test.go000066400000000000000000000020121511331344600266260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpagesextension import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestUnmarshalDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) } func TestInvalidConfig(t *testing.T) { assert.Error(t, (&Config{}).Validate()) } func TestUnmarshalConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) assert.Equal(t, &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: "localhost:56888", }, }, cfg) } opentelemetry-collector-0.141.0/extension/zpagesextension/doc.go000066400000000000000000000005001511331344600250670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package zpagesextension implements an extension that exposes zPages of // properly instrumented components. package zpagesextension // import "go.opentelemetry.io/collector/extension/zpagesextension" opentelemetry-collector-0.141.0/extension/zpagesextension/factory.go000066400000000000000000000020021511331344600257700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpagesextension // import "go.opentelemetry.io/collector/extension/zpagesextension" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/zpagesextension/internal/metadata" ) const ( defaultEndpoint = "localhost:55679" ) // NewFactory creates a factory for Z-Pages extension. func NewFactory() extension.Factory { return extension.NewFactory(metadata.Type, createDefaultConfig, create, metadata.ExtensionStability) } func createDefaultConfig() component.Config { return &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: defaultEndpoint, }, } } // create creates the extension based on this config. func create(_ context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) { return newServer(cfg.(*Config), set.TelemetrySettings), nil } opentelemetry-collector-0.141.0/extension/zpagesextension/factory_test.go000066400000000000000000000024211511331344600270340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpagesextension import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/extension/zpagesextension/internal/metadata" "go.opentelemetry.io/collector/internal/testutil" ) func TestFactory_CreateDefaultConfig(t *testing.T) { cfg := createDefaultConfig() assert.Equal(t, &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: "localhost:55679", }, }, cfg) require.NoError(t, componenttest.CheckConfigStruct(cfg)) ext, err := create(context.Background(), extensiontest.NewNopSettings(metadata.Type), cfg) require.NoError(t, err) require.NotNil(t, ext) } func TestFactoryCreate(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.Endpoint = testutil.GetAvailableLocalAddress(t) set := extensiontest.NewNopSettings(extensiontest.NopType) set.ID = component.NewID(NewFactory().Type()) ext, err := create(context.Background(), set, cfg) require.NoError(t, err) require.NotNil(t, ext) } opentelemetry-collector-0.141.0/extension/zpagesextension/generated_component_test.go000066400000000000000000000040431511331344600314070ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package zpagesextension import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/extension/extensiontest" ) var typ = component.MustNewType("zpages") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) t.Run("shutdown", func(t *testing.T) { e, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) err = e.Shutdown(context.Background()) require.NoError(t, err) }) t.Run("lifecycle", func(t *testing.T) { firstExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, firstExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, firstExt.Shutdown(context.Background())) secondExt, err := factory.Create(context.Background(), extensiontest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondExt.Start(context.Background(), newMdatagenNopHost())) require.NoError(t, secondExt.Shutdown(context.Background())) }) } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/extension/zpagesextension/generated_package_test.go000066400000000000000000000002561511331344600310020ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package zpagesextension import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/extension/zpagesextension/go.mod000066400000000000000000000132541511331344600251130ustar00rootroot00000000000000module go.opentelemetry.io/collector/extension/zpagesextension go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componentstatus v0.141.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configauth v1.47.0 go.opentelemetry.io/collector/config/confighttp v0.141.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensiontest v0.141.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/contrib/zpages v0.63.0 go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.1 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/cors v1.11.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configcompression v1.47.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/config/configopaque v1.47.0 // indirect go.opentelemetry.io/collector/config/configtls v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/extension => ../ replace go.opentelemetry.io/collector/extension/extensiontest => ../extensiontest replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/extension/extensionauth => ../extensionauth replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/pipeline => ../../pipeline retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/extension/zpagesextension/go.sum000066400000000000000000000255321511331344600251420ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLImUqiTPGnX4= go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/extension/zpagesextension/internal/000077500000000000000000000000001511331344600256145ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/zpagesextension/internal/metadata/000077500000000000000000000000001511331344600273745ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/zpagesextension/internal/metadata/generated_status.go000066400000000000000000000004601511331344600332640ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("zpages") ScopeName = "go.opentelemetry.io/collector/extension/zpagesextension" ) const ( ExtensionStability = component.StabilityLevelBeta ) opentelemetry-collector-0.141.0/extension/zpagesextension/metadata.yaml000066400000000000000000000004651511331344600264510ustar00rootroot00000000000000type: zpages github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: extension stability: beta: [extension] distributions: [core, contrib, k8s] warnings: - The zPages extension is incompatible with `service::telemetry::traces::level` set to `none` opentelemetry-collector-0.141.0/extension/zpagesextension/testdata/000077500000000000000000000000001511331344600256115ustar00rootroot00000000000000opentelemetry-collector-0.141.0/extension/zpagesextension/testdata/config.yaml000066400000000000000000000000341511331344600277370ustar00rootroot00000000000000endpoint: "localhost:56888" opentelemetry-collector-0.141.0/extension/zpagesextension/zpagesextension.go000066400000000000000000000101431511331344600275540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpagesextension // import "go.opentelemetry.io/collector/extension/zpagesextension" import ( "context" "errors" "expvar" "net/http" "path" "go.opentelemetry.io/contrib/zpages" traceSdk "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" ) const ( tracezPath = "tracez" expvarzPath = "expvarz" ) type zpagesExtension struct { config *Config telemetry component.TelemetrySettings zpagesSpanProcessor *zpages.SpanProcessor server *http.Server stopCh chan struct{} } // registerableTracerProvider is a tracer that supports // the SDK methods RegisterSpanProcessor and UnregisterSpanProcessor. // // We use an interface instead of casting to the SDK tracer type to support tracer providers // that extend the SDK. type registerableTracerProvider interface { // RegisterSpanProcessor adds the given SpanProcessor to the list of SpanProcessors. // https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#TracerProvider.RegisterSpanProcessor. RegisterSpanProcessor(SpanProcessor traceSdk.SpanProcessor) // UnregisterSpanProcessor removes the given SpanProcessor from the list of SpanProcessors. // https://pkg.go.dev/go.opentelemetry.io/otel/sdk/trace#TracerProvider.UnregisterSpanProcessor. UnregisterSpanProcessor(SpanProcessor traceSdk.SpanProcessor) } func (zpe *zpagesExtension) Start(ctx context.Context, host component.Host) error { zPagesMux := http.NewServeMux() tp := zpe.telemetry.TracerProvider // If the TracerProvider was wrapped by the service implementation, access the underlying SDK provider for { wrapped, ok := tp.(interface{ Unwrap() trace.TracerProvider }) if !ok { break } tp = wrapped.Unwrap() } sdktracer, ok := tp.(registerableTracerProvider) if ok { sdktracer.RegisterSpanProcessor(zpe.zpagesSpanProcessor) zPagesMux.Handle(path.Join("/debug", tracezPath), zpages.NewTracezHandler(zpe.zpagesSpanProcessor)) zpe.telemetry.Logger.Info("Registered zPages span processor on tracer provider") } else { zpe.telemetry.Logger.Warn("zPages span processor registration is not available") } if zpe.config.Expvar.Enabled { zPagesMux.Handle(path.Join("/debug", expvarzPath), expvar.Handler()) zpe.telemetry.Logger.Info("Registered zPages expvar handler") } hostZPages, ok := host.(interface { RegisterZPages(mux *http.ServeMux, pathPrefix string) }) if ok { hostZPages.RegisterZPages(zPagesMux, "/debug") zpe.telemetry.Logger.Info("Registered Host's zPages") } else { zpe.telemetry.Logger.Warn("Host's zPages not available") } // Start the listener here so we can have earlier failure if port is // already in use. ln, err := zpe.config.ToListener(ctx) if err != nil { return err } zpe.telemetry.Logger.Info("Starting zPages extension", zap.Any("config", zpe.config)) zpe.server, err = zpe.config.ToServer(ctx, host.GetExtensions(), zpe.telemetry, zPagesMux) if err != nil { return err } zpe.stopCh = make(chan struct{}) go func() { defer close(zpe.stopCh) if errHTTP := zpe.server.Serve(ln); errHTTP != nil && !errors.Is(errHTTP, http.ErrServerClosed) { componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errHTTP)) } }() return nil } func (zpe *zpagesExtension) Shutdown(context.Context) error { if zpe.server == nil { return nil } err := zpe.server.Close() if zpe.stopCh != nil { <-zpe.stopCh } sdktracer, ok := zpe.telemetry.TracerProvider.(registerableTracerProvider) if ok { sdktracer.UnregisterSpanProcessor(zpe.zpagesSpanProcessor) zpe.telemetry.Logger.Info("Unregistered zPages span processor on tracer provider") } else { zpe.telemetry.Logger.Warn("zPages span processor registration is not available") } return err } func newServer(config *Config, telemetry component.TelemetrySettings) *zpagesExtension { return &zpagesExtension{ config: config, telemetry: telemetry, zpagesSpanProcessor: zpages.NewSpanProcessor(), } } opentelemetry-collector-0.141.0/extension/zpagesextension/zpagesextension_test.go000066400000000000000000000122751511331344600306230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpagesextension import ( "context" "net" "net/http" "runtime" "testing" "github.com/stretchr/testify/require" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/internal/testutil" ) type zpagesHost struct { component.Host } func newZPagesHost() *zpagesHost { return &zpagesHost{Host: componenttest.NewNopHost()} } func (*zpagesHost) RegisterZPages(*http.ServeMux, string) {} var ( _ registerableTracerProvider = (*registerableProvider)(nil) _ registerableTracerProvider = sdktrace.NewTracerProvider() ) type registerableProvider struct { trace.TracerProvider } func (*registerableProvider) RegisterSpanProcessor(sdktrace.SpanProcessor) {} func (*registerableProvider) UnregisterSpanProcessor(sdktrace.SpanProcessor) {} func newZpagesTelemetrySettings() component.TelemetrySettings { set := componenttest.NewNopTelemetrySettings() set.TracerProvider = ®isterableProvider{set.TracerProvider} return set } func TestZPagesExtensionUsage(t *testing.T) { cfg := &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), }, } zpagesExt := newServer(cfg, newZpagesTelemetrySettings()) require.NotNil(t, zpagesExt) require.NoError(t, zpagesExt.Start(context.Background(), newZPagesHost())) t.Cleanup(func() { require.NoError(t, zpagesExt.Shutdown(context.Background())) }) // Give a chance for the server goroutine to run. runtime.Gosched() _, zpagesPort, err := net.SplitHostPort(cfg.Endpoint) require.NoError(t, err) client := &http.Client{} resp, err := client.Get("http://localhost:" + zpagesPort + "/debug/tracez") require.NoError(t, err) defer resp.Body.Close() require.Equal(t, http.StatusOK, resp.StatusCode) } func TestZPagesExtensionBadAuthExtension(t *testing.T) { cfg := &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: "localhost:0", Auth: configoptional.Some(confighttp.AuthConfig{ Config: configauth.Config{ AuthenticatorID: component.MustNewIDWithName("foo", "bar"), }, }), }, } zpagesExt := newServer(cfg, newZpagesTelemetrySettings()) require.EqualError(t, zpagesExt.Start(context.Background(), componenttest.NewNopHost()), `failed to resolve authenticator "foo/bar": authenticator not found`) } func TestZPagesExtensionPortAlreadyInUse(t *testing.T) { endpoint := testutil.GetAvailableLocalAddress(t) ln, err := net.Listen("tcp", endpoint) require.NoError(t, err) defer ln.Close() cfg := &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: endpoint, }, } zpagesExt := newServer(cfg, newZpagesTelemetrySettings()) require.NotNil(t, zpagesExt) require.Error(t, zpagesExt.Start(context.Background(), componenttest.NewNopHost())) } func TestZPagesMultipleStarts(t *testing.T) { cfg := &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), }, } zpagesExt := newServer(cfg, newZpagesTelemetrySettings()) require.NotNil(t, zpagesExt) require.NoError(t, zpagesExt.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, zpagesExt.Shutdown(context.Background())) }) // Try to start it again, it will fail since it is on the same endpoint. require.Error(t, zpagesExt.Start(context.Background(), componenttest.NewNopHost())) } func TestZPagesMultipleShutdowns(t *testing.T) { cfg := &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), }, } zpagesExt := newServer(cfg, newZpagesTelemetrySettings()) require.NotNil(t, zpagesExt) require.NoError(t, zpagesExt.Start(context.Background(), componenttest.NewNopHost())) require.NoError(t, zpagesExt.Shutdown(context.Background())) require.NoError(t, zpagesExt.Shutdown(context.Background())) } func TestZPagesShutdownWithoutStart(t *testing.T) { cfg := &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), }, } zpagesExt := newServer(cfg, newZpagesTelemetrySettings()) require.NotNil(t, zpagesExt) require.NoError(t, zpagesExt.Shutdown(context.Background())) } func TestZPagesEnableExpvar(t *testing.T) { cfg := &Config{ ServerConfig: confighttp.ServerConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), }, Expvar: ExpvarConfig{ Enabled: true, }, } zpagesExt := newServer(cfg, newZpagesTelemetrySettings()) require.NotNil(t, zpagesExt) require.NoError(t, zpagesExt.Start(context.Background(), newZPagesHost())) t.Cleanup(func() { require.NoError(t, zpagesExt.Shutdown(context.Background())) }) // Give a chance for the server goroutine to run. runtime.Gosched() _, zpagesPort, err := net.SplitHostPort(cfg.Endpoint) require.NoError(t, err) client := &http.Client{} resp, err := client.Get("http://localhost:" + zpagesPort + "/debug/expvarz") require.NoError(t, err) defer resp.Body.Close() require.Equal(t, http.StatusOK, resp.StatusCode) } opentelemetry-collector-0.141.0/featuregate/000077500000000000000000000000001511331344600210325ustar00rootroot00000000000000opentelemetry-collector-0.141.0/featuregate/Makefile000066400000000000000000000000331511331344600224660ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/featuregate/README.md000066400000000000000000000070151511331344600223140ustar00rootroot00000000000000# Collector Feature Gates This package provides a mechanism that allows operators to enable and disable experimental or transitional features at deployment time. These flags should be able to govern the behavior of the application starting as early as possible and should be available to every component such that decisions may be made based on flags at the component level. ## Usage Feature gates must be defined and registered with the global registry in an `init()` function. This makes the `Gate` available to be configured and queried with the defined [`Stage`](#feature-lifecycle) default value. A `Gate` can have a list of associated issues that allow users to refer to the issue and report any additional problems or understand the context of the `Gate`. Once a `Gate` has been marked as `Stable`, it must have a `RemovalVersion` set. ```go var myFeatureGate = featuregate.GlobalRegistry().MustRegister( "namespaced.uniqueIdentifier", featuregate.Stable, featuregate.WithRegisterFromVersion("v0.65.0") featuregate.WithRegisterDescription("A brief description of what the gate controls"), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/issues/6167"), featuregate.WithRegisterToVersion("v0.70.0")) ``` The status of the gate may later be checked by interrogating the global feature gate registry: ```go if myFeatureGate.IsEnabled() { setupNewFeature() } ``` Note that querying the registry takes a read lock and accesses a map, so it should be done once and the result cached for local use if repeated checks are required. Avoid querying the registry in a loop. ## Controlling Gates Feature gates can be enabled or disabled via the CLI, with the `--feature-gates` flag. When using the CLI flag, gate identifiers must be presented as a comma-delimited list. Gate identifiers prefixed with `-` will disable the gate and prefixing with `+` or with no prefix will enable the gate. ```shell otelcol --config=config.yaml --feature-gates=gate1,-gate2,+gate3 ``` This will enable `gate1` and `gate3` and disable `gate2`. ## Feature Lifecycle Features controlled by a `Gate` should follow a three-stage lifecycle, modeled after the [system used by Kubernetes](https://kubernetes.io/docs/reference/command-line-tools-reference/feature-gates/#feature-stages): 1. An `alpha` stage where the feature is disabled by default and must be enabled through a `Gate`. 2. A `beta` stage where the feature has been well tested and is enabled by default but can be disabled through a `Gate`. 3. A generally available or `stable` stage where the feature is permanently enabled. At this stage the gate should no longer be explicitly used. Disabling the gate will produce an error and explicitly enabling will produce a warning log. 4. A `stable` feature gate will be removed in the version specified by its `ToVersion` value. Features that prove unworkable in the `alpha` stage may be discontinued without proceeding to the `beta` stage. Instead, they will proceed to the `deprecated` stage, which will feature is permanently disabled. A feature gate will be removed once it has been `deprecated` for at least 2 releases of the collector. Features that make it to the `beta` stage are intended to reach general availability but may still be discontinued. If, after wider use, it is determined that the gate should be discontinued it will be reverted to the `alpha` stage for 2 releases and then proceed to the `deprecated` stage. If instead it is ready for general availability it will proceed to the `stable` stage. opentelemetry-collector-0.141.0/featuregate/flag.go000066400000000000000000000032631511331344600222760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate // import "go.opentelemetry.io/collector/featuregate" import ( "flag" "strings" "go.uber.org/multierr" ) const ( featureGatesFlag = "feature-gates" featureGatesFlagDescription = "Comma-delimited list of feature gate identifiers. Prefix with '-' to disable the feature. '+' or no prefix will enable the feature." ) // RegisterFlagsOption is an option for RegisterFlags. type RegisterFlagsOption interface { private() } // RegisterFlags that directly applies feature gate statuses to a Registry. func (r *Registry) RegisterFlags(flagSet *flag.FlagSet, _ ...RegisterFlagsOption) { flagSet.Var(&flagValue{reg: r}, featureGatesFlag, featureGatesFlagDescription) } // flagValue implements the flag.Value interface and directly applies feature gate statuses to a Registry. type flagValue struct { reg *Registry } func (f *flagValue) String() string { // This function can be called by isZeroValue https://github.com/golang/go/blob/go1.23.3/src/flag/flag.go#L630 // which creates an instance of flagValue using reflect.New. In this case, the field `reg` is nil. if f.reg == nil { return "" } var ids []string f.reg.VisitAll(func(g *Gate) { id := g.ID() if !g.IsEnabled() { id = "-" + id } ids = append(ids, id) }) return strings.Join(ids, ",") } func (f *flagValue) Set(s string) error { if s == "" { return nil } var errs error ids := strings.Split(s, ",") for i := range ids { id := ids[i] val := true switch id[0] { case '-': id = id[1:] val = false case '+': id = id[1:] } errs = multierr.Append(errs, f.reg.Set(id, val)) } return errs } opentelemetry-collector-0.141.0/featuregate/flag_test.go000066400000000000000000000110271511331344600233320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate import ( "flag" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewFlag(t *testing.T) { for _, tt := range []struct { name string input string expectedSetErr bool expected map[string]bool expectedStr string }{ { name: "empty item", input: "", expected: map[string]bool{"alpha": false, "beta": true, "deprecated": false, "stable": true}, expectedStr: "-alpha,beta,-deprecated,stable", }, { name: "simple enable alpha", input: "alpha", expected: map[string]bool{"alpha": true, "beta": true, "deprecated": false, "stable": true}, expectedStr: "alpha,beta,-deprecated,stable", }, { name: "plus enable alpha", input: "+alpha", expected: map[string]bool{"alpha": true, "beta": true, "deprecated": false, "stable": true}, expectedStr: "alpha,beta,-deprecated,stable", }, { name: "disabled beta", input: "-beta", expected: map[string]bool{"alpha": false, "beta": false, "deprecated": false, "stable": true}, expectedStr: "-alpha,-beta,-deprecated,stable", }, { name: "multiple items", input: "-beta,alpha", expected: map[string]bool{"alpha": true, "beta": false, "deprecated": false, "stable": true}, expectedStr: "alpha,-beta,-deprecated,stable", }, { name: "multiple items with plus", input: "-beta,+alpha", expected: map[string]bool{"alpha": true, "beta": false, "deprecated": false, "stable": true}, expectedStr: "alpha,-beta,-deprecated,stable", }, { name: "repeated items", input: "alpha,-beta,-alpha", expected: map[string]bool{"alpha": false, "beta": false, "deprecated": false, "stable": true}, expectedStr: "-alpha,-beta,-deprecated,stable", }, { name: "multiple plus items", input: "+alpha,+beta", expected: map[string]bool{"alpha": true, "beta": true, "deprecated": false, "stable": true}, expectedStr: "alpha,beta,-deprecated,stable", }, { name: "enable stable", input: "stable", expected: map[string]bool{"alpha": false, "beta": true, "deprecated": false, "stable": true}, expectedStr: "-alpha,beta,-deprecated,stable", }, { name: "disable stable", input: "-stable", expectedSetErr: true, expected: map[string]bool{"alpha": false, "beta": true, "deprecated": false, "stable": true}, expectedStr: "-alpha,beta,-deprecated,stable", }, { name: "enable deprecated", input: "deprecated", expectedSetErr: true, expected: map[string]bool{"alpha": false, "beta": true, "deprecated": false, "stable": true}, expectedStr: "-alpha,beta,-deprecated,stable", }, { name: "disable deprecated", input: "-deprecated", expected: map[string]bool{"alpha": false, "beta": true, "deprecated": false, "stable": true}, expectedStr: "-alpha,beta,-deprecated,stable", }, { name: "enable missing", input: "missing", expectedSetErr: true, expected: map[string]bool{"alpha": false, "beta": true, "deprecated": false, "stable": true}, expectedStr: "-alpha,beta,-deprecated,stable", }, { name: "disable missing", input: "missing", expectedSetErr: true, expected: map[string]bool{"alpha": false, "beta": true, "deprecated": false, "stable": true}, expectedStr: "-alpha,beta,-deprecated,stable", }, } { t.Run(tt.name, func(t *testing.T) { reg := NewRegistry() reg.MustRegister("alpha", StageAlpha) reg.MustRegister("beta", StageBeta) reg.MustRegister("deprecated", StageDeprecated, WithRegisterToVersion("1.0.0")) reg.MustRegister("stable", StageStable, WithRegisterToVersion("1.0.0")) fs := flag.NewFlagSet("test", flag.ContinueOnError) reg.RegisterFlags(fs) registrationFlag := fs.Lookup(featureGatesFlag) require.NotNil(t, registrationFlag) if tt.expectedSetErr { require.Error(t, registrationFlag.Value.Set(tt.input)) } else { require.NoError(t, registrationFlag.Value.Set(tt.input)) } got := map[string]bool{} reg.VisitAll(func(g *Gate) { got[g.ID()] = g.IsEnabled() }) assert.Equal(t, tt.expected, got) assert.Equal(t, tt.expectedStr, registrationFlag.Value.String()) }) } } func TestFlagStringNotInitialize(t *testing.T) { flag := &flagValue{} assert.Empty(t, flag.String()) } opentelemetry-collector-0.141.0/featuregate/gate.go000066400000000000000000000027461511331344600223120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate // import "go.opentelemetry.io/collector/featuregate" import ( "fmt" "sync/atomic" "github.com/hashicorp/go-version" ) // Gate is an immutable object that is owned by the Registry and represents an individual feature that // may be enabled or disabled based on the lifecycle state of the feature and CLI flags specified by the user. type Gate struct { id string description string referenceURL string fromVersion *version.Version toVersion *version.Version stage Stage enabled *atomic.Bool } // ID returns the id of the Gate. func (g *Gate) ID() string { return g.id } // IsEnabled returns true if the feature described by the Gate is enabled. func (g *Gate) IsEnabled() bool { return g.enabled.Load() } // Description returns the description for the Gate. func (g *Gate) Description() string { return g.description } // Stage returns the Gate's lifecycle stage. func (g *Gate) Stage() Stage { return g.stage } // ReferenceURL returns the URL to the contextual information about the Gate. func (g *Gate) ReferenceURL() string { return g.referenceURL } // FromVersion returns the version information when the Gate's was added. func (g *Gate) FromVersion() string { return fmt.Sprintf("v%s", g.fromVersion) } // ToVersion returns the version information when Gate's in StageStable. func (g *Gate) ToVersion() string { return fmt.Sprintf("v%s", g.toVersion) } opentelemetry-collector-0.141.0/featuregate/gate_test.go000066400000000000000000000017071511331344600233450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate import ( "sync/atomic" "testing" "github.com/hashicorp/go-version" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestGate(t *testing.T) { enabled := &atomic.Bool{} enabled.Store(true) from, err := version.NewVersion("v0.61.0") require.NoError(t, err) to, err := version.NewVersion("v0.64.0") require.NoError(t, err) g := &Gate{ id: "test", description: "test gate", enabled: enabled, stage: StageAlpha, referenceURL: "http://example.com", fromVersion: from, toVersion: to, } assert.Equal(t, "test", g.ID()) assert.Equal(t, "test gate", g.Description()) assert.True(t, g.IsEnabled()) assert.Equal(t, StageAlpha, g.Stage()) assert.Equal(t, "http://example.com", g.ReferenceURL()) assert.Equal(t, "v0.61.0", g.FromVersion()) assert.Equal(t, "v0.64.0", g.ToVersion()) } opentelemetry-collector-0.141.0/featuregate/go.mod000066400000000000000000000011761511331344600221450ustar00rootroot00000000000000module go.opentelemetry.io/collector/featuregate go 1.24.0 require ( github.com/hashicorp/go-version v1.7.0 github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) opentelemetry-collector-0.141.0/featuregate/go.sum000066400000000000000000000047251511331344600221750ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/featuregate/package_test.go000066400000000000000000000003141511331344600240110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/featuregate/registry.go000066400000000000000000000146651511331344600232450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate // import "go.opentelemetry.io/collector/featuregate" import ( "errors" "fmt" "net/url" "regexp" "sort" "sync" "sync/atomic" "github.com/hashicorp/go-version" ) var ( globalRegistry = NewRegistry() // idRegexp is used to validate the ID of a Gate. // IDs' characters must be alphanumeric or dots. idRegexp = regexp.MustCompile(`^[0-9a-zA-Z.]*$`) ) // ErrAlreadyRegistered is returned when adding a Gate that is already registered. var ErrAlreadyRegistered = errors.New("gate is already registered") // GlobalRegistry returns the global Registry. func GlobalRegistry() *Registry { return globalRegistry } type Registry struct { gates sync.Map } // NewRegistry returns a new empty Registry. func NewRegistry() *Registry { return &Registry{} } // RegisterOption allows to configure additional information about a Gate during registration. type RegisterOption interface { apply(g *Gate) error } type registerOptionFunc func(g *Gate) error func (ro registerOptionFunc) apply(g *Gate) error { return ro(g) } // WithRegisterDescription adds description for the Gate. func WithRegisterDescription(description string) RegisterOption { return registerOptionFunc(func(g *Gate) error { g.description = description return nil }) } // WithRegisterReferenceURL adds a URL that has all the contextual information about the Gate. // referenceURL must be a valid URL as defined by `net/url.Parse`. func WithRegisterReferenceURL(referenceURL string) RegisterOption { return registerOptionFunc(func(g *Gate) error { if _, err := url.Parse(referenceURL); err != nil { return fmt.Errorf("WithRegisterReferenceURL: invalid reference URL %q: %w", referenceURL, err) } g.referenceURL = referenceURL return nil }) } // WithRegisterFromVersion is used to set the Gate "FromVersion". // The "FromVersion" contains the Collector release when a feature is introduced. // fromVersion must be a valid version string: it may start with 'v' and must be in the format Major.Minor.Patch[-PreRelease]. // PreRelease is optional and may have dashes, tildes and ASCII alphanumeric characters. func WithRegisterFromVersion(fromVersion string) RegisterOption { return registerOptionFunc(func(g *Gate) error { from, err := version.NewVersion(fromVersion) if err != nil { return fmt.Errorf("WithRegisterFromVersion: invalid version %q: %w", fromVersion, err) } g.fromVersion = from return nil }) } // WithRegisterToVersion is used to set the Gate "ToVersion". // The "ToVersion", if not empty, contains the last Collector release in which you can still use a feature gate. // If the feature stage is either "Deprecated" or "Stable", the "ToVersion" is the Collector release when the feature is removed. // toVersion must be a valid version string: it may start with 'v' and must be in the format Major.Minor.Patch[-PreRelease]. // PreRelease is optional and may have dashes, tildes and ASCII alphanumeric characters. func WithRegisterToVersion(toVersion string) RegisterOption { return registerOptionFunc(func(g *Gate) error { to, err := version.NewVersion(toVersion) if err != nil { return fmt.Errorf("WithRegisterToVersion: invalid version %q: %w", toVersion, err) } g.toVersion = to return nil }) } // MustRegister like Register but panics if an invalid ID or gate options are provided. func (r *Registry) MustRegister(id string, stage Stage, opts ...RegisterOption) *Gate { g, err := r.Register(id, stage, opts...) if err != nil { panic(err) } return g } func validateID(id string) error { if id == "" { return errors.New("empty ID") } if !idRegexp.MatchString(id) { return errors.New("invalid character(s) in ID") } return nil } // Register a Gate and return it. The returned Gate can be used to check if is enabled or not. // id must be an ASCII alphanumeric nonempty string. Dots are allowed for namespacing. func (r *Registry) Register(id string, stage Stage, opts ...RegisterOption) (*Gate, error) { if err := validateID(id); err != nil { return nil, fmt.Errorf("invalid ID %q: %w", id, err) } g := &Gate{ id: id, stage: stage, } for _, opt := range opts { err := opt.apply(g) if err != nil { return nil, fmt.Errorf("failed to apply option: %w", err) } } switch g.stage { case StageAlpha, StageDeprecated: g.enabled = &atomic.Bool{} case StageBeta, StageStable: enabled := &atomic.Bool{} enabled.Store(true) g.enabled = enabled default: return nil, fmt.Errorf("unknown stage value %q for gate %q", stage, id) } if (g.stage == StageStable || g.stage == StageDeprecated) && g.toVersion == nil { return nil, fmt.Errorf("no removal version set for %v gate %q", g.stage.String(), id) } if g.fromVersion != nil && g.toVersion != nil && g.toVersion.LessThan(g.fromVersion) { return nil, fmt.Errorf("toVersion %q is before fromVersion %q", g.toVersion, g.fromVersion) } if _, loaded := r.gates.LoadOrStore(id, g); loaded { return nil, fmt.Errorf("failed to register %q: %w", id, ErrAlreadyRegistered) } return g, nil } // Set the enabled valued for a Gate identified by the given id. func (r *Registry) Set(id string, enabled bool) error { v, ok := r.gates.Load(id) if !ok { validGates := []string{} r.VisitAll(func(g *Gate) { validGates = append(validGates, g.ID()) }) return fmt.Errorf("no such feature gate %q. valid gates: %v", id, validGates) } g := v.(*Gate) switch g.stage { case StageStable: if !enabled { return fmt.Errorf("feature gate %q is stable, can not be disabled", id) } fmt.Printf("Feature gate %q is stable and already enabled. It will be removed in version %v and continued use of the gate after version %v will result in an error.\n", id, g.toVersion, g.toVersion) case StageDeprecated: if enabled { return fmt.Errorf("feature gate %q is deprecated, can not be enabled", id) } fmt.Printf("Feature gate %q is deprecated and already disabled. It will be removed in version %v and continued use of the gate after version %v will result in an error.\n", id, g.toVersion, g.toVersion) default: g.enabled.Store(enabled) } return nil } // VisitAll visits all the gates in lexicographical order, calling fn for each. func (r *Registry) VisitAll(fn func(*Gate)) { var gates []*Gate r.gates.Range(func(_, value any) bool { gates = append(gates, value.(*Gate)) return true }) sort.Slice(gates, func(i, j int) bool { return gates[i].ID() < gates[j].ID() }) for i := range gates { fn(gates[i]) } } opentelemetry-collector-0.141.0/featuregate/registry_test.go000066400000000000000000000117521511331344600242760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestGlobalRegistry(t *testing.T) { assert.Same(t, globalRegistry, GlobalRegistry()) } func TestRegistry(t *testing.T) { r := NewRegistry() // Expect that no gates to visit. r.VisitAll(func(*Gate) { t.FailNow() }) const id = "foo" g, err := r.Register(id, StageBeta, WithRegisterDescription("Test Gate")) require.NoError(t, err) r.VisitAll(func(gate *Gate) { assert.Equal(t, id, gate.ID()) }) assert.True(t, g.IsEnabled()) require.NoError(t, r.Set(id, false)) assert.False(t, g.IsEnabled()) _, err = r.Register(id, StageBeta) require.ErrorIs(t, err, ErrAlreadyRegistered) assert.Panics(t, func() { r.MustRegister(id, StageBeta) }) } func TestRegistryApplyError(t *testing.T) { r := NewRegistry() require.Error(t, r.Set("foo", true)) r.MustRegister("bar", StageAlpha) require.Error(t, r.Set("foo", true)) _, err := r.Register("foo", StageStable) require.Error(t, err) require.Error(t, r.Set("foo", true)) r.MustRegister("foo", StageStable, WithRegisterToVersion("v1.0.0")) require.Error(t, r.Set("foo", false)) require.Error(t, r.Set("deprecated", true)) _, err = r.Register("deprecated", StageDeprecated) require.Error(t, err) require.Error(t, r.Set("deprecated", true)) r.MustRegister("deprecated", StageDeprecated, WithRegisterToVersion("v1.0.0")) assert.Error(t, r.Set("deprecated", true)) } func TestRegistryApply(t *testing.T) { r := NewRegistry() fooGate := r.MustRegister("foo", StageAlpha, WithRegisterDescription("Test Gate")) assert.False(t, fooGate.IsEnabled()) require.NoError(t, r.Set(fooGate.ID(), true)) assert.True(t, fooGate.IsEnabled()) } func TestRegisterGateLifecycle(t *testing.T) { for _, tc := range []struct { name string id string stage Stage opts []RegisterOption enabled bool shouldErr bool }{ { name: "StageAlpha Flag", id: "test.gate", stage: StageAlpha, enabled: false, shouldErr: false, }, { name: "StageAlpha Flag with all options", id: "test.gate", stage: StageAlpha, opts: []RegisterOption{ WithRegisterDescription("test.gate"), WithRegisterReferenceURL("http://example.com/issue/1"), WithRegisterToVersion("v0.88.0"), }, enabled: false, shouldErr: false, }, { name: "StageBeta Flag", id: "test.gate", stage: StageBeta, enabled: true, shouldErr: false, }, { name: "StageStable Flag", id: "test.gate", stage: StageStable, opts: []RegisterOption{ WithRegisterToVersion("v1.0.0-rcv.0014"), }, enabled: true, shouldErr: false, }, { name: "StageDeprecated Flag", id: "test.gate", stage: StageDeprecated, opts: []RegisterOption{ WithRegisterToVersion("v0.89.0"), }, enabled: false, shouldErr: false, }, { name: "Invalid stage", id: "test.gate", stage: Stage(-1), shouldErr: true, }, { name: "StageStable gate missing removal version", id: "test.gate", stage: StageStable, shouldErr: true, }, { name: "StageDeprecated gate missing removal version", id: "test.gate", stage: StageDeprecated, shouldErr: true, }, { name: "Duplicate gate", id: "existing.gate", stage: StageStable, shouldErr: true, }, { name: "Invalid gate name", id: "+invalid.gate.name", stage: StageAlpha, shouldErr: true, }, { name: "Invalid empty gate", id: "", stage: StageAlpha, shouldErr: true, }, { name: "Invalid gate to version", id: "invalid.gate.to.version", stage: StageAlpha, opts: []RegisterOption{WithRegisterToVersion("invalid-version")}, shouldErr: true, }, { name: "Invalid gate from version", id: "invalid.gate.from.version", stage: StageAlpha, opts: []RegisterOption{WithRegisterFromVersion("invalid-version")}, shouldErr: true, }, { name: "Invalid gate reference URL", id: "invalid.gate.reference.URL", stage: StageAlpha, opts: []RegisterOption{WithRegisterReferenceURL(":invalid-url")}, shouldErr: true, }, { name: "Empty version range", id: "invalid.gate.version.range", stage: StageAlpha, opts: []RegisterOption{ WithRegisterFromVersion("v0.88.0"), WithRegisterToVersion("v0.87.0"), }, shouldErr: true, }, } { t.Run(tc.name, func(t *testing.T) { r := NewRegistry() r.MustRegister("existing.gate", StageBeta) if tc.shouldErr { _, err := r.Register(tc.id, tc.stage, tc.opts...) require.Error(t, err) assert.Panics(t, func() { r.MustRegister(tc.id, tc.stage, tc.opts...) }) return } g, err := r.Register(tc.id, tc.stage, tc.opts...) require.NoError(t, err) assert.Equal(t, tc.enabled, g.IsEnabled()) }) } } opentelemetry-collector-0.141.0/featuregate/stage.go000066400000000000000000000026421511331344600224700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate // import "go.opentelemetry.io/collector/featuregate" // Stage represents the Gate's lifecycle and what is the expected state of it. type Stage int8 const ( // StageAlpha is used when creating a new feature and the Gate must be explicitly enabled // by the operator. // // The Gate will be disabled by default. StageAlpha Stage = iota // StageBeta is used when the feature gate is well tested and is enabled by default, // but can be disabled by a Gate. // // The Gate will be enabled by default. StageBeta // StageStable is used when feature is permanently enabled and can not be disabled by a Gate. // This value is used to provide feedback to the user that the gate will be removed in the next versions. // // The Gate will be enabled by default and will return an error if disabled. StageStable // StageDeprecated is used when feature is permanently disabled and can not be enabled by a Gate. // This value is used to provide feedback to the user that the gate will be removed in the next versions. // // The Gate will be disabled by default and will return an error if modified. StageDeprecated ) func (s Stage) String() string { switch s { case StageAlpha: return "Alpha" case StageBeta: return "Beta" case StageStable: return "Stable" case StageDeprecated: return "Deprecated" } return "Unknown" } opentelemetry-collector-0.141.0/featuregate/stage_test.go000066400000000000000000000006771511331344600235350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package featuregate import ( "testing" "github.com/stretchr/testify/assert" ) func TestStageString(t *testing.T) { assert.Equal(t, "Alpha", StageAlpha.String()) assert.Equal(t, "Beta", StageBeta.String()) assert.Equal(t, "Stable", StageStable.String()) assert.Equal(t, "Deprecated", StageDeprecated.String()) assert.Equal(t, "Unknown", Stage(-1).String()) } opentelemetry-collector-0.141.0/filter/000077500000000000000000000000001511331344600200235ustar00rootroot00000000000000opentelemetry-collector-0.141.0/filter/Makefile000066400000000000000000000000331511331344600214570ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/filter/config.go000066400000000000000000000030301511331344600216130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package filter // import "go.opentelemetry.io/collector/filter" import ( "errors" "regexp" ) // Config configures the matching behavior of a Filter. type Config struct { Strict string `mapstructure:"strict"` Regex string `mapstructure:"regexp"` // prevent unkeyed literal initialization _ struct{} } func (c Config) Validate() error { if c.Strict == "" && c.Regex == "" { return errors.New("must specify either strict or regex") } if c.Strict != "" && c.Regex != "" { return errors.New("strict and regex cannot be used together") } if c.Regex != "" { _, err := regexp.Compile(c.Regex) if err != nil { return err } } return nil } type combinedFilter struct { stricts map[any]struct{} regexes []*regexp.Regexp } // CreateFilter creates a Filter out of a set of Config configuration objects. func CreateFilter(configs []Config) Filter { cf := &combinedFilter{ stricts: make(map[any]struct{}), } for _, config := range configs { if config.Strict != "" { cf.stricts[config.Strict] = struct{}{} } if config.Regex != "" { // Validate() call above ensures that the regex is valid. re := regexp.MustCompile(config.Regex) cf.regexes = append(cf.regexes, re) } } return cf } func (cf *combinedFilter) Matches(toMatch any) bool { _, ok := cf.stricts[toMatch] if ok { return ok } if str, ok := toMatch.(string); ok { for _, re := range cf.regexes { if re.MatchString(str) { return true } } } return false } opentelemetry-collector-0.141.0/filter/config_test.go000066400000000000000000000043001511331344600226530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package filter import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func readTestdataConfigYamls(t *testing.T, filename string) map[string][]Config { testFile := filepath.Join("testdata", filename) v, err := confmaptest.LoadConf(testFile) require.NoError(t, err) cfgs := map[string][]Config{} require.NoErrorf(t, v.Unmarshal(&cfgs, confmap.WithIgnoreUnused()), "unable to unmarshal yaml from file %v", testFile) return cfgs } func TestConfig(t *testing.T) { actualConfigs := readTestdataConfigYamls(t, "config.yaml") expectedConfigs := map[string][]Config{ "regexp/default": { { Regex: "one|two", }, }, "strict/default": { { Strict: "strict", }, }, } for testName, actualCfg := range actualConfigs { t.Run(testName, func(t *testing.T) { expCfg, ok := expectedConfigs[testName] assert.True(t, ok) assert.Equal(t, expCfg, actualCfg) for _, cfg := range actualCfg { require.NoError(t, cfg.Validate()) } fs := CreateFilter(actualCfg) assert.NotNil(t, fs) }) } } func TestMatches(t *testing.T) { cfg := []Config{ { Strict: "a", }, { Strict: "b", }, { Regex: "a|b|c", }, } for _, c := range cfg { require.NoError(t, c.Validate()) } fs := CreateFilter(cfg) assert.True(t, fs.Matches("a")) assert.True(t, fs.Matches("b")) assert.True(t, fs.Matches("c")) } func TestConfigInvalid(t *testing.T) { actualConfigs := readTestdataConfigYamls(t, "config_invalid.yaml") expectedConfigs := map[string][]Config{ "invalid/regexp": { { Regex: "(.*[", }, }, "invalid/config_empty": { { Regex: "", Strict: "", }, }, "invalid/config_both_set": { { Regex: "1", Strict: "1", }, }, } for testName, actualCfg := range actualConfigs { t.Run(testName, func(t *testing.T) { expCfg, ok := expectedConfigs[testName] assert.True(t, ok) assert.Equal(t, expCfg, actualCfg) for _, cfg := range actualCfg { assert.Error(t, cfg.Validate()) } }) } } opentelemetry-collector-0.141.0/filter/doc.go000066400000000000000000000003551511331344600211220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package filter provides an interface for matching strings against a set of string filters. package filter // import "go.opentelemetry.io/collector/filter" opentelemetry-collector-0.141.0/filter/filter.go000066400000000000000000000005651511331344600216450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package filter // import "go.opentelemetry.io/collector/filter" // Filter is an interface for matching values against a set of filters. type Filter interface { // Matches returns true if the given value matches at least one // of the filters encapsulated by the Filter. Matches(any) bool } opentelemetry-collector-0.141.0/filter/go.mod000066400000000000000000000021211511331344600211250ustar00rootroot00000000000000module go.opentelemetry.io/collector/filter go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/confmap v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.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 gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../confmap replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/filter/go.sum000066400000000000000000000067421511331344600211670ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/filter/testdata/000077500000000000000000000000001511331344600216345ustar00rootroot00000000000000opentelemetry-collector-0.141.0/filter/testdata/config.yaml000066400000000000000000000004331511331344600237650ustar00rootroot00000000000000# Yaml form of the configuration for Filters # This configuration can be embedded into other component's yamls # The top level here are just test names and do not represent part of the actual configuration. regexp/default: - regexp: "one|two" strict/default: - strict: "strict" opentelemetry-collector-0.141.0/filter/testdata/config_invalid.yaml000066400000000000000000000005401511331344600254720ustar00rootroot00000000000000# Yaml form of the configuration for Filters # This configuration can be embedded into other component's yamls # The top level here are just test names and do not represent part of the actual configuration. invalid/regexp: - regexp: "(.*[" invalid/config_empty: - regexp: "" strict: "" invalid/config_both_set: - regexp: "1" strict: "1" opentelemetry-collector-0.141.0/go.mod000066400000000000000000000023731511331344600176510ustar00rootroot00000000000000module go.opentelemetry.io/collector // NOTE: // This go.mod is NOT used to build any official binary. // To see the builder manifests used for official binaries, // check https://github.com/open-telemetry/opentelemetry-collector-releases // // For the OpenTelemetry Collector Core distribution specifically, see // https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol go 1.24.0 require ( github.com/stretchr/testify v1.11.1 google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.10 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 v0.57.1 // Release failed, use v0.57.2 v0.57.0 // Release failed, use v0.57.2 v0.32.0 // Contains incomplete metrics transition to proto 0.9.0, random components are not working. ) opentelemetry-collector-0.141.0/go.sum000066400000000000000000000066241511331344600177010ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/internal/000077500000000000000000000000001511331344600203525ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/buildscripts/000077500000000000000000000000001511331344600230615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/buildscripts/compare-apidiff.sh000077500000000000000000000031251511331344600264470ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # This script is used to compare API state snapshots to the current package state in order to validate releases are not breaking backwards compatibility. usage() { echo "Usage: $0" echo echo "-c Check-incompatibility mode. Script will fail if an incompatible change is found. Default: 'false'" echo "-p Package to generate API state snapshot of. Default: ''" echo "-d directory where prior states will be read from. Default: './internal/data/apidiff'" exit 1 } package="" input_dir="./internal/data/apidiff" check_only=false repo_toplevel="$( git rev-parse --show-toplevel )" tools_mod_file="${repo_toplevel}/internal/tools/go.mod" while getopts "cp:d:" o; do case "${o}" in c) check_only=true ;; p) package=$OPTARG ;; d) input_dir=$OPTARG ;; *) usage ;; esac done shift $((OPTIND-1)) if [ -z "$package" ]; then usage fi set -e if [ -e "$input_dir"/"$package"/apidiff.state ]; then changes=$(go tool -modfile "${tools_mod_file}" apidiff "$input_dir"/"$package"/apidiff.state "$package") if [ -n "$changes" ] && [ "$changes" != " " ]; then SUB='Incompatible changes:' if [ $check_only = true ] && [[ "$changes" =~ .*"$SUB".* ]]; then echo "Incompatible Changes Found." echo "Check the logs in the GitHub Action log group: 'Compare-States'." exit 1 else echo "Changes found in $package:" echo "$changes" fi fi fi opentelemetry-collector-0.141.0/internal/buildscripts/gen-apidiff.sh000077500000000000000000000032161511331344600255730ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # This script is used to create API state snapshots used to validate releases are not breaking backwards compatibility. usage() { echo "Usage: $0" echo echo "-d Dry-run mode. No project files will not be modified. Default: 'false'" echo "-p Package to generate API state snapshot of. Default: ''" echo "-o Output directory where state will be written to. Default: './internal/data/apidiff'" exit 1 } dry_run=false package="" output_dir="./internal/data/apidiff" repo_toplevel="$( git rev-parse --show-toplevel )" tools_mod_file="${repo_toplevel}/internal/tools/go.mod" while getopts "dp:o:" o; do case "${o}" in d) dry_run=true ;; p) package=$OPTARG ;; o) output_dir=$OPTARG ;; *) usage ;; esac done shift $((OPTIND-1)) if [ -z "$package" ]; then usage fi set -ex # Create temp dir for generated files. # Source: https://unix.stackexchange.com/a/84980 tmp_dir=$(mktemp -d 2>/dev/null || mktemp -d -t 'apidiff') clean_up() { ARG=$? if [ $dry_run = true ]; then echo "Dry-run complete. Generated files can be found in $tmp_dir" else rm -rf "$tmp_dir" fi exit $ARG } trap clean_up EXIT mkdir -p "$tmp_dir/$package" go tool -modfile "${tools_mod_file}" apidiff -w "$tmp_dir"/"$package"/apidiff.state "$package" # Copy files if not in dry-run mode. if [ $dry_run = false ]; then mkdir -p "$output_dir/$package" && \ cp "$tmp_dir/$package/apidiff.state" \ "$output_dir/$package" fi opentelemetry-collector-0.141.0/internal/buildscripts/gen-certs.sh000077500000000000000000000072471511331344600253210ustar00rootroot00000000000000#!/usr/bin/env bash # # Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 # This script is used to create the CA, server and client's certificates and keys required by unit tests. # These certificates use the Subject Alternative Name extension rather than the Common Name, which will be unsupported from Go 1.15. usage() { echo "Usage: $0 [-d]" echo echo "-d Dry-run mode. No project files will not be modified. Default: 'false'" echo "-m Domain name to use in the certificate. Default: 'localhost'" echo "-o Output directory where certificates will be written to. Default: '.'; the current directory" echo "-s A suffix for the generated certificate. Default: \"\"; an empty string" exit 1 } dry_run=false domain="localhost" output_dir="." suffix="" while getopts "dm:o:s:" o; do case "${o}" in d) dry_run=true ;; m) domain=$OPTARG ;; o) output_dir=$OPTARG ;; s) suffix=$OPTARG ;; *) usage ;; esac done shift $((OPTIND-1)) set -ex # Create temp dir for generated files. tmp_dir=$(mktemp -d -t certificatesXXX) clean_up() { ARG=$? if [ $dry_run = true ]; then echo "Dry-run complete. Generated files can be found in $tmp_dir" else rm -rf "$tmp_dir" fi exit $ARG } trap clean_up EXIT gen_ssl_conf() { domain_name=$1 output_file=$2 cat << EOF > "$output_file" [ req ] prompt = no default_bits = 2048 distinguished_name = req_distinguished_name req_extensions = req_ext [ req_distinguished_name ] countryName = AU stateOrProvinceName = Australia localityName = Sydney organizationName = MyOrgName commonName = MyCommonName [ req_ext ] subjectAltName = @alt_names [alt_names] DNS.1 = $domain_name EOF } # Generate config files. gen_ssl_conf "$domain" "$tmp_dir/ssl.conf" # Create CA (accept defaults from prompts). openssl genrsa -out "$tmp_dir/ca${suffix}.key" 2048 openssl req -new -key "$tmp_dir/ca${suffix}.key" -x509 -days 3650 -out "$tmp_dir/ca${suffix}.crt" -config "$tmp_dir/ssl.conf" # Create client and server keys. openssl genrsa -out "$tmp_dir/server${suffix}.key" 2048 openssl genrsa -out "$tmp_dir/client${suffix}.key" 2048 # Create certificate sign request using the above created keys. openssl req -new -nodes -key "$tmp_dir/server${suffix}.key" -out "$tmp_dir/server${suffix}.csr" -config "$tmp_dir/ssl.conf" openssl req -new -nodes -key "$tmp_dir/client${suffix}.key" -out "$tmp_dir/client${suffix}.csr" -config "$tmp_dir/ssl.conf" # Creating the client and server certificates. openssl x509 -req \ -sha256 \ -days 3650 \ -in "$tmp_dir/server${suffix}.csr" \ -out "$tmp_dir/server${suffix}.crt" \ -extensions req_ext \ -CA "$tmp_dir/ca${suffix}.crt" \ -CAkey "$tmp_dir/ca${suffix}.key" \ -CAcreateserial \ -extfile "$tmp_dir/ssl.conf" openssl x509 -req \ -sha256 \ -days 3650 \ -in "$tmp_dir/client${suffix}.csr" \ -out "$tmp_dir/client${suffix}.crt" \ -extensions req_ext \ -CA "$tmp_dir/ca${suffix}.crt" \ -CAkey "$tmp_dir/ca${suffix}.key" \ -CAcreateserial \ -extfile "$tmp_dir/ssl.conf" # Copy files if not in dry-run mode. if [ $dry_run = false ]; then cp "$tmp_dir/ca${suffix}.crt" \ "$tmp_dir/client${suffix}.crt" \ "$tmp_dir/client${suffix}.key" \ "$tmp_dir/server${suffix}.crt" \ "$tmp_dir/server${suffix}.key" \ "$output_dir" fi opentelemetry-collector-0.141.0/internal/cmd/000077500000000000000000000000001511331344600211155ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/000077500000000000000000000000001511331344600227005ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/Makefile000066400000000000000000000000411511331344600243330ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/internal/cmd/pdatagen/go.mod000066400000000000000000000001571511331344600240110ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/cmd/pdatagen go 1.24.0 require github.com/ettle/strcase v0.2.0 opentelemetry-collector-0.141.0/internal/cmd/pdatagen/go.sum000066400000000000000000000002471511331344600240360ustar00rootroot00000000000000github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/000077500000000000000000000000001511331344600245145ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/000077500000000000000000000000001511331344600256055ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/base_slices.go000066400000000000000000000051461511331344600304160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) type baseSlice interface { getName() string getHasWrapper() bool getOriginFullName() string getElementOriginName() string getElementNullable() bool getPackageName() string } // messageSlice generates code for a slice of pointer fields. The generated structs cannot be used from other packages. type messageSlice struct { structName string packageName string elementNullable bool element *messageStruct } func (ss *messageSlice) getProtoMessage() *proto.Message { return nil } func (ss *messageSlice) getName() string { return ss.structName } func (ss *messageSlice) getPackageName() string { return ss.packageName } func (ss *messageSlice) generate(packageInfo *PackageInfo) []byte { return []byte(template.Execute(sliceTemplate, ss.templateFields(packageInfo))) } func (ss *messageSlice) generateTests(packageInfo *PackageInfo) []byte { return []byte(template.Execute(sliceTestTemplate, ss.templateFields(packageInfo))) } func (ss *messageSlice) generateInternal(packageInfo *PackageInfo) []byte { return []byte(template.Execute(sliceInternalTemplate, ss.templateFields(packageInfo))) } func (ss *messageSlice) templateFields(packageInfo *PackageInfo) map[string]any { hasWrapper := usedByOtherDataTypes(ss.packageName) return map[string]any{ "hasWrapper": usedByOtherDataTypes(ss.packageName), "structName": ss.structName, "elementName": ss.element.getName(), "elementOriginName": ss.getElementOriginName(), "elementNullable": ss.elementNullable, "origAccessor": origAccessor(hasWrapper), "stateAccessor": stateAccessor(hasWrapper), "packageName": packageInfo.name, "imports": packageInfo.imports, "testImports": packageInfo.testImports, } } func (ss *messageSlice) getOriginName() string { return ss.element.getOriginName() + "Slice" } func (ss *messageSlice) getOriginFullName() string { return ss.element.getOriginFullName() } func (ss *messageSlice) getHasWrapper() bool { return usedByOtherDataTypes(ss.packageName) } func (ss *messageSlice) getHasOnlyInternal() bool { return false } func (ss *messageSlice) getElementOriginName() string { return ss.element.getOriginName() } func (ss *messageSlice) getElementNullable() bool { return ss.elementNullable } var _ baseStruct = (*messageSlice)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/base_struct.go000066400000000000000000000060671511331344600304630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) type baseStruct interface { getName() string getOriginName() string getOriginFullName() string getHasWrapper() bool getHasOnlyInternal() bool generate(packageInfo *PackageInfo) []byte generateTests(packageInfo *PackageInfo) []byte generateInternal(packageInfo *PackageInfo) []byte getProtoMessage() *proto.Message } // messageStruct generates a struct for a proto message. The struct can be generated both as a common struct // that can be used as a field in struct from other packages and as an isolated struct with depending on a package name. type messageStruct struct { structName string packageName string description string protoName string upstreamProto string fields []Field hasWrapper bool hasOnlyInternal bool } func (ms *messageStruct) getName() string { return ms.structName } func (ms *messageStruct) generate(packageInfo *PackageInfo) []byte { return []byte(template.Execute(messageTemplate, ms.templateFields(packageInfo))) } func (ms *messageStruct) generateTests(packageInfo *PackageInfo) []byte { return []byte(template.Execute(messageTestTemplate, ms.templateFields(packageInfo))) } func (ms *messageStruct) generateInternal(packageInfo *PackageInfo) []byte { return []byte(template.Execute(messageInternalTemplate, ms.templateFields(packageInfo))) } func (ms *messageStruct) getProtoMessage() *proto.Message { fields := make([]proto.FieldInterface, len(ms.fields)) for i := range ms.fields { fields[i] = ms.fields[i].toProtoField(ms) } return &proto.Message{ Name: ms.protoName, Description: ms.description, UpstreamMessage: ms.upstreamProto, Fields: fields, } } func (ms *messageStruct) templateFields(packageInfo *PackageInfo) map[string]any { hasWrapper := ms.hasWrapper if !hasWrapper { hasWrapper = usedByOtherDataTypes(ms.packageName) } return map[string]any{ "messageStruct": ms, "fields": ms.fields, "structName": ms.getName(), "protoName": ms.getOriginFullName(), "originName": ms.getOriginName(), "description": ms.description, "hasWrapper": hasWrapper, "origAccessor": origAccessor(hasWrapper), "stateAccessor": stateAccessor(hasWrapper), "packageName": packageInfo.name, "imports": packageInfo.imports, "testImports": packageInfo.testImports, } } func (ms *messageStruct) getHasWrapper() bool { if ms.hasWrapper { return true } if ms.hasOnlyInternal { return false } return usedByOtherDataTypes(ms.packageName) } func (ms *messageStruct) getHasOnlyInternal() bool { return ms.hasOnlyInternal } func (ms *messageStruct) getOriginName() string { return ms.protoName } func (ms *messageStruct) getOriginFullName() string { return ms.protoName } var _ baseStruct = (*messageStruct)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/field.go000066400000000000000000000012541511331344600272210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) type Field interface { GenerateAccessors(ms *messageStruct) string GenerateAccessorsTest(ms *messageStruct) string GenerateTestValue(ms *messageStruct) string toProtoField(ms *messageStruct) proto.FieldInterface } func origAccessor(hasWrapper bool) string { if hasWrapper { return "getOrig()" } return "orig" } func stateAccessor(hasWrapper bool) string { if hasWrapper { return "getState()" } return "state" } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/message_field.go000066400000000000000000000067111511331344600307300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const messageAccessorsTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType }} { {{- if .messageHasWrapper }} return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}Wrapper(&ms.{{ .origAccessor }}.{{ .fieldOriginFullName }}, ms.{{ .stateAccessor }})) {{- else }} return new{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .fieldOriginFullName }}, ms.{{ .stateAccessor }}) {{- end }} }` const messageAccessorsTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { ms := New{{ .structName }}() assert.Equal(t, {{ .packageName }}New{{ .returnType }}{{- if eq .returnType "Value" }}Empty{{- end }}(), ms.{{ .fieldName }}()) ms.{{ .origAccessor }}.{{ .fieldOriginFullName }} = *internal.GenTest{{ .fieldOriginName }}() {{- if .messageHasWrapper }} assert.Equal(t, {{ .packageName }}{{ .returnType }}(internal.GenTest{{ .returnType }}Wrapper()), ms.{{ .fieldName }}()) {{- else }} assert.Equal(t, generateTest{{ .returnType }}(), ms.{{ .fieldName }}()) {{- end }} }` const messageSetTestTemplate = `orig.{{ .fieldOriginFullName }} = *GenTest{{ .fieldOriginName }}()` type MessageField struct { fieldName string protoID uint32 nullable bool returnMessage *messageStruct } func (mf *MessageField) GenerateAccessors(ms *messageStruct) string { t := template.Parse("messageAccessorsTemplate", []byte(messageAccessorsTemplate)) return template.Execute(t, mf.templateFields(ms)) } func (mf *MessageField) GenerateAccessorsTest(ms *messageStruct) string { t := template.Parse("messageAccessorsTestTemplate", []byte(messageAccessorsTestTemplate)) return template.Execute(t, mf.templateFields(ms)) } func (mf *MessageField) GenerateTestValue(ms *messageStruct) string { t := template.Parse("messageSetTestTemplate", []byte(messageSetTestTemplate)) return template.Execute(t, mf.templateFields(ms)) } func (mf *MessageField) toProtoField(ms *messageStruct) proto.FieldInterface { pt := proto.TypeMessage if mf.returnMessage.getName() == "TraceState" { pt = proto.TypeString } return &proto.Field{ Type: pt, ID: mf.protoID, Name: mf.fieldName, MessageName: mf.returnMessage.getOriginName(), ParentMessageName: ms.protoName, Nullable: mf.nullable, } } func (mf *MessageField) templateFields(ms *messageStruct) map[string]any { return map[string]any{ "messageHasWrapper": usedByOtherDataTypes(mf.returnMessage.packageName), "structName": ms.getName(), "fieldName": mf.fieldName, "fieldOriginFullName": mf.fieldName, "fieldOriginName": mf.returnMessage.getOriginName(), "lowerFieldName": strings.ToLower(mf.fieldName), "returnType": mf.returnMessage.getName(), "packageName": func() string { if mf.returnMessage.packageName != ms.packageName { return mf.returnMessage.packageName + "." } return "" }(), "origAccessor": origAccessor(ms.getHasWrapper()), "stateAccessor": stateAccessor(ms.getHasWrapper()), } } var _ Field = (*MessageField)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/one_of_field.go000066400000000000000000000175531511331344600305570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const oneOfAccessorTemplate = `// {{ .typeFuncName }} returns the type of the {{ .lowerOriginFieldName }} for this {{ .structName }}. // Calling this function on zero-initialized {{ .structName }} will cause a panic. func (ms {{ .structName }}) {{ .typeFuncName }}() {{ .typeName }} { switch ms.{{ .origAccessor }}.{{ .originFieldName }}.(type) { {{- range .values }} {{ .GenerateType $.baseStruct $.OneOfField }} {{- end }} } return {{ .typeName }}Empty } {{ range .values }} {{ .GenerateAccessors $.baseStruct $.OneOfField }} {{ end }}` const oneOfAccessorTestTemplate = `func Test{{ .structName }}_{{ .typeFuncName }}(t *testing.T) { tv := New{{ .structName }}() assert.Equal(t, {{ .typeName }}Empty, tv.{{ .typeFuncName }}()) } {{ range .values -}} {{ .GenerateTests $.baseStruct $.OneOfField }} {{ end }} ` const oneOfTestFailingUnmarshalProtoValuesTemplate = ` {{- range .fields }} {{ .GenTestFailingUnmarshalProtoValues }} {{- end }}` const oneOfTestValuesTemplate = ` {{- range .fields }} {{ .GenTestEncodingValues }} {{- end }}` const oneOfPoolOrigTemplate = ` {{- range .fields }} {{ .GenPool }} {{- end }}` const oneOfMessageOrigTemplate = ` func (m *{{ .protoName }}) Get{{ .originFieldName }}() any { if m != nil { return m.{{ .originFieldName }} } return nil } {{- range .fields }} {{ .GenOneOfMessages }} {{- end }}` const oneOfDeleteOrigTemplate = `switch ov := orig.{{ .originFieldName }}.(type) { {{ range .fields -}} case *{{ $.protoName }}_{{ .GetName }}: {{ .GenDelete }}{{- end }} } ` const oneOfCopyOrigTemplate = `switch t := src.{{ .originFieldName }}.(type) { {{- range .fields }} case *{{ $.protoName }}_{{ .GetName }}: {{ .GenCopy }} {{- end }} default: dest.{{ .originFieldName }} = nil }` const oneOfMarshalJSONTemplate = `switch orig := orig.{{ .originFieldName }}.(type) { {{- range .fields }} case *{{ $.protoName }}_{{ .GetName }}: {{ .GenMarshalJSON }} {{- end }} }` const oneOfUnmarshalJSONTemplate = ` {{- range .fields }} {{ .GenUnmarshalJSON }} {{- end }}` const oneOfSizeProtoTemplate = `switch orig := orig.{{ .originFieldName }}.(type) { case nil: _ = orig break {{ range .fields -}} case *{{ $.protoName }}_{{ .GetName }}: {{ .GenSizeProto }} {{ end -}} }` const oneOfMarshalProtoTemplate = `switch orig := orig.{{ .originFieldName }}.(type) { {{- range .fields }} case *{{ $.protoName }}_{{ .GetName }}: {{ .GenMarshalProto }} {{- end }} }` const oneOfUnmarshalProtoTemplate = ` {{- range .fields }} {{ .GenUnmarshalProto }} {{- end }}` type OneOfField struct { originFieldName string typeName string testValueIdx int values []oneOfValue omitOriginFieldNameInNames bool } func (of *OneOfField) GenerateAccessors(ms *messageStruct) string { return template.Execute(template.Parse("oneOfAccessorTemplate", []byte(oneOfAccessorTemplate)), of.templateFields(ms)) } func (of *OneOfField) typeFuncName() string { const typeSuffix = "Type" if of.omitOriginFieldNameInNames { return typeSuffix } return of.originFieldName + typeSuffix } func (of *OneOfField) GenerateAccessorsTest(ms *messageStruct) string { return template.Execute(template.Parse("oneOfAccessorTestTemplate", []byte(oneOfAccessorTestTemplate)), of.templateFields(ms)) } func (of *OneOfField) GenerateTestValue(ms *messageStruct) string { return of.values[of.testValueIdx].GenerateTestValue(ms, of) } func (of *OneOfField) toProtoField(ms *messageStruct) proto.FieldInterface { fields := make([]proto.FieldInterface, len(of.values)) for i := range of.values { fields[i] = of.values[i].toProtoField(ms, of) } return &oneOfProtoField{ originFieldName: of.originFieldName, protoName: ms.protoName, fields: fields, } } type oneOfProtoField struct { originFieldName string protoName string fields []proto.FieldInterface } func (of *oneOfProtoField) GenMessageField() string { return of.originFieldName + " any" } func (of *oneOfProtoField) GenOneOfMessages() string { return template.Execute(template.Parse("oneOfMessageOrigTemplate", []byte(oneOfMessageOrigTemplate)), of.templateFields()) } func (of *oneOfProtoField) GetName() string { return of.originFieldName } func (of *oneOfProtoField) GoType() string { panic("implement me") } func (of *oneOfProtoField) DefaultValue() string { panic("implement me") } func (of *oneOfProtoField) TestValue() string { return "&" + of.protoName + "_" + of.fields[0].GetName() + "{" + of.fields[0].GetName() + ": " + of.fields[0].TestValue() + "}" } func (of *oneOfProtoField) GenTestFailingUnmarshalProtoValues() string { return template.Execute(template.Parse("oneOfTestFailingUnmarshalProtoValuesTemplate", []byte(oneOfTestFailingUnmarshalProtoValuesTemplate)), of.templateFields()) } func (of *oneOfProtoField) GenTestEncodingValues() string { return template.Execute(template.Parse("oneOfTestValuesTemplate", []byte(oneOfTestValuesTemplate)), of.templateFields()) } func (of *oneOfProtoField) GenPool() string { return template.Execute(template.Parse("oneOfPoolOrigTemplate", []byte(oneOfPoolOrigTemplate)), of.templateFields()) } func (of *oneOfProtoField) GenDelete() string { return template.Execute(template.Parse("oneOfDeleteOrigTemplate", []byte(oneOfDeleteOrigTemplate)), of.templateFields()) } func (of *oneOfProtoField) GenCopy() string { return template.Execute(template.Parse("oneOfCopyOrigTemplate", []byte(oneOfCopyOrigTemplate)), of.templateFields()) } func (of *oneOfProtoField) GenMarshalJSON() string { return template.Execute(template.Parse("oneOfMarshalJSONTemplate", []byte(oneOfMarshalJSONTemplate)), of.templateFields()) } func (of *oneOfProtoField) GenUnmarshalJSON() string { return template.Execute(template.Parse("oneOfUnmarshalJSONTemplate", []byte(oneOfUnmarshalJSONTemplate)), of.templateFields()) } func (of *oneOfProtoField) GenSizeProto() string { t := template.Parse("oneOfSizeProtoTemplate", []byte(oneOfSizeProtoTemplate)) return template.Execute(t, of.templateFields()) } func (of *oneOfProtoField) GenMarshalProto() string { t := template.Parse("oneOfMarshalProtoTemplate", []byte(oneOfMarshalProtoTemplate)) return template.Execute(t, of.templateFields()) } func (of *oneOfProtoField) GenUnmarshalProto() string { t := template.Parse("oneOfUnmarshalProtoTemplate", []byte(oneOfUnmarshalProtoTemplate)) return template.Execute(t, of.templateFields()) } func (of *oneOfProtoField) templateFields() map[string]any { return map[string]any{ "originFieldName": of.originFieldName, "fields": of.fields, "protoName": of.protoName, } } func (of *OneOfField) templateFields(ms *messageStruct) map[string]any { return map[string]any{ "baseStruct": ms, "OneOfField": of, "packageName": "", "structName": ms.getName(), "typeFuncName": of.typeFuncName(), "typeName": of.typeName, "originName": ms.getOriginName(), "originFieldName": of.originFieldName, "lowerOriginFieldName": strings.ToLower(of.originFieldName), "origAccessor": origAccessor(ms.getHasWrapper()), "stateAccessor": stateAccessor(ms.getHasWrapper()), "values": of.values, } } var _ Field = (*OneOfField)(nil) type oneOfValue interface { GetOriginFieldName() string GenerateAccessors(ms *messageStruct, of *OneOfField) string GenerateType(ms *messageStruct, of *OneOfField) string GenerateTests(ms *messageStruct, of *OneOfField) string GenerateTestValue(ms *messageStruct, of *OneOfField) string toProtoField(ms *messageStruct, of *OneOfField) proto.FieldInterface } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/one_of_message_value.go000066400000000000000000000120671511331344600323070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const oneOfMessageAccessorsTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. // // Calling this function when {{ .originOneOfTypeFuncName }}() != {{ .typeName }} returns an invalid // zero-initialized instance of {{ .returnType }}. Note that using such {{ .returnType }} instance can cause panic. // // Calling this function on zero-initialized {{ .structName }} will cause a panic. func (ms {{ .structName }}) {{ .fieldName }}() {{ .returnType }} { v, ok := ms.orig.Get{{ .originOneOfFieldName }}().(*internal.{{ .originStructType }}) if !ok { return {{ .returnType }}{} } return new{{ .returnType }}(v.{{ .fieldName }}, ms.state) } // SetEmpty{{ .fieldName }} sets an empty {{ .lowerFieldName }} to this {{ .structName }}. // // After this, {{ .originOneOfTypeFuncName }}() function will return {{ .typeName }}". // // Calling this function on zero-initialized {{ .structName }} will cause a panic. func (ms {{ .structName }}) SetEmpty{{ .fieldName }}() {{ .returnType }} { ms.state.AssertMutable() var ov *internal.{{ .originStructType }} if !internal.UseProtoPooling.IsEnabled() { ov = &internal.{{ .originStructType }}{} } else { ov = internal.ProtoPool{{ .oneOfName }}.Get().(*internal.{{ .originStructType }}) } ov.{{ .fieldName }} = internal.New{{ .fieldOriginName }}() ms.orig.{{ .originOneOfFieldName }} = ov return new{{ .returnType }}(ov.{{ .fieldName }}, ms.state) }` const oneOfMessageAccessorsTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { ms := New{{ .structName }}() ms.SetEmpty{{ .fieldName }}() assert.Equal(t, New{{ .returnType }}(), ms.{{ .fieldName }}()) ms.orig.Get{{ .originOneOfFieldName }}().(*internal.{{ .originStructType }}).{{ .fieldName }} = internal.GenTest{{ .returnType }}() assert.Equal(t, {{ .typeName }}, ms.{{ .originOneOfTypeFuncName }}()) assert.Equal(t, generateTest{{ .returnType }}(), ms.{{ .fieldName }}()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { new{{ .structName }}(internal.New{{ .originStructName }}(), sharedState).SetEmpty{{ .fieldName }}() }) } ` const oneOfMessageSetTestTemplate = `orig.{{ .originOneOfFieldName }} = &internal.{{ .originStructType }}{ {{- .fieldName }}: GenTest{{ .fieldOriginName }}() }` const oneOfMessageTypeTemplate = `case *internal.{{ .originStructType }}: return {{ .typeName }}` type OneOfMessageValue struct { fieldName string protoID uint32 returnMessage *messageStruct } func (omv *OneOfMessageValue) GetOriginFieldName() string { return omv.fieldName } func (omv *OneOfMessageValue) GenerateAccessors(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfMessageAccessorsTemplate", []byte(oneOfMessageAccessorsTemplate)) return template.Execute(t, omv.templateFields(ms, of)) } func (omv *OneOfMessageValue) GenerateTests(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfMessageAccessorsTestTemplate", []byte(oneOfMessageAccessorsTestTemplate)) return template.Execute(t, omv.templateFields(ms, of)) } func (omv *OneOfMessageValue) GenerateTestValue(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfMessageSetTestTemplate", []byte(oneOfMessageSetTestTemplate)) return template.Execute(t, omv.templateFields(ms, of)) } func (omv *OneOfMessageValue) GenerateType(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfMessageTypeTemplate", []byte(oneOfMessageTypeTemplate)) return template.Execute(t, omv.templateFields(ms, of)) } func (omv *OneOfMessageValue) toProtoField(ms *messageStruct, of *OneOfField) proto.FieldInterface { return &proto.Field{ Type: proto.TypeMessage, ID: omv.protoID, OneOfGroup: of.originFieldName, OneOfMessageName: ms.protoName + "_" + omv.fieldName, Name: omv.fieldName, MessageName: omv.returnMessage.getOriginFullName(), ParentMessageName: ms.protoName, Nullable: true, } } func (omv *OneOfMessageValue) templateFields(ms *messageStruct, of *OneOfField) map[string]any { return map[string]any{ "fieldName": omv.fieldName, "originOneOfFieldName": of.originFieldName, "fieldOriginName": omv.returnMessage.getOriginName(), "typeName": of.typeName + omv.fieldName, "structName": ms.getName(), "returnType": omv.returnMessage.getName(), "originOneOfTypeFuncName": of.typeFuncName(), "lowerFieldName": strings.ToLower(omv.fieldName), "originStructName": ms.protoName, "originStructType": ms.protoName + "_" + omv.fieldName, "oneOfName": proto.ExtractNameFromFull(ms.protoName + "_" + omv.fieldName), } } var _ oneOfValue = (*OneOfMessageValue)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/one_of_primitive_value.go000066400000000000000000000122301511331344600326630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const oneOfPrimitiveAccessorsTemplate = `// {{ .accessorFieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .accessorFieldName }}() {{ .returnType }} { return ms.orig.Get{{ .originFieldName }}() } // Set{{ .accessorFieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .accessorFieldName }}(v {{ .returnType }}) { ms.state.AssertMutable() var ov *internal.{{ .originStructType }} if !internal.UseProtoPooling.IsEnabled() { ov = &internal.{{ .originStructType }}{} } else { ov = internal.ProtoPool{{ .oneOfName }}.Get().(*internal.{{ .originStructType }}) } ov.{{ .originFieldName }} = v ms.orig.{{ .originOneOfFieldName }} = ov }` const oneOfPrimitiveAccessorTestTemplate = `func Test{{ .structName }}_{{ .accessorFieldName }}(t *testing.T) { ms := New{{ .structName }}() {{- if eq .returnType "float64"}} assert.InDelta(t, {{ .defaultVal }}, ms.{{ .accessorFieldName }}(), 0.01) {{- else if and (eq .returnType "string") (eq .defaultVal "\"\"") }} assert.Empty(t, ms.{{ .accessorFieldName }}()) {{- else }} assert.Equal(t, {{ .defaultVal }}, ms.{{ .accessorFieldName }}()) {{- end }} ms.Set{{ .accessorFieldName }}({{ .testValue }}) {{- if eq .returnType "float64" }} assert.InDelta(t, {{ .testValue }}, ms.{{ .accessorFieldName }}(), 0.01) {{- else if and (eq .returnType "string") (eq .testValue "\"\"") }} assert.Empty(t, ms.{{ .accessorFieldName }}()) {{- else }} assert.Equal(t, {{ .testValue }}, ms.{{ .accessorFieldName }}()) {{- end }} assert.Equal(t, {{ .typeName }}, ms.{{ .originOneOfTypeFuncName }}()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { new{{ .structName }}(internal.New{{ .originStructName }}(), sharedState).Set{{ .accessorFieldName }}({{ .testValue }}) }) } ` const oneOfPrimitiveSetTestTemplate = `orig.{{ .originOneOfFieldName }} = &internal.{{ .originStructType }}{ {{- .originFieldName }}: {{ .testValue }}}` const oneOfPrimitiveTypeTemplate = `case *internal.{{ .originStructType }}: return {{ .typeName }}` type OneOfPrimitiveValue struct { fieldName string protoID uint32 protoType proto.Type originFieldName string } func (opv *OneOfPrimitiveValue) GetOriginFieldName() string { return opv.originFieldName } func (opv *OneOfPrimitiveValue) GenerateAccessors(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfPrimitiveAccessorsTemplate", []byte(oneOfPrimitiveAccessorsTemplate)) return template.Execute(t, opv.templateFields(ms, of)) } func (opv *OneOfPrimitiveValue) GenerateTests(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfPrimitiveAccessorTestTemplate", []byte(oneOfPrimitiveAccessorTestTemplate)) return template.Execute(t, opv.templateFields(ms, of)) } func (opv *OneOfPrimitiveValue) GenerateTestValue(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfPrimitiveSetTestTemplate", []byte(oneOfPrimitiveSetTestTemplate)) return template.Execute(t, opv.templateFields(ms, of)) } func (opv *OneOfPrimitiveValue) GenerateType(ms *messageStruct, of *OneOfField) string { t := template.Parse("oneOfPrimitiveCopyOrigTemplate", []byte(oneOfPrimitiveTypeTemplate)) return template.Execute(t, opv.templateFields(ms, of)) } func (opv *OneOfPrimitiveValue) toProtoField(ms *messageStruct, of *OneOfField) proto.FieldInterface { pf := &proto.Field{ Type: opv.protoType, ID: opv.protoID, OneOfGroup: of.originFieldName, Name: opv.originFieldName, OneOfMessageName: ms.protoName + "_" + opv.originFieldName, ParentMessageName: ms.protoName, Nullable: true, } return pf } func (opv *OneOfPrimitiveValue) templateFields(ms *messageStruct, of *OneOfField) map[string]any { pf := opv.toProtoField(ms, of) return map[string]any{ "structName": ms.getName(), "defaultVal": pf.DefaultValue(), "packageName": "", "accessorFieldName": opv.getAccessorFieldName(of), "testValue": pf.TestValue(), "originOneOfTypeFuncName": of.typeFuncName(), "typeName": of.typeName + opv.fieldName, "lowerFieldName": strings.ToLower(opv.fieldName), "returnType": pf.GoType(), "originFieldName": opv.originFieldName, "originOneOfFieldName": of.originFieldName, "originStructName": ms.protoName, "originStructType": ms.protoName + "_" + opv.originFieldName, "oneOfName": proto.ExtractNameFromFull(ms.protoName + "_" + opv.originFieldName), } } func (opv *OneOfPrimitiveValue) getAccessorFieldName(of *OneOfField) string { if of.omitOriginFieldNameInNames { return opv.fieldName } return opv.fieldName + of.originFieldName } var _ oneOfValue = (*OneOfPrimitiveValue)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/optional_primitive_field.go000066400000000000000000000134001511331344600332120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const optionalPrimitiveAccessorsTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .returnType }} { return ms.orig.Get{{ .fieldName }}() } // Has{{ .fieldName }} returns true if the {{ .structName }} contains a // {{ .fieldName }} value otherwise. func (ms {{ .structName }}) Has{{ .fieldName }}() bool { return ms.orig.{{ .fieldName }}_ != nil } // Set{{ .fieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .fieldName }}(v {{ .returnType }}) { ms.state.AssertMutable() ms.orig.{{ .fieldName }}_ = &internal.{{ .originStructType }}{{ "{" }}{{ .fieldName }}: v} } // Remove{{ .fieldName }} removes the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Remove{{ .fieldName }}() { ms.state.AssertMutable() ms.orig.{{ .fieldName }}_ = nil }` const optionalPrimitiveAccessorsTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { ms := New{{ .structName }}() {{- if eq .returnType "float64" }} assert.InDelta(t, {{ .defaultVal }}, ms.{{ .fieldName }}() , 0.01) {{- else }} assert.Equal(t, {{ .defaultVal }}, ms.{{ .fieldName }}()) {{- end }} ms.Set{{ .fieldName }}({{ .testValue }}) assert.True(t, ms.Has{{ .fieldName }}()) {{- if eq .returnType "float64" }} assert.InDelta(t, {{.testValue }}, ms.{{ .fieldName }}(), 0.01) {{- else }} assert.Equal(t, {{ .testValue }}, ms.{{ .fieldName }}()) {{- end }} ms.Remove{{ .fieldName }}() assert.False(t, ms.Has{{ .fieldName }}()) dest := New{{ .structName }}() dest.Set{{ .fieldName }}({{ .testValue }}) ms.CopyTo(dest) assert.False(t, dest.Has{{ .fieldName }}()) }` const optionalPrimitiveSetTestTemplate = `orig.{{ .fieldName }}_ = &internal.{{ .originStructType }}{ {{- .fieldName }}: {{ .testValue }}}` const optionalOneOfMessageOrigTemplate = ` func (m *{{ .ParentMessageName }}) Get{{ .OneOfGroup }}() any { if m != nil { return m.{{ .Name }}_ } return nil } ` type OptionalPrimitiveField struct { fieldName string protoID uint32 protoType proto.Type } func (opv *OptionalPrimitiveField) GenerateAccessors(ms *messageStruct) string { return template.Execute(template.Parse("optionalPrimitiveAccessorsTemplate", []byte(optionalPrimitiveAccessorsTemplate)), opv.templateFields(ms)) } func (opv *OptionalPrimitiveField) GenerateAccessorsTest(ms *messageStruct) string { return template.Execute(template.Parse("optionalPrimitiveAccessorsTestTemplate", []byte(optionalPrimitiveAccessorsTestTemplate)), opv.templateFields(ms)) } func (opv *OptionalPrimitiveField) GenerateTestValue(ms *messageStruct) string { return template.Execute(template.Parse("optionalPrimitiveSetTestTemplate", []byte(optionalPrimitiveSetTestTemplate)), opv.templateFields(ms)) } type optionalPrimitiveProtoField struct { *proto.Field } func (opv optionalPrimitiveProtoField) GetName() string { return opv.Name + "_" } func (opv optionalPrimitiveProtoField) TestValue() string { return "&" + opv.OneOfMessageName + "{" + opv.Name + ": " + opv.Field.TestValue() + "}" } func (opv optionalPrimitiveProtoField) GenMessageField() string { return opv.Name + "_ any" } func (opv optionalPrimitiveProtoField) GenOneOfMessages() string { return template.Execute(template.Parse("optionalOneOfMessageOrigTemplate", []byte(optionalOneOfMessageOrigTemplate)), opv.Field) + opv.Field.GenOneOfMessages() } func (opv optionalPrimitiveProtoField) GenCopy() string { return "switch t := src." + opv.Name + "_.(type) {\n\tcase *" + opv.OneOfMessageName + ":\n\t" + opv.Field.GenCopy() + "\ndefault: dest." + opv.Name + "_ = nil\n}\n" } func (opv optionalPrimitiveProtoField) GenDelete() string { return "switch ov := orig." + opv.Name + "_.(type) {\n\tcase *" + opv.OneOfMessageName + ":\n\t" + opv.Field.GenDelete() + "\n}\n" } func (opv optionalPrimitiveProtoField) GenMarshalJSON() string { return "if orig, ok := orig." + opv.Name + "_.(*" + opv.OneOfMessageName + "); ok {\n\t" + opv.Field.GenMarshalJSON() + "}" } func (opv optionalPrimitiveProtoField) GenSizeProto() string { return "if orig, ok := orig." + opv.Name + "_.(*" + opv.OneOfMessageName + "); ok {\n\t_ = orig\n\t" + opv.Field.GenSizeProto() + "}" } func (opv optionalPrimitiveProtoField) GenMarshalProto() string { return "if orig, ok := orig." + opv.Name + "_.(*" + opv.OneOfMessageName + "); ok {\n\t" + opv.Field.GenMarshalProto() + "}" } func (opv *OptionalPrimitiveField) toProtoField(ms *messageStruct) proto.FieldInterface { return optionalPrimitiveProtoField{&proto.Field{ Type: opv.protoType, ID: opv.protoID, OneOfGroup: opv.fieldName + "_", Name: opv.fieldName, OneOfMessageName: ms.protoName + "_" + opv.fieldName, ParentMessageName: ms.protoName, Nullable: true, }} } func (opv *OptionalPrimitiveField) templateFields(ms *messageStruct) map[string]any { pf := opv.toProtoField(ms).(optionalPrimitiveProtoField) return map[string]any{ "structName": ms.getName(), "defaultVal": pf.DefaultValue(), "fieldName": opv.fieldName, "lowerFieldName": strings.ToLower(opv.fieldName), "testValue": pf.Field.TestValue(), "returnType": pf.GoType(), "originName": ms.getOriginName(), "originStructName": ms.getOriginFullName(), "originStructType": ms.getOriginFullName() + "_" + opv.fieldName, } } var _ Field = (*OptionalPrimitiveField)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/packages.go000066400000000000000000000123021511331344600277100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "fmt" "os" "path/filepath" "slices" "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var nonInternalDeps = []string{ `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, `"go.opentelemetry.io/collector/pdata/plog"`, `"go.opentelemetry.io/collector/pdata/pmetric"`, `"go.opentelemetry.io/collector/pdata/pprofile"`, `"go.opentelemetry.io/collector/pdata/ptrace"`, `"go.opentelemetry.io/collector/pdata/xpdata"`, } // AllPackages is a list of all packages that needs to be generated. var AllPackages = []*Package{ pcommon, plog, plogotlp, pmetric, pmetricotlp, ptrace, ptraceotlp, pprofile, pprofileotlp, xpdataEntity, prequest, } // Package is a struct used to generate files. type Package struct { info *PackageInfo // Can be any of sliceStruct, sliceOfValues, messageStruct. structs []baseStruct enums []*proto.Enum } type PackageInfo struct { name string path string imports []string testImports []string } // Path returns the package path for file generation. func (p *Package) Path() string { return p.info.path } // DeleteGeneratedFiles removes all generated files matching the pattern in the given directory. func DeleteGeneratedFiles(dir string) error { matches, err := filepath.Glob(filepath.Join(dir, "generated_*.go")) if err != nil { return err } for _, match := range matches { if err := os.Remove(match); err != nil && !os.IsNotExist(err) { return fmt.Errorf("failed to remove %s: %w", match, err) } } return nil } // GenerateFiles generates files with the configured data structures for this Package. func (p *Package) GenerateFiles() error { for _, s := range p.structs { if s.getHasOnlyInternal() { continue } path := filepath.Join("pdata", p.info.path, "generated_"+strings.ToLower(s.getName())+".go") if err := os.WriteFile(path, s.generate(p.info), 0o600); err != nil { return err } } return nil } // GenerateTestFiles generates files with tests for the configured data structures for this Package. func (p *Package) GenerateTestFiles() error { for _, s := range p.structs { if s.getHasOnlyInternal() { continue } path := filepath.Join("pdata", p.info.path, "generated_"+strings.ToLower(s.getName())+"_test.go") if err := os.WriteFile(path, s.generateTests(p.info), 0o600); err != nil { return err } } return nil } // GenerateInternalFiles generates files with internal structs for this Package. func (p *Package) GenerateInternalFiles() error { for _, s := range p.structs { if !s.getHasWrapper() { continue } path := filepath.Join("pdata", "internal", "generated_wrapper_"+strings.ToLower(s.getOriginName())+".go") saveImports := slices.Clone(p.info.imports) p.info.imports = slices.DeleteFunc(p.info.imports, func(s string) bool { return slices.Contains(nonInternalDeps, s) }) if err := os.WriteFile(path, s.generateInternal(p.info), 0o600); err != nil { return err } p.info.imports = saveImports } return nil } // GenerateProtoMessageFiles generates files with proto messages for this Package. func (p *Package) GenerateProtoMessageFiles() error { for _, s := range p.structs { pm := s.getProtoMessage() if pm == nil { continue } saveTestImports := slices.Clone(p.info.testImports) p.info.testImports = slices.DeleteFunc(p.info.testImports, func(s string) bool { return slices.Contains(nonInternalDeps, s) }) path := filepath.Join("pdata", "internal", "generated_proto_"+strings.ToLower(s.getOriginName())+".go") if err := os.WriteFile(path, pm.GenerateMessage(p.info.imports, p.info.testImports), 0o600); err != nil { return err } p.info.testImports = saveTestImports } return nil } // GenerateProtoMessageTestsFiles generates files with proto messages tests for this Package. func (p *Package) GenerateProtoMessageTestsFiles() error { for _, s := range p.structs { pm := s.getProtoMessage() if pm == nil { continue } saveTestImports := slices.Clone(p.info.testImports) p.info.testImports = slices.DeleteFunc(p.info.testImports, func(s string) bool { return slices.Contains(nonInternalDeps, s) }) path := filepath.Join("pdata", "internal", "generated_proto_"+strings.ToLower(pm.Name)+"_test.go") if err := os.WriteFile(path, pm.GenerateMessageTests(p.info.imports, p.info.testImports), 0o600); err != nil { return err } p.info.testImports = saveTestImports } return nil } // GenerateProtoEnumFiles generates files with proto messages for this Package. func (p *Package) GenerateProtoEnumFiles() error { for _, s := range p.enums { path := filepath.Join("pdata", "internal", "generated_enum_"+strings.ToLower(s.Name)+".go") if err := os.WriteFile(path, s.GenerateEnum(), 0o600); err != nil { return err } } return nil } // usedByOtherDataTypes defines if the package is used by other data types and orig fields of the package's structs // need to be accessible from other pdata packages. func usedByOtherDataTypes(packageName string) bool { return packageName == "pcommon" || packageName == "entity" } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/pcommon_package.go000066400000000000000000000214561511331344600312670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var pcommon = &Package{ info: &PackageInfo{ name: "pcommon", path: "pcommon", imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/internal/proto"`, }, testImports: []string{ `"strconv"`, `"testing"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1"`, `gootlpresource "go.opentelemetry.io/proto/slim/otlp/resource/v1"`, ``, `"go.opentelemetry.io/collector/internal/testutil"`, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, }, }, structs: []baseStruct{ anyValueStruct, arrayValueStruct, keyValueStruct, keyValueListStruct, anyValueSlice, scope, resource, byteSlice, float64Slice, uInt64Slice, int64Slice, int32Slice, stringSlice, }, } var scope = &messageStruct{ structName: "InstrumentationScope", packageName: "pcommon", description: "// InstrumentationScope is a message representing the instrumentation scope information.", protoName: "InstrumentationScope", upstreamProto: "gootlpcommon.InstrumentationScope", fields: []Field{ &PrimitiveField{ fieldName: "Name", protoID: 1, protoType: proto.TypeString, }, &PrimitiveField{ fieldName: "Version", protoID: 2, protoType: proto.TypeString, }, &SliceField{ fieldName: "Attributes", protoType: proto.TypeMessage, protoID: 3, returnSlice: mapStruct, }, &PrimitiveField{ fieldName: "DroppedAttributesCount", protoID: 4, protoType: proto.TypeUint32, }, }, } // This will not be generated by this class. // Defined here just to be available as returned message for the fields. var mapStruct = &messageSlice{ structName: "Map", packageName: "pcommon", elementNullable: false, element: keyValueStruct, } var keyValueStruct = &messageStruct{ structName: "KeyValue", protoName: "KeyValue", upstreamProto: "gootlpcommon.KeyValue", fields: []Field{ &PrimitiveField{ fieldName: "Key", protoID: 1, protoType: proto.TypeString, }, &MessageField{ fieldName: "Value", protoID: 2, returnMessage: anyValueClone, }, }, hasOnlyInternal: true, } var anyValueClone = &messageStruct{ structName: "Value", protoName: "AnyValue", } // anyValueStruct needs to be different from anyValue because otherwise we cause initialization circular deps with mapStruct. var anyValueStruct = &messageStruct{ structName: "Value", packageName: "pcommon", protoName: "AnyValue", upstreamProto: "gootlpcommon.AnyValue", fields: []Field{ &OneOfField{ typeName: "ValueType", originFieldName: "Value", testValueIdx: 1, // omitOriginFieldNameInNames: true, values: []oneOfValue{ &OneOfPrimitiveValue{ fieldName: "StringValue", protoID: 1, originFieldName: "StringValue", protoType: proto.TypeString, }, &OneOfPrimitiveValue{ fieldName: "BoolValue", protoID: 2, originFieldName: "BoolValue", protoType: proto.TypeBool, }, &OneOfPrimitiveValue{ fieldName: "IntValue", protoID: 3, originFieldName: "IntValue", protoType: proto.TypeInt64, }, &OneOfPrimitiveValue{ fieldName: "DoubleValue", protoID: 4, originFieldName: "DoubleValue", protoType: proto.TypeDouble, }, &OneOfMessageValue{ fieldName: "ArrayValue", protoID: 5, returnMessage: arrayValueStruct, }, &OneOfMessageValue{ fieldName: "KvlistValue", protoID: 6, returnMessage: keyValueListStruct, }, &OneOfPrimitiveValue{ fieldName: "BytesValue", protoID: 7, originFieldName: "BytesValue", protoType: proto.TypeBytes, }, }, }, }, hasOnlyInternal: true, } var keyValueListStruct = &messageStruct{ structName: "KeyValueList", description: "// KeyValueList is a list of KeyValue messages. We need KeyValueList as a message since oneof in AnyValue does not allow repeated fields.", protoName: "KeyValueList", upstreamProto: "gootlpcommon.KeyValueList", fields: []Field{ &SliceField{ fieldName: "Values", protoID: 1, protoType: proto.TypeMessage, returnSlice: mapStruct, }, }, hasOnlyInternal: true, } var arrayValueStruct = &messageStruct{ structName: "ArrayValue", description: "// ArrayValue is a list of AnyValue messages. We need ArrayValue as a message since oneof in AnyValue does not allow repeated fields.", protoName: "ArrayValue", upstreamProto: "gootlpcommon.ArrayValue", fields: []Field{ &SliceField{ fieldName: "Values", protoID: 1, protoType: proto.TypeMessage, returnSlice: anyValueSlice, }, }, hasOnlyInternal: true, } var anyValueSlice = &messageSlice{ structName: "Slice", packageName: "pcommon", elementNullable: false, element: anyValueClone, } var traceState = &messageStruct{ structName: "TraceState", packageName: "pcommon", protoName: "TraceState", // Fake name to generate correct CopyOrig* name. } var timestampType = &TypedType{ structName: "Timestamp", packageName: "pcommon", protoType: proto.TypeFixed64, defaultVal: "0", testVal: "1234567890", } var traceIDType = &TypedType{ structName: "TraceID", packageName: "pcommon", protoType: proto.TypeMessage, messageName: "TraceID", defaultVal: "TraceID([16]byte{})", testVal: "TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})", } var spanIDType = &TypedType{ structName: "SpanID", packageName: "pcommon", protoType: proto.TypeMessage, messageName: "SpanID", defaultVal: "SpanID([8]byte{})", testVal: "SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})", } var resource = &messageStruct{ structName: "Resource", packageName: "pcommon", description: "// Resource is a message representing the resource information.", protoName: "Resource", upstreamProto: "gootlpresource.Resource", fields: []Field{ &SliceField{ fieldName: "Attributes", protoType: proto.TypeMessage, protoID: 1, returnSlice: mapStruct, }, &PrimitiveField{ fieldName: "DroppedAttributesCount", protoID: 2, protoType: proto.TypeUint32, }, &SliceField{ fieldName: "EntityRefs", protoType: proto.TypeMessage, protoID: 3, returnSlice: entityRefSlice, // Hide accessors for this field from 1.x public API since the proto field is experimental. // It's available via the xpdata/entity.ResourceEntityRefs. hideAccessors: true, }, }, } var byteSlice = &primitiveSliceStruct{ structName: "ByteSlice", packageName: "pcommon", itemType: "byte", testOrigVal: "1, 2, 3", testInterfaceOrigVal: []any{1, 2, 3}, testSetVal: "5", testNewVal: "1, 5, 3", } var float64Slice = &primitiveSliceStruct{ structName: "Float64Slice", packageName: "pcommon", itemType: "float64", testOrigVal: "1.1, 2.2, 3.3", testInterfaceOrigVal: []any{1.1, 2.2, 3.3}, testSetVal: "5.5", testNewVal: "1.1, 5.5, 3.3", } var uInt64Slice = &primitiveSliceStruct{ structName: "UInt64Slice", packageName: "pcommon", itemType: "uint64", testOrigVal: "1, 2, 3", testInterfaceOrigVal: []any{1, 2, 3}, testSetVal: "5", testNewVal: "1, 5, 3", } var int64Slice = &primitiveSliceStruct{ structName: "Int64Slice", packageName: "pcommon", itemType: "int64", testOrigVal: "1, 2, 3", testInterfaceOrigVal: []any{1, 2, 3}, testSetVal: "5", testNewVal: "1, 5, 3", } var int32Slice = &primitiveSliceStruct{ structName: "Int32Slice", packageName: "pcommon", itemType: "int32", testOrigVal: "1, 2, 3", testInterfaceOrigVal: []any{1, 2, 3}, testSetVal: "5", testNewVal: "1, 5, 3", } var stringSlice = &primitiveSliceStruct{ structName: "StringSlice", packageName: "pcommon", itemType: "string", testOrigVal: `"a", "b", "c"`, testInterfaceOrigVal: []any{`"a"`, `"b"`, `"c"`}, testSetVal: `"d"`, testNewVal: `"a", "d", "c"`, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/plog_package.go000066400000000000000000000166261511331344600305630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var plog = &Package{ info: &PackageInfo{ name: "plog", path: "plog", imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/internal/proto"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, testImports: []string{ `"strconv"`, `"testing"`, `"unsafe"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectorlogs "go.opentelemetry.io/proto/slim/otlp/collector/logs/v1"`, `gootlplogs "go.opentelemetry.io/proto/slim/otlp/logs/v1"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, }, structs: []baseStruct{ logs, logsData, resourceLogsSlice, resourceLogs, scopeLogsSlice, scopeLogs, logSlice, logRecord, }, enums: []*proto.Enum{ severityNumberEnum, }, } var logs = &messageStruct{ structName: "Logs", description: "// Logs is the top-level struct that is propagated through the logs pipeline.\n// Use NewLogs to create new instance, zero-initialized instance is not valid for use.", protoName: "ExportLogsServiceRequest", upstreamProto: "gootlpcollectorlogs.ExportLogsServiceRequest", fields: []Field{ &SliceField{ fieldName: "ResourceLogs", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceLogsSlice, }, }, hasWrapper: true, } var logsData = &messageStruct{ structName: "LogsData", description: "// LogsData represents the logs data that can be stored in a persistent storage,\n// OR can be embedded by other protocols that transfer OTLP logs data but do not\n// implement the OTLP protocol.", protoName: "LogsData", upstreamProto: "gootlplogs.LogsData", fields: []Field{ &SliceField{ fieldName: "ResourceLogs", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceLogsSlice, }, }, hasOnlyInternal: true, } var resourceLogsSlice = &messageSlice{ structName: "ResourceLogsSlice", elementNullable: true, element: resourceLogs, } var resourceLogs = &messageStruct{ structName: "ResourceLogs", description: "// ResourceLogs is a collection of logs from a Resource.", protoName: "ResourceLogs", upstreamProto: "gootlplogs.ResourceLogs", fields: []Field{ &MessageField{ fieldName: "Resource", protoID: 1, returnMessage: resource, }, &SliceField{ fieldName: "ScopeLogs", protoID: 2, protoType: proto.TypeMessage, returnSlice: scopeLogsSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, &SliceField{ fieldName: "DeprecatedScopeLogs", protoType: proto.TypeMessage, protoID: 1000, returnSlice: scopeLogsSlice, // Hide accessors for this field because it is a HACK: // Workaround for istio 1.15 / envoy 1.23.1 mistakenly emitting deprecated field. hideAccessors: true, }, }, } var scopeLogsSlice = &messageSlice{ structName: "ScopeLogsSlice", elementNullable: true, element: scopeLogs, } var scopeLogs = &messageStruct{ structName: "ScopeLogs", description: "// ScopeLogs is a collection of logs from a LibraryInstrumentation.", protoName: "ScopeLogs", upstreamProto: "gootlplogs.ScopeLogs", fields: []Field{ &MessageField{ fieldName: "Scope", protoID: 1, returnMessage: scope, }, &SliceField{ fieldName: "LogRecords", protoID: 2, protoType: proto.TypeMessage, returnSlice: logSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, }, } var logSlice = &messageSlice{ structName: "LogRecordSlice", elementNullable: true, element: logRecord, } var logRecord = &messageStruct{ structName: "LogRecord", description: "// LogRecord are experimental implementation of OpenTelemetry Log Data Model.\n", protoName: "LogRecord", upstreamProto: "gootlplogs.LogRecord", fields: []Field{ &TypedField{ fieldName: "Timestamp", protoID: 1, originFieldName: "TimeUnixNano", returnType: timestampType, }, &TypedField{ fieldName: "ObservedTimestamp", protoID: 11, originFieldName: "ObservedTimeUnixNano", returnType: timestampType, }, &TypedField{ fieldName: "SeverityNumber", protoID: 2, returnType: &TypedType{ structName: "SeverityNumber", protoType: proto.TypeEnum, messageName: "SeverityNumber", defaultVal: `SeverityNumber_SEVERITY_NUMBER_UNSPECIFIED`, testVal: `SeverityNumber_SEVERITY_NUMBER_DEBUG`, }, }, &PrimitiveField{ fieldName: "SeverityText", protoID: 3, protoType: proto.TypeString, }, &MessageField{ fieldName: "Body", protoID: 5, returnMessage: anyValueStruct, }, &SliceField{ fieldName: "Attributes", protoID: 6, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &PrimitiveField{ fieldName: "DroppedAttributesCount", protoID: 7, protoType: proto.TypeUint32, }, &TypedField{ fieldName: "Flags", protoID: 8, returnType: &TypedType{ structName: "LogRecordFlags", protoType: proto.TypeFixed32, defaultVal: "0", testVal: "1", }, }, &TypedField{ fieldName: "TraceID", originFieldName: "TraceId", protoID: 9, returnType: traceIDType, }, &TypedField{ fieldName: "SpanID", originFieldName: "SpanId", protoID: 10, returnType: spanIDType, }, &PrimitiveField{ fieldName: "EventName", protoID: 12, protoType: proto.TypeString, }, }, } var severityNumberEnum = &proto.Enum{ Name: "SeverityNumber", Description: "// SeverityNumber represent possible values for LogRecord.SeverityNumber", Fields: []*proto.EnumField{ {Name: "SEVERITY_NUMBER_UNSPECIFIED", Value: 0}, {Name: "SEVERITY_NUMBER_TRACE ", Value: 1}, {Name: "SEVERITY_NUMBER_TRACE2", Value: 2}, {Name: "SEVERITY_NUMBER_TRACE3", Value: 3}, {Name: "SEVERITY_NUMBER_TRACE4", Value: 4}, {Name: "SEVERITY_NUMBER_DEBUG", Value: 5}, {Name: "SEVERITY_NUMBER_DEBUG2", Value: 6}, {Name: "SEVERITY_NUMBER_DEBUG3", Value: 7}, {Name: "SEVERITY_NUMBER_DEBUG4", Value: 8}, {Name: "SEVERITY_NUMBER_INFO", Value: 9}, {Name: "SEVERITY_NUMBER_INFO2", Value: 10}, {Name: "SEVERITY_NUMBER_INFO3", Value: 11}, {Name: "SEVERITY_NUMBER_INFO4", Value: 12}, {Name: "SEVERITY_NUMBER_WARN", Value: 13}, {Name: "SEVERITY_NUMBER_WARN2", Value: 14}, {Name: "SEVERITY_NUMBER_WARN3", Value: 15}, {Name: "SEVERITY_NUMBER_WARN4", Value: 16}, {Name: "SEVERITY_NUMBER_ERROR", Value: 17}, {Name: "SEVERITY_NUMBER_ERROR2", Value: 18}, {Name: "SEVERITY_NUMBER_ERROR3", Value: 19}, {Name: "SEVERITY_NUMBER_ERROR4", Value: 20}, {Name: "SEVERITY_NUMBER_FATAL", Value: 21}, {Name: "SEVERITY_NUMBER_FATAL2", Value: 22}, {Name: "SEVERITY_NUMBER_FATAL3", Value: 23}, {Name: "SEVERITY_NUMBER_FATAL4", Value: 24}, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/plogotlp_package.go000066400000000000000000000036241511331344600314540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "path/filepath" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var plogotlp = &Package{ info: &PackageInfo{ name: "plogotlp", path: filepath.Join("plog", "plogotlp"), imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, testImports: []string{ `"strconv"`, `"testing"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectorlogs "go.opentelemetry.io/proto/slim/otlp/collector/logs/v1"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, }, structs: []baseStruct{ exportLogsResponse, exportLogsPartialSuccess, }, } var exportLogsResponse = &messageStruct{ structName: "ExportResponse", description: "// ExportResponse represents the response for gRPC/HTTP client/server.", protoName: "ExportLogsServiceResponse", upstreamProto: "gootlpcollectorlogs.ExportLogsServiceResponse", fields: []Field{ &MessageField{ fieldName: "PartialSuccess", protoID: 1, returnMessage: exportLogsPartialSuccess, }, }, } var exportLogsPartialSuccess = &messageStruct{ structName: "ExportPartialSuccess", description: "// ExportPartialSuccess represents the details of a partially successful export request.", protoName: "ExportLogsPartialSuccess", upstreamProto: "gootlpcollectorlogs.ExportLogsPartialSuccess", fields: []Field{ &PrimitiveField{ fieldName: "RejectedLogRecords", protoID: 1, protoType: proto.TypeInt64, }, &PrimitiveField{ fieldName: "ErrorMessage", protoID: 2, protoType: proto.TypeString, }, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/pmetric_package.go000066400000000000000000000476621511331344600312710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var pmetric = &Package{ info: &PackageInfo{ name: "pmetric", path: "pmetric", imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/internal/proto"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, testImports: []string{ `"strconv"`, `"testing"`, `"unsafe"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectormetrics "go.opentelemetry.io/proto/slim/otlp/collector/metrics/v1"`, `gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, }, structs: []baseStruct{ metrics, metricsData, resourceMetricsSlice, resourceMetrics, scopeMetricsSlice, scopeMetrics, metricSlice, metric, gauge, sum, histogram, exponentialHistogram, summary, numberDataPointSlice, numberDataPoint, histogramDataPointSlice, histogramDataPoint, exponentialHistogramDataPointSlice, exponentialHistogramDataPoint, bucketsValues, summaryDataPointSlice, summaryDataPoint, quantileValuesSlice, quantileValues, exemplarSlice, exemplar, }, enums: []*proto.Enum{ aggregationTemporalityEnum, }, } var metrics = &messageStruct{ structName: "Metrics", description: "// Metrics is the top-level struct that is propagated through the metrics pipeline.\n// Use NewMetrics to create new instance, zero-initialized instance is not valid for use.", protoName: "ExportMetricsServiceRequest", upstreamProto: "gootlpcollectormetrics.ExportMetricsServiceRequest", fields: []Field{ &SliceField{ fieldName: "ResourceMetrics", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceMetricsSlice, }, }, hasWrapper: true, } var metricsData = &messageStruct{ structName: "MetricsData", description: "// MetricsData represents the metrics data that can be stored in a persistent storage,\n// OR can be embedded by other protocols that transfer OTLP metrics data but do not\n// implement the OTLP protocol..", protoName: "MetricsData", upstreamProto: "gootlpmetrics.MetricsData", fields: []Field{ &SliceField{ fieldName: "ResourceMetrics", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceMetricsSlice, }, }, hasOnlyInternal: true, } var resourceMetricsSlice = &messageSlice{ structName: "ResourceMetricsSlice", elementNullable: true, element: resourceMetrics, } var resourceMetrics = &messageStruct{ structName: "ResourceMetrics", description: "// ResourceMetrics is a collection of metrics from a Resource.", protoName: "ResourceMetrics", upstreamProto: "gootlpmetrics.ResourceMetrics", fields: []Field{ &MessageField{ fieldName: "Resource", protoID: 1, returnMessage: resource, }, &SliceField{ fieldName: "ScopeMetrics", protoID: 2, protoType: proto.TypeMessage, returnSlice: scopeMetricsSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, &SliceField{ fieldName: "DeprecatedScopeMetrics", protoType: proto.TypeMessage, protoID: 1000, returnSlice: scopeMetricsSlice, // Hide accessors for this field because it is a HACK: // Workaround for istio 1.15 / envoy 1.23.1 mistakenly emitting deprecated field. hideAccessors: true, }, }, } var scopeMetricsSlice = &messageSlice{ structName: "ScopeMetricsSlice", elementNullable: true, element: scopeMetrics, } var scopeMetrics = &messageStruct{ structName: "ScopeMetrics", description: "// ScopeMetrics is a collection of metrics from a LibraryInstrumentation.", protoName: "ScopeMetrics", upstreamProto: "gootlpmetrics.ScopeMetrics", fields: []Field{ &MessageField{ fieldName: "Scope", protoID: 1, returnMessage: scope, }, &SliceField{ fieldName: "Metrics", protoID: 2, protoType: proto.TypeMessage, returnSlice: metricSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, }, } var metricSlice = &messageSlice{ structName: "MetricSlice", elementNullable: true, element: metric, } var metric = &messageStruct{ structName: "Metric", description: "// Metric represents one metric as a collection of datapoints.\n" + "// See Metric definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto", protoName: "Metric", upstreamProto: "gootlpmetrics.Metric", fields: []Field{ &PrimitiveField{ fieldName: "Name", protoID: 1, protoType: proto.TypeString, }, &PrimitiveField{ fieldName: "Description", protoID: 2, protoType: proto.TypeString, }, &PrimitiveField{ fieldName: "Unit", protoID: 3, protoType: proto.TypeString, }, &OneOfField{ typeName: "MetricType", originFieldName: "Data", testValueIdx: 1, // Sum omitOriginFieldNameInNames: true, values: []oneOfValue{ &OneOfMessageValue{ fieldName: "Gauge", protoID: 5, returnMessage: gauge, }, &OneOfMessageValue{ fieldName: "Sum", protoID: 7, returnMessage: sum, }, &OneOfMessageValue{ fieldName: "Histogram", protoID: 9, returnMessage: histogram, }, &OneOfMessageValue{ fieldName: "ExponentialHistogram", protoID: 10, returnMessage: exponentialHistogram, }, &OneOfMessageValue{ fieldName: "Summary", protoID: 11, returnMessage: summary, }, }, }, &SliceField{ fieldName: "Metadata", protoID: 12, protoType: proto.TypeMessage, returnSlice: mapStruct, }, }, } var gauge = &messageStruct{ structName: "Gauge", description: "// Gauge represents the type of a numeric metric that always exports the \"current value\" for every data point.", protoName: "Gauge", upstreamProto: "gootlpmetrics.Gauge", fields: []Field{ &SliceField{ fieldName: "DataPoints", protoID: 1, protoType: proto.TypeMessage, returnSlice: numberDataPointSlice, }, }, } var sum = &messageStruct{ structName: "Sum", description: "// Sum represents the type of a numeric metric that is calculated as a sum of all reported measurements over a time interval.", protoName: "Sum", upstreamProto: "gootlpmetrics.Sum", fields: []Field{ &SliceField{ fieldName: "DataPoints", protoID: 1, protoType: proto.TypeMessage, returnSlice: numberDataPointSlice, }, &TypedField{ fieldName: "AggregationTemporality", protoID: 2, returnType: aggregationTemporalityType, }, &PrimitiveField{ fieldName: "IsMonotonic", protoID: 3, protoType: proto.TypeBool, }, }, } var histogram = &messageStruct{ structName: "Histogram", description: "// Histogram represents the type of a metric that is calculated by aggregating as a Histogram of all reported measurements over a time interval.", protoName: "Histogram", upstreamProto: "gootlpmetrics.Histogram", fields: []Field{ &SliceField{ fieldName: "DataPoints", protoID: 1, protoType: proto.TypeMessage, returnSlice: histogramDataPointSlice, }, &TypedField{ fieldName: "AggregationTemporality", protoID: 2, returnType: aggregationTemporalityType, }, }, } var exponentialHistogram = &messageStruct{ structName: "ExponentialHistogram", description: `// ExponentialHistogram represents the type of a metric that is calculated by aggregating // as a ExponentialHistogram of all reported double measurements over a time interval.`, protoName: "ExponentialHistogram", upstreamProto: "gootlpmetrics.ExponentialHistogram", fields: []Field{ &SliceField{ fieldName: "DataPoints", protoID: 1, protoType: proto.TypeMessage, returnSlice: exponentialHistogramDataPointSlice, }, &TypedField{ fieldName: "AggregationTemporality", protoID: 2, returnType: aggregationTemporalityType, }, }, } var summary = &messageStruct{ structName: "Summary", description: "// Summary represents the type of a metric that is calculated by aggregating as a Summary of all reported double measurements over a time interval.", protoName: "Summary", upstreamProto: "gootlpmetrics.Summary", fields: []Field{ &SliceField{ fieldName: "DataPoints", protoID: 1, protoType: proto.TypeMessage, returnSlice: summaryDataPointSlice, }, }, } var numberDataPointSlice = &messageSlice{ structName: "NumberDataPointSlice", elementNullable: true, element: numberDataPoint, } var numberDataPoint = &messageStruct{ structName: "NumberDataPoint", description: "// NumberDataPoint is a single data point in a timeseries that describes the time-varying value of a number metric.", protoName: "NumberDataPoint", upstreamProto: "gootlpmetrics.NumberDataPoint", fields: []Field{ &SliceField{ fieldName: "Attributes", protoID: 7, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &TypedField{ fieldName: "StartTimestamp", originFieldName: "StartTimeUnixNano", protoID: 2, returnType: timestampType, }, &TypedField{ fieldName: "Timestamp", originFieldName: "TimeUnixNano", protoID: 3, returnType: timestampType, }, &OneOfField{ typeName: "NumberDataPointValueType", originFieldName: "Value", testValueIdx: 0, // Double values: []oneOfValue{ &OneOfPrimitiveValue{ fieldName: "Double", protoID: 4, originFieldName: "AsDouble", protoType: proto.TypeDouble, }, &OneOfPrimitiveValue{ fieldName: "Int", protoID: 6, originFieldName: "AsInt", protoType: proto.TypeSFixed64, }, }, }, &SliceField{ fieldName: "Exemplars", protoID: 5, protoType: proto.TypeMessage, returnSlice: exemplarSlice, }, &TypedField{ fieldName: "Flags", protoID: 8, returnType: &TypedType{ structName: "DataPointFlags", protoType: proto.TypeUint32, defaultVal: "0", testVal: "1", }, }, }, } var histogramDataPointSlice = &messageSlice{ structName: "HistogramDataPointSlice", elementNullable: true, element: histogramDataPoint, } var histogramDataPoint = &messageStruct{ structName: "HistogramDataPoint", description: "// HistogramDataPoint is a single data point in a timeseries that describes the time-varying values of a Histogram of values.", protoName: "HistogramDataPoint", upstreamProto: "gootlpmetrics.HistogramDataPoint", fields: []Field{ &SliceField{ fieldName: "Attributes", protoID: 9, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &TypedField{ fieldName: "StartTimestamp", originFieldName: "StartTimeUnixNano", protoID: 2, returnType: timestampType, }, &TypedField{ fieldName: "Timestamp", originFieldName: "TimeUnixNano", protoID: 3, returnType: timestampType, }, &PrimitiveField{ fieldName: "Count", protoID: 4, protoType: proto.TypeFixed64, }, &OptionalPrimitiveField{ fieldName: "Sum", protoID: 5, protoType: proto.TypeDouble, }, &SliceField{ fieldName: "BucketCounts", protoID: 6, protoType: proto.TypeFixed64, returnSlice: uInt64Slice, }, &SliceField{ fieldName: "ExplicitBounds", protoID: 7, protoType: proto.TypeDouble, returnSlice: float64Slice, }, &SliceField{ fieldName: "Exemplars", protoID: 8, protoType: proto.TypeMessage, returnSlice: exemplarSlice, }, &TypedField{ fieldName: "Flags", protoID: 10, returnType: &TypedType{ structName: "DataPointFlags", protoType: proto.TypeUint32, defaultVal: "0", testVal: "1", }, }, &OptionalPrimitiveField{ fieldName: "Min", protoID: 11, protoType: proto.TypeDouble, }, &OptionalPrimitiveField{ fieldName: "Max", protoID: 12, protoType: proto.TypeDouble, }, }, } var exponentialHistogramDataPointSlice = &messageSlice{ structName: "ExponentialHistogramDataPointSlice", elementNullable: true, element: exponentialHistogramDataPoint, } var exponentialHistogramDataPoint = &messageStruct{ structName: "ExponentialHistogramDataPoint", description: `// ExponentialHistogramDataPoint is a single data point in a timeseries that describes the // time-varying values of a ExponentialHistogram of double values. A ExponentialHistogram contains // summary statistics for a population of values, it may optionally contain the // distribution of those values across a set of buckets.`, protoName: "ExponentialHistogramDataPoint", upstreamProto: "gootlpmetrics.ExponentialHistogramDataPoint", fields: []Field{ &SliceField{ fieldName: "Attributes", protoID: 1, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &TypedField{ fieldName: "StartTimestamp", protoID: 2, originFieldName: "StartTimeUnixNano", returnType: timestampType, }, &TypedField{ fieldName: "Timestamp", protoID: 3, originFieldName: "TimeUnixNano", returnType: timestampType, }, &PrimitiveField{ fieldName: "Count", protoID: 4, protoType: proto.TypeFixed64, }, &OptionalPrimitiveField{ fieldName: "Sum", protoID: 5, protoType: proto.TypeDouble, }, &PrimitiveField{ fieldName: "Scale", protoID: 6, protoType: proto.TypeSInt32, }, &PrimitiveField{ fieldName: "ZeroCount", protoID: 7, protoType: proto.TypeFixed64, }, &MessageField{ fieldName: "Positive", protoID: 8, returnMessage: bucketsValues, }, &MessageField{ fieldName: "Negative", protoID: 9, returnMessage: bucketsValues, }, &TypedField{ fieldName: "Flags", protoID: 10, returnType: &TypedType{ structName: "DataPointFlags", protoType: proto.TypeUint32, defaultVal: "0", testVal: "1", }, }, &SliceField{ fieldName: "Exemplars", protoID: 11, protoType: proto.TypeMessage, returnSlice: exemplarSlice, }, &OptionalPrimitiveField{ fieldName: "Min", protoID: 12, protoType: proto.TypeDouble, }, &OptionalPrimitiveField{ fieldName: "Max", protoID: 13, protoType: proto.TypeDouble, }, &PrimitiveField{ fieldName: "ZeroThreshold", protoID: 14, protoType: proto.TypeDouble, }, }, } var bucketsValues = &messageStruct{ structName: "ExponentialHistogramDataPointBuckets", description: "// ExponentialHistogramDataPointBuckets are a set of bucket counts, encoded in a contiguous array of counts.", protoName: "ExponentialHistogramDataPointBuckets", upstreamProto: "gootlpmetrics.ExponentialHistogramDataPoint_Buckets", fields: []Field{ &PrimitiveField{ fieldName: "Offset", protoID: 1, protoType: proto.TypeSInt32, }, &SliceField{ fieldName: "BucketCounts", protoID: 2, protoType: proto.TypeUint64, returnSlice: uInt64Slice, }, }, } var summaryDataPointSlice = &messageSlice{ structName: "SummaryDataPointSlice", elementNullable: true, element: summaryDataPoint, } var summaryDataPoint = &messageStruct{ structName: "SummaryDataPoint", description: "// SummaryDataPoint is a single data point in a timeseries that describes the time-varying values of a Summary of double values.", protoName: "SummaryDataPoint", upstreamProto: "gootlpmetrics.SummaryDataPoint", fields: []Field{ &SliceField{ fieldName: "Attributes", protoID: 7, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &TypedField{ fieldName: "StartTimestamp", originFieldName: "StartTimeUnixNano", protoID: 2, returnType: timestampType, }, &TypedField{ fieldName: "Timestamp", originFieldName: "TimeUnixNano", protoID: 3, returnType: timestampType, }, &PrimitiveField{ fieldName: "Count", protoID: 4, protoType: proto.TypeFixed64, }, &PrimitiveField{ fieldName: "Sum", protoID: 5, protoType: proto.TypeDouble, }, &SliceField{ fieldName: "QuantileValues", protoID: 6, protoType: proto.TypeMessage, returnSlice: quantileValuesSlice, }, &TypedField{ fieldName: "Flags", protoID: 8, returnType: &TypedType{ structName: "DataPointFlags", protoType: proto.TypeUint32, defaultVal: "0", testVal: "1", }, }, }, } var quantileValuesSlice = &messageSlice{ structName: "SummaryDataPointValueAtQuantileSlice", elementNullable: true, element: quantileValues, } var quantileValues = &messageStruct{ structName: "SummaryDataPointValueAtQuantile", description: "// SummaryDataPointValueAtQuantile is a quantile value within a Summary data point.", protoName: "SummaryDataPointValueAtQuantile", upstreamProto: "gootlpmetrics.SummaryDataPoint_ValueAtQuantile", fields: []Field{ &PrimitiveField{ fieldName: "Quantile", protoID: 1, protoType: proto.TypeDouble, }, &PrimitiveField{ fieldName: "Value", protoID: 2, protoType: proto.TypeDouble, }, }, } var exemplarSlice = &messageSlice{ structName: "ExemplarSlice", elementNullable: false, element: exemplar, } var exemplar = &messageStruct{ structName: "Exemplar", description: "// Exemplar is a sample input double measurement.\n//\n" + "// Exemplars also hold information about the environment when the measurement was recorded,\n" + "// for example the span and trace ID of the active span when the exemplar was recorded.", protoName: "Exemplar", upstreamProto: "gootlpmetrics.Exemplar", fields: []Field{ &SliceField{ fieldName: "FilteredAttributes", protoID: 7, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &TypedField{ fieldName: "Timestamp", originFieldName: "TimeUnixNano", protoID: 2, returnType: timestampType, }, &OneOfField{ typeName: "ExemplarValueType", originFieldName: "Value", testValueIdx: 1, // Int values: []oneOfValue{ &OneOfPrimitiveValue{ fieldName: "Double", originFieldName: "AsDouble", protoID: 3, protoType: proto.TypeDouble, }, &OneOfPrimitiveValue{ fieldName: "Int", originFieldName: "AsInt", protoID: 6, protoType: proto.TypeSFixed64, }, }, }, &TypedField{ fieldName: "TraceID", originFieldName: "TraceId", protoID: 5, returnType: traceIDType, }, &TypedField{ fieldName: "SpanID", originFieldName: "SpanId", protoID: 4, returnType: spanIDType, }, }, } var aggregationTemporalityType = &TypedType{ structName: "AggregationTemporality", protoType: proto.TypeEnum, messageName: "AggregationTemporality", defaultVal: "AggregationTemporality(0)", testVal: "AggregationTemporality(1)", } var aggregationTemporalityEnum = &proto.Enum{ Name: "AggregationTemporality", Description: "// AggregationTemporality defines how a metric aggregator reports aggregated values.\n// It describes how those values relate to the time interval over which they are aggregated.", Fields: []*proto.EnumField{ {Name: "AGGREGATION_TEMPORALITY_UNSPECIFIED", Value: 0}, {Name: "AGGREGATION_TEMPORALITY_DELTA", Value: 1}, {Name: "AGGREGATION_TEMPORALITY_CUMULATIVE", Value: 2}, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/pmetricotlp_package.go000066400000000000000000000037101511331344600321520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "path/filepath" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var pmetricotlp = &Package{ info: &PackageInfo{ name: "pmetricotlp", path: filepath.Join("pmetric", "pmetricotlp"), imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, testImports: []string{ `"strconv"`, `"testing"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectormetrics "go.opentelemetry.io/proto/slim/otlp/collector/metrics/v1"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, }, structs: []baseStruct{ exportMetricsResponse, exportMetricsPartialSuccess, }, } var exportMetricsResponse = &messageStruct{ structName: "ExportResponse", description: "// ExportResponse represents the response for gRPC/HTTP client/server.", protoName: "ExportMetricsServiceResponse", upstreamProto: "gootlpcollectormetrics.ExportMetricsServiceResponse", fields: []Field{ &MessageField{ fieldName: "PartialSuccess", protoID: 1, returnMessage: exportMetricsPartialSuccess, }, }, } var exportMetricsPartialSuccess = &messageStruct{ structName: "ExportPartialSuccess", description: "// ExportPartialSuccess represents the details of a partially successful export request.", protoName: "ExportMetricsPartialSuccess", upstreamProto: "gootlpcollectormetrics.ExportMetricsPartialSuccess", fields: []Field{ &PrimitiveField{ fieldName: "RejectedDataPoints", protoID: 1, protoType: proto.TypeInt64, }, &PrimitiveField{ fieldName: "ErrorMessage", protoID: 2, protoType: proto.TypeString, }, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/pprofile_package.go000066400000000000000000000342771511331344600314440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var pprofile = &Package{ info: &PackageInfo{ name: "pprofile", path: "pprofile", imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/internal/proto"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, testImports: []string{ `"strconv"`, `"testing"`, `"unsafe"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectorprofiles "go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development"`, `gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1"`, `gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, }, structs: []baseStruct{ profiles, profilesData, resourceProfilesSlice, resourceProfiles, profilesDictionary, scopeProfilesSlice, scopeProfiles, profilesSlice, profile, valueTypeSlice, valueType, sampleSlice, sample, mappingSlice, mapping, locationSlice, location, lineSlice, line, functionSlice, function, keyValueAndUnitSlice, keyValueAndUnit, linkSlice, link, stackSlice, stack, }, } var profiles = &messageStruct{ structName: "Profiles", description: "// Profiles is the top-level struct that is propagated through the profiles pipeline.\n// Use NewProfiles to create new instance, zero-initialized instance is not valid for use.", protoName: "ExportProfilesServiceRequest", upstreamProto: "gootlpcollectorprofiles.ExportProfilesServiceRequest", fields: []Field{ &SliceField{ fieldName: "ResourceProfiles", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceProfilesSlice, }, &MessageField{ fieldName: "Dictionary", protoID: 2, returnMessage: profilesDictionary, }, }, hasWrapper: true, } var profilesData = &messageStruct{ structName: "ProfilesData", description: "// ProfilesData represents the profiles data that can be stored in persistent storage,\n// OR can be embedded by other protocols that transfer OTLP profiles data but do not\n// implement the OTLP protocol.", protoName: "ProfilesData", upstreamProto: "gootlpprofiles.ProfilesData", fields: []Field{ &SliceField{ fieldName: "ResourceProfiles", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceProfilesSlice, }, &MessageField{ fieldName: "Dictionary", protoID: 2, returnMessage: profilesDictionary, }, }, hasWrapper: true, } var resourceProfilesSlice = &messageSlice{ structName: "ResourceProfilesSlice", elementNullable: true, element: resourceProfiles, } var resourceProfiles = &messageStruct{ structName: "ResourceProfiles", description: "// ResourceProfiles is a collection of profiles from a Resource.", protoName: "ResourceProfiles", upstreamProto: "gootlpprofiles.ResourceProfiles", fields: []Field{ &MessageField{ fieldName: "Resource", protoID: 1, returnMessage: resource, }, &SliceField{ fieldName: "ScopeProfiles", protoID: 2, protoType: proto.TypeMessage, returnSlice: scopeProfilesSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, }, } var profilesDictionary = &messageStruct{ structName: "ProfilesDictionary", description: "// ProfilesDictionary is the reference table containing all data shared by profiles across the message being sent.", protoName: "ProfilesDictionary", upstreamProto: "gootlpprofiles.ProfilesDictionary", fields: []Field{ &SliceField{ fieldName: "MappingTable", protoID: 1, protoType: proto.TypeMessage, returnSlice: mappingSlice, }, &SliceField{ fieldName: "LocationTable", protoID: 2, protoType: proto.TypeMessage, returnSlice: locationSlice, }, &SliceField{ fieldName: "FunctionTable", protoID: 3, protoType: proto.TypeMessage, returnSlice: functionSlice, }, &SliceField{ fieldName: "LinkTable", protoID: 4, protoType: proto.TypeMessage, returnSlice: linkSlice, }, &SliceField{ fieldName: "StringTable", protoID: 5, protoType: proto.TypeString, returnSlice: stringSlice, }, &SliceField{ fieldName: "AttributeTable", protoID: 6, protoType: proto.TypeMessage, returnSlice: keyValueAndUnitSlice, }, &SliceField{ fieldName: "StackTable", protoID: 7, protoType: proto.TypeMessage, returnSlice: stackSlice, }, }, } var scopeProfilesSlice = &messageSlice{ structName: "ScopeProfilesSlice", elementNullable: true, element: scopeProfiles, } var scopeProfiles = &messageStruct{ structName: "ScopeProfiles", description: "// ScopeProfiles is a collection of profiles from a LibraryInstrumentation.", protoName: "ScopeProfiles", upstreamProto: "gootlpprofiles.ScopeProfiles", fields: []Field{ &MessageField{ fieldName: "Scope", protoID: 1, returnMessage: scope, }, &SliceField{ fieldName: "Profiles", protoID: 2, protoType: proto.TypeMessage, returnSlice: profilesSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, }, } var profilesSlice = &messageSlice{ structName: "ProfilesSlice", elementNullable: true, element: profile, } var profile = &messageStruct{ structName: "Profile", description: "// Profile are an implementation of the pprofextended data model.\n", protoName: "Profile", upstreamProto: "gootlpprofiles.Profile", fields: []Field{ &MessageField{ fieldName: "SampleType", protoID: 1, returnMessage: valueType, }, &SliceField{ fieldName: "Samples", protoID: 2, protoType: proto.TypeMessage, returnSlice: sampleSlice, }, &TypedField{ fieldName: "Time", originFieldName: "TimeUnixNano", protoID: 3, returnType: timestampType, }, &PrimitiveField{ fieldName: "DurationNano", protoID: 4, protoType: proto.TypeUint64, }, &MessageField{ fieldName: "PeriodType", protoID: 5, returnMessage: valueType, }, &PrimitiveField{ fieldName: "Period", protoID: 6, protoType: proto.TypeInt64, }, &TypedField{ fieldName: "ProfileID", originFieldName: "ProfileId", protoID: 7, returnType: &TypedType{ structName: "ProfileID", protoType: proto.TypeMessage, messageName: "ProfileID", defaultVal: "ProfileID([16]byte{})", testVal: "ProfileID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})", }, }, &PrimitiveField{ fieldName: "DroppedAttributesCount", protoID: 8, protoType: proto.TypeUint32, }, &PrimitiveField{ fieldName: "OriginalPayloadFormat", protoID: 9, protoType: proto.TypeString, }, &SliceField{ fieldName: "OriginalPayload", protoID: 10, protoType: proto.TypeBytes, returnSlice: byteSlice, }, &SliceField{ fieldName: "AttributeIndices", protoID: 11, protoType: proto.TypeInt32, returnSlice: int32Slice, }, }, } var keyValueAndUnitSlice = &messageSlice{ structName: "KeyValueAndUnitSlice", elementNullable: true, element: keyValueAndUnit, } var keyValueAndUnit = &messageStruct{ structName: "KeyValueAndUnit", description: `// KeyValueAndUnit represents a custom 'dictionary native' // style of encoding attributes which is more convenient // for profiles than opentelemetry.proto.common.v1.KeyValue.`, protoName: "KeyValueAndUnit", upstreamProto: "gootlpprofiles.KeyValueAndUnit", fields: []Field{ &PrimitiveField{ fieldName: "KeyStrindex", protoID: 1, protoType: proto.TypeInt32, }, &MessageField{ fieldName: "Value", protoID: 2, returnMessage: anyValueStruct, }, &PrimitiveField{ fieldName: "UnitStrindex", protoID: 3, protoType: proto.TypeInt32, }, }, } var linkSlice = &messageSlice{ structName: "LinkSlice", elementNullable: true, element: link, } var link = &messageStruct{ structName: "Link", description: "// Link represents a pointer from a profile Sample to a trace Span.", protoName: "Link", upstreamProto: "gootlpprofiles.Link", fields: []Field{ &TypedField{ fieldName: "TraceID", originFieldName: "TraceId", protoID: 1, returnType: traceIDType, }, &TypedField{ fieldName: "SpanID", originFieldName: "SpanId", protoID: 2, returnType: spanIDType, }, }, } var valueTypeSlice = &messageSlice{ structName: "ValueTypeSlice", elementNullable: true, element: valueType, } var valueType = &messageStruct{ structName: "ValueType", description: "// ValueType describes the type and units of a value.", protoName: "ValueType", upstreamProto: "gootlpprofiles.ValueType", fields: []Field{ &PrimitiveField{ fieldName: "TypeStrindex", protoID: 1, protoType: proto.TypeInt32, }, &PrimitiveField{ fieldName: "UnitStrindex", protoID: 2, protoType: proto.TypeInt32, }, }, } var sampleSlice = &messageSlice{ structName: "SampleSlice", elementNullable: true, element: sample, } var sample = &messageStruct{ structName: "Sample", description: "// Sample represents each record value encountered within a profiled program.", protoName: "Sample", upstreamProto: "gootlpprofiles.Sample", fields: []Field{ &PrimitiveField{ fieldName: "StackIndex", protoID: 1, protoType: proto.TypeInt32, }, &SliceField{ fieldName: "Values", protoID: 2, protoType: proto.TypeInt64, returnSlice: int64Slice, }, &SliceField{ fieldName: "AttributeIndices", protoID: 3, protoType: proto.TypeInt32, returnSlice: int32Slice, }, &PrimitiveField{ fieldName: "LinkIndex", protoID: 4, protoType: proto.TypeInt32, }, &SliceField{ fieldName: "TimestampsUnixNano", protoID: 5, protoType: proto.TypeFixed64, returnSlice: uInt64Slice, }, }, } var mappingSlice = &messageSlice{ structName: "MappingSlice", elementNullable: true, element: mapping, } var mapping = &messageStruct{ structName: "Mapping", description: "// Mapping describes the mapping of a binary in memory, including its address range, file offset, and metadata like build ID", protoName: "Mapping", upstreamProto: "gootlpprofiles.Mapping", fields: []Field{ &PrimitiveField{ fieldName: "MemoryStart", protoID: 1, protoType: proto.TypeUint64, }, &PrimitiveField{ fieldName: "MemoryLimit", protoID: 2, protoType: proto.TypeUint64, }, &PrimitiveField{ fieldName: "FileOffset", protoID: 3, protoType: proto.TypeUint64, }, &PrimitiveField{ fieldName: "FilenameStrindex", protoID: 4, protoType: proto.TypeInt32, }, &SliceField{ fieldName: "AttributeIndices", protoID: 5, protoType: proto.TypeInt32, returnSlice: int32Slice, }, }, } var locationSlice = &messageSlice{ structName: "LocationSlice", elementNullable: true, element: location, } var location = &messageStruct{ structName: "Location", description: "// Location describes function and line table debug information.", protoName: "Location", upstreamProto: "gootlpprofiles.Location", fields: []Field{ &PrimitiveField{ fieldName: "MappingIndex", protoID: 1, protoType: proto.TypeInt32, }, &PrimitiveField{ fieldName: "Address", protoID: 2, protoType: proto.TypeUint64, }, &SliceField{ fieldName: "Lines", protoID: 3, protoType: proto.TypeMessage, returnSlice: lineSlice, }, &SliceField{ fieldName: "AttributeIndices", protoID: 4, protoType: proto.TypeInt32, returnSlice: int32Slice, }, }, } var lineSlice = &messageSlice{ structName: "LineSlice", elementNullable: true, element: line, } var line = &messageStruct{ structName: "Line", description: "// Line details a specific line in a source code, linked to a function.", protoName: "Line", upstreamProto: "gootlpprofiles.Line", fields: []Field{ &PrimitiveField{ fieldName: "FunctionIndex", protoID: 1, protoType: proto.TypeInt32, }, &PrimitiveField{ fieldName: "Line", protoID: 2, protoType: proto.TypeInt64, }, &PrimitiveField{ fieldName: "Column", protoID: 3, protoType: proto.TypeInt64, }, }, } var functionSlice = &messageSlice{ structName: "FunctionSlice", elementNullable: true, element: function, } var function = &messageStruct{ structName: "Function", description: "// Function describes a function, including its human-readable name, system name, source file, and starting line number in the source.", protoName: "Function", upstreamProto: "gootlpprofiles.Function", fields: []Field{ &PrimitiveField{ fieldName: "NameStrindex", protoID: 1, protoType: proto.TypeInt32, }, &PrimitiveField{ fieldName: "SystemNameStrindex", protoID: 2, protoType: proto.TypeInt32, }, &PrimitiveField{ fieldName: "FilenameStrindex", protoID: 3, protoType: proto.TypeInt32, }, &PrimitiveField{ fieldName: "StartLine", protoID: 4, protoType: proto.TypeInt64, }, }, } var stackSlice = &messageSlice{ structName: "StackSlice", elementNullable: true, element: stack, } var stack = &messageStruct{ structName: "Stack", description: "// Stack represents a stack trace as a list of locations.\n", protoName: "Stack", upstreamProto: "gootlpprofiles.Stack", fields: []Field{ &SliceField{ fieldName: "LocationIndices", protoID: 1, protoType: proto.TypeInt32, returnSlice: int32Slice, }, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/pprofileotlp_package.go000066400000000000000000000037411511331344600323330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "path/filepath" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var pprofileotlp = &Package{ info: &PackageInfo{ name: "pprofileotlp", path: filepath.Join("pprofile", "pprofileotlp"), imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, testImports: []string{ `"strconv"`, `"testing"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectorprofiles "go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, }, structs: []baseStruct{ exportProfilesResponse, exportProfilesPartialSuccess, }, } var exportProfilesResponse = &messageStruct{ structName: "ExportResponse", description: "// ExportResponse represents the response for gRPC/HTTP client/server.", protoName: "ExportProfilesServiceResponse", upstreamProto: "gootlpcollectorprofiles.ExportProfilesServiceResponse", fields: []Field{ &MessageField{ fieldName: "PartialSuccess", protoID: 1, returnMessage: exportProfilesPartialSuccess, }, }, } var exportProfilesPartialSuccess = &messageStruct{ structName: "ExportPartialSuccess", description: "// ExportPartialSuccess represents the details of a partially successful export request.", protoName: "ExportProfilesPartialSuccess", upstreamProto: "gootlpcollectorprofiles.ExportProfilesPartialSuccess", fields: []Field{ &PrimitiveField{ fieldName: "RejectedProfiles", protoID: 1, protoType: proto.TypeInt64, }, &PrimitiveField{ fieldName: "ErrorMessage", protoID: 2, protoType: proto.TypeString, }, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/primitive_field.go000066400000000000000000000072221511331344600313120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const primitiveAccessorsTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType }} { return ms.{{ .origAccessor }}.{{ .originFieldName }} } // Set{{ .fieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .fieldName }}(v {{ .returnType }}) { ms.{{ .stateAccessor }}.AssertMutable() ms.{{ .origAccessor }}.{{ .originFieldName }} = v }` const primitiveAccessorsTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { ms := New{{ .structName }}() {{- if eq .returnType "bool" }} assert.{{- if eq .defaultVal "true" }}True{{- else }}False{{- end }}(t, ms.{{ .fieldName }}()) {{- else if eq .returnType "float64" }} assert.InDelta(t, {{ .defaultVal }}, ms.{{ .fieldName }}(), 0.01) {{- else if and (eq .returnType "string") (eq .defaultVal "\"\"") }} assert.Empty(t, ms.{{ .fieldName }}()) {{- else }} assert.Equal(t, {{ .defaultVal }}, ms.{{ .fieldName }}()) {{- end }} ms.Set{{ .fieldName }}({{ .testValue }}) {{- if eq .returnType "bool" }} assert.{{- if eq .testValue "true" }}True{{- else }}False{{- end }}(t, ms.{{ .fieldName }}()) {{- else if eq .returnType "float64"}} assert.InDelta(t, {{ .testValue }}, ms.{{ .fieldName }}(), 0.01) {{- else if and (eq .returnType "string") (eq .testValue "\"\"") }} assert.Empty(t, ms.{{ .fieldName }}()) {{- else }} assert.Equal(t, {{ .testValue }}, ms.{{ .fieldName }}()) {{- end }} sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { new{{ .structName }}(internal.New{{ .originStructName }}(), sharedState).Set{{ .fieldName }}({{ .testValue }}) }) }` const primitiveSetTestTemplate = `orig.{{ .originFieldName }} = {{ .testValue }}` type PrimitiveField struct { fieldName string protoType proto.Type protoID uint32 } func (pf *PrimitiveField) GenerateAccessors(ms *messageStruct) string { t := template.Parse("primitiveAccessorsTemplate", []byte(primitiveAccessorsTemplate)) return template.Execute(t, pf.templateFields(ms)) } func (pf *PrimitiveField) GenerateAccessorsTest(ms *messageStruct) string { t := template.Parse("primitiveAccessorsTestTemplate", []byte(primitiveAccessorsTestTemplate)) return template.Execute(t, pf.templateFields(ms)) } func (pf *PrimitiveField) GenerateTestValue(ms *messageStruct) string { t := template.Parse("primitiveSetTestTemplate", []byte(primitiveSetTestTemplate)) return template.Execute(t, pf.templateFields(ms)) } func (pf *PrimitiveField) toProtoField(*messageStruct) proto.FieldInterface { return &proto.Field{ Type: pf.protoType, ID: pf.protoID, Name: pf.fieldName, } } func (pf *PrimitiveField) templateFields(ms *messageStruct) map[string]any { prf := pf.toProtoField(ms) return map[string]any{ "structName": ms.getName(), "packageName": "", "defaultVal": prf.DefaultValue(), "fieldName": pf.fieldName, "lowerFieldName": strings.ToLower(pf.fieldName), "testValue": prf.TestValue(), "returnType": prf.GoType(), "origAccessor": origAccessor(ms.getHasWrapper()), "stateAccessor": stateAccessor(ms.getHasWrapper()), "originStructName": ms.protoName, "originFieldName": pf.fieldName, } } var _ Field = (*PrimitiveField)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/primitive_slice_structs.go000066400000000000000000000054141511331344600331160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) // primitiveSliceStruct generates a struct for a slice of primitive value elements. The structs are always generated // in a way that they can be used as fields in structs from other packages (using the internal package). type primitiveSliceStruct struct { structName string packageName string itemType string testOrigVal string testInterfaceOrigVal []any testSetVal string testNewVal string } func (iss *primitiveSliceStruct) getName() string { return iss.structName } func (iss *primitiveSliceStruct) getPackageName() string { return iss.packageName } func (iss *primitiveSliceStruct) generate(packageInfo *PackageInfo) []byte { return []byte(template.Execute(primitiveSliceTemplate, iss.templateFields(packageInfo))) } func (iss *primitiveSliceStruct) generateTests(packageInfo *PackageInfo) []byte { return []byte(template.Execute(primitiveSliceTestTemplate, iss.templateFields(packageInfo))) } func (iss *primitiveSliceStruct) generateInternal(packageInfo *PackageInfo) []byte { return []byte(template.Execute(primitiveSliceInternalTemplate, iss.templateFields(packageInfo))) } func (iss *primitiveSliceStruct) getOriginName() string { return iss.getName() } func (iss *primitiveSliceStruct) getOriginFullName() string { return iss.getName() } func (iss *primitiveSliceStruct) getHasWrapper() bool { return usedByOtherDataTypes(iss.packageName) } func (iss *primitiveSliceStruct) getHasOnlyInternal() bool { return false } func (iss *primitiveSliceStruct) getElementOriginName() string { return upperFirst(iss.itemType) } func (iss *primitiveSliceStruct) getElementNullable() bool { return false } func (iss *primitiveSliceStruct) getProtoMessage() *proto.Message { return nil } func (iss *primitiveSliceStruct) templateFields(packageInfo *PackageInfo) map[string]any { return map[string]any{ "structName": iss.getName(), "itemType": iss.itemType, "elementOriginName": iss.getElementOriginName(), "lowerStructName": strings.ToLower(iss.structName[:1]) + iss.structName[1:], "testOrigVal": iss.testOrigVal, "testInterfaceOrigVal": iss.testInterfaceOrigVal, "testSetVal": iss.testSetVal, "testNewVal": iss.testNewVal, "packageName": packageInfo.name, "imports": packageInfo.imports, "testImports": packageInfo.testImports, } } func upperFirst(s string) string { return strings.ToUpper(s[0:1]) + s[1:] } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/ptrace_package.go000066400000000000000000000250611511331344600310710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var ptrace = &Package{ info: &PackageInfo{ name: "ptrace", path: "ptrace", imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/internal/proto"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, testImports: []string{ `"strconv"`, `"testing"`, `"unsafe"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectortrace "go.opentelemetry.io/proto/slim/otlp/collector/trace/v1"`, `gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, }, structs: []baseStruct{ traces, tracesData, resourceSpansSlice, resourceSpans, scopeSpansSlice, scopeSpans, spanSlice, span, spanEventSlice, spanEvent, spanLinkSlice, spanLink, spanStatus, }, enums: []*proto.Enum{ spanKindEnum, statusCodeEnum, }, } var traces = &messageStruct{ structName: "Traces", description: "// Traces is the top-level struct that is propagated through the traces pipeline.\n// Use NewTraces to create new instance, zero-initialized instance is not valid for use.", protoName: "ExportTraceServiceRequest", upstreamProto: "gootlpcollectortrace.ExportTraceServiceRequest", fields: []Field{ &SliceField{ fieldName: "ResourceSpans", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceSpansSlice, }, }, hasWrapper: true, } var tracesData = &messageStruct{ structName: "TracesData", description: "// TracesData represents the traces data that can be stored in a persistent storage,\n// OR can be embedded by other protocols that transfer OTLP traces data but do not\n// implement the OTLP protocol.", protoName: "TracesData", upstreamProto: "gootlptrace.TracesData", fields: []Field{ &SliceField{ fieldName: "ResourceSpans", protoID: 1, protoType: proto.TypeMessage, returnSlice: resourceSpansSlice, }, }, hasOnlyInternal: true, } var resourceSpansSlice = &messageSlice{ structName: "ResourceSpansSlice", elementNullable: true, element: resourceSpans, } var resourceSpans = &messageStruct{ structName: "ResourceSpans", description: "// ResourceSpans is a collection of spans from a Resource.", protoName: "ResourceSpans", upstreamProto: "gootlptrace.ResourceSpans", fields: []Field{ &MessageField{ fieldName: "Resource", protoID: 1, returnMessage: resource, }, &SliceField{ fieldName: "ScopeSpans", protoID: 2, protoType: proto.TypeMessage, returnSlice: scopeSpansSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, &SliceField{ fieldName: "DeprecatedScopeSpans", protoType: proto.TypeMessage, protoID: 1000, returnSlice: scopeSpansSlice, // Hide accessors for this field because it is a HACK: // Workaround for istio 1.15 / envoy 1.23.1 mistakenly emitting deprecated field. hideAccessors: true, }, }, } var scopeSpansSlice = &messageSlice{ structName: "ScopeSpansSlice", elementNullable: true, element: scopeSpans, } var scopeSpans = &messageStruct{ structName: "ScopeSpans", description: "// ScopeSpans is a collection of spans from a LibraryInstrumentation.", protoName: "ScopeSpans", upstreamProto: "gootlptrace.ScopeSpans", fields: []Field{ &MessageField{ fieldName: "Scope", protoID: 1, returnMessage: scope, }, &SliceField{ fieldName: "Spans", protoID: 2, protoType: proto.TypeMessage, returnSlice: spanSlice, }, &PrimitiveField{ fieldName: "SchemaUrl", protoID: 3, protoType: proto.TypeString, }, }, } var spanSlice = &messageSlice{ structName: "SpanSlice", elementNullable: true, element: span, } var span = &messageStruct{ structName: "Span", description: "// Span represents a single operation within a trace.\n" + "// See Span definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto", protoName: "Span", upstreamProto: "gootlptrace.Span", fields: []Field{ &TypedField{ fieldName: "TraceID", originFieldName: "TraceId", protoID: 1, returnType: traceIDType, }, &TypedField{ fieldName: "SpanID", originFieldName: "SpanId", protoID: 2, returnType: spanIDType, }, &MessageField{ fieldName: "TraceState", protoID: 3, returnMessage: traceState, }, &TypedField{ fieldName: "ParentSpanID", originFieldName: "ParentSpanId", protoID: 4, returnType: spanIDType, }, &PrimitiveField{ fieldName: "Flags", protoID: 16, protoType: proto.TypeFixed32, }, &PrimitiveField{ fieldName: "Name", protoID: 5, protoType: proto.TypeString, }, &TypedField{ fieldName: "Kind", protoID: 6, returnType: &TypedType{ structName: "SpanKind", protoType: proto.TypeEnum, messageName: "SpanKind", defaultVal: "SpanKind_SPAN_KIND_UNSPECIFIED", testVal: "SpanKind_SPAN_KIND_CLIENT", }, }, &TypedField{ fieldName: "StartTimestamp", originFieldName: "StartTimeUnixNano", protoID: 7, returnType: timestampType, }, &TypedField{ fieldName: "EndTimestamp", originFieldName: "EndTimeUnixNano", protoID: 8, returnType: timestampType, }, &SliceField{ fieldName: "Attributes", protoID: 9, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &PrimitiveField{ fieldName: "DroppedAttributesCount", protoID: 10, protoType: proto.TypeUint32, }, &SliceField{ fieldName: "Events", protoID: 11, protoType: proto.TypeMessage, returnSlice: spanEventSlice, }, &PrimitiveField{ fieldName: "DroppedEventsCount", protoID: 12, protoType: proto.TypeUint32, }, &SliceField{ fieldName: "Links", protoID: 13, protoType: proto.TypeMessage, returnSlice: spanLinkSlice, }, &PrimitiveField{ fieldName: "DroppedLinksCount", protoID: 14, protoType: proto.TypeUint32, }, &MessageField{ fieldName: "Status", protoID: 15, returnMessage: spanStatus, }, }, } var spanEventSlice = &messageSlice{ structName: "SpanEventSlice", elementNullable: true, element: spanEvent, } var spanEvent = &messageStruct{ structName: "SpanEvent", description: "// SpanEvent is a time-stamped annotation of the span, consisting of user-supplied\n" + "// text description and key-value pairs. See OTLP for event definition.", protoName: "SpanEvent", upstreamProto: "gootlptrace.Span_Event", fields: []Field{ &TypedField{ fieldName: "Timestamp", originFieldName: "TimeUnixNano", protoID: 1, returnType: timestampType, }, &PrimitiveField{ fieldName: "Name", protoID: 2, protoType: proto.TypeString, }, &SliceField{ fieldName: "Attributes", protoID: 3, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &PrimitiveField{ fieldName: "DroppedAttributesCount", protoID: 4, protoType: proto.TypeUint32, }, }, } var spanLinkSlice = &messageSlice{ structName: "SpanLinkSlice", elementNullable: true, element: spanLink, } var spanLink = &messageStruct{ structName: "SpanLink", description: "// SpanLink is a pointer from the current span to another span in the same trace or in a\n" + "// different trace.\n" + "// See Link definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto", protoName: "SpanLink", upstreamProto: "gootlptrace.Span_Link", fields: []Field{ &TypedField{ fieldName: "TraceID", originFieldName: "TraceId", protoID: 1, returnType: traceIDType, }, &TypedField{ fieldName: "SpanID", originFieldName: "SpanId", protoID: 2, returnType: spanIDType, }, &MessageField{ fieldName: "TraceState", protoID: 3, returnMessage: traceState, }, &SliceField{ fieldName: "Attributes", protoID: 4, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &PrimitiveField{ fieldName: "DroppedAttributesCount", protoID: 5, protoType: proto.TypeUint32, }, &PrimitiveField{ fieldName: "Flags", protoID: 6, protoType: proto.TypeFixed32, }, }, } var spanStatus = &messageStruct{ structName: "Status", description: "// Status is an optional final status for this span. Semantically, when Status was not\n" + "// set, that means the span ended without errors and to assume Status.Ok (code = 0).", protoName: "Status", upstreamProto: "gootlptrace.Status", fields: []Field{ &PrimitiveField{ fieldName: "Message", protoID: 2, protoType: proto.TypeString, }, &TypedField{ fieldName: "Code", protoID: 3, returnType: &TypedType{ structName: "StatusCode", protoType: proto.TypeEnum, messageName: "StatusCode", defaultVal: "StatusCode_STATUS_CODE_UNSET", testVal: "StatusCode_STATUS_CODE_OK", }, }, }, } var spanKindEnum = &proto.Enum{ Name: "SpanKind", Description: "// SpanKind is the type of span.\n// Can be used to specify additional relationships between spans in addition to a parent/child relationship.", Fields: []*proto.EnumField{ {Name: "SPAN_KIND_UNSPECIFIED", Value: 0}, {Name: "SPAN_KIND_INTERNAL", Value: 1}, {Name: "SPAN_KIND_SERVER", Value: 2}, {Name: "SPAN_KIND_CLIENT", Value: 3}, {Name: "SPAN_KIND_PRODUCER", Value: 4}, {Name: "SPAN_KIND_CONSUMER", Value: 5}, }, } var statusCodeEnum = &proto.Enum{ Name: "StatusCode", Description: "// StatusCode is the status of the span, for the semantics of codes see\n// https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status", Fields: []*proto.EnumField{ {Name: "STATUS_CODE_UNSET", Value: 0}, {Name: "STATUS_CODE_OK", Value: 1}, {Name: "STATUS_CODE_ERROR", Value: 2}, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/ptraceotlp_package.go000066400000000000000000000036451511331344600317740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "path/filepath" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var ptraceotlp = &Package{ info: &PackageInfo{ name: "ptraceotlp", path: filepath.Join("ptrace", "ptraceotlp"), imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, `"sync"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, testImports: []string{ `"strconv"`, `"testing"`, ``, `"github.com/stretchr/testify/assert"`, `"github.com/stretchr/testify/require"`, `"google.golang.org/protobuf/proto"`, `gootlpcollectortrace "go.opentelemetry.io/proto/slim/otlp/collector/trace/v1"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, }, }, structs: []baseStruct{ exportTraceResponse, exportTracePartialSuccess, }, } var exportTraceResponse = &messageStruct{ structName: "ExportResponse", description: "// ExportResponse represents the response for gRPC/HTTP client/server.", protoName: "ExportTraceServiceResponse", upstreamProto: "gootlpcollectortrace.ExportTraceServiceResponse", fields: []Field{ &MessageField{ fieldName: "PartialSuccess", protoID: 1, returnMessage: exportTracePartialSuccess, }, }, } var exportTracePartialSuccess = &messageStruct{ structName: "ExportPartialSuccess", description: "// ExportPartialSuccess represents the details of a partially successful export request.", protoName: "ExportTracePartialSuccess", upstreamProto: "gootlpcollectortrace.ExportTracePartialSuccess", fields: []Field{ &PrimitiveField{ fieldName: "RejectedSpans", protoID: 1, protoType: proto.TypeInt64, }, &PrimitiveField{ fieldName: "ErrorMessage", protoID: 2, protoType: proto.TypeString, }, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/request_package.go000066400000000000000000000155361511331344600313110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "path/filepath" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var prequest = &Package{ info: &PackageInfo{ name: "request", path: filepath.Join("xpdata", "request", "internal"), imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/internal/proto"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, testImports: []string{ `"testing"`, ``, `"github.com/stretchr/testify/assert"`, `"google.golang.org/protobuf/types/known/emptypb"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, }, structs: []baseStruct{ spanContext, ipAddr, tcpAddr, udpAddr, unixAddr, requestContext, tracesRequest, metricsRequest, logsRequest, profilesRequest, }, } var spanContext = &messageStruct{ structName: "SpanContext", packageName: "request", protoName: "SpanContext", upstreamProto: "emptypb.Empty", fields: []Field{ &TypedField{ fieldName: "TraceID", protoID: 1, returnType: traceIDType, }, &TypedField{ fieldName: "SpanID", protoID: 2, returnType: spanIDType, }, &PrimitiveField{ fieldName: "TraceFlags", protoID: 3, protoType: proto.TypeFixed32, }, &MessageField{ fieldName: "TraceState", protoID: 4, returnMessage: traceState, }, &PrimitiveField{ fieldName: "Remote", protoID: 5, protoType: proto.TypeBool, }, }, hasOnlyInternal: true, } var ipAddr = &messageStruct{ structName: "IPAddr", packageName: "request", protoName: "IPAddr", upstreamProto: "emptypb.Empty", fields: []Field{ &PrimitiveField{ fieldName: "IP", protoID: 1, protoType: proto.TypeBytes, }, &PrimitiveField{ fieldName: "Zone", protoID: 2, protoType: proto.TypeString, }, }, hasOnlyInternal: true, } var tcpAddr = &messageStruct{ structName: "TCPAddr", packageName: "request", protoName: "TCPAddr", upstreamProto: "emptypb.Empty", fields: []Field{ &PrimitiveField{ fieldName: "IP", protoID: 1, protoType: proto.TypeBytes, }, &PrimitiveField{ fieldName: "Port", protoID: 2, protoType: proto.TypeInt64, }, &PrimitiveField{ fieldName: "Zone", protoID: 3, protoType: proto.TypeString, }, }, hasOnlyInternal: true, } var udpAddr = &messageStruct{ structName: "UDPAddr", packageName: "request", protoName: "UDPAddr", upstreamProto: "emptypb.Empty", fields: []Field{ &PrimitiveField{ fieldName: "IP", protoID: 1, protoType: proto.TypeBytes, }, &PrimitiveField{ fieldName: "Port", protoID: 2, protoType: proto.TypeInt64, }, &PrimitiveField{ fieldName: "Zone", protoID: 3, protoType: proto.TypeString, }, }, hasOnlyInternal: true, } var unixAddr = &messageStruct{ structName: "UnixAddr", packageName: "request", protoName: "UnixAddr", upstreamProto: "emptypb.Empty", fields: []Field{ &PrimitiveField{ fieldName: "Name", protoID: 1, protoType: proto.TypeString, }, &PrimitiveField{ fieldName: "Net", protoID: 2, protoType: proto.TypeString, }, }, hasOnlyInternal: true, } var requestContext = &messageStruct{ structName: "RequestContext", packageName: "request", protoName: "RequestContext", upstreamProto: "emptypb.Empty", fields: []Field{ &MessageField{ fieldName: "SpanContext", protoID: 1, nullable: true, returnMessage: spanContext, }, &SliceField{ fieldName: "ClientMetadata", protoID: 2, protoType: proto.TypeMessage, returnSlice: mapStruct, }, &OneOfField{ typeName: "ClientAddressType", originFieldName: "ClientAddress", testValueIdx: 1, // omitOriginFieldNameInNames: true, values: []oneOfValue{ &OneOfMessageValue{ fieldName: "IP", protoID: 3, returnMessage: ipAddr, }, &OneOfMessageValue{ fieldName: "TCP", protoID: 4, returnMessage: tcpAddr, }, &OneOfMessageValue{ fieldName: "UDP", protoID: 5, returnMessage: udpAddr, }, &OneOfMessageValue{ fieldName: "Unix", protoID: 6, returnMessage: unixAddr, }, }, }, }, hasOnlyInternal: true, } var tracesRequest = &messageStruct{ structName: "TracesRequest", packageName: "request", protoName: "TracesRequest", upstreamProto: "emptypb.Empty", fields: []Field{ &MessageField{ fieldName: "RequestContext", protoID: 2, nullable: true, returnMessage: requestContext, }, &MessageField{ fieldName: "TracesData", protoID: 3, returnMessage: tracesData, }, &PrimitiveField{ fieldName: "FormatVersion", protoID: 1, protoType: proto.TypeFixed32, }, }, hasOnlyInternal: true, } var metricsRequest = &messageStruct{ structName: "MetricsRequest", packageName: "request", protoName: "MetricsRequest", upstreamProto: "emptypb.Empty", fields: []Field{ &MessageField{ fieldName: "RequestContext", protoID: 2, nullable: true, returnMessage: requestContext, }, &MessageField{ fieldName: "MetricsData", protoID: 3, returnMessage: metricsData, }, &PrimitiveField{ fieldName: "FormatVersion", protoID: 1, protoType: proto.TypeFixed32, }, }, hasOnlyInternal: true, } var logsRequest = &messageStruct{ structName: "LogsRequest", packageName: "request", protoName: "LogsRequest", upstreamProto: "emptypb.Empty", fields: []Field{ &MessageField{ fieldName: "RequestContext", protoID: 2, nullable: true, returnMessage: requestContext, }, &MessageField{ fieldName: "LogsData", protoID: 3, returnMessage: logsData, }, &PrimitiveField{ fieldName: "FormatVersion", protoID: 1, protoType: proto.TypeFixed32, }, }, hasOnlyInternal: true, } var profilesRequest = &messageStruct{ structName: "ProfilesRequest", packageName: "request", protoName: "ProfilesRequest", upstreamProto: "emptypb.Empty", fields: []Field{ &MessageField{ fieldName: "RequestContext", protoID: 2, nullable: true, returnMessage: requestContext, }, &MessageField{ fieldName: "ProfilesData", protoID: 3, returnMessage: profilesData, }, &PrimitiveField{ fieldName: "FormatVersion", protoID: 1, protoType: proto.TypeFixed32, }, }, hasOnlyInternal: true, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/slice_field.go000066400000000000000000000070031511331344600303760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const sliceAccessorTemplate = `// {{ .fieldName }} returns the {{ .fieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType }} { {{- if .elementHasWrapper }} return {{ .packageName }}{{ .returnType }}(internal.New{{ .returnType }}Wrapper(&ms.{{ .origAccessor }}.{{ .originFieldName }}, ms.{{ .stateAccessor }})) {{- else }} return new{{ .returnType }}(&ms.{{ .origAccessor }}.{{ .originFieldName }}, ms.{{ .stateAccessor }}) {{- end }} }` const sliceAccessorsTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { ms := New{{ .structName }}() assert.Equal(t, {{ .packageName }}New{{ .returnType }}(), ms.{{ .fieldName }}()) ms.{{ .origAccessor }}.{{ .originFieldName }} = internal.GenTest{{ .elementOriginName }}{{ if .elementNullable }}Ptr{{ end }}Slice() {{- if .elementHasWrapper }} assert.Equal(t, {{ .packageName }}{{ .returnType }}(internal.GenTest{{ .returnType }}Wrapper()), ms.{{ .fieldName }}()) {{- else }} assert.Equal(t, generateTest{{ .returnType }}(), ms.{{ .fieldName }}()) {{- end }} }` const sliceSetTestTemplate = `orig.{{ .originFieldName }} = internal.GenTest{{ .elementOriginName }}{{ if .elementNullable }}Ptr{{ end }}Slice()` type SliceField struct { fieldName string protoType proto.Type protoID uint32 returnSlice baseSlice hideAccessors bool } func (sf *SliceField) GenerateAccessors(ms *messageStruct) string { if sf.hideAccessors { return "" } t := template.Parse("sliceAccessorTemplate", []byte(sliceAccessorTemplate)) return template.Execute(t, sf.templateFields(ms)) } func (sf *SliceField) GenerateAccessorsTest(ms *messageStruct) string { if sf.hideAccessors { return "" } t := template.Parse("sliceAccessorsTestTemplate", []byte(sliceAccessorsTestTemplate)) return template.Execute(t, sf.templateFields(ms)) } func (sf *SliceField) GenerateTestValue(ms *messageStruct) string { t := template.Parse("sliceSetTestTemplate", []byte(sliceSetTestTemplate)) return template.Execute(t, sf.templateFields(ms)) } func (sf *SliceField) toProtoField(ms *messageStruct) proto.FieldInterface { return &proto.Field{ Type: sf.protoType, ID: sf.protoID, Name: sf.fieldName, MessageName: sf.returnSlice.getElementOriginName(), ParentMessageName: ms.protoName, Repeated: sf.protoType != proto.TypeBytes, Nullable: sf.returnSlice.getElementNullable(), } } func (sf *SliceField) templateFields(ms *messageStruct) map[string]any { return map[string]any{ "structName": ms.getName(), "fieldName": sf.fieldName, "originFieldName": sf.fieldName, "elementOriginName": sf.returnSlice.getElementOriginName(), "packageName": func() string { if sf.returnSlice.getPackageName() != ms.packageName { return sf.returnSlice.getPackageName() + "." } return "" }(), "returnType": sf.returnSlice.getName(), "origAccessor": origAccessor(ms.getHasWrapper()), "stateAccessor": stateAccessor(ms.getHasWrapper()), "elementHasWrapper": sf.returnSlice.getHasWrapper(), "elementNullable": sf.returnSlice.getElementNullable(), } } var _ Field = (*SliceField)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates.go000066400000000000000000000035341511331344600301370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( _ "embed" // Blank import required for go:embed to work. "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) var ( //go:embed templates/message.go.tmpl messageTemplateBytes []byte messageTemplate = template.Parse("message.go", messageTemplateBytes) //go:embed templates/message_internal.go.tmpl messageInternalTemplateBytes []byte messageInternalTemplate = template.Parse("message_internal.go", messageInternalTemplateBytes) //go:embed templates/message_test.go.tmpl messageTestTemplateBytes []byte messageTestTemplate = template.Parse("message_test.go", messageTestTemplateBytes) //go:embed templates/primitive_slice.go.tmpl primitiveSliceTemplateBytes []byte primitiveSliceTemplate = template.Parse("primitive_slice.go", primitiveSliceTemplateBytes) //go:embed templates/primitive_slice_internal.go.tmpl primitiveSliceInternalTemplateBytes []byte primitiveSliceInternalTemplate = template.Parse("primitive_slice_internal.go", primitiveSliceInternalTemplateBytes) //go:embed templates/primitive_slice_test.go.tmpl primitiveSliceTestTemplateBytes []byte primitiveSliceTestTemplate = template.Parse("primitive_slice_test.go", primitiveSliceTestTemplateBytes) //go:embed templates/slice.go.tmpl sliceTemplateBytes []byte sliceTemplate = template.Parse("slice.go", sliceTemplateBytes) //go:embed templates/slice_internal.go.tmpl sliceInternalTemplateBytes []byte sliceInternalTemplate = template.Parse("slice_internal.go", sliceInternalTemplateBytes) //go:embed templates/slice_test.go.tmpl sliceTestTemplateBytes []byte sliceTestTemplate = template.Parse("slice_test.go", sliceTestTemplateBytes) ) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates/000077500000000000000000000000001511331344600276035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates/message.go.tmpl000066400000000000000000000052001511331344600325260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package {{ .packageName }} import ( {{ range $index, $element := .imports -}} {{ $element }} {{ end }} ) {{ .description }} // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use New{{ .structName }} function to create new instances. // Important: zero-initialized instance is not valid for use. {{- if .hasWrapper }} type {{ .structName }} internal.{{ .structName }}Wrapper {{- else }} type {{ .structName }} struct { orig *internal.{{ .originName }} state *internal.State } {{- end }} func new{{ .structName }}(orig *internal.{{ .originName }}, state *internal.State) {{ .structName }} { {{- if .hasWrapper }} return {{ .structName }}(internal.New{{ .structName }}Wrapper(orig, state)) {{- else }} return {{ .structName }}{orig: orig, state: state} {{- end }} } // New{{ .structName }} creates a new empty {{ .structName }}. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func New{{ .structName }}() {{ .structName }} { return new{{ .structName }}(internal.New{{ .originName }}(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms {{ .structName }}) MoveTo(dest {{ .structName }}) { ms.{{ .stateAccessor }}.AssertMutable() dest.{{ .stateAccessor }}.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.{{ .origAccessor }} == dest.{{ .origAccessor }} { return } internal.Delete{{ .originName }}(dest.{{ .origAccessor }}, false) *dest.{{ .origAccessor }}, *ms.{{ .origAccessor }} = *ms.{{ .origAccessor }}, *dest.{{ .origAccessor }} } {{ range .fields -}} {{ .GenerateAccessors $.messageStruct }} {{ end }} // CopyTo copies all properties from the current struct overriding the destination. func (ms {{ .structName }}) CopyTo(dest {{ .structName }}) { dest.{{ .stateAccessor }}.AssertMutable() internal.Copy{{ .originName }}(dest.{{ .origAccessor }}, ms.{{ .origAccessor }}) } {{ if .hasWrapper -}} func (ms {{ .structName }}) getOrig() *internal.{{ .originName }} { return internal.Get{{ .structName }}Orig(internal.{{ .structName }}Wrapper(ms)) } func (ms {{ .structName }}) getState() *internal.State { return internal.Get{{ .structName }}State(internal.{{ .structName }}Wrapper(ms)) } {{- end }} message_internal.go.tmpl000066400000000000000000000015501511331344600343470ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( {{ range $index, $element := .imports -}} {{ $element }} {{ end }} ) type {{ .structName }}Wrapper struct { orig *{{ .originName }} state *State } func Get{{ .structName }}Orig(ms {{ .structName }}Wrapper) *{{ .originName }} { return ms.orig } func Get{{ .structName }}State(ms {{ .structName }}Wrapper) *State { return ms.state } func New{{ .structName }}Wrapper(orig *{{ .originName }}, state *State) {{ .structName }}Wrapper { return {{ .structName }}Wrapper{orig: orig, state: state} } func GenTest{{ .structName }}Wrapper() {{ .structName }}Wrapper { return New{{ .structName }}Wrapper(GenTest{{ .originName }}(), NewState()) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates/message_test.go.tmpl000066400000000000000000000030111511331344600335630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package {{ .packageName }} import ( {{ range $index, $element := .testImports -}} {{ $element }} {{ end }} ) func Test{{ .structName }}_MoveTo(t *testing.T) { ms := generateTest{{ .structName }}() dest := New{{ .structName }}() ms.MoveTo(dest) assert.Equal(t, New{{ .structName }}(), ms) assert.Equal(t, generateTest{{ .structName }}(), dest) dest.MoveTo(dest) assert.Equal(t, generateTest{{ .structName }}(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(new{{ .structName }}(internal.New{{ .originName }}(), sharedState)) }) assert.Panics(t, func() { new{{ .structName }}(internal.New{{ .originName }}(), sharedState).MoveTo(dest) }) } func Test{{ .structName }}_CopyTo(t *testing.T) { ms := New{{ .structName }}() orig := New{{ .structName }}() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTest{{ .structName }}() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(new{{ .structName }}(internal.New{{ .originName }}(), sharedState)) }) } {{ range .fields }} {{ .GenerateAccessorsTest $.messageStruct }} {{ end }} func generateTest{{ .structName }}() {{ .structName }} { return new{{ .structName }}(internal.GenTest{{ .originName }}(), internal.NewState()) } primitive_slice.go.tmpl000066400000000000000000000126521511331344600342230ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package {{ .packageName }} import ( {{ range $index, $element := .imports -}} {{ $element }} {{ end }} ) // {{ .structName }} represents a []{{ .itemType }} slice. // The instance of {{ .structName }} can be assigned to multiple objects since it's immutable. // // Must use New{{ .structName }} function to create new instances. // Important: zero-initialized instance is not valid for use. type {{ .structName }} internal.{{ .structName }}Wrapper func (ms {{ .structName }}) getOrig() *[]{{ .itemType }} { return internal.Get{{ .structName }}Orig(internal.{{ .structName }}Wrapper(ms)) } func (ms {{ .structName }}) getState() *internal.State { return internal.Get{{ .structName }}State(internal.{{ .structName }}Wrapper(ms)) } // New{{ .structName }} creates a new empty {{ .structName }}. func New{{ .structName }}() {{ .structName }} { orig := []{{ .itemType }}(nil) return {{ .structName }}(internal.New{{ .structName }}Wrapper(&orig, internal.NewState())) } // AsRaw returns a copy of the []{{ .itemType }} slice. func (ms {{ .structName }}) AsRaw() []{{ .itemType }} { return copy{{ .elementOriginName }}Slice(nil, *ms.getOrig()) } // FromRaw copies raw []{{ .itemType }} into the slice {{ .structName }}. func (ms {{ .structName }}) FromRaw(val []{{ .itemType }}) { ms.getState().AssertMutable() *ms.getOrig() = copy{{ .elementOriginName }}Slice(*ms.getOrig(), val) } // Len returns length of the []{{ .itemType }} slice value. // Equivalent of len({{ .lowerStructName }}). func (ms {{ .structName }}) Len() int { return len(*ms.getOrig()) } // At returns an item from particular index. // Equivalent of {{ .lowerStructName }}[i]. func (ms {{ .structName }}) At(i int) {{ .itemType }} { return (*ms.getOrig())[i] } // All returns an iterator over index-value pairs in the slice. func (ms {{ .structName }}) All() iter.Seq2[int, {{ .itemType }}] { return func(yield func(int, {{ .itemType }}) bool) { for i := 0; i < ms.Len(); i++ { if !yield(i, ms.At(i)) { return } } } } // SetAt sets {{ .itemType }} item at particular index. // Equivalent of {{ .lowerStructName }}[i] = val func (ms {{ .structName }}) SetAt(i int, val {{ .itemType }}) { ms.getState().AssertMutable() (*ms.getOrig())[i] = val } // EnsureCapacity ensures {{ .structName }} has at least the specified capacity. // 1. If the newCap <= cap, then is no change in capacity. // 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of: // buf := make([]{{ .itemType }}, len({{ .lowerStructName }}), newCap) // copy(buf, {{ .lowerStructName }}) // {{ .lowerStructName }} = buf func (ms {{ .structName }}) EnsureCapacity(newCap int) { ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return } newOrig := make([]{{ .itemType }}, len(*ms.getOrig()), newCap) copy(newOrig, *ms.getOrig()) *ms.getOrig() = newOrig } // Append appends extra elements to {{ .structName }}. // Equivalent of {{ .lowerStructName }} = append({{ .lowerStructName }}, elms...) func (ms {{ .structName }}) Append(elms ...{{ .itemType }}) { ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms {{ .structName }}) MoveTo(dest {{ .structName }}) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (ms {{ .structName }}) MoveAndAppendTo(dest {{ .structName }}) { ms.getState().AssertMutable() dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *ms.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *ms.getOrig()...) } *ms.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (ms {{ .structName }}) RemoveIf(f func({{ .itemType }}) bool) { ms.getState().AssertMutable() newLen := 0 for i := 0; i < len(*ms.getOrig()); i++ { if f((*ms.getOrig())[i]) { continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*ms.getOrig())[newLen] = (*ms.getOrig())[i] var zero {{ .itemType }} (*ms.getOrig())[i] = zero newLen++ } *ms.getOrig() = (*ms.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (ms {{ .structName }}) CopyTo(dest {{ .structName }}) { dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = copy{{ .elementOriginName }}Slice(*dest.getOrig(), *ms.getOrig()) } // Equal checks equality with another {{ .structName }} func (ms {{ .structName }}) Equal(val {{ .structName }}) bool { return slices.Equal(*ms.getOrig(), *val.getOrig()) } func copy{{ .elementOriginName }}Slice(dst, src []{{ .itemType }}) []{{ .itemType }} { return append(dst[:0], src...) } primitive_slice_internal.go.tmpl000066400000000000000000000017671511331344600361240ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( {{ range $index, $element := .imports -}} {{ $element }} {{ end }} ) type {{ .structName }}Wrapper struct { orig *[]{{ .itemType }} state *State } func Get{{ .structName }}Orig(ms {{ .structName }}Wrapper) *[]{{ .itemType }} { return ms.orig } func Get{{ .structName }}State(ms {{ .structName }}Wrapper) *State { return ms.state } func New{{ .structName }}Wrapper(orig *[]{{ .itemType }}, state *State) {{ .structName }}Wrapper { return {{ .structName }}Wrapper{orig: orig, state: state} } func GenTest{{ .structName }}Wrapper() {{ .structName }}Wrapper { orig := []{{ .itemType }}{ {{ .testOrigVal }} } return New{{ .structName }}Wrapper(&orig, NewState()) } func GenTest{{ .elementOriginName }}Slice() []{{ .itemType }} { return []{{ .itemType }}{ {{ .testOrigVal }} } } primitive_slice_test.go.tmpl000066400000000000000000000144131511331344600352570ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package {{ .packageName }} import ( {{ range $index, $element := .testImports -}} {{ $element }} {{ end }} ) func TestNew{{ .structName }}(t *testing.T) { ms := New{{ .structName }}() assert.Equal(t, 0, ms.Len()) ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) assert.Equal(t, 3, ms.Len()) assert.Equal(t, []{{ .itemType }}{ {{ .testOrigVal }} }, ms.AsRaw()) ms.SetAt(1, {{ .itemType }}( {{ .testSetVal }} )) assert.Equal(t, []{{ .itemType }}{ {{ .testNewVal }} }, ms.AsRaw()) ms.FromRaw([]{{ .itemType }}{ {{ index .testInterfaceOrigVal 2 }} }) assert.Equal(t, 1, ms.Len()) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), ms.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), ms.At(0)) {{- end }} cp := New{{ .structName }}() ms.CopyTo(cp) ms.SetAt(0, {{ .itemType }}( {{ index .testInterfaceOrigVal 1 }} )) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), ms.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), ms.At(0)) {{- end }} {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), cp.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 2 }}), cp.At(0)) {{- end }} ms.CopyTo(cp) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), cp.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 1 }}), cp.At(0)) {{- end }} mv := New{{ .structName }}() ms.MoveTo(mv) assert.Equal(t, 0, ms.Len()) assert.Equal(t, 1, mv.Len()) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{index .testInterfaceOrigVal 1 }}), mv.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{index .testInterfaceOrigVal 1 }}), mv.At(0)) {{- end }} ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) ms.MoveTo(mv) assert.Equal(t, 3, mv.Len()) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0)) {{- end }} mv.MoveTo(mv) assert.Equal(t, 3, mv.Len()) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{index .testInterfaceOrigVal 0 }}), mv.At(0)) {{- end }} } func Test{{ .structName }}ReadOnly(t *testing.T) { raw := []{{ .itemType }}{ {{ .testOrigVal }}} sharedState := internal.NewState() sharedState.MarkReadOnly() ms := {{ .structName }}(internal.New{{ .structName }}Wrapper(&raw, sharedState)) assert.Equal(t, 3, ms.Len()) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}( {{index .testInterfaceOrigVal 0 }} ), ms.At(0), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{ index .testInterfaceOrigVal 0 }}), ms.At(0)) {{- end }} assert.Panics(t, func() { ms.Append({{ index .testInterfaceOrigVal 0 }}) }) assert.Panics(t, func() { ms.EnsureCapacity(2) }) assert.Equal(t, raw, ms.AsRaw()) assert.Panics(t, func() { ms.FromRaw(raw) }) ms2 := New{{ .structName }}() ms.CopyTo(ms2) assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) assert.Panics(t, func() { ms2.CopyTo(ms) }) assert.Panics(t, func() { ms.MoveTo(ms2) }) assert.Panics(t, func() { ms2.MoveTo(ms) }) } func Test{{ .structName }}Append(t *testing.T) { ms := New{{ .structName }}() ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) ms.Append({{ .testSetVal }}, {{ .testSetVal }}) assert.Equal(t, 5, ms.Len()) {{- if eq .itemType "float64" }} assert.InDelta(t, {{ .itemType }}({{ .testSetVal }} ), ms.At(4), 0.01) {{- else }} assert.Equal(t, {{ .itemType }}({{ .testSetVal }}), ms.At(4)) {{- end }} } func Test{{ .structName }}EnsureCapacity(t *testing.T) { ms := New{{ .structName }}() ms.EnsureCapacity(4) assert.Equal(t, 4, cap(*ms.getOrig())) ms.EnsureCapacity(2) assert.Equal(t, 4, cap(*ms.getOrig())) } func Test{{ .structName }}All(t *testing.T) { ms := New{{ .structName }}() ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func Test{{ .structName }}MoveAndAppendTo(t *testing.T) { // Test moving from an empty slice ms := New{{ .structName }}() ms2 := New{{ .structName }}() ms.MoveAndAppendTo(ms2) assert.Equal(t, New{{ .structName }}(), ms2) assert.Equal(t, ms.Len(), 0) // Test moving to empty slice ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 3) // Test moving to a non empty slice ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 6) } func Test{{ .structName }}RemoveIf(t *testing.T) { emptySlice := New{{ .structName }}() emptySlice.RemoveIf(func(el {{ .itemType }}) bool { t.Fail() return false }) ms := New{{ .structName }}() ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) pos := 0 ms.RemoveIf(func(el {{ .itemType }}) bool { pos++ return pos%2 == 1 }) assert.Equal(t, pos/2, ms.Len()) } func Test{{ .structName }}RemoveIfAll(t *testing.T) { ms := New{{ .structName }}() ms.FromRaw([]{{ .itemType }}{ {{ .testOrigVal }} }) ms.RemoveIf(func(el {{ .itemType }}) bool { return true }) assert.Equal(t, 0, ms.Len()) } func Test{{ .structName }}Equal(t *testing.T) { ms := New{{ .structName }}() ms2 := New{{ .structName }}() assert.True(t, ms.Equal(ms2)) ms.Append({{ .testOrigVal }}) assert.False(t, ms.Equal(ms2)) ms2.Append({{ .testOrigVal }}) assert.True(t, ms.Equal(ms2)) } func Benchmark{{ .structName }}Equal(b *testing.B) { testutil.SkipMemoryBench(b) ms := New{{ .structName }}() ms.Append({{ .testOrigVal }}) cmp := New{{ .structName }}() cmp.Append({{ .testOrigVal }}) b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { _ = ms.Equal(cmp) } } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates/slice.go.tmpl000066400000000000000000000153121511331344600322060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package {{ .packageName }} import ( {{ range $index, $element := .imports -}} {{ $element }} {{ end }} ) // {{ .structName }} logically represents a slice of {{ .elementName }}. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use New{{ .structName }} function to create new instances. // Important: zero-initialized instance is not valid for use. {{- if .hasWrapper }} type {{ .structName }} internal.{{ .structName }}Wrapper {{- else }} type {{ .structName }} struct { orig *[]{{ if .elementNullable }}*{{ end }}internal.{{ .elementOriginName }} state *internal.State } {{- end }} func new{{ .structName }}(orig *[]{{ if .elementNullable }}*{{ end }}internal.{{ .elementOriginName }}, state *internal.State) {{ .structName }} { {{- if .hasWrapper }} return {{ .structName }}(internal.New{{ .structName }}Wrapper(orig, state)) {{- else }} return {{ .structName }}{orig: orig, state: state} {{- end }} } // New{{ .structName }} creates a {{ .structName }}Wrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func New{{ .structName }}() {{ .structName }} { orig := []{{ if .elementNullable }}*{{ end }}internal.{{ .elementOriginName }}(nil) return new{{ .structName }}(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "New{{ .structName }}()". func (es {{ .structName }}) Len() int { return len(*es.{{ .origAccessor }}) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es {{ .structName }}) At(i int) {{ .elementName }} { return new{{ .elementName }}({{ if not .elementNullable }}&{{ end }}(*es.{{ .origAccessor }})[i], es.{{ .stateAccessor }}) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es {{ .structName }}) All() iter.Seq2[int, {{ .elementName }}] { return func(yield func(int, {{ .elementName }}) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new {{ .structName }} can be initialized: // es := New{{ .structName }}() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es {{ .structName }}) EnsureCapacity(newCap int) { es.{{ .stateAccessor }}.AssertMutable() oldCap := cap(*es.{{ .origAccessor }}) if newCap <= oldCap { return } newOrig := make([]{{ if .elementNullable }}*{{ end }}internal.{{ .elementOriginName }}, len(*es.{{ .origAccessor }}), newCap) copy(newOrig, *es.{{ .origAccessor }}) *es.{{ .origAccessor }} = newOrig } // AppendEmpty will append to the end of the slice an empty {{ .elementName }}. // It returns the newly added {{ .elementName }}. func (es {{ .structName }}) AppendEmpty() {{ .elementName }} { es.{{ .stateAccessor }}.AssertMutable() *es.{{ .origAccessor }} = append(*es.{{ .origAccessor }}, {{- if .elementNullable }}internal.New{{ .elementOriginName }}(){{ else }}internal.{{ .elementOriginName }}{}{{ end }}) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es {{ .structName }}) MoveAndAppendTo(dest {{ .structName }}) { es.{{ .stateAccessor }}.AssertMutable() dest.{{ .stateAccessor }}.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.{{ .origAccessor }} == dest.{{ .origAccessor }} { return } if *dest.{{ .origAccessor }} == nil { // We can simply move the entire vector and avoid any allocations. *dest.{{ .origAccessor }} = *es.{{ .origAccessor }} } else { *dest.{{ .origAccessor }} = append(*dest.{{ .origAccessor }}, *es.{{ .origAccessor }}...) } *es.{{ .origAccessor }} = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es {{ .structName }}) RemoveIf(f func({{ .elementName }}) bool) { es.{{ .stateAccessor }}.AssertMutable() newLen := 0 for i := 0; i < len(*es.{{ .origAccessor }}); i++ { if f(es.At(i)) { {{ if .elementNullable -}} internal.Delete{{ .elementOriginName }}((*es.{{ .origAccessor }})[i], true) (*es.{{ .origAccessor }})[i] = nil {{ else -}} internal.Delete{{ .elementOriginName }}(&(*es.{{ .origAccessor }})[i], false) {{- end }} continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.{{ .origAccessor }})[newLen] = (*es.{{ .origAccessor }})[i] {{ if .elementNullable -}} // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.{{ .origAccessor }})[i] = nil{{ else -}} (*es.{{ .origAccessor }})[i].Reset() {{- end }} newLen++ } *es.{{ .origAccessor }} = (*es.{{ .origAccessor }})[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es {{ .structName }}) CopyTo(dest {{ .structName }}) { dest.{{ .stateAccessor }}.AssertMutable() if es.{{ .origAccessor }} == dest.{{ .origAccessor }} { return } *dest.{{ .origAccessor }} = internal.Copy{{ .elementOriginName }}{{ if .elementNullable }}Ptr{{ end }}Slice(*dest.{{ .origAccessor }}, *es.{{ .origAccessor }}) } {{ if .elementNullable -}} // Sort sorts the {{ .elementName }} elements within {{ .structName }} given the // provided less function so that two instances of {{ .structName }} // can be compared. func (es {{ .structName }}) Sort(less func(a, b {{ .elementName }}) bool) { es.{{ .stateAccessor }}.AssertMutable() sort.SliceStable(*es.{{ .origAccessor }}, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } {{- end }} {{ if .hasWrapper -}} func (ms {{ .structName }}) getOrig() *[]{{ if .elementNullable }}*{{ end }}internal.{{ .elementOriginName }} { return internal.Get{{ .structName }}Orig(internal.{{ .structName }}Wrapper(ms)) } func (ms {{ .structName }}) getState() *internal.State { return internal.Get{{ .structName }}State(internal.{{ .structName }}Wrapper(ms)) } {{- end }} slice_internal.go.tmpl000066400000000000000000000020571511331344600340250ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( {{ range $index, $element := .imports -}} {{ $element }} {{ end }} ) type {{ .structName }}Wrapper struct { orig *[]{{ if .elementNullable }}*{{ end }}{{ .elementOriginName }} state *State } func Get{{ .structName }}Orig(ms {{ .structName }}Wrapper) *[]{{ if .elementNullable }}*{{ end }}{{ .elementOriginName }} { return ms.orig } func Get{{ .structName }}State(ms {{ .structName }}Wrapper) *State { return ms.state } func New{{ .structName }}Wrapper(orig *[]{{ if .elementNullable }}*{{ end }}{{ .elementOriginName }}, state *State) {{ .structName }}Wrapper { return {{ .structName }}Wrapper{orig: orig, state: state} } func GenTest{{ .structName }}Wrapper() {{ .structName }}Wrapper { orig := GenTest{{ .elementOriginName }}{{ if .elementNullable }}Ptr{{ end }}Slice() return New{{ .structName }}Wrapper(&orig, NewState()) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/templates/slice_test.go.tmpl000066400000000000000000000130321511331344600332420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package {{ .packageName }} import ( {{ range $index, $element := .testImports -}} {{ $element }} {{ end }} ) func Test{{ .structName }}(t *testing.T) { es := New{{ .structName }}() assert.Equal(t, 0, es.Len()) es = new{{ .structName }}(&[]{{ if .elementNullable }}*{{ end }}internal.{{ .elementOriginName }}{}, internal.NewState()) assert.Equal(t, 0, es.Len()) {{ if eq .elementName "Value" -}} emptyVal := New{{ .elementName }}Empty() {{- else }} emptyVal := New{{ .elementName }}() {{- end }} {{- if .hasWrapper }} testVal := {{ .elementName }}(internal.GenTest{{ .elementName }}Wrapper()) {{- else }} testVal := generateTest{{ .elementName }}() {{- end }} for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.{{ .origAccessor }})[i] = {{ if not .elementNullable }}*{{ end }}internal.GenTest{{ .elementOriginName }}() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func Test{{ .structName }}ReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := new{{ .structName }}(&[]{{ if .elementNullable }}*{{ end }}internal.{{ .elementOriginName }}{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := New{{ .structName }}() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func Test{{ .structName }}_CopyTo(t *testing.T) { dest := New{{ .structName }}() src := generateTest{{ .structName }}() src.CopyTo(dest) assert.Equal(t, generateTest{{ .structName }}(), dest) dest.CopyTo(dest) assert.Equal(t, generateTest{{ .structName }}(), dest) } func Test{{ .structName }}_EnsureCapacity(t *testing.T) { es := generateTest{{ .structName }}() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.{{ .origAccessor }})) assert.Equal(t, generateTest{{ .structName }}(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTest{{ .structName }}().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.{{ .origAccessor }})) assert.Equal(t, generateTest{{ .structName }}(), es) } func Test{{ .structName }}_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTest{{ .structName }}() dest := New{{ .structName }}() src := generateTest{{ .structName }}() src.MoveAndAppendTo(dest) assert.Equal(t, generateTest{{ .structName }}(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTest{{ .structName }}(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTest{{ .structName }}().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func Test{{ .structName }}_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := New{{ .structName }}() emptySlice.RemoveIf(func(el {{ .elementName }}) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTest{{ .structName }}() pos := 0 filtered.RemoveIf(func(el {{ .elementName }}) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func Test{{ .structName }}_RemoveIfAll(t *testing.T) { got := generateTest{{ .structName }}() got.RemoveIf(func(el {{ .elementName }}) bool { return true }) assert.Equal(t, 0, got.Len()) } func Test{{ .structName }}All(t *testing.T) { ms := generateTest{{ .structName }}() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } {{ if .elementNullable -}} func Test{{ .structName }}_Sort(t *testing.T) { es := generateTest{{ .structName }}() es.Sort(func(a, b {{ .elementName }}) bool { return uintptr(unsafe.Pointer(a.{{ .origAccessor }})) < uintptr(unsafe.Pointer(b.{{ .origAccessor }})) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).{{ .origAccessor }})), uintptr(unsafe.Pointer(es.At(i).{{ .origAccessor }}))) } es.Sort(func(a, b {{ .elementName }}) bool { return uintptr(unsafe.Pointer(a.{{ .origAccessor }})) > uintptr(unsafe.Pointer(b.{{ .origAccessor }})) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).{{ .origAccessor }})), uintptr(unsafe.Pointer(es.At(i).{{ .origAccessor }}))) } } {{- end }} func generateTest{{ .structName }}() {{ .structName }} { ms := New{{ .structName }}() *ms.{{ .origAccessor }} = internal.GenTest{{ .elementOriginName }}{{ if .elementNullable }}Ptr{{ end }}Slice() return ms } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/typed_field.go000066400000000000000000000101631511331344600304250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const typedAccessorsTemplate = `// {{ .fieldName }} returns the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) {{ .fieldName }}() {{ .packageName }}{{ .returnType }} { return {{ .packageName }}{{ .returnType }}(ms.orig.{{ .originFieldName }}) } // Set{{ .fieldName }} replaces the {{ .lowerFieldName }} associated with this {{ .structName }}. func (ms {{ .structName }}) Set{{ .fieldName }}(v {{ .packageName }}{{ .returnType }}) { ms.state.AssertMutable() ms.orig.{{ .originFieldName }} = {{ .messageType }}(v) }` const typedAccessorsTestTemplate = `func Test{{ .structName }}_{{ .fieldName }}(t *testing.T) { ms := New{{ .structName }}() assert.Equal(t, {{ .packageName }}{{ .returnType }}({{ .defaultVal }}), ms.{{ .fieldName }}()) testVal{{ .fieldName }} := {{ .packageName }}{{ .returnType }}({{ .testValue }}) ms.Set{{ .fieldName }}(testVal{{ .fieldName }}) assert.Equal(t, testVal{{ .fieldName }}, ms.{{ .fieldName }}()) }` const typedSetTestTemplate = `orig.{{ .originFieldName }} = {{ .testValue }}` // TypedField is a field that has defined a custom type (e.g. "type Timestamp uint64") type TypedField struct { fieldName string originFieldName string protoID uint32 returnType *TypedType } type TypedType struct { structName string packageName string protoType proto.Type messageName string defaultVal string testVal string } func (ptf *TypedField) GenerateAccessors(ms *messageStruct) string { t := template.Parse("typedAccessorsTemplate", []byte(typedAccessorsTemplate)) return template.Execute(t, ptf.templateFields(ms)) } func (ptf *TypedField) GenerateAccessorsTest(ms *messageStruct) string { t := template.Parse("typedAccessorsTestTemplate", []byte(typedAccessorsTestTemplate)) return template.Execute(t, ptf.templateFields(ms)) } func (ptf *TypedField) GenerateTestValue(ms *messageStruct) string { t := template.Parse("typedSetTestTemplate", []byte(typedSetTestTemplate)) return template.Execute(t, ptf.templateFields(ms)) } type ProtoTypedField struct { *proto.Field } func (ptf ProtoTypedField) GenMarshalJSON() string { if ptf.MessageName == "TraceID" || ptf.MessageName == "SpanID" || ptf.MessageName == "ProfileID" { return "if !orig." + ptf.Name + ".IsEmpty() {\n" + ptf.Field.GenMarshalJSON() + "\n}" } return ptf.Field.GenMarshalJSON() } func (ptf *TypedField) toProtoField(ms *messageStruct) proto.FieldInterface { return ProtoTypedField{&proto.Field{ Type: ptf.returnType.protoType, ID: ptf.protoID, Name: ptf.getOriginFieldName(), MessageName: ptf.returnType.messageName, ParentMessageName: ms.protoName, }} } func (ptf *TypedField) getOriginFieldName() string { if ptf.originFieldName == "" { return ptf.fieldName } return ptf.originFieldName } func (ptf *TypedField) templateFields(ms *messageStruct) map[string]any { pf := ptf.toProtoField(ms) messageType := pf.GoType() defaultVal := ptf.returnType.defaultVal testVal := ptf.returnType.testVal if ptf.returnType.protoType == proto.TypeMessage || ptf.returnType.protoType == proto.TypeEnum { messageType = "internal." + messageType defaultVal = "internal." + defaultVal testVal = "internal." + testVal } return map[string]any{ "structName": ms.getName(), "defaultVal": defaultVal, "packageName": func() string { if ptf.returnType.packageName != ms.packageName { return ptf.returnType.packageName + "." } return "" }(), "hasWrapper": usedByOtherDataTypes(ptf.returnType.packageName), "returnType": ptf.returnType.structName, "fieldName": ptf.fieldName, "originFieldName": ptf.getOriginFieldName(), "lowerFieldName": strings.ToLower(ptf.fieldName), "testValue": testVal, "messageType": messageType, } } var _ Field = (*TypedField)(nil) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/pdata/xpdata_entity_package.go000066400000000000000000000035671511331344600324770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pdata // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" import ( "path/filepath" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" ) var xpdataEntity = &Package{ info: &PackageInfo{ name: "entity", path: filepath.Join("xpdata", "entity"), imports: []string{ `"encoding/binary"`, `"fmt"`, `"iter"`, `"math"`, `"sort"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/internal/proto"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, testImports: []string{ `"testing"`, ``, `"github.com/stretchr/testify/assert"`, `gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1"`, ``, `"go.opentelemetry.io/collector/pdata/internal"`, `"go.opentelemetry.io/collector/pdata/internal/json"`, `"go.opentelemetry.io/collector/pdata/pcommon"`, }, }, structs: []baseStruct{ entityRefSlice, entityRef, }, } var entityRefSlice = &messageSlice{ structName: "EntityRefSlice", packageName: "entity", elementNullable: true, element: entityRef, } var entityRef = &messageStruct{ structName: "EntityRef", packageName: "entity", protoName: "EntityRef", upstreamProto: "gootlpcommon.EntityRef", fields: []Field{ &PrimitiveField{ fieldName: "SchemaUrl", protoID: 1, protoType: proto.TypeString, }, &PrimitiveField{ fieldName: "Type", protoID: 2, protoType: proto.TypeString, }, &SliceField{ fieldName: "IdKeys", protoID: 3, protoType: proto.TypeString, returnSlice: stringSlice, }, &SliceField{ fieldName: "DescriptionKeys", protoID: 4, protoType: proto.TypeString, returnSlice: stringSlice, }, }, } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/000077500000000000000000000000001511331344600256575ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/copy.go000066400000000000000000000033261511331344600271640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const copyOther = `{{ if .repeated -}} dest.{{ .fieldName }} = append(dest.{{ .fieldName }}[:0], src.{{ .fieldName }}...) {{- else if not .nullable -}} dest.{{ .fieldName }} = src.{{ .fieldName }} {{ else -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = t.{{ .fieldName }} dest.{{ .oneOfGroup }} = ov {{- end }}` const copyMessage = `{{ if .repeated -}} dest.{{ .fieldName }} = Copy{{ .messageName }}{{ if .nullable }}Ptr{{ end }}Slice(dest.{{ .fieldName }}, src.{{ .fieldName }}) {{- else if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = New{{ .messageName }}() Copy{{ .messageName }}(ov.{{ .fieldName }}, t.{{ .fieldName }}) dest.{{ .oneOfGroup }} = ov {{- else if .nullable -}} dest.{{ .fieldName }} = Copy{{ .messageName }}(dest.{{ .fieldName }}, src.{{ .fieldName }}) {{- else -}} Copy{{ .messageName }}(&dest.{{ .fieldName }}, &src.{{ .fieldName }}) {{- end }} ` func (pf *Field) GenCopy() string { tf := pf.getTemplateFields() if pf.Type == TypeMessage { return template.Execute(template.Parse("copyMessage", []byte(copyMessage)), tf) } return template.Execute(template.Parse("copyOther", []byte(copyOther)), tf) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/delete.go000066400000000000000000000024571511331344600274600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const deleteOther = `{{ if ne .oneOfGroup "" -}} if UseProtoPooling.IsEnabled() { ov.{{ .fieldName }} = {{ .defaultValue }} ProtoPool{{ .oneOfMessageName }}.Put(ov) } {{ end }}` const deleteMessage = `{{ if .repeated -}} for i := range orig.{{ .fieldName }} { {{ if .nullable -}} Delete{{ .messageName }}(orig.{{ .fieldName }}[i], true) {{- else -}} Delete{{ .messageName }}(&orig.{{ .fieldName }}[i], false) {{- end }} } {{- else if ne .oneOfGroup "" -}} Delete{{ .messageName }}(ov.{{ .fieldName }}, true) ov.{{ .fieldName }} = nil ProtoPool{{ .oneOfMessageName }}.Put(ov) {{- else if .nullable -}} Delete{{ .messageName }}(orig.{{ .fieldName }}, true) {{- else -}} Delete{{ .messageName }}(&orig.{{ .fieldName }}, false) {{- end }} ` func (pf *Field) GenDelete() string { tf := pf.getTemplateFields() if pf.Type == TypeMessage { return template.Execute(template.Parse("deleteMessage", []byte(deleteMessage)), tf) } if pf.OneOfGroup != "" { return template.Execute(template.Parse("deleteOther", []byte(deleteOther)), tf) } return "" } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/enum.go000066400000000000000000000025751511331344600271630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const enumMessageTemplate = ` // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal const ( {{- range .Fields }} {{ $.Name }}_{{ .Name }} = {{ $.Name }}({{ .Value }}) {{- end }} ) {{ .Description }} type {{ .Name }} int32 var {{ .Name }}_name = map[int32]string { {{- range .Fields }} {{ .Value }}: "{{ .Name }}", {{- end }} } var {{ .Name }}_value = map[string]int32 { {{- range .Fields }} "{{ .Name }}": {{ .Value }}, {{- end }} } ` type Enum struct { Name string Description string Fields []*EnumField } type EnumField struct { Name string Value int } func (ms *Enum) GenerateEnum() []byte { return []byte(template.Execute(template.Parse("enumMessageTemplate", []byte(enumMessageTemplate)), ms)) } func (ms *Enum) templateFields(imports, testImports []string) map[string]any { return map[string]any{ "fields": ms.Fields, "messageName": ms.Name, "description": ms.Description, "imports": imports, "testImports": testImports, } } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/field.go000066400000000000000000000135401511331344600272740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "fmt" "strings" ) // FieldInterface temporary interface until we generate the proto fields with pdatagen. // TODO: Remove when no more wrappers needed. type FieldInterface interface { GenTestFailingUnmarshalProtoValues() string GenTestEncodingValues() string GenPool() string GenDelete() string GenCopy() string GenMarshalJSON() string GenUnmarshalJSON() string GenSizeProto() string GenMarshalProto() string GenUnmarshalProto() string GenMessageField() string GenOneOfMessages() string GoType() string DefaultValue() string TestValue() string GetName() string } type Field struct { Type Type Name string OneOfGroup string OneOfMessageName string MessageName string ParentMessageName string ID uint32 Repeated bool Nullable bool } func (pf *Field) GetName() string { return pf.Name } func (pf *Field) wireType() WireType { switch pf.Type { case TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeSInt32, TypeSInt64, TypeBool, TypeEnum: // In proto3, repeated scalar types are packed; hence they use Length-Delimited (Wire Type 2). if pf.Repeated { return WireTypeLen } return WireTypeVarint case TypeFixed32, TypeSFixed32, TypeFloat: // In proto3, repeated scalar types are packed; hence they use Length-Delimited (Wire Type 2). if pf.Repeated { return WireTypeLen } return WireTypeI32 case TypeFixed64, TypeSFixed64, TypeDouble: // In proto3, repeated scalar types are packed; hence they use Length-Delimited (Wire Type 2). if pf.Repeated { return WireTypeLen } return WireTypeI64 case TypeBytes, TypeMessage, TypeString: return WireTypeLen default: panic("unsupported field type") } } func (pf *Field) DefaultValue() string { switch pf.Type { case TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeSInt32, TypeSInt64, TypeEnum, TypeFixed32, TypeSFixed32, TypeFloat, TypeFixed64, TypeSFixed64, TypeDouble: return pf.GoType() + `(0)` case TypeBool: return `false` case TypeBytes: return `nil` case TypeString: return `""` case TypeMessage: if pf.Nullable { return `&` + pf.MessageName + `{}` } return pf.MessageName + `{}` default: panic("unsupported field type") } } func (pf *Field) TestValue() string { if pf.Repeated { return pf.MemberGoType() + "{" + pf.DefaultValue() + ", " + pf.rawTestValue() + "}" } return pf.rawTestValue() } func (pf *Field) rawTestValue() string { switch pf.Type { case TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeSInt32, TypeSInt64, TypeEnum, TypeFixed32, TypeSFixed32, TypeFixed64, TypeSFixed64: return pf.GoType() + "(13)" case TypeFloat, TypeDouble: return pf.GoType() + "(3.1415926)" case TypeBool: return `true` case TypeBytes: return `[]byte{1, 2, 3}` case TypeString: return `"test_` + strings.ToLower(pf.Name) + `"` case TypeMessage: if pf.Nullable { return `GenTest` + pf.MessageName + `()` } return `*GenTest` + pf.MessageName + `()` default: panic("unsupported field type") } } func (pf *Field) GoType() string { switch pf.Type { case TypeDouble: return "float64" case TypeFloat: return "float32" case TypeInt32, TypeSInt32, TypeSFixed32: return "int32" case TypeInt64, TypeSInt64, TypeSFixed64: return "int64" case TypeUint32, TypeFixed32: return "uint32" case TypeUint64, TypeFixed64: return "uint64" case TypeBool: return "bool" case TypeString: return "string" case TypeBytes: return "[]byte" case TypeMessage, TypeEnum: return pf.MessageName default: panic("unsupported field type") } } func (pf *Field) MemberGoType() string { ptrGoType := func() string { if pf.Nullable { return "*" + pf.GoType() } return pf.GoType() } if pf.Repeated { return "[]" + ptrGoType() } return ptrGoType() } func (pf *Field) GenMessageField() string { return pf.Name + " " + pf.MemberGoType() } func (pf *Field) getTemplateFields() map[string]any { bitSize := 0 switch pf.Type { case TypeFixed64, TypeSFixed64, TypeInt64, TypeUint64, TypeSInt64, TypeDouble: bitSize = 64 case TypeFixed32, TypeSFixed32, TypeInt32, TypeUint32, TypeSInt32, TypeFloat, TypeEnum: bitSize = 32 } protoTag := genProtoTag(pf.ID, pf.wireType()) return map[string]any{ "protoTagSize": len(protoTag), "protoTag": protoTag, "protoFieldID": pf.ID, "jsonTag": genJSONTag(pf.Name), "fieldName": pf.Name, "messageName": pf.MessageName, "parentMessageName": pf.ParentMessageName, "oneOfGroup": pf.OneOfGroup, "oneOfMessageName": pf.OneOfMessageName, "repeated": pf.Repeated, "nullable": pf.Nullable, "bitSize": bitSize, "goType": pf.GoType(), "defaultValue": pf.DefaultValue(), "testValue": pf.TestValue(), } } func genJSONTag(fieldName string) string { // Extract last word because for Enums we use the full name. return lowerFirst(ExtractNameFromFull(fieldName)) } // genProtoTag encodes the field key, and returns it in the reverse order. func genProtoTag(fieldNumber uint32, wt WireType) []string { x := fieldNumber<<3 | uint32(wt) i := 0 keybuf := make([]byte, 0) for i = 0; x > 127; i++ { keybuf = append(keybuf, 0x80|uint8(x&0x7F)) x >>= 7 } keybuf = append(keybuf, uint8(x)) ret := make([]string, 0, len(keybuf)) for i = len(keybuf) - 1; i >= 0; i-- { ret = append(ret, fmt.Sprintf("%#v", keybuf[i])) } return ret } func ExtractNameFromFull(fullName string) string { // Extract last word because for Enums we use the full name. lastSpaceIndex := strings.LastIndex(fullName, ".") if lastSpaceIndex != -1 { return fullName[lastSpaceIndex+1:] } return fullName } func lowerFirst(s string) string { return strings.ToLower(s[0:1]) + s[1:] } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/json_marshal.go000066400000000000000000000063221511331344600306710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "fmt" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const marshalJSONPrimitive = `{{ if .repeated -}} if len(orig.{{ .fieldName }}) > 0 { dest.WriteObjectField("{{ .jsonTag }}") dest.WriteArrayStart() dest.Write{{ upperFirst .goType }}(orig.{{ .fieldName }}[0]) for i := 1; i < len(orig.{{ .fieldName }}); i++ { dest.WriteMore() dest.Write{{ upperFirst .goType }}(orig.{{ .fieldName }}[i]) } dest.WriteArrayEnd() } {{- else }} {{- if not .nullable -}} if orig.{{ .fieldName }} != {{ .defaultValue }} { {{ end -}} dest.WriteObjectField("{{ .jsonTag }}") dest.Write{{ upperFirst .goType }}(orig.{{ .fieldName }}) {{- if not .nullable -}} } {{- end }}{{- end }}` const marshalJSONEnum = `{{ if .repeated -}} if len(orig.{{ .fieldName }}) > 0 { dest.WriteObjectField("{{ .jsonTag }}") dest.WriteArrayStart() dest.WriteInt32(int32(orig.{{ .fieldName }}[0])) for i := 1; i < len(orig.{{ .fieldName }}); i++ { dest.WriteMore() dest.WriteInt32(int32(orig.{{ .fieldName }}[i])) } dest.WriteArrayEnd() } {{- else }} if int32(orig.{{ .fieldName }}) != 0 { dest.WriteObjectField("{{ .jsonTag }}") dest.WriteInt32(int32(orig.{{ .fieldName }})) } {{- end }}` const marshalJSONMessage = `{{ if .repeated -}} if len(orig.{{ .fieldName }}) > 0 { dest.WriteObjectField("{{ .jsonTag }}") dest.WriteArrayStart() orig.{{ .fieldName }}[0].MarshalJSON(dest) for i := 1; i < len(orig.{{ .fieldName }}); i++ { dest.WriteMore() orig.{{ .fieldName }}[i].MarshalJSON(dest) } dest.WriteArrayEnd() } {{- else }} {{- if .nullable -}} if orig.{{ .fieldName }} != nil { {{ end -}} dest.WriteObjectField("{{ .jsonTag }}") orig.{{ .fieldName }}.MarshalJSON(dest) {{- if .nullable -}} } {{- end }}{{- end }}` const marshalJSONBytes = `{{ if .repeated -}} if len(orig.{{ .fieldName }}) > 0 { dest.WriteObjectField("{{ .jsonTag }}") dest.WriteArrayStart() dest.WriteBytes(orig.{{ .fieldName }}[0]) for i := 1; i < len(orig.{{ .fieldName }}); i++ { dest.WriteMore() dest.WriteBytes(orig.{{ .fieldName }}[i]) } dest.WriteArrayEnd() } {{- else }}{{ if not .nullable }} if len(orig.{{ .fieldName }}) > 0 { {{- end }} dest.WriteObjectField("{{ .jsonTag }}") dest.WriteBytes(orig.{{ .fieldName }}) {{- if not .nullable -}} } {{- end }}{{- end }}` func (pf *Field) GenMarshalJSON() string { tf := pf.getTemplateFields() switch pf.Type { case TypeBytes: return template.Execute(template.Parse("marshalJSONBytes", []byte(marshalJSONBytes)), tf) case TypeMessage: return template.Execute(template.Parse("marshalJSONMessage", []byte(marshalJSONMessage)), tf) case TypeEnum: return template.Execute(template.Parse("marshalJSONEnum", []byte(marshalJSONEnum)), tf) case TypeDouble, TypeFloat, TypeFixed64, TypeSFixed64, TypeFixed32, TypeSFixed32, TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeSInt32, TypeSInt64, TypeBool, TypeString: return template.Execute(template.Parse("marshalJSONPrimitive", []byte(marshalJSONPrimitive)), tf) } panic(fmt.Sprintf("unhandled case %T", pf.Type)) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/json_unmarshal.go000066400000000000000000000070461511331344600312400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "fmt" "strings" "github.com/ettle/strcase" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const unmarshalJSONPrimitive = ` case {{ .allJSONTags }}: {{ if .repeated -}} for iter.ReadArray() { orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, iter.Read{{ upperFirst .goType }}()) } {{ else if .nullable -}} { var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = iter.Read{{ upperFirst .goType }}() orig.{{ .oneOfGroup }} = ov } {{ else -}} orig.{{ .fieldName }} = iter.Read{{ upperFirst .goType }}() {{- end }}` const unmarshalJSONEnum = ` case {{ .allJSONTags }}: {{ if .repeated -}} for iter.ReadArray() { orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, {{ .messageName }}(iter.ReadEnumValue({{ .messageName }}_value))) } {{ else -}} orig.{{ .fieldName }} = {{ .messageName }}(iter.ReadEnumValue({{ .messageName }}_value)) {{- end }}` const unmarshalJSONMessage = ` case {{ .allJSONTags }}: {{ if .repeated -}} for iter.ReadArray() { orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, {{ if .nullable }}New{{ .messageName }}(){{ else }}{{ .defaultValue }}{{ end }}) orig.{{ .fieldName }}[len(orig.{{ .fieldName }}) - 1].UnmarshalJSON(iter) } {{ else if ne .oneOfGroup "" -}} { var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = New{{ .messageName }}() ov.{{ .fieldName }}.UnmarshalJSON(iter) orig.{{ .oneOfGroup }} = ov } {{ else -}} {{ if .nullable }}orig.{{ .fieldName }} = New{{ .messageName }}(){{ end }} orig.{{ .fieldName }}.UnmarshalJSON(iter) {{- end }}` const unmarshalJSONBytes = ` case {{ .allJSONTags }}: {{ if .repeated -}} for iter.ReadArray() { orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, iter.ReadBytes()) } {{ else if ne .oneOfGroup "" -}} { var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = iter.ReadBytes() orig.{{ .oneOfGroup }} = ov } {{ else -}} orig.{{ .fieldName }} = iter.ReadBytes() {{- end }}` func (pf *Field) GenUnmarshalJSON() string { tf := pf.getTemplateFields() tf["allJSONTags"] = allJSONTags(pf.Name) switch pf.Type { case TypeBytes: return template.Execute(template.Parse("unmarshalJSONBytes", []byte(unmarshalJSONBytes)), tf) case TypeMessage: return template.Execute(template.Parse("unmarshalJSONMessage", []byte(unmarshalJSONMessage)), tf) case TypeEnum: return template.Execute(template.Parse("unmarshalJSONEnum", []byte(unmarshalJSONEnum)), tf) case TypeDouble, TypeFloat, TypeFixed64, TypeSFixed64, TypeFixed32, TypeSFixed32, TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeSInt32, TypeSInt64, TypeBool, TypeString: return template.Execute(template.Parse("unmarshalJSONPrimitive", []byte(unmarshalJSONPrimitive)), tf) } panic(fmt.Sprintf("unhandled case %T", pf.Type)) } func allJSONTags(str string) string { snake := strcase.ToSnake(str) if !strings.EqualFold(str, snake) { return `"` + lowerFirst(str) + `", "` + snake + `"` } return `"` + lowerFirst(str) + `"` } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/message.go000066400000000000000000000026221511331344600276340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( _ "embed" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) var ( //go:embed templates/message.go.tmpl messageTemplateBytes []byte messageTemplate = template.Parse("message_internal_test.go", messageTemplateBytes) //go:embed templates/message_test.go.tmpl messageTestTemplateBytes []byte messageTestTemplate = template.Parse("message_internal_test.go", messageTestTemplateBytes) ) type Message struct { Name string Description string OriginFullName string UpstreamMessage string Fields []FieldInterface } func (ms *Message) GenerateMessage(imports, testImports []string) []byte { return []byte(template.Execute(messageTemplate, ms.templateFields(imports, testImports))) } func (ms *Message) GenerateMessageTests(imports, testImports []string) []byte { return []byte(template.Execute(messageTestTemplate, ms.templateFields(imports, testImports))) } func (ms *Message) templateFields(imports, testImports []string) map[string]any { return map[string]any{ "fields": ms.Fields, "messageName": ms.Name, "upstreamMessage": ms.UpstreamMessage, "description": ms.Description, "imports": imports, "testImports": testImports, } } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/oneof_message.go000066400000000000000000000024001511331344600310140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const oneOfMessageOrigOtherTemplate = ` type {{ .oneOfMessageName }} struct { {{ .fieldName }} {{ .goType }} } func (m *{{ .parentMessageName }}) Get{{ .fieldName }}() {{ .goType }} { if v, ok := m.Get{{ .oneOfGroup }}().(*{{ .oneOfMessageName }}); ok { return v.{{ .fieldName }} } return {{ .defaultValue }} } ` const oneOfMessageOrigMessageTemplate = ` type {{ .oneOfMessageName }} struct { {{ .fieldName }} *{{ .goType }} } func (m *{{ .parentMessageName }}) Get{{ .fieldName }}() *{{ .goType }} { if v, ok := m.Get{{ .oneOfGroup }}().(*{{ .oneOfMessageName }}); ok { return v.{{ .fieldName }} } return nil } ` func (pf *Field) GenOneOfMessages() string { tf := pf.getTemplateFields() if pf.OneOfGroup != "" { if pf.Type == TypeMessage { return template.Execute(template.Parse("oneOfMessageOrigMessageTemplate", []byte(oneOfMessageOrigMessageTemplate)), tf) } return template.Execute(template.Parse("oneOfMessageOrigOtherTemplate", []byte(oneOfMessageOrigOtherTemplate)), tf) } return "" } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/pools.go000066400000000000000000000011411511331344600273370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const poolVarOrigTemplate = ` ProtoPool{{ .oneOfMessageName }} = sync.Pool{ New: func() any { return &{{ .oneOfMessageName }}{} }, } ` func (pf *Field) GenPool() string { tf := pf.getTemplateFields() if pf.OneOfGroup != "" { return template.Execute(template.Parse("poolVarOrigTemplate", []byte(poolVarOrigTemplate)), tf) } return "" } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/proto.go000066400000000000000000000006451511331344600273560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" type Type int32 const ( TypeDouble Type = iota TypeFloat TypeInt32 TypeInt64 TypeUint32 TypeUint64 TypeSInt32 TypeSInt64 TypeFixed32 TypeFixed64 TypeSFixed32 TypeSFixed64 TypeBool TypeEnum TypeString TypeBytes TypeMessage ) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/proto_marshal.go000066400000000000000000000140621511331344600310630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "fmt" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const marshalProtoFloat = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { for i := l - 1; i >= 0; i-- { pos -= {{ div .bitSize 8 }} binary.LittleEndian.PutUint{{ .bitSize }}(buf[pos:], math.Float{{ .bitSize }}bits(orig.{{ .fieldName }}[i])) } pos = proto.EncodeVarint(buf, pos, uint64(l*{{ div .bitSize 8 }})) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else }} {{- if not .nullable -}} if orig.{{ .fieldName }} != 0 { {{ end -}} pos -= {{ div .bitSize 8 }} binary.LittleEndian.PutUint{{ .bitSize }}(buf[pos:], math.Float{{ .bitSize }}bits(orig.{{ .fieldName }})) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} {{- if not .nullable -}} } {{- end }}{{- end }}` const marshalProtoFixed = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { for i := l - 1; i >= 0; i-- { pos -= {{ div .bitSize 8 }} binary.LittleEndian.PutUint{{ .bitSize }}(buf[pos:], uint{{ .bitSize }}(orig.{{ .fieldName }}[i])) } pos = proto.EncodeVarint(buf, pos, uint64(l*{{ div .bitSize 8 }})) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else }} {{- if not .nullable -}} if orig.{{ .fieldName }} != 0 { {{ end -}} pos -= {{ div .bitSize 8 }} binary.LittleEndian.PutUint{{ .bitSize }}(buf[pos:], uint{{ .bitSize }}(orig.{{ .fieldName }})) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} {{- if not .nullable -}} } {{- end }}{{- end }}` const marshalProtoBool = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { for i := l - 1; i >= 0; i-- { pos-- if orig.{{ .fieldName }}[i] { buf[pos] = 1 } else { buf[pos] = 0 } } pos = proto.EncodeVarint(buf, pos, uint64(l)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else }} {{- if not .nullable -}} if orig.{{ .fieldName }} { {{ end -}} pos-- if orig.{{ .fieldName }} { buf[pos] = 1 } else { buf[pos] = 0 } {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} {{- if not .nullable -}} } {{- end }}{{- end }}` const marshalProtoVarint = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.{{ .fieldName }}[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else }} {{- if not .nullable -}} if orig.{{ .fieldName }} != 0 { {{ end -}} pos = proto.EncodeVarint(buf, pos, uint64(orig.{{ .fieldName }})) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} {{- if not .nullable -}} } {{- end }}{{- end }}` const marshalProtoBytesString = `{{ if .repeated -}} for i := len(orig.{{ .fieldName }}) - 1; i >= 0; i-- { l = len(orig.{{ .fieldName }}[i]) pos -= l copy(buf[pos:], orig.{{ .fieldName }}[i]) pos = proto.EncodeVarint(buf, pos, uint64(l)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else -}} l = len(orig.{{ .fieldName }}) {{ if not .nullable -}} if l > 0 { {{ end -}} pos -= l copy(buf[pos:], orig.{{ .fieldName }}) pos = proto.EncodeVarint(buf, pos, uint64(l)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} {{- if not .nullable -}} } {{- end }}{{- end }}` const marshalProtoMessage = `{{ if .repeated -}} for i := len(orig.{{ .fieldName }}) - 1; i >= 0; i-- { l = orig.{{ .fieldName }}[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else if .nullable -}} if orig.{{ .fieldName }} != nil { l = orig.{{ .fieldName }}.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else -}} l = orig.{{ .fieldName }}.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} {{- end }}` const marshalProtoSignedVarint = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64((uint{{ .bitSize }}(orig.{{ .fieldName }}[i])<<1)^uint{{ .bitSize }}(orig.{{ .fieldName }}[i]>>{{ sub .bitSize 1}}))) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} } {{- else }} {{- if not .nullable -}} if orig.{{ .fieldName }} != 0 { {{ end -}} pos = proto.EncodeVarint(buf, pos, uint64((uint{{ .bitSize }}(orig.{{ .fieldName }})<<1)^uint{{ .bitSize }}(orig.{{ .fieldName }}>>{{ sub .bitSize 1}}))) {{ range .protoTag -}} pos-- buf[pos] = {{ . }} {{ end -}} {{- if not .nullable -}} } {{- end }}{{- end }}` func (pf *Field) GenMarshalProto() string { tf := pf.getTemplateFields() switch pf.Type { case TypeDouble, TypeFloat: return template.Execute(template.Parse("marshalProtoFloat", []byte(marshalProtoFloat)), tf) case TypeFixed64, TypeSFixed64, TypeFixed32, TypeSFixed32: return template.Execute(template.Parse("marshalProtoFixed", []byte(marshalProtoFixed)), tf) case TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeEnum: return template.Execute(template.Parse("marshalProtoVarint", []byte(marshalProtoVarint)), tf) case TypeBool: return template.Execute(template.Parse("marshalProtoBool", []byte(marshalProtoBool)), tf) case TypeBytes, TypeString: return template.Execute(template.Parse("marshalProtoBytesString", []byte(marshalProtoBytesString)), tf) case TypeMessage: return template.Execute(template.Parse("marshalProtoMessage", []byte(marshalProtoMessage)), tf) case TypeSInt32, TypeSInt64: return template.Execute(template.Parse("marshalProtoSignedVarint", []byte(marshalProtoSignedVarint)), tf) } panic(fmt.Sprintf("unhandled case %T", pf.Type)) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/proto_size.go000066400000000000000000000075771511331344600304230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "fmt" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const sizeProtoI8 = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { l *= 8 n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else if not .nullable -}} if orig.{{ .fieldName }} != 0 { n+= {{ add .protoTagSize 8 }} } {{- else -}} n+= {{ add .protoTagSize 8 }} {{- end }}` const sizeProtoI4 = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { l *= 4 n+= + {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else if not .nullable -}} if orig.{{ .fieldName }} != 0 { n+= {{ add .protoTagSize 4 }} } {{- else -}} n+= {{ add .protoTagSize 4 }} {{- end }}` const sizeProtoBool = `{{ if .repeated -}} l = len(orig.{{ .fieldName }}) if l > 0 { n+= + {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else if not .nullable -}} if orig.{{ .fieldName }} { n+= {{ add .protoTagSize 1 }} } {{- else -}} n+= {{ add .protoTagSize 1 }} {{- end }}` const sizeProtoVarint = `{{ if .repeated -}} if len(orig.{{ .fieldName }}) > 0 { l = 0 for _, e := range orig.{{ .fieldName }} { l += proto.Sov(uint64(e)) } n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else if not .nullable -}} if orig.{{ .fieldName }} != 0 { n+= {{ .protoTagSize }} + proto.Sov(uint64(orig.{{ .fieldName }})) } {{- else -}} n+= {{ .protoTagSize }} + proto.Sov(uint64(orig.{{ .fieldName }})) {{- end }}` const sizeProtoBytesString = `{{ if .repeated -}} for _, s := range orig.{{ .fieldName }} { l = len(s) n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else if not .nullable -}} l = len(orig.{{ .fieldName }}) if l > 0 { n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else -}} l = len(orig.{{ .fieldName }}) n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l {{- end }}` const sizeProtoMessage = `{{ if .repeated -}} for i := range orig.{{ .fieldName }} { l = orig.{{ .fieldName }}[i].SizeProto() n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else if .nullable -}} if orig.{{ .fieldName }} != nil { l = orig.{{ .fieldName }}.SizeProto() n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else -}} l = orig.{{ .fieldName }}.SizeProto() n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l {{- end }}` const sizeProtoSignedVarint = `{{ if .repeated -}} if len(orig.{{ .fieldName }}) > 0 { l = 0 for _, e := range orig.{{ .fieldName }} { l += proto.Soz(uint64(e)) } n+= {{ .protoTagSize }} + proto.Sov(uint64(l)) + l } {{- else if not .nullable -}} if orig.{{ .fieldName }} != 0 { n+= {{ .protoTagSize }} + proto.Soz(uint64(orig.{{ .fieldName }})) } {{- else -}} n+= {{ .protoTagSize }} + proto.Soz(uint64(orig.{{ .fieldName }})) {{- end }}` func (pf *Field) GenSizeProto() string { tf := pf.getTemplateFields() switch pf.Type { case TypeFixed64, TypeSFixed64, TypeDouble: return template.Execute(template.Parse("sizeProtoI8", []byte(sizeProtoI8)), tf) case TypeFixed32, TypeSFixed32, TypeFloat: return template.Execute(template.Parse("sizeProtoI4", []byte(sizeProtoI4)), tf) case TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeEnum: return template.Execute(template.Parse("sizeProtoVarint", []byte(sizeProtoVarint)), tf) case TypeBool: return template.Execute(template.Parse("sizeProtoBool", []byte(sizeProtoBool)), tf) case TypeBytes, TypeString: return template.Execute(template.Parse("sizeProtoBytesString", []byte(sizeProtoBytesString)), tf) case TypeMessage: return template.Execute(template.Parse("sizeProtoMessage", []byte(sizeProtoMessage)), tf) case TypeSInt32, TypeSInt64: return template.Execute(template.Parse("sizeProtoSignedVarint", []byte(sizeProtoSignedVarint)), tf) } panic(fmt.Sprintf("unhandled case %T", pf.Type)) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/proto_unmarshal.go000066400000000000000000000324521511331344600314310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "fmt" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const unmarshalProtoFloat = `{{ if .repeated -}} case {{ .protoFieldID }}: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length size := length / {{ div .bitSize 8 }} orig.{{ .fieldName }} = make([]{{ .goType }}, size) var num uint{{ .bitSize }} for i := 0; i < size; i++ { num, startPos, err = proto.ConsumeI{{ .bitSize }}(buf[:pos], startPos) if err != nil { return err } orig.{{ .fieldName }}[i] = math.Float{{ .bitSize }}frombits(num) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field {{ .fieldName }}", pos - startPos) } case proto.WireTypeI{{ .bitSize }}: var num uint{{ .bitSize }} num, pos, err = proto.ConsumeI{{ .bitSize }}(buf, pos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, math.Float{{ .bitSize }}frombits(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } {{- else }} case {{ .protoFieldID }}: if wireType != proto.WireTypeI{{ .bitSize }} { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var num uint{{ .bitSize }} num, pos, err = proto.ConsumeI{{ .bitSize }}(buf, pos) if err != nil { return err } {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = math.Float{{ .bitSize }}frombits(num) orig.{{ .oneOfGroup }} = ov {{- else }} orig.{{ .fieldName }} = math.Float{{ .bitSize }}frombits(num) {{- end }}{{- end }}` const unmarshalProtoFixed = `{{ if .repeated -}} case {{ .protoFieldID }}: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length size := length / {{ div .bitSize 8 }} orig.{{ .fieldName }} = make([]{{ .goType }}, size) var num uint{{ .bitSize }} for i := 0; i < size; i++ { num, startPos, err = proto.ConsumeI{{ .bitSize }}(buf[:pos], startPos) if err != nil { return err } orig.{{ .fieldName }}[i] = {{ .goType }}(num) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field {{ .fieldName }}", pos - startPos) } case proto.WireTypeI{{ .bitSize }}: var num uint{{ .bitSize }} num, pos, err = proto.ConsumeI{{ .bitSize }}(buf, pos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, {{ .goType }}(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } {{- else }} case {{ .protoFieldID }}: if wireType != proto.WireTypeI{{ .bitSize }} { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var num uint{{ .bitSize }} num, pos, err = proto.ConsumeI{{ .bitSize }}(buf, pos) if err != nil { return err } {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = {{ .goType }}(num) orig.{{ .oneOfGroup }} = ov {{- else }} orig.{{ .fieldName }} = {{ .goType }}(num) {{- end }}{{- end }}` const unmarshalProtoBool = `{{ if .repeated -}} case {{ .protoFieldID }}: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length // Optimistically assume that bools are encoded as 1 byte even in variant form. orig.{{ .fieldName }} = make([]bool, 0, length) var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, num != 0) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field {{ .fieldName }}", pos - startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, num != 0) default: return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } {{- else }} case {{ .protoFieldID }}: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = num != 0 orig.{{ .oneOfGroup }} = ov {{- else }} orig.{{ .fieldName }} = num != 0 {{- end }}{{- end }}` const unmarshalProtoVarint = `{{ if .repeated -}} case {{ .protoFieldID }}: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, {{ .goType }}(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field {{ .fieldName }}", pos - startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, {{ .goType }}(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } {{- else }} case {{ .protoFieldID }}: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = {{ .goType }}(num) orig.{{ .oneOfGroup }} = ov {{- else }} orig.{{ .fieldName }} = {{ .goType }}(num) {{- end }}{{- end }}` const unmarshalProtoString = ` case {{ .protoFieldID }}: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = string(buf[startPos:pos]) orig.{{ .oneOfGroup }} = ov {{- else if .repeated -}} orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, string(buf[startPos:pos])) {{- else -}} orig.{{ .fieldName }} = string(buf[startPos:pos]) {{- end }}` const unmarshalProtoBytes = ` case {{ .protoFieldID }}: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } if length != 0 { ov.{{ .fieldName }} = make([]byte, length) copy(ov.{{ .fieldName }}, buf[startPos:pos]) } orig.{{ .oneOfGroup }} = ov {{- else if .repeated -}} if length != 0 { orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, make([]byte, length)) copy(orig.{{ .fieldName }}[len(orig.{{ .fieldName }}) - 1], buf[startPos:pos]) } else { orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, nil) } {{- else -}} if length != 0 { orig.{{ .fieldName }} = make([]byte, length) copy(orig.{{ .fieldName }}, buf[startPos:pos]) } {{- end }}` const unmarshalProtoMessage = ` case {{ .protoFieldID }}: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = New{{ .messageName }}() err = ov.{{ .fieldName }}.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.{{ .oneOfGroup }} = ov {{- else if .repeated -}} orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, {{ if .nullable }}New{{ .messageName }}(){{ else }}{{ .defaultValue }}{{ end }}) err = orig.{{ .fieldName }}[len(orig.{{ .fieldName }})-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } {{- else }} {{ if .nullable }}orig.{{ .fieldName }} = New{{ .messageName }}(){{ end }} err = orig.{{ .fieldName }}.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } {{- end }}` const unmarshalProtoSignedVarint = `{{ if .repeated -}} case {{ .protoFieldID }}: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length // Optimistically assume that bools are encoded as 1 byte even in variant form. orig.{{ .fieldName }} = make([]bool, 0, pos - startPos) var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, int{{ .bitSize }}(uint{{ .bitSize }}(num >> 1) ^ uint{{ .bitSize }}(int{{ .bitSize }}((num&1)<<{{ sub .bitSize 1 }})>>{{ sub .bitSize 1 }}))) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field {{ .fieldName }}", pos - startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.{{ .fieldName }} = append(orig.{{ .fieldName }}, int{{ .bitSize }}(uint{{ .bitSize }}(num >> 1) ^ uint{{ .bitSize }}(int{{ .bitSize }}((num&1)<<{{ sub .bitSize 1 }})>>{{ sub .bitSize 1 }}))) default: return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } {{- else }} case {{ .protoFieldID }}: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field {{ .fieldName }}", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } {{ if ne .oneOfGroup "" -}} var ov *{{ .oneOfMessageName }} if !UseProtoPooling.IsEnabled() { ov = &{{ .oneOfMessageName }}{} } else { ov = ProtoPool{{ .oneOfMessageName }}.Get().(*{{ .oneOfMessageName }}) } ov.{{ .fieldName }} = int{{ .bitSize }}(uint{{ .bitSize }}(num >> 1) ^ uint{{ .bitSize }}(int{{ .bitSize }}((num&1)<<{{ sub .bitSize 1 }})>>{{ sub .bitSize 1 }})) orig.{{ .oneOfGroup }} = ov {{- else }} orig.{{ .fieldName }} = int{{ .bitSize }}(uint{{ .bitSize }}(num >> 1) ^ uint{{ .bitSize }}(int{{ .bitSize }}((num&1)<<{{ sub .bitSize 1 }})>>{{ sub .bitSize 1 }})) {{- end }}{{- end }}` func (pf *Field) GenUnmarshalProto() string { tf := pf.getTemplateFields() switch pf.Type { case TypeDouble, TypeFloat: return template.Execute(template.Parse("unmarshalProtoFloat", []byte(unmarshalProtoFloat)), tf) case TypeFixed64, TypeSFixed64, TypeFixed32, TypeSFixed32: return template.Execute(template.Parse("unmarshalProtoFixed", []byte(unmarshalProtoFixed)), tf) case TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeEnum: return template.Execute(template.Parse("unmarshalProtoVarint", []byte(unmarshalProtoVarint)), tf) case TypeBool: return template.Execute(template.Parse("unmarshalProtoBool", []byte(unmarshalProtoBool)), tf) case TypeString: return template.Execute(template.Parse("unmarshalProtoString", []byte(unmarshalProtoString)), tf) case TypeBytes: return template.Execute(template.Parse("unmarshalProtoBytes", []byte(unmarshalProtoBytes)), tf) case TypeMessage: return template.Execute(template.Parse("unmarshalProtoMessage", []byte(unmarshalProtoMessage)), tf) case TypeSInt32, TypeSInt64: return template.Execute(template.Parse("unmarshalProtoSignedVarint", []byte(unmarshalProtoSignedVarint)), tf) } panic(fmt.Sprintf("unhandled case %T", pf.Type)) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/templates/000077500000000000000000000000001511331344600276555ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/templates/message.go.tmpl000066400000000000000000000126251511331344600326110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( {{ range $index, $element := .imports -}} {{ $element }} {{ end }} ) {{- range .fields }} {{ .GenOneOfMessages }} {{- end }} {{ .description }} type {{ .messageName }} struct { {{- range .fields }} {{ .GenMessageField }} {{- end }}} var ( protoPool{{ .messageName }} = sync.Pool{ New: func() any { return &{{ .messageName }}{} }, } {{- range .fields }}{{ .GenPool }}{{- end }} ) func New{{ .messageName }}() *{{ .messageName }} { if !UseProtoPooling.IsEnabled() { return &{{ .messageName }}{} } return protoPool{{ .messageName }}.Get().(*{{ .messageName }}) } func Delete{{ .messageName }}(orig *{{ .messageName }}, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } {{ range .fields }}{{ .GenDelete }}{{ end }} orig.Reset() if nullable { protoPool{{ .messageName }}.Put(orig) } } func Copy{{ .messageName }}(dest, src *{{ .messageName }}) *{{ .messageName }}{ // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil; } if dest == nil { dest = New{{ .messageName }}(); } {{- range .fields }} {{ .GenCopy }} {{- end }} return dest } func Copy{{ .messageName }}Slice(dest, src []{{ .messageName }}) []{{ .messageName }} { var newDest []{{ .messageName }} if cap(dest) < len(src) { newDest = make([]{{ .messageName }}, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { Delete{{ .messageName }}(&dest[i], false) } } for i := range src { Copy{{ .messageName }}(&newDest[i], &src[i]) } return newDest } func Copy{{ .messageName }}PtrSlice(dest, src []*{{ .messageName }}) []*{{ .messageName }} { var newDest []*{{ .messageName }} if cap(dest) < len(src) { newDest = make([]*{{ .messageName }}, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = New{{ .messageName }}() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { Delete{{ .messageName }}(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = New{{ .messageName }}() } } for i := range src { Copy{{ .messageName }}(newDest[i], src[i]) } return newDest } func (orig *{{ .messageName }}) Reset() { *orig = {{ .messageName }}{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *{{ .messageName }}) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() {{ range .fields -}} {{ .GenMarshalJSON }} {{ end -}} dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *{{ .messageName }}) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { {{ range .fields -}} {{ .GenUnmarshalJSON }} {{ end -}} default: iter.Skip() } } } func (orig *{{ .messageName }}) SizeProto() int { var n int var l int _ = l {{ range .fields -}} {{ .GenSizeProto }} {{ end -}} return n } func (orig *{{ .messageName }}) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l {{ range .fields -}} {{ .GenMarshalProto }} {{ end -}} return len(buf) - pos } func (orig *{{ .messageName }}) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { {{ range .fields -}} {{ .GenUnmarshalProto }} {{ end -}} default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTest{{ .messageName }}() *{{ .messageName }} { orig := New{{ .messageName }}() {{- range .fields }} orig.{{ .GetName }} = {{ .TestValue }} {{- end }} return orig } func GenTest{{ .messageName }}PtrSlice() []*{{ .messageName }} { orig := make([]*{{ .messageName }}, 5) orig[0] = New{{ .messageName }}() orig[1] = GenTest{{ .messageName }}() orig[2] = New{{ .messageName }}() orig[3] = GenTest{{ .messageName }}() orig[4] = New{{ .messageName }}() return orig } func GenTest{{ .messageName }}Slice() []{{ .messageName }} { orig := make([]{{ .messageName }}, 5) orig[1] = *GenTest{{ .messageName }}() orig[3] = *GenTest{{ .messageName }}() return orig } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/templates/message_test.go.tmpl000066400000000000000000000157631511331344600336560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( {{ range $index, $element := .testImports -}} {{ $element }} {{ end }} ) func TestCopy{{ .messageName }}(t *testing.T) { for name, src := range genTestEncodingValues{{ .messageName }}() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := New{{ .messageName }}() Copy{{ .messageName }}(dest, src) assert.Equal(t, src, dest) Copy{{ .messageName }}(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopy{{ .messageName }}Slice(t *testing.T) { src := []{{ .messageName }}{} dest := []{{ .messageName }}{} // Test CopyTo empty dest = Copy{{ .messageName }}Slice(dest, src) assert.Equal(t, []{{ .messageName }}{}, dest) // Test CopyTo larger slice src = GenTest{{ .messageName }}Slice() dest = Copy{{ .messageName }}Slice(dest, src) assert.Equal(t, GenTest{{ .messageName }}Slice(), dest) // Test CopyTo same size slice dest = Copy{{ .messageName }}Slice(dest, src) assert.Equal(t, GenTest{{ .messageName }}Slice(), dest) // Test CopyTo smaller size slice dest = Copy{{ .messageName }}Slice(dest, []{{ .messageName }}{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = Copy{{ .messageName }}Slice(dest, src) assert.Equal(t, GenTest{{ .messageName }}Slice(), dest) } func TestCopy{{ .messageName }}PtrSlice(t *testing.T) { src := []*{{ .messageName }}{} dest := []*{{ .messageName }}{} // Test CopyTo empty dest = Copy{{ .messageName }}PtrSlice(dest, src) assert.Equal(t, []*{{ .messageName }}{}, dest) // Test CopyTo larger slice src = GenTest{{ .messageName }}PtrSlice() dest = Copy{{ .messageName }}PtrSlice(dest, src) assert.Equal(t, GenTest{{ .messageName }}PtrSlice(), dest) // Test CopyTo same size slice dest = Copy{{ .messageName }}PtrSlice(dest, src) assert.Equal(t, GenTest{{ .messageName }}PtrSlice(), dest) // Test CopyTo smaller size slice dest = Copy{{ .messageName }}PtrSlice(dest, []*{{ .messageName }}{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = Copy{{ .messageName }}PtrSlice(dest, src) assert.Equal(t, GenTest{{ .messageName }}PtrSlice(), dest) } func TestMarshalAndUnmarshalJSON{{ .messageName }}Unknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := New{{ .messageName }}() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, New{{ .messageName }}(), dest) } func TestMarshalAndUnmarshalJSON{{ .messageName }}(t *testing.T) { for name, src := range genTestEncodingValues{{ .messageName }}() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := New{{ .messageName }}() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) Delete{{ .messageName }}(dest, true) }) } } } func TestMarshalAndUnmarshalProto{{ .messageName }}Failing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValues{{ .messageName }}() { t.Run(name, func(t *testing.T) { dest := New{{ .messageName }}() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProto{{ .messageName }}Unknown(t *testing.T) { dest := New{{ .messageName }}() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, New{{ .messageName }}(), dest) } func TestMarshalAndUnmarshalProto{{ .messageName }}(t *testing.T) { for name, src := range genTestEncodingValues{{ .messageName }}(){ for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := New{{ .messageName }}() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) Delete{{ .messageName }}(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobuf{{ .messageName }}(t *testing.T) { for name, src := range genTestEncodingValues{{ .messageName }}(){ t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &{{ .upstreamMessage }}{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := New{{ .messageName }}() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValues{{ .messageName }}() map[string][]byte { return map[string][]byte{ "invalid_field": { 0x02 }, {{- range .fields }}{{ .GenTestFailingUnmarshalProtoValues }}{{- end }} } } func genTestEncodingValues{{ .messageName }}() map[string]*{{ .messageName }} { return map[string]*{{ .messageName }}{ "empty": New{{ .messageName }}(), {{- range .fields }}{{ .GenTestEncodingValues }}{{- end }} } } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/test_encoding_values.go000066400000000000000000000050111511331344600324070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" import ( "slices" "strings" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" ) const encodingTestValuesScalar = `{{ if ne .oneOfGroup "" -}} "{{ .fieldName }}/default": { {{ .oneOfGroup }}: &{{ .oneOfMessageName }}{{ "{" }}{{ .fieldName }}: {{ .defaultValue }}} }, "{{ .fieldName }}/test": { {{ .oneOfGroup }}: &{{ .oneOfMessageName }}{{ "{" }}{{ .fieldName }}: {{ .testValue }}} }, {{- else }} "{{ .fieldName }}/test": { {{ .fieldName }}: {{ .testValue }} }, {{- end }}` const encodingTestValuesMessage = `{{ if ne .oneOfGroup "" -}} "{{ .fieldName }}/default": { {{ .oneOfGroup }}: &{{ .oneOfMessageName }}{{ "{" }}{{ .fieldName }}: {{ .defaultValue }}} }, "{{ .fieldName }}/test": { {{ .oneOfGroup }}: &{{ .oneOfMessageName }}{{ "{" }}{{ .fieldName }}: {{ .testValue }}} }, {{- else }} "{{ .fieldName }}/test": { {{ .fieldName }}: {{ .testValue }} }, {{- end }}` func (pf *Field) GenTestEncodingValues() string { tf := pf.getTemplateFields() switch pf.Type { case TypeMessage: return template.Execute(template.Parse("encodingTestValuesMessage", []byte(encodingTestValuesMessage)), tf) case TypeDouble, TypeFloat, TypeFixed64, TypeSFixed64, TypeFixed32, TypeSFixed32, TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeSInt32, TypeSInt64, TypeBool, TypeString, TypeBytes, TypeEnum: return template.Execute(template.Parse("encodingTestValuesScalar", []byte(encodingTestValuesScalar)), tf) } return "" } const failingUnmarshalProtoValuesScalar = ` "{{ .fieldName }}/wrong_wire_type": []byte{ {{ .wrongWireTypeArray }} }, "{{ .fieldName }}/missing_value": []byte{ {{ .missingValueArray }} },` func (pf *Field) GenTestFailingUnmarshalProtoValues() string { tf := pf.getTemplateFields() tf["wrongWireTypeArray"] = protoTagAsByteArray(genProtoTag(pf.ID, WireTypeEndGroup)) tf["missingValueArray"] = protoTagAsByteArray(tf["protoTag"].([]string)) switch pf.Type { case TypeMessage, TypeDouble, TypeFloat, TypeFixed64, TypeSFixed64, TypeFixed32, TypeSFixed32, TypeInt32, TypeInt64, TypeUint32, TypeUint64, TypeSInt32, TypeSInt64, TypeBool, TypeString, TypeBytes, TypeEnum: return template.Execute(template.Parse("failingUnmarshalProtoValuesScalar", []byte(failingUnmarshalProtoValuesScalar)), tf) } return "" } func protoTagAsByteArray(protoTag []string) string { slices.Reverse(protoTag) return strings.Join(protoTag, ", ") } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/proto/wire_type.go000066400000000000000000000006771511331344600302270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/proto" // WireType represents the proto wire type. type WireType uint32 const ( WireTypeVarint WireType = 0 WireTypeI64 WireType = 1 WireTypeLen WireType = 2 WireTypeStartGroup WireType = 3 WireTypeEndGroup WireType = 4 WireTypeI32 WireType = 5 ) opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/template/000077500000000000000000000000001511331344600263275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/cmd/pdatagen/internal/template/template.go000066400000000000000000000022601511331344600304710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package template // import "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/template" import ( "strings" "text/template" "github.com/ettle/strcase" ) func Parse(name string, bytes []byte) *template.Template { return template.Must(newTemplate(name).Parse(string(bytes))) } func Execute(tmpl *template.Template, data any) string { var sb strings.Builder if err := tmpl.Execute(&sb, data); err != nil { panic(err) } return sb.String() } func newTemplate(name string) *template.Template { return template.New(name).Funcs(template.FuncMap{ "upperFirst": upperFirst, "lowerFirst": lowerFirst, "add": add, "sub": sub, "div": div, "needSnake": needSnake, "toSnake": strcase.ToSnake, }) } func upperFirst(s string) string { return strings.ToUpper(s[0:1]) + s[1:] } func lowerFirst(s string) string { return strings.ToLower(s[0:1]) + s[1:] } func add(a, b int) int { return a + b } func sub(a, b int) int { return a - b } func div(a, b int) int { return a / b } func needSnake(str string) bool { return strings.ToLower(str) != strcase.ToSnake(str) } opentelemetry-collector-0.141.0/internal/cmd/pdatagen/main.go000066400000000000000000000016271511331344600241610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package main import ( "flag" "fmt" "os" "path/filepath" "go.opentelemetry.io/collector/internal/cmd/pdatagen/internal/pdata" ) // checkErr prints the given error and exits when e is non-nil. func checkErr(e error) { if e != nil { fmt.Println(e) os.Exit(1) } } func main() { var workdir string flag.StringVar(&workdir, "C", ".", "set work directory") flag.Parse() checkErr(os.Chdir(workdir)) checkErr(pdata.DeleteGeneratedFiles(filepath.Join("pdata", "internal"))) for _, fp := range pdata.AllPackages { checkErr(pdata.DeleteGeneratedFiles(filepath.Join("pdata", fp.Path()))) checkErr(fp.GenerateFiles()) checkErr(fp.GenerateTestFiles()) checkErr(fp.GenerateInternalFiles()) checkErr(fp.GenerateProtoMessageFiles()) checkErr(fp.GenerateProtoMessageTestsFiles()) checkErr(fp.GenerateProtoEnumFiles()) } } opentelemetry-collector-0.141.0/internal/e2e/000077500000000000000000000000001511331344600210255ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/e2e/Makefile000066400000000000000000000000361511331344600224640ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/internal/e2e/configauth_test.go000066400000000000000000000007271511331344600245500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/confmap" ) func TestConfmapMarshalConfigAuth(t *testing.T) { conf := confmap.New() require.NoError(t, conf.Marshal(configauth.Config{})) assert.Equal(t, map[string]any{}, conf.ToStringMap()) } opentelemetry-collector-0.141.0/internal/e2e/configgrpc_test.go000066400000000000000000000033231511331344600245350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/confmap" ) func TestConfmapMarshalConfigGRPC(t *testing.T) { keepaliveClientConfig := map[string]any{ "time": time.Second * 10, "timeout": time.Second * 10, } keepaliveServerConfig := map[string]any{ "server_parameters": map[string]any{}, "enforcement_policy": map[string]any{}, } conf := confmap.New() require.NoError(t, conf.Marshal(configgrpc.NewDefaultClientConfig())) assert.Equal(t, map[string]any{ "keepalive": keepaliveClientConfig, "balancer_name": "round_robin", }, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(configgrpc.NewDefaultKeepaliveClientConfig())) assert.Equal(t, keepaliveClientConfig, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(configgrpc.NewDefaultKeepaliveEnforcementPolicy())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(configgrpc.NewDefaultKeepaliveServerConfig())) assert.Equal(t, keepaliveServerConfig, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(configgrpc.NewDefaultKeepaliveServerParameters())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(configgrpc.NewDefaultServerConfig())) assert.Equal(t, map[string]any{ "keepalive": keepaliveServerConfig, "transport": confignet.TransportType("tcp"), }, conf.ToStringMap()) } opentelemetry-collector-0.141.0/internal/e2e/confighttp_test.go000066400000000000000000000023501511331344600245600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/confmap" ) func TestConfmapMarshalConfigHTTP(t *testing.T) { conf := confmap.New() require.NoError(t, conf.Marshal(confighttp.NewDefaultClientConfig())) assert.Equal(t, map[string]any{ "idle_conn_timeout": 90 * time.Second, "max_idle_conns": 100, "force_attempt_http2": true, }, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(confighttp.NewDefaultCORSConfig())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(confighttp.NewDefaultServerConfig())) assert.Equal(t, map[string]any{ "cors": nil, "idle_timeout": 60 * time.Second, "keep_alives_enabled": true, "read_header_timeout": 60 * time.Second, "tls": nil, "write_timeout": 30 * time.Second, }, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(confighttp.AuthConfig{})) assert.Equal(t, map[string]any{}, conf.ToStringMap()) } opentelemetry-collector-0.141.0/internal/e2e/confignet_test.go000066400000000000000000000014131511331344600243660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/confmap" ) func TestConfmapMarshalConfigNet(t *testing.T) { conf := confmap.New() require.NoError(t, conf.Marshal(confignet.NewDefaultDialerConfig())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(confignet.NewDefaultAddrConfig())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(confignet.NewDefaultTCPAddrConfig())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) } opentelemetry-collector-0.141.0/internal/e2e/configtls_test.go000066400000000000000000000014061511331344600244040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap" ) func TestConfmapMarshalConfigTLS(t *testing.T) { conf := confmap.New() require.NoError(t, conf.Marshal(configtls.NewDefaultConfig())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(configtls.NewDefaultClientConfig())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) conf = confmap.New() require.NoError(t, conf.Marshal(configtls.NewDefaultServerConfig())) assert.Equal(t, map[string]any{}, conf.ToStringMap()) } opentelemetry-collector-0.141.0/internal/e2e/consume_contract_test.go000066400000000000000000000055001511331344600257610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/configretry" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/exporter/exporterhelper" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/otlpexporter" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver/otlpreceiver" ) func testExporterConfig(endpoint string) component.Config { retryConfig := configretry.NewDefaultBackOffConfig() retryConfig.InitialInterval = time.Millisecond // interval is short for the test purposes return &otlpexporter.Config{ QueueConfig: exporterhelper.QueueBatchConfig{Enabled: false}, RetryConfig: retryConfig, ClientConfig: configgrpc.ClientConfig{ Endpoint: endpoint, TLS: configtls.ClientConfig{ Insecure: true, }, }, } } func testReceiverConfig(endpoint string) component.Config { cfg := otlpreceiver.NewFactory().CreateDefaultConfig() cfg.(*otlpreceiver.Config).GRPC.GetOrInsertDefault().NetAddr.Endpoint = endpoint return cfg } // TestConsumeContract is an example of testing of the exporter for the contract between the // exporter and the receiver. func TestConsumeContractOtlpLogs(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) exportertest.CheckConsumeContract(exportertest.CheckConsumeContractParams{ T: t, NumberOfTestElements: 10, ExporterFactory: otlpexporter.NewFactory(), Signal: pipeline.SignalLogs, ExporterConfig: testExporterConfig(addr), ReceiverFactory: otlpreceiver.NewFactory(), ReceiverConfig: testReceiverConfig(addr), }) } func TestConsumeContractOtlpTraces(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) exportertest.CheckConsumeContract(exportertest.CheckConsumeContractParams{ T: t, NumberOfTestElements: 10, Signal: pipeline.SignalTraces, ExporterFactory: otlpexporter.NewFactory(), ExporterConfig: testExporterConfig(addr), ReceiverFactory: otlpreceiver.NewFactory(), ReceiverConfig: testReceiverConfig(addr), }) } func TestConsumeContractOtlpMetrics(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) exportertest.CheckConsumeContract(exportertest.CheckConsumeContractParams{ T: t, NumberOfTestElements: 10, ExporterFactory: otlpexporter.NewFactory(), Signal: pipeline.SignalMetrics, ExporterConfig: testExporterConfig(addr), ReceiverFactory: otlpreceiver.NewFactory(), ReceiverConfig: testReceiverConfig(addr), }) } opentelemetry-collector-0.141.0/internal/e2e/error_propagation_test.go000066400000000000000000000226251511331344600261560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "bytes" "context" "io" "net" "net/http" "net/http/httptest" "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/otlpexporter" "go.opentelemetry.io/collector/exporter/otlphttpexporter" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/otlpreceiver" ) var _ plogotlp.GRPCServer = &logsServer{} type logsServer struct { plogotlp.UnimplementedGRPCServer exportError error } func (r *logsServer) Export(_ context.Context, _ plogotlp.ExportRequest) (plogotlp.ExportResponse, error) { return plogotlp.NewExportResponse(), r.exportError } func TestGRPCToGRPC(t *testing.T) { // gRPC supports 17 different status codes. // Source: https://github.com/grpc/grpc/blob/41788c90bc66caf29f28ef808d066db806389792/doc/statuscodes.md for i := range uint32(16) { s := status.New(codes.Code(i), "Testing error") t.Run("Code "+s.Code().String(), func(t *testing.T) { e := createGRPCExporter(t, s) assertOnGRPCCode(t, e, s) }) } } func TestHTTPToGRPC(t *testing.T) { testCases := []struct { grpc codes.Code http int }{ {codes.OK, http.StatusOK}, {codes.Canceled, http.StatusServiceUnavailable}, {codes.DeadlineExceeded, http.StatusServiceUnavailable}, {codes.Aborted, http.StatusServiceUnavailable}, {codes.OutOfRange, http.StatusServiceUnavailable}, {codes.Unavailable, http.StatusServiceUnavailable}, {codes.DataLoss, http.StatusServiceUnavailable}, {codes.ResourceExhausted, http.StatusTooManyRequests}, {codes.InvalidArgument, http.StatusBadRequest}, {codes.Unauthenticated, http.StatusUnauthorized}, {codes.PermissionDenied, http.StatusForbidden}, {codes.Unimplemented, http.StatusNotFound}, } for _, tt := range testCases { s := status.New(tt.grpc, "Testing error") t.Run("Code "+s.Code().String(), func(t *testing.T) { e := createGRPCExporter(t, s) assertOnHTTPCode(t, e, tt.http) }) } } func TestGRPCToHTTP(t *testing.T) { testCases := []struct { http int grpc codes.Code }{ {http.StatusOK, codes.OK}, {http.StatusBadRequest, codes.InvalidArgument}, {http.StatusUnauthorized, codes.Unauthenticated}, {http.StatusForbidden, codes.PermissionDenied}, {http.StatusNotFound, codes.Unimplemented}, {http.StatusTooManyRequests, codes.ResourceExhausted}, {http.StatusBadGateway, codes.Unavailable}, {http.StatusServiceUnavailable, codes.Unavailable}, {http.StatusGatewayTimeout, codes.Unavailable}, } for _, tt := range testCases { s := status.New(tt.grpc, "Testing error") t.Run("Code "+s.Code().String(), func(t *testing.T) { e := createHTTPExporter(t, tt.http) assertOnGRPCCode(t, e, s) }) } } func TestHTTPToHTTP(t *testing.T) { testCases := []struct { code int mapping int }{ {code: http.StatusOK}, {code: http.StatusServiceUnavailable}, {code: http.StatusTooManyRequests}, {code: http.StatusBadRequest}, {code: http.StatusUnauthorized}, {code: http.StatusForbidden}, {code: http.StatusNotFound}, {code: http.StatusInternalServerError}, // Mappings won't be necessary once the OTLP/HTTP Exporter returns consumererror.Error types. {code: http.StatusBadGateway, mapping: http.StatusServiceUnavailable}, {code: http.StatusGatewayTimeout, mapping: http.StatusServiceUnavailable}, {code: http.StatusTeapot, mapping: http.StatusInternalServerError}, {code: http.StatusConflict, mapping: http.StatusInternalServerError}, } for _, tt := range testCases { t.Run("Code "+strconv.Itoa(tt.code), func(t *testing.T) { e := createHTTPExporter(t, tt.code) code := tt.code if tt.mapping != 0 { code = tt.mapping } assertOnHTTPCode(t, e, code) }) } } func createGRPCExporter(t *testing.T, s *status.Status) consumer.Logs { t.Helper() ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) srv := grpc.NewServer() rcv := &logsServer{ exportError: s.Err(), } plogotlp.RegisterGRPCServer(srv, rcv) go func() { assert.NoError(t, srv.Serve(ln)) }() t.Cleanup(func() { srv.Stop() }) f := otlpexporter.NewFactory() cfg := f.CreateDefaultConfig().(*otlpexporter.Config) cfg.QueueConfig.Enabled = false cfg.RetryConfig.Enabled = false cfg.ClientConfig = configgrpc.ClientConfig{ Endpoint: ln.Addr().String(), TLS: configtls.ClientConfig{ Insecure: true, }, } e, err := f.CreateLogs(context.Background(), exportertest.NewNopSettings(component.MustNewType("otlp")), cfg) require.NoError(t, err) err = e.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, e.Shutdown(context.Background())) }) return e } func createHTTPExporter(t *testing.T, code int) consumer.Logs { t.Helper() mux := http.NewServeMux() mux.HandleFunc("/v1/logs", func(writer http.ResponseWriter, _ *http.Request) { writer.WriteHeader(code) }) srv := httptest.NewServer(mux) t.Cleanup(func() { srv.Close() }) f := otlphttpexporter.NewFactory() cfg := f.CreateDefaultConfig().(*otlphttpexporter.Config) cfg.QueueConfig.Enabled = false cfg.RetryConfig.Enabled = false cfg.Encoding = otlphttpexporter.EncodingProto cfg.LogsEndpoint = srv.URL + "/v1/logs" e, err := f.CreateLogs(context.Background(), exportertest.NewNopSettings(component.MustNewType("otlphttp")), cfg) require.NoError(t, err) err = e.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, e.Shutdown(context.Background())) }) return e } func assertOnGRPCCode(t *testing.T, l consumer.Logs, s *status.Status) { t.Helper() rf := otlpreceiver.NewFactory() rcfg := rf.CreateDefaultConfig().(*otlpreceiver.Config) rcfg.GRPC = configoptional.Some( configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), Transport: confignet.TransportTypeTCP, }, }, ) r, err := rf.CreateLogs(context.Background(), receiver.Settings{ ID: component.MustNewID("otlp"), TelemetrySettings: componenttest.NewNopTelemetrySettings(), }, rcfg, l) require.NoError(t, err) err = r.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, r.Shutdown(context.Background())) }) conn, err := grpc.NewClient(rcfg.GRPC.Get().NetAddr.Endpoint, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, conn.Close()) }) ld := testdata.GenerateLogs(2) acc := plogotlp.NewGRPCClient(conn) req := plogotlp.NewExportRequestFromLogs(ld) res, err := acc.Export(context.Background(), req) if s.Code() == codes.OK { require.NoError(t, err) } else { got := status.Convert(err).Code() require.Equal(t, s.Code(), got, "Expected code %s but got %s", s.Code().String(), got.String()) } require.NotNil(t, res) } func assertOnHTTPCode(t *testing.T, l consumer.Logs, code int) { t.Helper() ld := testdata.GenerateLogs(2) protoMarshaler := &plog.ProtoMarshaler{} logProto, err := protoMarshaler.MarshalLogs(ld) require.NoError(t, err) rf := otlpreceiver.NewFactory() rcfg := rf.CreateDefaultConfig().(*otlpreceiver.Config) rcfg.HTTP = configoptional.Some( otlpreceiver.HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), }, LogsURLPath: "/v1/logs", }, ) r, err := rf.CreateLogs(context.Background(), receiver.Settings{ ID: component.MustNewID("otlp"), TelemetrySettings: componenttest.NewNopTelemetrySettings(), }, rcfg, l) require.NoError(t, err) err = r.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, r.Shutdown(context.Background())) }) doHTTPRequest(t, rcfg.HTTP.Get().ServerConfig.Endpoint+"/v1/logs", logProto, code) } func doHTTPRequest( t *testing.T, url string, data []byte, expectStatusCode int, ) []byte { req := createHTTPRequest(t, url, data) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) respBytes, err := io.ReadAll(resp.Body) require.NoError(t, err) require.NoError(t, resp.Body.Close()) if expectStatusCode == 0 { require.Equal(t, http.StatusOK, resp.StatusCode) } else { require.Equal(t, expectStatusCode, resp.StatusCode) } return respBytes } func createHTTPRequest( t *testing.T, url string, data []byte, ) *http.Request { buf := bytes.NewBuffer(data) req, err := http.NewRequest(http.MethodPost, "http://"+url, buf) require.NoError(t, err) req.Header.Set("Content-Type", "application/x-protobuf") return req } opentelemetry-collector-0.141.0/internal/e2e/go.mod000066400000000000000000000363071511331344600221440ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/e2e go 1.24.0 require ( github.com/google/go-cmp v0.7.0 github.com/prometheus/common v0.67.1 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componentstatus v0.141.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configauth v1.47.0 go.opentelemetry.io/collector/config/configgrpc v0.141.0 go.opentelemetry.io/collector/config/confighttp v0.141.0 go.opentelemetry.io/collector/config/confignet v1.47.0 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/config/configretry v1.47.0 go.opentelemetry.io/collector/config/configtelemetry v0.141.0 go.opentelemetry.io/collector/config/configtls v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/provider/envprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.47.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/connector/connectortest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/debugexporter v0.141.0 go.opentelemetry.io/collector/exporter/exporterhelper v0.141.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/exporter/otlpexporter v0.141.0 go.opentelemetry.io/collector/exporter/otlphttpexporter v0.141.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/internal/sharedcomponent v0.141.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/collector/otelcol v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/batchprocessor v0.141.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/otlpreceiver v0.141.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.opentelemetry.io/collector/service v0.141.0 go.opentelemetry.io/proto/otlp v1.9.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.10 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // 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-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.1 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/mostynb/go-grpc-compression v1.2.3 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/rs/cors v1.11.1 // indirect github.com/shirou/gopsutil/v4 v4.25.10 // indirect github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector v0.141.0 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configcompression v1.47.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 // indirect go.opentelemetry.io/collector/connector/xconnector v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror/xconsumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper v0.141.0 // indirect go.opentelemetry.io/collector/exporter/xexporter v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensioncapabilities v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensiontest v0.141.0 // indirect go.opentelemetry.io/collector/extension/xextension v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 // indirect go.opentelemetry.io/collector/internal/telemetry v0.141.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/processor/processortest v0.141.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.141.0 // indirect go.opentelemetry.io/collector/receiver/receiverhelper v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/collector/service/hostcapabilities v0.141.0 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.38.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector => ../.. replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/config/configgrpc => ../../config/configgrpc replace go.opentelemetry.io/collector/config/confignet => ../../config/confignet replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/exporter/otlpexporter => ../../exporter/otlpexporter replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/exporter/otlphttpexporter => ../../exporter/otlphttpexporter replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/receiver/otlpreceiver => ../../receiver/otlpreceiver replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/receiver/receiverhelper => ../../receiver/receiverhelper replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/exporter => ../../exporter replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/connector => ../../connector replace go.opentelemetry.io/collector/connector/connectortest => ../../connector/connectortest replace go.opentelemetry.io/collector/processor => ../../processor replace go.opentelemetry.io/collector/extension/zpagesextension => ../../extension/zpagesextension replace go.opentelemetry.io/collector/service => ../../service replace go.opentelemetry.io/collector/service/telemetry/telemetrytest => ../../service/telemetry/telemetrytest replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../../extension/extensioncapabilities replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/processor/xprocessor => ../../processor/xprocessor replace go.opentelemetry.io/collector/connector/xconnector => ../../connector/xconnector replace go.opentelemetry.io/collector/exporter/xexporter => ../../exporter/xexporter replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../../exporter/exportertest replace go.opentelemetry.io/collector/processor/processortest => ../../processor/processortest replace go.opentelemetry.io/collector/consumer/consumererror/xconsumererror => ../../consumer/consumererror/xconsumererror replace go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper => ../../exporter/exporterhelper/xexporterhelper replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer replace go.opentelemetry.io/collector/internal/sharedcomponent => ../../internal/sharedcomponent replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/otelcol => ../../otelcol replace go.opentelemetry.io/collector/confmap/provider/yamlprovider => ../../confmap/provider/yamlprovider replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider replace go.opentelemetry.io/collector/service/hostcapabilities => ../../service/hostcapabilities replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/exporter/debugexporter => ../../exporter/debugexporter replace go.opentelemetry.io/collector/processor/batchprocessor => ../../processor/batchprocessor replace go.opentelemetry.io/collector/confmap/provider/envprovider => ../../confmap/provider/envprovider replace go.opentelemetry.io/collector/exporter/exporterhelper => ../../exporter/exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/internal/e2e/go.sum000066400000000000000000000513531511331344600221670ustar00rootroot00000000000000github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 h1:aBKdhLVieqvwWe9A79UHI/0vgp2t/s2euY8X59pGRlw= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0/go.mod h1:SYqtxLQE7iINgh6WFuVi2AI70148B8EI35DSk0Wr8m4= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo= go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU= go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLImUqiTPGnX4= go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.opentelemetry.io/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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= 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= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/internal/e2e/metric_stability_test.go000066400000000000000000000272251511331344600257720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "bufio" "bytes" "context" "fmt" "net" "net/http" "path/filepath" "strconv" "testing" "time" "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/envprovider" "go.opentelemetry.io/collector/confmap/provider/fileprovider" "go.opentelemetry.io/collector/confmap/provider/yamlprovider" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/debugexporter" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/batchprocessor" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/otlpreceiver" "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" ) func assertMetrics(t *testing.T, metricsAddr string, expectedMetrics map[string]bool) bool { client := &http.Client{} resp, err := client.Get(fmt.Sprintf("http://%s/metrics", metricsAddr)) if err != nil { return false } if resp.StatusCode != http.StatusOK { return false } defer resp.Body.Close() reader := bufio.NewReader(resp.Body) parser := expfmt.NewTextParser(model.UTF8Validation) parsed, err := parser.TextToMetricFamilies(reader) if err != nil { return false } for metricName, metricFamily := range parsed { if _, ok := expectedMetrics[metricName]; ok { expectedMetrics[metricName] = true assert.GreaterOrEqual(t, len(metricFamily.Metric), 1, "metric %s should have at least one data point", metricName) } } for metricName, found := range expectedMetrics { if !found { t.Logf("expected metric %s was not found", metricName) return false } } return true } func TestMetricStability(t *testing.T) { tests := []struct { name string configFile string expectedMetrics map[string]bool otelPort string metricsPort string }{ { name: "No metric readers (default)", configFile: "metric_stability_test_no_readers.yaml", expectedMetrics: map[string]bool{ // Process metrics "otelcol_process_uptime": false, "otelcol_process_cpu_seconds": false, "otelcol_process_memory_rss": false, "otelcol_process_runtime_heap_alloc_bytes": false, "otelcol_process_runtime_total_alloc_bytes": false, "otelcol_process_runtime_total_sys_memory_bytes": false, // Batch processor metrics "otelcol_processor_batch_batch_send_size": false, "otelcol_processor_batch_batch_send_size_bytes": false, "otelcol_processor_batch_metadata_cardinality": false, "otelcol_processor_batch_timeout_trigger_send": false, // HTTP server metrics "http_server_request_body_size": false, "http_server_request_duration": false, "http_server_response_body_size": false, // Exporter metrics "otelcol_exporter_sent_metric_points": false, "otelcol_exporter_send_failed_metric_points": false, "otelcol_exporter_sent_spans": false, "otelcol_exporter_send_failed_spans": false, "otelcol_exporter_sent_log_records": false, "otelcol_exporter_send_failed_log_records": false, // Receiver metrics "otelcol_receiver_accepted_metric_points": false, "otelcol_receiver_refused_metric_points": false, "otelcol_receiver_accepted_spans": false, "otelcol_receiver_refused_spans": false, "otelcol_receiver_accepted_log_records": false, "otelcol_receiver_refused_log_records": false, // Other metrics "promhttp_metric_handler_errors_total": false, "target_info": false, }, otelPort: getFreePort(t), metricsPort: "8888", // default metrics port }, { name: "Metric readers", configFile: "metric_stability_test_readers.yaml", expectedMetrics: map[string]bool{ // Process metrics "otelcol_process_uptime_seconds_total": false, "otelcol_process_cpu_seconds_total": false, "otelcol_process_memory_rss_bytes": false, "otelcol_process_runtime_heap_alloc_bytes": false, "otelcol_process_runtime_total_alloc_bytes_total": false, "otelcol_process_runtime_total_sys_memory_bytes": false, // Batch processor metrics "otelcol_processor_batch_batch_send_size": false, "otelcol_processor_batch_batch_send_size_bytes": false, "otelcol_processor_batch_metadata_cardinality": false, "otelcol_processor_batch_timeout_trigger_send_total": false, // HTTP server metrics "http_server_request_body_size_bytes": false, "http_server_request_duration_seconds": false, "http_server_response_body_size_bytes": false, // Exporter metrics - Metrics "otelcol_exporter_sent_metric_points_total": false, "otelcol_exporter_send_failed_metric_points_total": false, // Exporter metrics - Traces "otelcol_exporter_sent_spans_total": false, "otelcol_exporter_send_failed_spans_total": false, // Exporter metrics - Logs "otelcol_exporter_sent_log_records_total": false, "otelcol_exporter_send_failed_log_records_total": false, // Receiver metrics "otelcol_receiver_accepted_metric_points_total": false, "otelcol_receiver_refused_metric_points_total": false, // Receiver metrics - Traces "otelcol_receiver_accepted_spans_total": false, "otelcol_receiver_refused_spans_total": false, // Receiver metrics - Logs "otelcol_receiver_accepted_log_records_total": false, "otelcol_receiver_refused_log_records_total": false, // Other metrics "promhttp_metric_handler_errors_total": false, "target_info": false, }, otelPort: getFreePort(t), metricsPort: getFreePort(t), }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { testMetricStability(t, test.configFile, test.expectedMetrics, test.metricsPort, test.otelPort) }) } } func testMetricStability(t *testing.T, configFile string, expectedMetrics map[string]bool, metricsPort, otelPort string) { t.Setenv("METRICS_PORT", metricsPort) t.Setenv("OTEL_PORT", otelPort) collector, err := otelcol.NewCollector(otelcol.CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: func() (otelcol.Factories, error) { return otelcol.Factories{ Receivers: map[component.Type]receiver.Factory{otlpreceiver.NewFactory().Type(): otlpreceiver.NewFactory()}, Processors: map[component.Type]processor.Factory{batchprocessor.NewFactory().Type(): batchprocessor.NewFactory()}, Exporters: map[component.Type]exporter.Factory{debugexporter.NewFactory().Type(): debugexporter.NewFactory()}, Telemetry: otelconftelemetry.NewFactory(), }, nil }, ConfigProviderSettings: otelcol.ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{filepath.Join("testdata", configFile)}, ProviderFactories: []confmap.ProviderFactory{ fileprovider.NewFactory(), yamlprovider.NewFactory(), envprovider.NewFactory(), }, }, }, }) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) defer cancel() go func() { err := collector.Run(ctx) if err != nil { t.Logf("Collector stopped with error: %v", err) } }() require.Eventually(t, func() bool { resp, err := http.Get(fmt.Sprintf("http://localhost:%s/metrics", metricsPort)) if err != nil { return false } resp.Body.Close() return resp.StatusCode == http.StatusOK }, 5*time.Second, 100*time.Millisecond, "collector failed to start") for range 5 { sendTestData(t, otelPort) } require.Eventually(t, func() bool { return assertMetrics(t, "localhost:"+metricsPort, expectedMetrics) }, 10*time.Second, 200*time.Millisecond, "failed to verify metrics") } func sendTestData(t *testing.T, otelPort string) { require.NoError(t, sendTestMetrics(otelPort)) require.NoError(t, sendTestTraces(otelPort)) require.NoError(t, sendTestLogs(otelPort)) } func sendTestMetrics(otelPort string) error { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() sm := rm.ScopeMetrics().AppendEmpty() metric := sm.Metrics().AppendEmpty() metric.SetName("test_metric") metric.SetDescription("test metric") metric.SetUnit("1") dp := metric.SetEmptyGauge().DataPoints().AppendEmpty() dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) dp.SetDoubleValue(42.0) client := &http.Client{} metricsMarshaler := pmetric.ProtoMarshaler{} metricsBytes, err := metricsMarshaler.MarshalMetrics(metrics) if err != nil { return fmt.Errorf("failed to marshal metrics: %w", err) } req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:%s/v1/metrics", otelPort), bytes.NewReader(metricsBytes)) if err != nil { return fmt.Errorf("failed to create metrics request: %w", err) } req.Header.Set("Content-Type", "application/x-protobuf") resp, err := client.Do(req) if err != nil { return fmt.Errorf("failed to send metrics: %w", err) } resp.Body.Close() return nil } func sendTestTraces(otelPort string) error { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() ss := rs.ScopeSpans().AppendEmpty() span := ss.Spans().AppendEmpty() span.SetName("test_span") now := time.Now() span.SetStartTimestamp(pcommon.NewTimestampFromTime(now)) span.SetEndTimestamp(pcommon.NewTimestampFromTime(now)) span.SetTraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) span.SetSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) client := &http.Client{} tracesMarshaler := ptrace.ProtoMarshaler{} tracesBytes, err := tracesMarshaler.MarshalTraces(traces) if err != nil { return fmt.Errorf("failed to marshal traces: %w", err) } req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:%s/v1/traces", otelPort), bytes.NewReader(tracesBytes)) if err != nil { return fmt.Errorf("failed to create traces request: %w", err) } req.Header.Set("Content-Type", "application/x-protobuf") resp, err := client.Do(req) if err != nil { return fmt.Errorf("failed to send traces: %w", err) } resp.Body.Close() return nil } func sendTestLogs(otelPort string) error { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() sl := rl.ScopeLogs().AppendEmpty() log := sl.LogRecords().AppendEmpty() log.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) log.SetSeverityText("INFO") log.SetSeverityNumber(plog.SeverityNumberInfo) log.Body().SetStr("test log message") client := &http.Client{} logsMarshaler := plog.ProtoMarshaler{} logsBytes, err := logsMarshaler.MarshalLogs(logs) if err != nil { return fmt.Errorf("failed to marshal logs: %w", err) } req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("http://localhost:%s/v1/logs", otelPort), bytes.NewReader(logsBytes)) if err != nil { return fmt.Errorf("failed to create logs request: %w", err) } req.Header.Set("Content-Type", "application/x-protobuf") resp, err := client.Do(req) if err != nil { return fmt.Errorf("failed to send logs: %w", err) } resp.Body.Close() return nil } func getFreePort(t *testing.T) string { t.Helper() l, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { t.Fatalf("could not get free port: %v", err) } defer l.Close() return strconv.Itoa(l.Addr().(*net.TCPAddr).Port) } opentelemetry-collector-0.141.0/internal/e2e/opaque_test.go000066400000000000000000000013101511331344600237000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/confmap" ) type TestStruct struct { Opaque configopaque.String `json:"opaque" yaml:"opaque"` Plain string `json:"plain" yaml:"plain"` } var example = TestStruct{ Opaque: "opaque", Plain: "plain", } func TestConfMapMarshalConfigOpaque(t *testing.T) { conf := confmap.New() require.NoError(t, conf.Marshal(example)) assert.Equal(t, "[REDACTED]", conf.Get("opaque")) assert.Equal(t, "plain", conf.Get("plain")) } opentelemetry-collector-0.141.0/internal/e2e/otlphttp_test.go000066400000000000000000000321151511331344600242730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "bytes" "compress/gzip" "context" "encoding/hex" "errors" "fmt" "io" "net/http" "net/http/httptest" "testing" "time" "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectortrace "go.opentelemetry.io/proto/otlp/collector/trace/v1" gootlpcommon "go.opentelemetry.io/proto/otlp/common/v1" gootlpresource "go.opentelemetry.io/proto/otlp/resource/v1" gootlptrace "go.opentelemetry.io/proto/otlp/trace/v1" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/testing/protocmp" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/otlphttpexporter" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/receiver/otlpreceiver" "go.opentelemetry.io/collector/receiver/receivertest" ) func TestInvalidConfig(t *testing.T) { config := &otlphttpexporter.Config{ ClientConfig: confighttp.ClientConfig{ Endpoint: "", }, } f := otlphttpexporter.NewFactory() set := exportertest.NewNopSettings(f.Type()) _, err := f.CreateTraces(context.Background(), set, config) require.Error(t, err) _, err = f.CreateMetrics(context.Background(), set, config) require.Error(t, err) _, err = f.CreateLogs(context.Background(), set, config) require.Error(t, err) } func TestTraceNoBackend(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) exp := startTraces(t, "", fmt.Sprintf("http://%s/v1/traces", addr)) td := testdata.GenerateTraces(1) assert.Error(t, exp.ConsumeTraces(context.Background(), td)) } func TestTraceInvalidUrl(t *testing.T) { exp := startTraces(t, "http:/\\//this_is_an/*/invalid_url", "") td := testdata.GenerateTraces(1) require.Error(t, exp.ConsumeTraces(context.Background(), td)) exp = startTraces(t, "", "http:/\\//this_is_an/*/invalid_url") td = testdata.GenerateTraces(1) assert.Error(t, exp.ConsumeTraces(context.Background(), td)) } func TestTraceError(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) startTracesReceiver(t, addr, consumertest.NewErr(errors.New("my_error"))) exp := startTraces(t, "", fmt.Sprintf("http://%s/v1/traces", addr)) td := testdata.GenerateTraces(1) assert.Error(t, exp.ConsumeTraces(context.Background(), td)) } func TestTraceRoundTrip(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) tests := []struct { name string baseURL string overrideURL string }{ { name: "wrongbase", baseURL: "http://wronghostname", overrideURL: fmt.Sprintf("http://%s/v1/traces", addr), }, { name: "onlybase", baseURL: "http://" + addr, overrideURL: "", }, { name: "override", baseURL: "", overrideURL: fmt.Sprintf("http://%s/v1/traces", addr), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink := new(consumertest.TracesSink) startTracesReceiver(t, addr, sink) exp := startTraces(t, tt.baseURL, tt.overrideURL) td := testdata.GenerateTraces(1) require.NoError(t, exp.ConsumeTraces(context.Background(), td)) require.Eventually(t, func() bool { return sink.SpanCount() > 0 }, 1*time.Second, 10*time.Millisecond) allTraces := sink.AllTraces() require.Len(t, allTraces, 1) assert.Equal(t, td, allTraces[0]) }) } } func TestMetricsError(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) startMetricsReceiver(t, addr, consumertest.NewErr(errors.New("my_error"))) exp := startMetrics(t, "", fmt.Sprintf("http://%s/v1/metrics", addr)) md := testdata.GenerateMetrics(1) assert.Error(t, exp.ConsumeMetrics(context.Background(), md)) } func TestMetricsRoundTrip(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) tests := []struct { name string baseURL string overrideURL string }{ { name: "wrongbase", baseURL: "http://wronghostname", overrideURL: fmt.Sprintf("http://%s/v1/metrics", addr), }, { name: "onlybase", baseURL: "http://" + addr, overrideURL: "", }, { name: "override", baseURL: "", overrideURL: fmt.Sprintf("http://%s/v1/metrics", addr), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink := new(consumertest.MetricsSink) startMetricsReceiver(t, addr, sink) exp := startMetrics(t, tt.baseURL, tt.overrideURL) md := testdata.GenerateMetrics(1) require.NoError(t, exp.ConsumeMetrics(context.Background(), md)) require.Eventually(t, func() bool { return sink.DataPointCount() > 0 }, 1*time.Second, 10*time.Millisecond) allMetrics := sink.AllMetrics() require.Len(t, allMetrics, 1) assert.Equal(t, md, allMetrics[0]) }) } } func TestLogsError(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) startLogsReceiver(t, addr, consumertest.NewErr(errors.New("my_error"))) exp := startLogs(t, "", fmt.Sprintf("http://%s/v1/logs", addr)) md := testdata.GenerateLogs(1) assert.Error(t, exp.ConsumeLogs(context.Background(), md)) } func TestLogsRoundTrip(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) tests := []struct { name string baseURL string overrideURL string }{ { name: "wrongbase", baseURL: "http://wronghostname", overrideURL: fmt.Sprintf("http://%s/v1/logs", addr), }, { name: "onlybase", baseURL: "http://" + addr, overrideURL: "", }, { name: "override", baseURL: "", overrideURL: fmt.Sprintf("http://%s/v1/logs", addr), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink := new(consumertest.LogsSink) startLogsReceiver(t, addr, sink) exp := startLogs(t, tt.baseURL, tt.overrideURL) md := testdata.GenerateLogs(1) require.NoError(t, exp.ConsumeLogs(context.Background(), md)) require.Eventually(t, func() bool { return sink.LogRecordCount() > 0 }, 1*time.Second, 10*time.Millisecond) allLogs := sink.AllLogs() require.Len(t, allLogs, 1) assert.Equal(t, md, allLogs[0]) }) } } func TestIssue_4221(t *testing.T) { traceIDBytesSlice, err := hex.DecodeString("4303853f086f4f8c86cf198b6551df84") require.NoError(t, err) spanIDBytesSlice, err := hex.DecodeString("e5513c32795c41b9") require.NoError(t, err) svr := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, r *http.Request) { defer func() { assert.NoError(t, r.Body.Close()) }() compressedData, err := io.ReadAll(r.Body) assert.NoError(t, err) gzipReader, err := gzip.NewReader(bytes.NewReader(compressedData)) assert.NoError(t, err) data, err := io.ReadAll(gzipReader) assert.NoError(t, err) // Verify same base64 encoded string is received. req := &gootlpcollectortrace.ExportTraceServiceRequest{} assert.NoError(t, proto.Unmarshal(data, req)) assert.Empty(t, cmp.Diff(&gootlpcollectortrace.ExportTraceServiceRequest{ ResourceSpans: []*gootlptrace.ResourceSpans{ { Resource: &gootlpresource.Resource{ Attributes: []*gootlpcommon.KeyValue{ { Key: "service.name", Value: &gootlpcommon.AnyValue{ Value: &gootlpcommon.AnyValue_StringValue{ StringValue: "uop.stage-eu-1", }, }, }, { Key: "outsystems.module.version", Value: &gootlpcommon.AnyValue{ Value: &gootlpcommon.AnyValue_StringValue{ StringValue: "903386", }, }, }, }, }, ScopeSpans: []*gootlptrace.ScopeSpans{ { Scope: &gootlpcommon.InstrumentationScope{ Name: "uop_canaries", Version: "1", }, Spans: []*gootlptrace.Span{ { TraceId: traceIDBytesSlice, SpanId: spanIDBytesSlice, StartTimeUnixNano: 1634684637873000000, EndTimeUnixNano: 1634684637873000000, Attributes: []*gootlpcommon.KeyValue{ { Key: "span_index", Value: &gootlpcommon.AnyValue{ Value: &gootlpcommon.AnyValue_IntValue{ IntValue: 3, }, }, }, { Key: "code.function", Value: &gootlpcommon.AnyValue{ Value: &gootlpcommon.AnyValue_StringValue{ StringValue: "myFunction36", }, }, }, }, Status: &gootlptrace.Status{}, }, }, }, }, }, }, }, req, protocmp.Transform())) assert.NoError(t, err) tr := ptraceotlp.NewExportRequest() assert.NoError(t, tr.UnmarshalProto(data)) span := tr.Traces().ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0) traceID := span.TraceID() assert.Equal(t, "4303853f086f4f8c86cf198b6551df84", hex.EncodeToString(traceID[:])) spanID := span.SpanID() assert.Equal(t, "e5513c32795c41b9", hex.EncodeToString(spanID[:])) })) defer func() { svr.Close() }() exp := startTraces(t, "", svr.URL) md := ptrace.NewTraces() rms := md.ResourceSpans().AppendEmpty() rms.Resource().Attributes().PutStr("service.name", "uop.stage-eu-1") rms.Resource().Attributes().PutStr("outsystems.module.version", "903386") ils := rms.ScopeSpans().AppendEmpty() ils.Scope().SetName("uop_canaries") ils.Scope().SetVersion("1") span := ils.Spans().AppendEmpty() var traceIDBytes [16]byte copy(traceIDBytes[:], traceIDBytesSlice) span.SetTraceID(traceIDBytes) traceID := span.TraceID() assert.Equal(t, "4303853f086f4f8c86cf198b6551df84", hex.EncodeToString(traceID[:])) var spanIDBytes [8]byte copy(spanIDBytes[:], spanIDBytesSlice) span.SetSpanID(spanIDBytes) spanID := span.SpanID() assert.Equal(t, "e5513c32795c41b9", hex.EncodeToString(spanID[:])) span.SetEndTimestamp(1634684637873000000) span.Attributes().PutInt("span_index", 3) span.Attributes().PutStr("code.function", "myFunction36") span.SetStartTimestamp(1634684637873000000) assert.NoError(t, exp.ConsumeTraces(context.Background(), md)) } func startTraces(t *testing.T, baseURL, overrideURL string) exporter.Traces { factory := otlphttpexporter.NewFactory() cfg := createConfig(baseURL, factory.CreateDefaultConfig()) cfg.TracesEndpoint = overrideURL exp, err := factory.CreateTraces(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) startAndCleanup(t, exp) return exp } func startMetrics(t *testing.T, baseURL, overrideURL string) exporter.Metrics { factory := otlphttpexporter.NewFactory() cfg := createConfig(baseURL, factory.CreateDefaultConfig()) cfg.MetricsEndpoint = overrideURL exp, err := factory.CreateMetrics(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) startAndCleanup(t, exp) return exp } func startLogs(t *testing.T, baseURL, overrideURL string) exporter.Logs { factory := otlphttpexporter.NewFactory() cfg := createConfig(baseURL, factory.CreateDefaultConfig()) cfg.LogsEndpoint = overrideURL exp, err := factory.CreateLogs(context.Background(), exportertest.NewNopSettings(factory.Type()), cfg) require.NoError(t, err) startAndCleanup(t, exp) return exp } func createConfig(baseURL string, defaultCfg component.Config) *otlphttpexporter.Config { cfg := defaultCfg.(*otlphttpexporter.Config) cfg.ClientConfig.Endpoint = baseURL cfg.QueueConfig.Enabled = false cfg.RetryConfig.Enabled = false return cfg } func startTracesReceiver(t *testing.T, addr string, next consumer.Traces) { factory := otlpreceiver.NewFactory() cfg := createReceiverConfig(addr, factory.CreateDefaultConfig()) recv, err := factory.CreateTraces(context.Background(), receivertest.NewNopSettings(factory.Type()), cfg, next) require.NoError(t, err) startAndCleanup(t, recv) } func startMetricsReceiver(t *testing.T, addr string, next consumer.Metrics) { factory := otlpreceiver.NewFactory() cfg := createReceiverConfig(addr, factory.CreateDefaultConfig()) recv, err := factory.CreateMetrics(context.Background(), receivertest.NewNopSettings(factory.Type()), cfg, next) require.NoError(t, err) startAndCleanup(t, recv) } func startLogsReceiver(t *testing.T, addr string, next consumer.Logs) { factory := otlpreceiver.NewFactory() cfg := createReceiverConfig(addr, factory.CreateDefaultConfig()) recv, err := factory.CreateLogs(context.Background(), receivertest.NewNopSettings(factory.Type()), cfg, next) require.NoError(t, err) startAndCleanup(t, recv) } func createReceiverConfig(addr string, defaultCfg component.Config) *otlpreceiver.Config { cfg := defaultCfg.(*otlpreceiver.Config) cfg.HTTP.GetOrInsertDefault().ServerConfig.Endpoint = addr return cfg } func startAndCleanup(t *testing.T, cmp component.Component) { require.NoError(t, cmp.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, cmp.Shutdown(context.Background())) }) } opentelemetry-collector-0.141.0/internal/e2e/package_test.go000066400000000000000000000003041511331344600240030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/internal/e2e/status_test.go000066400000000000000000000225001511331344600237350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package e2e import ( "context" "errors" "fmt" "strings" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/internal/sharedcomponent" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/pipelines" "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" ) var nopType = component.MustNewType("nop") var wg = sync.WaitGroup{} func Test_ComponentStatusReporting_SharedInstance(t *testing.T) { eventsReceived := make(map[*componentstatus.InstanceID][]*componentstatus.Event) exporterFactory := exportertest.NewNopFactory() connectorFactory := connectortest.NewNopFactory() // Use a different ID than receivertest and exportertest to avoid ambiguous // configuration scenarios. Ambiguous IDs are detected in the 'otelcol' package, // but lower level packages such as 'service' assume that IDs are disambiguated. connID := component.NewIDWithName(nopType, "conn") set := service.Settings{ BuildInfo: component.NewDefaultBuildInfo(), CollectorConf: confmap.New(), ReceiversConfigs: map[component.ID]component.Config{ component.NewID(component.MustNewType("test")): &receiverConfig{}, }, ReceiversFactories: map[component.Type]receiver.Factory{ component.MustNewType("test"): newReceiverFactory(), }, ExportersConfigs: map[component.ID]component.Config{ component.NewID(nopType): exporterFactory.CreateDefaultConfig(), }, ExportersFactories: map[component.Type]exporter.Factory{ nopType: exporterFactory, }, ConnectorsConfigs: map[component.ID]component.Config{ connID: connectorFactory.CreateDefaultConfig(), }, ConnectorsFactories: map[component.Type]connector.Factory{ nopType: connectorFactory, }, ExtensionsConfigs: map[component.ID]component.Config{ component.NewID(component.MustNewType("watcher")): &extensionConfig{eventsReceived}, }, ExtensionsFactories: map[component.Type]extension.Factory{ component.MustNewType("watcher"): newExtensionFactory(), }, TelemetryFactory: otelconftelemetry.NewFactory(), } set.BuildInfo = component.BuildInfo{Version: "test version", Command: "otelcoltest"} cfg := service.Config{ Telemetry: &otelconftelemetry.Config{ Logs: otelconftelemetry.LogsConfig{ Level: zapcore.InfoLevel, Development: false, Encoding: "console", Sampling: &otelconftelemetry.LogsSamplingConfig{ Enabled: true, Tick: 10 * time.Second, Initial: 100, Thereafter: 100, }, OutputPaths: []string{"stderr"}, ErrorOutputPaths: []string{"stderr"}, DisableCaller: false, DisableStacktrace: false, InitialFields: map[string]any(nil), }, Metrics: otelconftelemetry.MetricsConfig{ Level: configtelemetry.LevelNone, }, }, Pipelines: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.NewID(component.MustNewType("test"))}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.NewID(component.MustNewType("test"))}, Exporters: []component.ID{component.NewID(nopType)}, }, }, Extensions: extensions.Config{component.NewID(component.MustNewType("watcher"))}, } s, err := service.New(context.Background(), set, cfg) require.NoError(t, err) wg.Add(1) err = s.Start(context.Background()) require.NoError(t, err) wg.Wait() err = s.Shutdown(context.Background()) require.NoError(t, err) require.Len(t, eventsReceived, 2) for instanceID, events := range eventsReceived { pipelineIDs := "" instanceID.AllPipelineIDs(func(id pipeline.ID) bool { pipelineIDs += id.String() + "," return true }) t.Logf("checking errors for %v - %v - %v", pipelineIDs, instanceID.Kind().String(), instanceID.ComponentID().String()) var expectedEvents []*componentstatus.Event // The StatusOk is not guaranteed to be in the slice, set it according to the number of captured states assert.True(t, len(events) == 4 || len(events) == 5) receiverTestAttrs := pcommon.NewMap() receiverTestAttrs.PutStr("scraper", "test") if len(events) == 4 { expectedEvents = []*componentstatus.Event{ componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusRecoverableError, componentstatus.WithAttributes(receiverTestAttrs)), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), } } else { expectedEvents = []*componentstatus.Event{ componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusRecoverableError, componentstatus.WithAttributes(receiverTestAttrs)), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), } } var eventStr strings.Builder for i, e := range events { fmt.Fprintf(&eventStr, "%v,", e.Status()) assert.Equal(t, expectedEvents[i].Status(), e.Status()) } t.Logf("events received: %v", eventStr.String()) } } func newReceiverFactory() receiver.Factory { return receiver.NewFactory( component.MustNewType("test"), createDefaultReceiverConfig, receiver.WithTraces(createTraces, component.StabilityLevelStable), receiver.WithMetrics(createMetrics, component.StabilityLevelStable), ) } type testReceiver struct{} func (t *testReceiver) Start(_ context.Context, host component.Host) error { scraperAttrs := pcommon.NewMap() scraperAttrs.PutStr("scraper", "test") componentstatus.ReportStatus(host, componentstatus.NewEvent( componentstatus.StatusRecoverableError, componentstatus.WithError(errors.New("test recoverable error")), componentstatus.WithAttributes(scraperAttrs), )) go func() { componentstatus.ReportStatus(host, componentstatus.NewEvent(componentstatus.StatusOK)) wg.Done() }() return nil } func (t *testReceiver) Shutdown(_ context.Context) error { return nil } type receiverConfig struct{} func createDefaultReceiverConfig() component.Config { return &receiverConfig{} } func createTraces( _ context.Context, _ receiver.Settings, cfg component.Config, _ consumer.Traces, ) (receiver.Traces, error) { oCfg := cfg.(*receiverConfig) r, err := receivers.LoadOrStore( oCfg, func() (*testReceiver, error) { return &testReceiver{}, nil }, ) if err != nil { return nil, err } return r, nil } func createMetrics( _ context.Context, _ receiver.Settings, cfg component.Config, _ consumer.Metrics, ) (receiver.Metrics, error) { oCfg := cfg.(*receiverConfig) r, err := receivers.LoadOrStore( oCfg, func() (*testReceiver, error) { return &testReceiver{}, nil }, ) if err != nil { return nil, err } return r, nil } var receivers = sharedcomponent.NewMap[*receiverConfig, *testReceiver]() func newExtensionFactory() extension.Factory { return extension.NewFactory( component.MustNewType("watcher"), createDefaultExtensionConfig, create, component.StabilityLevelStable, ) } func create(_ context.Context, _ extension.Settings, cfg component.Config) (extension.Extension, error) { oCfg := cfg.(*extensionConfig) return &testExtension{ eventsReceived: oCfg.eventsReceived, }, nil } type testExtension struct { eventsReceived map[*componentstatus.InstanceID][]*componentstatus.Event } type extensionConfig struct { eventsReceived map[*componentstatus.InstanceID][]*componentstatus.Event } func createDefaultExtensionConfig() component.Config { return &extensionConfig{} } // Start implements the component.Component interface. func (t *testExtension) Start(_ context.Context, _ component.Host) error { return nil } // Shutdown implements the component.Component interface. func (t *testExtension) Shutdown(_ context.Context) error { return nil } // ComponentStatusChanged implements the extension.StatusWatcher interface. func (t *testExtension) ComponentStatusChanged( source *componentstatus.InstanceID, event *componentstatus.Event, ) { if source.ComponentID() == component.NewID(component.MustNewType("test")) { t.eventsReceived[source] = append(t.eventsReceived[source], event) } } // NotifyConfig implements the extensioncapabilities.ConfigWatcher interface. func (t *testExtension) NotifyConfig(_ context.Context, _ *confmap.Conf) error { return nil } // Ready implements the extensioncapabilities.PipelineWatcher interface. func (t *testExtension) Ready() error { return nil } // NotReady implements the extensioncapabilities.PipelineWatcher interface. func (t *testExtension) NotReady() error { return nil } opentelemetry-collector-0.141.0/internal/e2e/testdata/000077500000000000000000000000001511331344600226365ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/e2e/testdata/metric_stability_test_no_readers.yaml000066400000000000000000000010621511331344600323300ustar00rootroot00000000000000receivers: otlp: protocols: http: endpoint: localhost:${env:OTEL_PORT} processors: batch: timeout: 100ms send_batch_size: 100 exporters: debug: verbosity: detailed service: telemetry: logs: level: info metrics: level: detailed pipelines: traces: receivers: [otlp] processors: [batch] exporters: [debug] metrics: receivers: [otlp] processors: [batch] exporters: [debug] logs: receivers: [otlp] processors: [batch] exporters: [debug] opentelemetry-collector-0.141.0/internal/e2e/testdata/metric_stability_test_readers.yaml000066400000000000000000000013131511331344600316330ustar00rootroot00000000000000receivers: otlp: protocols: http: endpoint: localhost:${env:OTEL_PORT} processors: batch: timeout: 100ms send_batch_size: 100 exporters: debug: verbosity: detailed service: telemetry: logs: level: info metrics: level: detailed readers: - pull: exporter: prometheus: host: localhost port: ${env:METRICS_PORT} pipelines: traces: receivers: [otlp] processors: [batch] exporters: [debug] metrics: receivers: [otlp] processors: [batch] exporters: [debug] logs: receivers: [otlp] processors: [batch] exporters: [debug] opentelemetry-collector-0.141.0/internal/fanoutconsumer/000077500000000000000000000000001511331344600234225ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/fanoutconsumer/Makefile000066400000000000000000000000361511331344600250610ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/internal/fanoutconsumer/go.mod000066400000000000000000000030521511331344600245300ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/fanoutconsumer go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../testutil opentelemetry-collector-0.141.0/internal/fanoutconsumer/go.sum000066400000000000000000000077271511331344600245720ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/internal/fanoutconsumer/logs.go000066400000000000000000000054321511331344600247210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package fanoutconsumer contains implementations of Traces/Metrics/Logs consumers // that fan out the data to multiple other consumers. package fanoutconsumer // import "go.opentelemetry.io/collector/internal/fanoutconsumer" import ( "context" "go.uber.org/multierr" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog" ) // NewLogs wraps multiple log consumers in a single one. // It fans out the incoming data to all the consumers, and does smart routing: // - Clones only to the consumer that needs to mutate the data. // - If all consumers needs to mutate the data one will get the original mutable data. func NewLogs(lcs []consumer.Logs) consumer.Logs { // Don't wrap if there is only one non-mutating consumer. if len(lcs) == 1 && !lcs[0].Capabilities().MutatesData { return lcs[0] } lc := &logsConsumer{} for i := range lcs { if lcs[i].Capabilities().MutatesData { lc.mutable = append(lc.mutable, lcs[i]) } else { lc.readonly = append(lc.readonly, lcs[i]) } } return lc } type logsConsumer struct { mutable []consumer.Logs readonly []consumer.Logs } func (lsc *logsConsumer) Capabilities() consumer.Capabilities { // If all consumers are mutating, then the original data will be passed to one of them. return consumer.Capabilities{MutatesData: len(lsc.mutable) > 0 && len(lsc.readonly) == 0} } // ConsumeLogs exports the plog.Logs to all consumers wrapped by the current one. func (lsc *logsConsumer) ConsumeLogs(ctx context.Context, ld plog.Logs) error { var errs error if len(lsc.mutable) > 0 { // Clone the data before sending to all mutating consumers except the last one. for i := 0; i < len(lsc.mutable)-1; i++ { errs = multierr.Append(errs, lsc.mutable[i].ConsumeLogs(ctx, cloneLogs(ld))) } // Send data as is to the last mutating consumer only if there are no other non-mutating consumers and the // data is mutable. Never share the same data between a mutating and a non-mutating consumer since the // non-mutating consumer may process data async and the mutating consumer may change the data before that. lastConsumer := lsc.mutable[len(lsc.mutable)-1] if len(lsc.readonly) == 0 && !ld.IsReadOnly() { errs = multierr.Append(errs, lastConsumer.ConsumeLogs(ctx, ld)) } else { errs = multierr.Append(errs, lastConsumer.ConsumeLogs(ctx, cloneLogs(ld))) } } // Mark the data as read-only if it will be sent to more than one read-only consumer. if len(lsc.readonly) > 1 && !ld.IsReadOnly() { ld.MarkReadOnly() } for _, lc := range lsc.readonly { errs = multierr.Append(errs, lc.ConsumeLogs(ctx, ld)) } return errs } func cloneLogs(ld plog.Logs) plog.Logs { clonedLogs := plog.NewLogs() ld.CopyTo(clonedLogs) return clonedLogs } opentelemetry-collector-0.141.0/internal/fanoutconsumer/logs_test.go000066400000000000000000000155541511331344600257660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/testdata" ) func TestLogsNotMultiplexing(t *testing.T) { nop := consumertest.NewNop() lfc := NewLogs([]consumer.Logs{nop}) assert.Same(t, nop, lfc) } func TestLogsNotMultiplexingMutating(t *testing.T) { p := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} lfc := NewLogs([]consumer.Logs{p}) assert.True(t, lfc.Capabilities().MutatesData) } func TestLogsMultiplexingNonMutating(t *testing.T) { p1 := new(consumertest.LogsSink) p2 := new(consumertest.LogsSink) p3 := new(consumertest.LogsSink) lfc := NewLogs([]consumer.Logs{p1, p2, p3}) assert.False(t, lfc.Capabilities().MutatesData) ld := testdata.GenerateLogs(1) for range 2 { err := lfc.ConsumeLogs(context.Background(), ld) if err != nil { t.Errorf("Wanted nil got error") return } } assert.Equal(t, ld, p1.AllLogs()[0]) assert.Equal(t, ld, p1.AllLogs()[1]) assert.Equal(t, ld, p1.AllLogs()[0]) assert.Equal(t, ld, p1.AllLogs()[1]) assert.Equal(t, ld, p2.AllLogs()[0]) assert.Equal(t, ld, p2.AllLogs()[1]) assert.Equal(t, ld, p2.AllLogs()[0]) assert.Equal(t, ld, p2.AllLogs()[1]) assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) // The data should be marked as read only. assert.True(t, ld.IsReadOnly()) } func TestLogsMultiplexingMutating(t *testing.T) { p1 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} p2 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} p3 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} lfc := NewLogs([]consumer.Logs{p1, p2, p3}) assert.True(t, lfc.Capabilities().MutatesData) ld := testdata.GenerateLogs(1) for range 2 { err := lfc.ConsumeLogs(context.Background(), ld) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &ld, &p1.AllLogs()[0]) assert.NotSame(t, &ld, &p1.AllLogs()[1]) assert.Equal(t, ld, p1.AllLogs()[0]) assert.Equal(t, ld, p1.AllLogs()[1]) assert.NotSame(t, &ld, &p2.AllLogs()[0]) assert.NotSame(t, &ld, &p2.AllLogs()[1]) assert.Equal(t, ld, p2.AllLogs()[0]) assert.Equal(t, ld, p2.AllLogs()[1]) // For this consumer, will receive the initial data. assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) // The data should not be marked as read only. assert.False(t, ld.IsReadOnly()) } func TestReadOnlyLogsMultiplexingMutating(t *testing.T) { p1 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} p2 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} p3 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} lfc := NewLogs([]consumer.Logs{p1, p2, p3}) assert.True(t, lfc.Capabilities().MutatesData) ldOrig := testdata.GenerateLogs(1) ld := testdata.GenerateLogs(1) ld.MarkReadOnly() for range 2 { err := lfc.ConsumeLogs(context.Background(), ld) if err != nil { t.Errorf("Wanted nil got error") return } } // All consumers should receive the cloned data. assert.NotEqual(t, ld, p1.AllLogs()[0]) assert.NotEqual(t, ld, p1.AllLogs()[1]) assert.Equal(t, ldOrig, p1.AllLogs()[0]) assert.Equal(t, ldOrig, p1.AllLogs()[1]) assert.NotEqual(t, ld, p2.AllLogs()[0]) assert.NotEqual(t, ld, p2.AllLogs()[1]) assert.Equal(t, ldOrig, p2.AllLogs()[0]) assert.Equal(t, ldOrig, p2.AllLogs()[1]) assert.NotEqual(t, ld, p3.AllLogs()[0]) assert.NotEqual(t, ld, p3.AllLogs()[1]) assert.Equal(t, ldOrig, p3.AllLogs()[0]) assert.Equal(t, ldOrig, p3.AllLogs()[1]) } func TestLogsMultiplexingMixLastMutating(t *testing.T) { p1 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} p2 := new(consumertest.LogsSink) p3 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} lfc := NewLogs([]consumer.Logs{p1, p2, p3}) assert.False(t, lfc.Capabilities().MutatesData) ld := testdata.GenerateLogs(1) for range 2 { err := lfc.ConsumeLogs(context.Background(), ld) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &ld, &p1.AllLogs()[0]) assert.NotSame(t, &ld, &p1.AllLogs()[1]) assert.Equal(t, ld, p1.AllLogs()[0]) assert.Equal(t, ld, p1.AllLogs()[1]) // For this consumer, will receive the initial data. assert.Equal(t, ld, p2.AllLogs()[0]) assert.Equal(t, ld, p2.AllLogs()[1]) assert.Equal(t, ld, p2.AllLogs()[0]) assert.Equal(t, ld, p2.AllLogs()[1]) // For this consumer, will clone the initial data. assert.NotSame(t, &ld, &p3.AllLogs()[0]) assert.NotSame(t, &ld, &p3.AllLogs()[1]) assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) // The data should not be marked as read only. assert.False(t, ld.IsReadOnly()) } func TestLogsMultiplexingMixLastNonMutating(t *testing.T) { p1 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} p2 := &mutatingLogsSink{LogsSink: new(consumertest.LogsSink)} p3 := new(consumertest.LogsSink) lfc := NewLogs([]consumer.Logs{p1, p2, p3}) assert.False(t, lfc.Capabilities().MutatesData) ld := testdata.GenerateLogs(1) for range 2 { err := lfc.ConsumeLogs(context.Background(), ld) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &ld, &p1.AllLogs()[0]) assert.NotSame(t, &ld, &p1.AllLogs()[1]) assert.Equal(t, ld, p1.AllLogs()[0]) assert.Equal(t, ld, p1.AllLogs()[1]) assert.NotSame(t, &ld, &p2.AllLogs()[0]) assert.NotSame(t, &ld, &p2.AllLogs()[1]) assert.Equal(t, ld, p2.AllLogs()[0]) assert.Equal(t, ld, p2.AllLogs()[1]) // For this consumer, will receive the initial data. assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) // The data should not be marked as read only. assert.False(t, ld.IsReadOnly()) } func TestLogsWhenErrors(t *testing.T) { p1 := mutatingErr{Consumer: consumertest.NewErr(errors.New("my error"))} p2 := consumertest.NewErr(errors.New("my error")) p3 := new(consumertest.LogsSink) lfc := NewLogs([]consumer.Logs{p1, p2, p3}) ld := testdata.GenerateLogs(1) for range 2 { require.Error(t, lfc.ConsumeLogs(context.Background(), ld)) } assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) assert.Equal(t, ld, p3.AllLogs()[0]) assert.Equal(t, ld, p3.AllLogs()[1]) } type mutatingLogsSink struct { *consumertest.LogsSink } func (mts *mutatingLogsSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } type mutatingErr struct { consumertest.Consumer } func (mts mutatingErr) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } opentelemetry-collector-0.141.0/internal/fanoutconsumer/metrics.go000066400000000000000000000053671511331344600254320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer // import "go.opentelemetry.io/collector/internal/fanoutconsumer" import ( "context" "go.uber.org/multierr" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pmetric" ) // NewMetrics wraps multiple metrics consumers in a single one. // It fans out the incoming data to all the consumers, and does smart routing: // - Clones only to the consumer that needs to mutate the data. // - If all consumers needs to mutate the data one will get the original mutable data. func NewMetrics(mcs []consumer.Metrics) consumer.Metrics { // Don't wrap if there is only one non-mutating consumer. if len(mcs) == 1 && !mcs[0].Capabilities().MutatesData { return mcs[0] } mc := &metricsConsumer{} for i := range mcs { if mcs[i].Capabilities().MutatesData { mc.mutable = append(mc.mutable, mcs[i]) } else { mc.readonly = append(mc.readonly, mcs[i]) } } return mc } type metricsConsumer struct { mutable []consumer.Metrics readonly []consumer.Metrics } func (msc *metricsConsumer) Capabilities() consumer.Capabilities { // If all consumers are mutating, then the original data will be passed to one of them. return consumer.Capabilities{MutatesData: len(msc.mutable) > 0 && len(msc.readonly) == 0} } // ConsumeMetrics exports the pmetric.Metrics to all consumers wrapped by the current one. func (msc *metricsConsumer) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { var errs error if len(msc.mutable) > 0 { // Clone the data before sending to all mutating consumers except the last one. for i := 0; i < len(msc.mutable)-1; i++ { errs = multierr.Append(errs, msc.mutable[i].ConsumeMetrics(ctx, cloneMetrics(md))) } // Send data as is to the last mutating consumer only if there are no other non-mutating consumers and the // data is mutable. Never share the same data between a mutating and a non-mutating consumer since the // non-mutating consumer may process data async and the mutating consumer may change the data before that. lastConsumer := msc.mutable[len(msc.mutable)-1] if len(msc.readonly) == 0 && !md.IsReadOnly() { errs = multierr.Append(errs, lastConsumer.ConsumeMetrics(ctx, md)) } else { errs = multierr.Append(errs, lastConsumer.ConsumeMetrics(ctx, cloneMetrics(md))) } } // Mark the data as read-only if it will be sent to more than one read-only consumer. if len(msc.readonly) > 1 && !md.IsReadOnly() { md.MarkReadOnly() } for _, mc := range msc.readonly { errs = multierr.Append(errs, mc.ConsumeMetrics(ctx, md)) } return errs } func cloneMetrics(md pmetric.Metrics) pmetric.Metrics { clonedMetrics := pmetric.NewMetrics() md.CopyTo(clonedMetrics) return clonedMetrics } opentelemetry-collector-0.141.0/internal/fanoutconsumer/metrics_test.go000066400000000000000000000161741511331344600264670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMetricsNotMultiplexing(t *testing.T) { nop := consumertest.NewNop() mfc := NewMetrics([]consumer.Metrics{nop}) assert.Same(t, nop, mfc) } func TestMetricssNotMultiplexingMutating(t *testing.T) { p := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} lfc := NewMetrics([]consumer.Metrics{p}) assert.True(t, lfc.Capabilities().MutatesData) } func TestMetricsMultiplexingNonMutating(t *testing.T) { p1 := new(consumertest.MetricsSink) p2 := new(consumertest.MetricsSink) p3 := new(consumertest.MetricsSink) mfc := NewMetrics([]consumer.Metrics{p1, p2, p3}) assert.False(t, mfc.Capabilities().MutatesData) md := testdata.GenerateMetrics(1) for range 2 { err := mfc.ConsumeMetrics(context.Background(), md) if err != nil { t.Errorf("Wanted nil got error") return } } assert.Equal(t, md, p1.AllMetrics()[0]) assert.Equal(t, md, p1.AllMetrics()[1]) assert.Equal(t, md, p1.AllMetrics()[0]) assert.Equal(t, md, p1.AllMetrics()[1]) assert.Equal(t, md, p2.AllMetrics()[0]) assert.Equal(t, md, p2.AllMetrics()[1]) assert.Equal(t, md, p2.AllMetrics()[0]) assert.Equal(t, md, p2.AllMetrics()[1]) assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) // The data should be marked as read only. assert.True(t, md.IsReadOnly()) } func TestMetricsMultiplexingMutating(t *testing.T) { p1 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} p2 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} p3 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} mfc := NewMetrics([]consumer.Metrics{p1, p2, p3}) assert.True(t, mfc.Capabilities().MutatesData) md := testdata.GenerateMetrics(1) for range 2 { err := mfc.ConsumeMetrics(context.Background(), md) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &md, &p1.AllMetrics()[0]) assert.NotSame(t, &md, &p1.AllMetrics()[1]) assert.Equal(t, md, p1.AllMetrics()[0]) assert.Equal(t, md, p1.AllMetrics()[1]) assert.NotSame(t, &md, &p2.AllMetrics()[0]) assert.NotSame(t, &md, &p2.AllMetrics()[1]) assert.Equal(t, md, p2.AllMetrics()[0]) assert.Equal(t, md, p2.AllMetrics()[1]) // For this consumer, will receive the initial data. assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) // The data should not be marked as read only. assert.False(t, md.IsReadOnly()) } func TestReadOnlyMetricsMultiplexingMixFirstMutating(t *testing.T) { p1 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} p2 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} p3 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} mfc := NewMetrics([]consumer.Metrics{p1, p2, p3}) assert.True(t, mfc.Capabilities().MutatesData) mdOrig := testdata.GenerateMetrics(1) md := testdata.GenerateMetrics(1) md.MarkReadOnly() for range 2 { err := mfc.ConsumeMetrics(context.Background(), md) if err != nil { t.Errorf("Wanted nil got error") return } } // All consumers should receive the cloned data. assert.NotEqual(t, md, p1.AllMetrics()[0]) assert.NotEqual(t, md, p1.AllMetrics()[1]) assert.Equal(t, mdOrig, p1.AllMetrics()[0]) assert.Equal(t, mdOrig, p1.AllMetrics()[1]) assert.NotEqual(t, md, p2.AllMetrics()[0]) assert.NotEqual(t, md, p2.AllMetrics()[1]) assert.Equal(t, mdOrig, p2.AllMetrics()[0]) assert.Equal(t, mdOrig, p2.AllMetrics()[1]) assert.NotEqual(t, md, p3.AllMetrics()[0]) assert.NotEqual(t, md, p3.AllMetrics()[1]) assert.Equal(t, mdOrig, p3.AllMetrics()[0]) assert.Equal(t, mdOrig, p3.AllMetrics()[1]) } func TestMetricsMultiplexingMixLastMutating(t *testing.T) { p1 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} p2 := new(consumertest.MetricsSink) p3 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} mfc := NewMetrics([]consumer.Metrics{p1, p2, p3}) assert.False(t, mfc.Capabilities().MutatesData) md := testdata.GenerateMetrics(1) for range 2 { err := mfc.ConsumeMetrics(context.Background(), md) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &md, &p1.AllMetrics()[0]) assert.NotSame(t, &md, &p1.AllMetrics()[1]) assert.Equal(t, md, p1.AllMetrics()[0]) assert.Equal(t, md, p1.AllMetrics()[1]) // For this consumer, will receive the initial data. assert.Equal(t, md, p2.AllMetrics()[0]) assert.Equal(t, md, p2.AllMetrics()[1]) assert.Equal(t, md, p2.AllMetrics()[0]) assert.Equal(t, md, p2.AllMetrics()[1]) // For this consumer, will clone the initial data. assert.NotSame(t, &md, &p3.AllMetrics()[0]) assert.NotSame(t, &md, &p3.AllMetrics()[1]) assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) // The data should not be marked as read only. assert.False(t, md.IsReadOnly()) } func TestMetricsMultiplexingMixLastNonMutating(t *testing.T) { p1 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} p2 := &mutatingMetricsSink{MetricsSink: new(consumertest.MetricsSink)} p3 := new(consumertest.MetricsSink) mfc := NewMetrics([]consumer.Metrics{p1, p2, p3}) assert.False(t, mfc.Capabilities().MutatesData) md := testdata.GenerateMetrics(1) for range 2 { err := mfc.ConsumeMetrics(context.Background(), md) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &md, &p1.AllMetrics()[0]) assert.NotSame(t, &md, &p1.AllMetrics()[1]) assert.Equal(t, md, p1.AllMetrics()[0]) assert.Equal(t, md, p1.AllMetrics()[1]) assert.NotSame(t, &md, &p2.AllMetrics()[0]) assert.NotSame(t, &md, &p2.AllMetrics()[1]) assert.Equal(t, md, p2.AllMetrics()[0]) assert.Equal(t, md, p2.AllMetrics()[1]) // For this consumer, will receive the initial data. assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) // The data should not be marked as read only. assert.False(t, md.IsReadOnly()) } func TestMetricsWhenErrors(t *testing.T) { p1 := mutatingErr{Consumer: consumertest.NewErr(errors.New("my error"))} p2 := consumertest.NewErr(errors.New("my error")) p3 := new(consumertest.MetricsSink) mfc := NewMetrics([]consumer.Metrics{p1, p2, p3}) md := testdata.GenerateMetrics(1) for range 2 { require.Error(t, mfc.ConsumeMetrics(context.Background(), md)) } assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) assert.Equal(t, md, p3.AllMetrics()[0]) assert.Equal(t, md, p3.AllMetrics()[1]) } type mutatingMetricsSink struct { *consumertest.MetricsSink } func (mts *mutatingMetricsSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } opentelemetry-collector-0.141.0/internal/fanoutconsumer/package_test.go000066400000000000000000000003171511331344600264040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/internal/fanoutconsumer/profiles.go000066400000000000000000000055201511331344600255760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer // import "go.opentelemetry.io/collector/internal/fanoutconsumer" import ( "context" "go.uber.org/multierr" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/pprofile" ) // NewProfiles wraps multiple profile consumers in a single one. // It fans out the incoming data to all the consumers, and does smart routing: // - Clones only to the consumer that needs to mutate the data. // - If all consumers needs to mutate the data one will get the original mutable data. func NewProfiles(tcs []xconsumer.Profiles) xconsumer.Profiles { // Don't wrap if there is only one non-mutating consumer. if len(tcs) == 1 && !tcs[0].Capabilities().MutatesData { return tcs[0] } tc := &profilesConsumer{} for i := range tcs { if tcs[i].Capabilities().MutatesData { tc.mutable = append(tc.mutable, tcs[i]) } else { tc.readonly = append(tc.readonly, tcs[i]) } } return tc } type profilesConsumer struct { mutable []xconsumer.Profiles readonly []xconsumer.Profiles } func (tsc *profilesConsumer) Capabilities() consumer.Capabilities { // If all consumers are mutating, then the original data will be passed to one of them. return consumer.Capabilities{MutatesData: len(tsc.mutable) > 0 && len(tsc.readonly) == 0} } // ConsumeProfiles exports the pprofile.Profiles to all consumers wrapped by the current one. func (tsc *profilesConsumer) ConsumeProfiles(ctx context.Context, td pprofile.Profiles) error { var errs error if len(tsc.mutable) > 0 { // Clone the data before sending to all mutating consumers except the last one. for i := 0; i < len(tsc.mutable)-1; i++ { errs = multierr.Append(errs, tsc.mutable[i].ConsumeProfiles(ctx, cloneProfiles(td))) } // Send data as is to the last mutating consumer only if there are no other non-mutating consumers and the // data is mutable. Never share the same data between a mutating and a non-mutating consumer since the // non-mutating consumer may process data async and the mutating consumer may change the data before that. lastConsumer := tsc.mutable[len(tsc.mutable)-1] if len(tsc.readonly) == 0 && !td.IsReadOnly() { errs = multierr.Append(errs, lastConsumer.ConsumeProfiles(ctx, td)) } else { errs = multierr.Append(errs, lastConsumer.ConsumeProfiles(ctx, cloneProfiles(td))) } } // Mark the data as read-only if it will be sent to more than one read-only consumer. if len(tsc.readonly) > 1 && !td.IsReadOnly() { td.MarkReadOnly() } for _, tc := range tsc.readonly { errs = multierr.Append(errs, tc.ConsumeProfiles(ctx, td)) } return errs } func cloneProfiles(td pprofile.Profiles) pprofile.Profiles { clonedProfiles := pprofile.NewProfiles() td.CopyTo(clonedProfiles) return clonedProfiles } opentelemetry-collector-0.141.0/internal/fanoutconsumer/profiles_test.go000066400000000000000000000164771511331344600266520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/testdata" ) func TestProfilesNotMultiplexing(t *testing.T) { nop := consumertest.NewNop() tfc := NewProfiles([]xconsumer.Profiles{nop}) assert.Same(t, nop, tfc) } func TestProfilesNotMultiplexingMutating(t *testing.T) { p := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} lfc := NewProfiles([]xconsumer.Profiles{p}) assert.True(t, lfc.Capabilities().MutatesData) } func TestProfilesMultiplexingNonMutating(t *testing.T) { p1 := new(consumertest.ProfilesSink) p2 := new(consumertest.ProfilesSink) p3 := new(consumertest.ProfilesSink) tfc := NewProfiles([]xconsumer.Profiles{p1, p2, p3}) assert.False(t, tfc.Capabilities().MutatesData) td := testdata.GenerateProfiles(1) for range 2 { err := tfc.ConsumeProfiles(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.Equal(t, td, p1.AllProfiles()[0]) assert.Equal(t, td, p1.AllProfiles()[1]) assert.Equal(t, td, p1.AllProfiles()[0]) assert.Equal(t, td, p1.AllProfiles()[1]) assert.Equal(t, td, p2.AllProfiles()[0]) assert.Equal(t, td, p2.AllProfiles()[1]) assert.Equal(t, td, p2.AllProfiles()[0]) assert.Equal(t, td, p2.AllProfiles()[1]) assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) // The data should be marked as read only. assert.True(t, td.IsReadOnly()) } func TestProfilesMultiplexingMutating(t *testing.T) { p1 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} p2 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} p3 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} tfc := NewProfiles([]xconsumer.Profiles{p1, p2, p3}) assert.True(t, tfc.Capabilities().MutatesData) td := testdata.GenerateProfiles(1) for range 2 { err := tfc.ConsumeProfiles(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &td, &p1.AllProfiles()[0]) assert.NotSame(t, &td, &p1.AllProfiles()[1]) assert.Equal(t, td, p1.AllProfiles()[0]) assert.Equal(t, td, p1.AllProfiles()[1]) assert.NotSame(t, &td, &p2.AllProfiles()[0]) assert.NotSame(t, &td, &p2.AllProfiles()[1]) assert.Equal(t, td, p2.AllProfiles()[0]) assert.Equal(t, td, p2.AllProfiles()[1]) // For this consumer, will receive the initial data. assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) // The data should not be marked as read only. assert.False(t, td.IsReadOnly()) } func TestReadOnlyProfilesMultiplexingMutating(t *testing.T) { p1 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} p2 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} p3 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} tfc := NewProfiles([]xconsumer.Profiles{p1, p2, p3}) assert.True(t, tfc.Capabilities().MutatesData) tdOrig := testdata.GenerateProfiles(1) td := testdata.GenerateProfiles(1) td.MarkReadOnly() for range 2 { err := tfc.ConsumeProfiles(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } // All consumers should receive the cloned data. assert.NotEqual(t, td, p1.AllProfiles()[0]) assert.NotEqual(t, td, p1.AllProfiles()[1]) assert.Equal(t, tdOrig, p1.AllProfiles()[0]) assert.Equal(t, tdOrig, p1.AllProfiles()[1]) assert.NotEqual(t, td, p2.AllProfiles()[0]) assert.NotEqual(t, td, p2.AllProfiles()[1]) assert.Equal(t, tdOrig, p2.AllProfiles()[0]) assert.Equal(t, tdOrig, p2.AllProfiles()[1]) assert.NotEqual(t, td, p3.AllProfiles()[0]) assert.NotEqual(t, td, p3.AllProfiles()[1]) assert.Equal(t, tdOrig, p3.AllProfiles()[0]) assert.Equal(t, tdOrig, p3.AllProfiles()[1]) } func TestProfilesMultiplexingMixLastMutating(t *testing.T) { p1 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} p2 := new(consumertest.ProfilesSink) p3 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} tfc := NewProfiles([]xconsumer.Profiles{p1, p2, p3}) assert.False(t, tfc.Capabilities().MutatesData) td := testdata.GenerateProfiles(1) for range 2 { err := tfc.ConsumeProfiles(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &td, &p1.AllProfiles()[0]) assert.NotSame(t, &td, &p1.AllProfiles()[1]) assert.Equal(t, td, p1.AllProfiles()[0]) assert.Equal(t, td, p1.AllProfiles()[1]) // For this consumer, will receive the initial data. assert.Equal(t, td, p2.AllProfiles()[0]) assert.Equal(t, td, p2.AllProfiles()[1]) assert.Equal(t, td, p2.AllProfiles()[0]) assert.Equal(t, td, p2.AllProfiles()[1]) // For this consumer, will clone the initial data. assert.NotSame(t, &td, &p3.AllProfiles()[0]) assert.NotSame(t, &td, &p3.AllProfiles()[1]) assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) // The data should not be marked as read only. assert.False(t, td.IsReadOnly()) } func TestProfilesMultiplexingMixLastNonMutating(t *testing.T) { p1 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} p2 := &mutatingProfilesSink{ProfilesSink: new(consumertest.ProfilesSink)} p3 := new(consumertest.ProfilesSink) tfc := NewProfiles([]xconsumer.Profiles{p1, p2, p3}) assert.False(t, tfc.Capabilities().MutatesData) td := testdata.GenerateProfiles(1) for range 2 { err := tfc.ConsumeProfiles(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &td, &p1.AllProfiles()[0]) assert.NotSame(t, &td, &p1.AllProfiles()[1]) assert.Equal(t, td, p1.AllProfiles()[0]) assert.Equal(t, td, p1.AllProfiles()[1]) assert.NotSame(t, &td, &p2.AllProfiles()[0]) assert.NotSame(t, &td, &p2.AllProfiles()[1]) assert.Equal(t, td, p2.AllProfiles()[0]) assert.Equal(t, td, p2.AllProfiles()[1]) // For this consumer, will receive the initial data. assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) // The data should not be marked as read only. assert.False(t, td.IsReadOnly()) } func TestProfilesWhenErrors(t *testing.T) { p1 := mutatingErr{Consumer: consumertest.NewErr(errors.New("my error"))} p2 := consumertest.NewErr(errors.New("my error")) p3 := new(consumertest.ProfilesSink) tfc := NewProfiles([]xconsumer.Profiles{p1, p2, p3}) td := testdata.GenerateProfiles(1) for range 2 { require.Error(t, tfc.ConsumeProfiles(context.Background(), td)) } assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) assert.Equal(t, td, p3.AllProfiles()[0]) assert.Equal(t, td, p3.AllProfiles()[1]) } type mutatingProfilesSink struct { *consumertest.ProfilesSink } func (mts *mutatingProfilesSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } opentelemetry-collector-0.141.0/internal/fanoutconsumer/traces.go000066400000000000000000000053241511331344600252360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer // import "go.opentelemetry.io/collector/internal/fanoutconsumer" import ( "context" "go.uber.org/multierr" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/ptrace" ) // NewTraces wraps multiple trace consumers in a single one. // It fans out the incoming data to all the consumers, and does smart routing: // - Clones only to the consumer that needs to mutate the data. // - If all consumers needs to mutate the data one will get the original mutable data. func NewTraces(tcs []consumer.Traces) consumer.Traces { // Don't wrap if there is only one non-mutating consumer. if len(tcs) == 1 && !tcs[0].Capabilities().MutatesData { return tcs[0] } tc := &tracesConsumer{} for i := range tcs { if tcs[i].Capabilities().MutatesData { tc.mutable = append(tc.mutable, tcs[i]) } else { tc.readonly = append(tc.readonly, tcs[i]) } } return tc } type tracesConsumer struct { mutable []consumer.Traces readonly []consumer.Traces } func (tsc *tracesConsumer) Capabilities() consumer.Capabilities { // If all consumers are mutating, then the original data will be passed to one of them. return consumer.Capabilities{MutatesData: len(tsc.mutable) > 0 && len(tsc.readonly) == 0} } // ConsumeTraces exports the ptrace.Traces to all consumers wrapped by the current one. func (tsc *tracesConsumer) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { var errs error if len(tsc.mutable) > 0 { // Clone the data before sending to all mutating consumers except the last one. for i := 0; i < len(tsc.mutable)-1; i++ { errs = multierr.Append(errs, tsc.mutable[i].ConsumeTraces(ctx, cloneTraces(td))) } // Send data as is to the last mutating consumer only if there are no other non-mutating consumers and the // data is mutable. Never share the same data between a mutating and a non-mutating consumer since the // non-mutating consumer may process data async and the mutating consumer may change the data before that. lastConsumer := tsc.mutable[len(tsc.mutable)-1] if len(tsc.readonly) == 0 && !td.IsReadOnly() { errs = multierr.Append(errs, lastConsumer.ConsumeTraces(ctx, td)) } else { errs = multierr.Append(errs, lastConsumer.ConsumeTraces(ctx, cloneTraces(td))) } } // Mark the data as read-only if it will be sent to more than one read-only consumer. if len(tsc.readonly) > 1 && !td.IsReadOnly() { td.MarkReadOnly() } for _, tc := range tsc.readonly { errs = multierr.Append(errs, tc.ConsumeTraces(ctx, td)) } return errs } func cloneTraces(td ptrace.Traces) ptrace.Traces { clonedTraces := ptrace.NewTraces() td.CopyTo(clonedTraces) return clonedTraces } opentelemetry-collector-0.141.0/internal/fanoutconsumer/traces_test.go000066400000000000000000000157451511331344600263050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package fanoutconsumer import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/testdata" ) func TestTracesNotMultiplexing(t *testing.T) { nop := consumertest.NewNop() tfc := NewTraces([]consumer.Traces{nop}) assert.Same(t, nop, tfc) } func TestTracesNotMultiplexingMutating(t *testing.T) { p := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} lfc := NewTraces([]consumer.Traces{p}) assert.True(t, lfc.Capabilities().MutatesData) } func TestTracesMultiplexingNonMutating(t *testing.T) { p1 := new(consumertest.TracesSink) p2 := new(consumertest.TracesSink) p3 := new(consumertest.TracesSink) tfc := NewTraces([]consumer.Traces{p1, p2, p3}) assert.False(t, tfc.Capabilities().MutatesData) td := testdata.GenerateTraces(1) for range 2 { err := tfc.ConsumeTraces(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.Equal(t, td, p1.AllTraces()[0]) assert.Equal(t, td, p1.AllTraces()[1]) assert.Equal(t, td, p1.AllTraces()[0]) assert.Equal(t, td, p1.AllTraces()[1]) assert.Equal(t, td, p2.AllTraces()[0]) assert.Equal(t, td, p2.AllTraces()[1]) assert.Equal(t, td, p2.AllTraces()[0]) assert.Equal(t, td, p2.AllTraces()[1]) assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) // The data should be marked as read only. assert.True(t, td.IsReadOnly()) } func TestTracesMultiplexingMutating(t *testing.T) { p1 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} p2 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} p3 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} tfc := NewTraces([]consumer.Traces{p1, p2, p3}) assert.True(t, tfc.Capabilities().MutatesData) td := testdata.GenerateTraces(1) for range 2 { err := tfc.ConsumeTraces(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &td, &p1.AllTraces()[0]) assert.NotSame(t, &td, &p1.AllTraces()[1]) assert.Equal(t, td, p1.AllTraces()[0]) assert.Equal(t, td, p1.AllTraces()[1]) assert.NotSame(t, &td, &p2.AllTraces()[0]) assert.NotSame(t, &td, &p2.AllTraces()[1]) assert.Equal(t, td, p2.AllTraces()[0]) assert.Equal(t, td, p2.AllTraces()[1]) // For this consumer, will receive the initial data. assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) // The data should not be marked as read only. assert.False(t, td.IsReadOnly()) } func TestReadOnlyTracesMultiplexingMutating(t *testing.T) { p1 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} p2 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} p3 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} tfc := NewTraces([]consumer.Traces{p1, p2, p3}) assert.True(t, tfc.Capabilities().MutatesData) tdOrig := testdata.GenerateTraces(1) td := testdata.GenerateTraces(1) td.MarkReadOnly() for range 2 { err := tfc.ConsumeTraces(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } // All consumers should receive the cloned data. assert.NotEqual(t, td, p1.AllTraces()[0]) assert.NotEqual(t, td, p1.AllTraces()[1]) assert.Equal(t, tdOrig, p1.AllTraces()[0]) assert.Equal(t, tdOrig, p1.AllTraces()[1]) assert.NotEqual(t, td, p2.AllTraces()[0]) assert.NotEqual(t, td, p2.AllTraces()[1]) assert.Equal(t, tdOrig, p2.AllTraces()[0]) assert.Equal(t, tdOrig, p2.AllTraces()[1]) assert.NotEqual(t, td, p3.AllTraces()[0]) assert.NotEqual(t, td, p3.AllTraces()[1]) assert.Equal(t, tdOrig, p3.AllTraces()[0]) assert.Equal(t, tdOrig, p3.AllTraces()[1]) } func TestTracesMultiplexingMixLastMutating(t *testing.T) { p1 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} p2 := new(consumertest.TracesSink) p3 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} tfc := NewTraces([]consumer.Traces{p1, p2, p3}) assert.False(t, tfc.Capabilities().MutatesData) td := testdata.GenerateTraces(1) for range 2 { err := tfc.ConsumeTraces(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &td, &p1.AllTraces()[0]) assert.NotSame(t, &td, &p1.AllTraces()[1]) assert.Equal(t, td, p1.AllTraces()[0]) assert.Equal(t, td, p1.AllTraces()[1]) // For this consumer, will receive the initial data. assert.Equal(t, td, p2.AllTraces()[0]) assert.Equal(t, td, p2.AllTraces()[1]) assert.Equal(t, td, p2.AllTraces()[0]) assert.Equal(t, td, p2.AllTraces()[1]) // For this consumer, will clone the initial data. assert.NotSame(t, &td, &p3.AllTraces()[0]) assert.NotSame(t, &td, &p3.AllTraces()[1]) assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) // The data should not be marked as read only. assert.False(t, td.IsReadOnly()) } func TestTracesMultiplexingMixLastNonMutating(t *testing.T) { p1 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} p2 := &mutatingTracesSink{TracesSink: new(consumertest.TracesSink)} p3 := new(consumertest.TracesSink) tfc := NewTraces([]consumer.Traces{p1, p2, p3}) assert.False(t, tfc.Capabilities().MutatesData) td := testdata.GenerateTraces(1) for range 2 { err := tfc.ConsumeTraces(context.Background(), td) if err != nil { t.Errorf("Wanted nil got error") return } } assert.NotSame(t, &td, &p1.AllTraces()[0]) assert.NotSame(t, &td, &p1.AllTraces()[1]) assert.Equal(t, td, p1.AllTraces()[0]) assert.Equal(t, td, p1.AllTraces()[1]) assert.NotSame(t, &td, &p2.AllTraces()[0]) assert.NotSame(t, &td, &p2.AllTraces()[1]) assert.Equal(t, td, p2.AllTraces()[0]) assert.Equal(t, td, p2.AllTraces()[1]) // For this consumer, will receive the initial data. assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) // The data should not be marked as read only. assert.False(t, td.IsReadOnly()) } func TestTracesWhenErrors(t *testing.T) { p1 := mutatingErr{Consumer: consumertest.NewErr(errors.New("my error"))} p2 := consumertest.NewErr(errors.New("my error")) p3 := new(consumertest.TracesSink) tfc := NewTraces([]consumer.Traces{p1, p2, p3}) td := testdata.GenerateTraces(1) for range 2 { require.Error(t, tfc.ConsumeTraces(context.Background(), td)) } assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) assert.Equal(t, td, p3.AllTraces()[0]) assert.Equal(t, td, p3.AllTraces()[1]) } type mutatingTracesSink struct { *consumertest.TracesSink } func (mts *mutatingTracesSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } opentelemetry-collector-0.141.0/internal/memorylimiter/000077500000000000000000000000001511331344600232505ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/Makefile000066400000000000000000000000361511331344600247070ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/000077500000000000000000000000001511331344600247325ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/cgroup.go000066400000000000000000000047711511331344600265710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups // import "go.opentelemetry.io/collector/internal/memorylimiter/cgroups" import ( "bufio" "io" "os" "path/filepath" "strconv" ) // CGroup represents the data structure for a Linux control group. type CGroup struct { path string } // NewCGroup returns a new *CGroup from a given path. func NewCGroup(path string) *CGroup { return &CGroup{path: path} } // Path returns the path of the CGroup*. func (cg *CGroup) Path() string { return cg.path } // ParamPath returns the path of the given cgroup param under itself. func (cg *CGroup) ParamPath(param string) string { return filepath.Join(cg.path, param) } // readFirstLine reads the first line from a cgroup param file. func (cg *CGroup) readFirstLine(param string) (string, error) { paramFile, err := os.Open(cg.ParamPath(param)) if err != nil { return "", err } defer paramFile.Close() scanner := bufio.NewScanner(paramFile) if scanner.Scan() { return scanner.Text(), nil } if err := scanner.Err(); err != nil { return "", err } return "", io.ErrUnexpectedEOF } // readInt parses the first line from a cgroup param file as int. func (cg *CGroup) readInt(param string) (int64, error) { text, err := cg.readFirstLine(param) if err != nil { return 0, err } return strconv.ParseInt(text, 10, 64) } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/cgroup_test.go000066400000000000000000000067301511331344600276250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" ) func TestCGroupParamPath(t *testing.T) { cgroup := NewCGroup("/sys/fs/cgroup/cpu") assert.Equal(t, "/sys/fs/cgroup/cpu", cgroup.Path()) assert.Equal(t, "/sys/fs/cgroup/cpu/cpu.cfs_quota_us", cgroup.ParamPath("cpu.cfs_quota_us")) } func TestCGroupReadFirstLine(t *testing.T) { testTable := []struct { name string paramName string expectedContent string shouldHaveError bool }{ { name: "cpu", paramName: "cpu.cfs_period_us", expectedContent: "100000", shouldHaveError: false, }, { name: "absent", paramName: "cpu.stat", expectedContent: "", shouldHaveError: true, }, { name: "empty", paramName: "cpu.cfs_quota_us", expectedContent: "", shouldHaveError: true, }, } for _, tt := range testTable { cgroupPath := filepath.Join(testDataCGroupsPath, tt.name) cgroup := NewCGroup(cgroupPath) content, err := cgroup.readFirstLine(tt.paramName) assert.Equal(t, tt.expectedContent, content, tt.name) if tt.shouldHaveError { assert.Error(t, err, tt.name) } else { assert.NoError(t, err, tt.name) } } } func TestCGroupReadInt(t *testing.T) { testTable := []struct { name string paramName string expectedValue int64 shouldHaveError bool }{ { name: "cpu", paramName: "cpu.cfs_period_us", expectedValue: 100000, shouldHaveError: false, }, { name: "empty", paramName: "cpu.cfs_quota_us", expectedValue: 0, shouldHaveError: true, }, { name: "invalid", paramName: "cpu.cfs_quota_us", expectedValue: 0, shouldHaveError: true, }, { name: "absent", paramName: "cpu.cfs_quota_us", expectedValue: 0, shouldHaveError: true, }, } for _, tt := range testTable { cgroupPath := filepath.Join(testDataCGroupsPath, tt.name) cgroup := NewCGroup(cgroupPath) value, err := cgroup.readInt(tt.paramName) assert.Equal(t, tt.expectedValue, value, "%s/%s", tt.name, tt.paramName) if tt.shouldHaveError { assert.Error(t, err, tt.name) } else { assert.NoError(t, err, tt.name) } } } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/cgroups.go000066400000000000000000000130601511331344600267430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups // import "go.opentelemetry.io/collector/internal/memorylimiter/cgroups" import ( "bufio" "io" "os" "path/filepath" "strconv" "strings" ) const ( // _cgroupFSType is the Linux CGroup file system type used in // `/proc/$PID/mountinfo`. _cgroupFSType = "cgroup" // _cgroupSubsysCPU is the CPU CGroup subsystem. _cgroupSubsysCPU = "cpu" // _cgroupSubsysCPUAcct is the CPU accounting CGroup subsystem. _cgroupSubsysCPUAcct = "cpuacct" // _cgroupSubsysCPUSet is the CPUSet CGroup subsystem. _cgroupSubsysCPUSet = "cpuset" // _cgroupSubsysMemory is the Memory CGroup subsystem. _cgroupSubsysMemory = "memory" _cgroupMemoryLimitBytes = "memory.limit_in_bytes" // _cgroupv2MemoryMax is the file name for the CGroup-V2 Memory max // parameter. _cgroupv2MemoryMax = "memory.max" // _cgroupFSType is the Linux CGroup-V2 file system type used in // `/proc/$PID/mountinfo`. _cgroupv2FSType = "cgroup2" ) const ( _procPathCGroup = "/proc/self/cgroup" _procPathMountInfo = "/proc/self/mountinfo" _cgroupv2MountPoint = "/sys/fs/cgroup" ) // CGroups is a map that associates each CGroup with its subsystem name. type CGroups map[string]*CGroup // NewCGroups returns a new *CGroups from given `mountinfo` and `cgroup` files // under for some process under `/proc` file system (see also proc(5) for more // information). func NewCGroups(procPathMountInfo, procPathCGroup string) (CGroups, error) { cgroupSubsystems, err := parseCGroupSubsystems(procPathCGroup) if err != nil { return nil, err } cgroups := make(CGroups) newMountPoint := func(mp *MountPoint) error { if mp.FSType != _cgroupFSType { return nil } for _, opt := range mp.SuperOptions { subsys, exists := cgroupSubsystems[opt] if !exists { continue } cgroupPath, err := mp.Translate(subsys.Name) if err != nil { return err } if strings.HasPrefix(cgroupPath, "/sys") { cgroups[opt] = NewCGroup(cgroupPath) } } return nil } if err := parseMountInfo(procPathMountInfo, newMountPoint); err != nil { return nil, err } return cgroups, nil } // NewCGroupsForCurrentProcess returns a new *CGroups instance for the current // process. func NewCGroupsForCurrentProcess() (CGroups, error) { return NewCGroups(_procPathMountInfo, _procPathCGroup) } // MemoryQuota returns the total memory limit of the process // It is a result of `memory.limit_in_bytes`. If the value of // `memory.limit_in_bytes` was not set (-1) or (9223372036854771712), the method returns `(-1, false, nil)`. func (cg CGroups) MemoryQuota() (int64, bool, error) { memCGroup, exists := cg[_cgroupSubsysMemory] if !exists { return -1, false, nil } memLimitBytes, err := memCGroup.readInt(_cgroupMemoryLimitBytes) if defined := memLimitBytes > 0; err != nil || !defined { return -1, defined, err } return memLimitBytes, true, nil } // IsCGroupV2 returns true if the system supports and uses cgroup2. // It gets the required information for deciding from mountinfo file. func IsCGroupV2() (bool, error) { return isCGroupV2(_procPathMountInfo) } func isCGroupV2(procPathMountInfo string) (bool, error) { isV2 := false newMountPoint := func(mp *MountPoint) error { if mp.FSType == _cgroupv2FSType && mp.MountPoint == _cgroupv2MountPoint { isV2 = true } return nil } if err := parseMountInfo(procPathMountInfo, newMountPoint); err != nil { return false, err } return isV2, nil } // MemoryQuotaV2 returns the total memory limit of the process // It is a result of cgroupv2 `memory.max`. If the value of // `memory.max` was not set (max), the method returns `(-1, false, nil)`. func MemoryQuotaV2() (int64, bool, error) { return memoryQuotaV2(_cgroupv2MountPoint, _cgroupv2MemoryMax) } func memoryQuotaV2(cgroupv2MountPoint, cgroupv2MemoryMax string) (int64, bool, error) { memoryMaxParams, err := os.Open(filepath.Clean(filepath.Join(cgroupv2MountPoint, cgroupv2MemoryMax))) if err != nil { if os.IsNotExist(err) { return -1, false, nil } return -1, false, err } scanner := bufio.NewScanner(memoryMaxParams) if scanner.Scan() { value := strings.TrimSpace(scanner.Text()) if value == "max" { return -1, false, nil } maxVal, err := strconv.ParseInt(value, 10, 64) if err != nil { return -1, false, err } return maxVal, true, nil } if err := scanner.Err(); err != nil { return -1, false, err } return -1, false, io.ErrUnexpectedEOF } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/cgroups_test.go000066400000000000000000000140401511331344600300010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewCGroups(t *testing.T) { cgroupsProcCGroupPath := filepath.Join(testDataProcPath, "cgroups", "cgroup") cgroupsProcMountInfoPath := filepath.Join(testDataProcPath, "cgroups", "mountinfo") testTable := []struct { subsys string path string }{ {_cgroupSubsysCPU, "/sys/fs/cgroup/cpu,cpuacct"}, {_cgroupSubsysCPUAcct, "/sys/fs/cgroup/cpu,cpuacct"}, {_cgroupSubsysCPUSet, "/sys/fs/cgroup/cpuset"}, {_cgroupSubsysMemory, "/sys/fs/cgroup/memory/large"}, } cgroups, err := NewCGroups(cgroupsProcMountInfoPath, cgroupsProcCGroupPath) assert.Len(t, cgroups, len(testTable)) require.NoError(t, err) for _, tt := range testTable { cgroup, exists := cgroups[tt.subsys] assert.True(t, exists, "%q expected to present in `cgroups`", tt.subsys) assert.Equal(t, tt.path, cgroup.path, "%q expected for `cgroups[%q].path`, got %q", tt.path, tt.subsys, cgroup.path) } } func TestNewCGroupsWithErrors(t *testing.T) { testTable := []struct { mountInfoPath string cgroupPath string }{ {"non-existing-file", "/dev/null"}, {"/dev/null", "non-existing-file"}, { "/dev/null", filepath.Join(testDataProcPath, "invalid-cgroup", "cgroup"), }, { filepath.Join(testDataProcPath, "invalid-mountinfo", "mountinfo"), "/dev/null", }, { filepath.Join(testDataProcPath, "untranslatable", "mountinfo"), filepath.Join(testDataProcPath, "untranslatable", "cgroup"), }, } for _, tt := range testTable { cgroups, err := NewCGroups(tt.mountInfoPath, tt.cgroupPath) assert.Nil(t, cgroups) assert.Error(t, err) } } func TestCGroupsMemoryQuota(t *testing.T) { testTable := []struct { name string expectedQuota int64 expectedDefined bool shouldHaveError bool }{ { name: "undefined", expectedQuota: int64(-1.0), expectedDefined: false, shouldHaveError: true, }, { name: "memory", expectedQuota: int64(8796093018112), expectedDefined: true, shouldHaveError: false, }, } cgroups := make(CGroups) quota, defined, err := cgroups.MemoryQuota() assert.Equal(t, int64(-1), quota, "nonexistent") assert.False(t, defined, "nonexistent") require.NoError(t, err, "nonexistent") for _, tt := range testTable { cgroupPath := filepath.Join(testDataCGroupsPath, tt.name) cgroups[_cgroupSubsysMemory] = NewCGroup(cgroupPath) quota, defined, err := cgroups.MemoryQuota() assert.Equal(t, tt.expectedQuota, quota, tt.name) assert.Equal(t, tt.expectedDefined, defined, tt.name) if tt.shouldHaveError { assert.Error(t, err, tt.name) } else { assert.NoError(t, err, tt.name) } } } func TestCGroupsIsCGroupV2(t *testing.T) { testTable := []struct { name string expectedIsV2 bool shouldHaveError bool }{ { name: "cgroupv1", expectedIsV2: false, shouldHaveError: false, }, { name: "cgroupv1v2", expectedIsV2: false, shouldHaveError: false, }, { name: "cgroupv2", expectedIsV2: true, shouldHaveError: false, }, { name: "nonexistent", expectedIsV2: false, shouldHaveError: true, }, } for _, tt := range testTable { mountInfoPath := filepath.Join(testDataProcPath, "v2", tt.name, "mountinfo") isV2, err := isCGroupV2(mountInfoPath) assert.Equal(t, tt.expectedIsV2, isV2, tt.name) if tt.shouldHaveError { assert.Error(t, err, tt.name) } else { assert.NoError(t, err, tt.name) } } } func TestCGroupsMemoryQuotaV2(t *testing.T) { testTable := []struct { name string expectedQuota int64 expectedDefined bool shouldHaveError bool }{ { name: "memory", expectedQuota: int64(250000000), expectedDefined: true, shouldHaveError: false, }, { name: "undefined", expectedQuota: int64(-1), expectedDefined: false, shouldHaveError: false, }, { name: "invalid", expectedQuota: int64(-1), expectedDefined: false, shouldHaveError: true, }, { name: "empty", expectedQuota: int64(-1), expectedDefined: false, shouldHaveError: true, }, } quota, defined, err := memoryQuotaV2("nonexistent", "nonexistent") assert.Equal(t, int64(-1), quota, "nonexistent") assert.False(t, defined, "nonexistent") require.NoError(t, err, "nonexistent") cgroupBasePath := filepath.Join(testDataCGroupsPath, "v2") for _, tt := range testTable { cgroupPath := filepath.Join(cgroupBasePath, tt.name) quota, defined, err := memoryQuotaV2(cgroupPath, "memory.max") assert.Equal(t, tt.expectedQuota, quota, tt.name) assert.Equal(t, tt.expectedDefined, defined, tt.name) if tt.shouldHaveError { assert.Error(t, err, tt.name) } else { assert.NoError(t, err, tt.name) } } } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/doc.go000066400000000000000000000030201511331344600260210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // Package cgroups provides utilities to access Linux control group (CGroups) // parameters (total memory, for example) for a given process. // The original implementation is taken from https://github.com/uber-go/automaxprocs package cgroups // import "go.opentelemetry.io/collector/internal/memorylimiter/cgroups" opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/errors.go000066400000000000000000000040011511331344600265700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups // import "go.opentelemetry.io/collector/internal/memorylimiter/cgroups" import "fmt" type cgroupSubsysFormatInvalidError struct { line string } type mountPointFormatInvalidError struct { line string } type pathNotExposedFromMountPointError struct { mountPoint string root string path string } func (err cgroupSubsysFormatInvalidError) Error() string { return fmt.Sprintf("invalid format for CGroupSubsys: %q", err.line) } func (err mountPointFormatInvalidError) Error() string { return fmt.Sprintf("invalid format for MountPoint: %q", err.line) } func (err pathNotExposedFromMountPointError) Error() string { return fmt.Sprintf("path %q is not a descendant of mount point root %q and cannot be exposed from %q", err.path, err.root, err.mountPoint) } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/mountpoint.go000066400000000000000000000116671511331344600275100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups // import "go.opentelemetry.io/collector/internal/memorylimiter/cgroups" import ( "bufio" "os" "path/filepath" "strconv" "strings" ) const ( _mountInfoSep = " " _mountInfoOptsSep = "," _mountInfoOptionalFieldsSep = "-" ) const ( _miFieldIDMountID = iota _miFieldIDParentID _miFieldIDDeviceID _miFieldIDRoot _miFieldIDMountPoint _miFieldIDOptions _miFieldIDOptionalFields _miFieldCountFirstHalf ) const ( _miFieldOffsetFSType = iota _miFieldOffsetMountSource _miFieldOffsetSuperOptions _miFieldCountSecondHalf ) const _miFieldCountMin = _miFieldCountFirstHalf + _miFieldCountSecondHalf // MountPoint is the data structure for the mount points in // `/proc/$PID/mountinfo`. See also proc(5) for more information. type MountPoint struct { MountID int ParentID int DeviceID string Root string MountPoint string Options []string OptionalFields []string FSType string MountSource string SuperOptions []string } // NewMountPointFromLine parses a line read from `/proc/$PID/mountinfo` and // returns a new *MountPoint. func NewMountPointFromLine(line string) (*MountPoint, error) { fields := strings.Split(line, _mountInfoSep) if len(fields) < _miFieldCountMin { return nil, mountPointFormatInvalidError{line} } mountID, err := strconv.Atoi(fields[_miFieldIDMountID]) if err != nil { return nil, err } parentID, err := strconv.Atoi(fields[_miFieldIDParentID]) if err != nil { return nil, err } for i, field := range fields[_miFieldIDOptionalFields:] { if field != _mountInfoOptionalFieldsSep { continue } fsTypeStart := _miFieldIDOptionalFields + i + 1 if len(fields) != fsTypeStart+_miFieldCountSecondHalf { return nil, mountPointFormatInvalidError{line} } miFieldIDFSType := _miFieldOffsetFSType + fsTypeStart miFieldIDMountSource := _miFieldOffsetMountSource + fsTypeStart miFieldIDSuperOptions := _miFieldOffsetSuperOptions + fsTypeStart return &MountPoint{ MountID: mountID, ParentID: parentID, DeviceID: fields[_miFieldIDDeviceID], Root: fields[_miFieldIDRoot], MountPoint: fields[_miFieldIDMountPoint], Options: strings.Split(fields[_miFieldIDOptions], _mountInfoOptsSep), OptionalFields: fields[_miFieldIDOptionalFields:(fsTypeStart - 1)], FSType: fields[miFieldIDFSType], MountSource: fields[miFieldIDMountSource], SuperOptions: strings.Split(fields[miFieldIDSuperOptions], _mountInfoOptsSep), }, nil } return nil, mountPointFormatInvalidError{line} } // Translate converts an absolute path inside the *MountPoint's file system to // the host file system path in the mount namespace the *MountPoint belongs to. func (mp *MountPoint) Translate(absPath string) (string, error) { relPath, err := filepath.Rel(mp.Root, absPath) if err != nil { return "", err } if relPath == ".." || strings.HasPrefix(relPath, "../") { return "", pathNotExposedFromMountPointError{ mountPoint: mp.MountPoint, root: mp.Root, path: absPath, } } return filepath.Join(mp.MountPoint, relPath), nil } // parseMountInfo parses procPathMountInfo (usually at `/proc/$PID/mountinfo`) // and yields parsed *MountPoint into newMountPoint. func parseMountInfo(procPathMountInfo string, newMountPoint func(*MountPoint) error) error { mountInfoFile, err := os.Open(filepath.Clean(procPathMountInfo)) if err != nil { return err } defer mountInfoFile.Close() scanner := bufio.NewScanner(mountInfoFile) for scanner.Scan() { mountPoint, err := NewMountPointFromLine(scanner.Text()) if err != nil { return err } if err := newMountPoint(mountPoint); err != nil { return err } } return scanner.Err() } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/mountpoint_test.go000066400000000000000000000137631511331344600305460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNewMountPointFromLine(t *testing.T) { testTable := []struct { name string line string expected *MountPoint }{ { name: "root", line: "1 0 252:0 / / rw,noatime - ext4 /dev/dm-0 rw,errors=remount-ro,data=ordered", expected: &MountPoint{ MountID: 1, ParentID: 0, DeviceID: "252:0", Root: "/", MountPoint: "/", Options: []string{"rw", "noatime"}, OptionalFields: []string{}, FSType: "ext4", MountSource: "/dev/dm-0", SuperOptions: []string{"rw", "errors=remount-ro", "data=ordered"}, }, }, { name: "cgroup", line: "31 23 0:24 /docker /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime shared:1 - cgroup cgroup rw,cpu", expected: &MountPoint{ MountID: 31, ParentID: 23, DeviceID: "0:24", Root: "/docker", MountPoint: "/sys/fs/cgroup/cpu", Options: []string{"rw", "nosuid", "nodev", "noexec", "relatime"}, OptionalFields: []string{"shared:1"}, FSType: "cgroup", MountSource: "cgroup", SuperOptions: []string{"rw", "cpu"}, }, }, } for _, tt := range testTable { mountPoint, err := NewMountPointFromLine(tt.line) assert.Equal(t, tt.expected, mountPoint, tt.name) assert.NoError(t, err, tt.name) } } func TestNewMountPointFromLineErr(t *testing.T) { linesWithInvalidIDs := []string{ "invalidMountID 0 252:0 / / rw,noatime - ext4 /dev/dm-0 rw,errors=remount-ro,data=ordered", "1 invalidParentID 252:0 / / rw,noatime - ext4 /dev/dm-0 rw,errors=remount-ro,data=ordered", "invalidMountID invalidParentID 252:0 / / rw,noatime - ext4 /dev/dm-0 rw,errors=remount-ro,data=ordered", } for i, line := range linesWithInvalidIDs { mountPoint, err := NewMountPointFromLine(line) assert.Nil(t, mountPoint, "[%d] %q", i, line) require.Error(t, err, line) } linesWithInvalidFields := []string{ "1 0 252:0 / / rw,noatime ext4 /dev/dm-0 rw,errors=remount-ro,data=ordered", "1 0 252:0 / / rw,noatime shared:1 - ext4 /dev/dm-0", "1 0 252:0 / / rw,noatime shared:1 ext4 - /dev/dm-0 rw,errors=remount-ro,data=ordered", "1 0 252:0 / / rw,noatime shared:1 ext4 /dev/dm-0 rw,errors=remount-ro,data=ordered", "random line", } for i, line := range linesWithInvalidFields { mountPoint, err := NewMountPointFromLine(line) errExpected := mountPointFormatInvalidError{line} assert.Nil(t, mountPoint, "[%d] %q", i, line) assert.Equal(t, errExpected, err, "[%d] %q", i, line) } } func TestMountPointTranslate(t *testing.T) { line := "31 23 0:24 /docker/0123456789abcdef /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime shared:1 - cgroup cgroup rw,cpu" cgroupMountPoint, err := NewMountPointFromLine(line) assert.NotNil(t, cgroupMountPoint) require.NoError(t, err) testTable := []struct { name string pathToTranslate string pathTranslated string }{ { name: "root", pathToTranslate: "/docker/0123456789abcdef", pathTranslated: "/sys/fs/cgroup/cpu", }, { name: "root-with-extra-slash", pathToTranslate: "/docker/0123456789abcdef/", pathTranslated: "/sys/fs/cgroup/cpu", }, { name: "descendant-from-root", pathToTranslate: "/docker/0123456789abcdef/large/cpu.cfs_quota_us", pathTranslated: "/sys/fs/cgroup/cpu/large/cpu.cfs_quota_us", }, } for _, tt := range testTable { path, err := cgroupMountPoint.Translate(tt.pathToTranslate) assert.Equal(t, tt.pathTranslated, path, tt.name) assert.NoError(t, err, tt.name) } } func TestMountPointTranslateError(t *testing.T) { line := "31 23 0:24 /docker/0123456789abcdef /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime shared:1 - cgroup cgroup rw,cpu" cgroupMountPoint, err := NewMountPointFromLine(line) assert.NotNil(t, cgroupMountPoint) require.NoError(t, err) inaccessiblePaths := []string{ "/", "/docker", "/docker/0123456789abcdef-let-me-hack-this-path", "/docker/0123456789abcde/abc/../../def", "/system.slice/docker.service", } for i, path := range inaccessiblePaths { translated, err := cgroupMountPoint.Translate(path) errExpected := pathNotExposedFromMountPointError{ mountPoint: cgroupMountPoint.MountPoint, root: cgroupMountPoint.Root, path: path, } assert.Empty(t, translated, "inaccessiblePaths[%d] == %q", i, path) assert.Equal(t, errExpected, err, "inaccessiblePaths[%d] == %q", i, path) } relPaths := []string{ "docker", "docker/0123456789abcde/large", "system.slice/docker.service", } for i, path := range relPaths { translated, err := cgroupMountPoint.Translate(path) assert.Empty(t, translated, "relPaths[%d] == %q", i, path) assert.Error(t, err, path) } } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/package_test.go000066400000000000000000000003101511331344600277050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package cgroups import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/subsys.go000066400000000000000000000060171511331344600266150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups // import "go.opentelemetry.io/collector/internal/memorylimiter/cgroups" import ( "bufio" "os" "path/filepath" "strconv" "strings" ) const ( _cgroupSep = ":" _cgroupSubsysSep = "," ) const ( _csFieldIDID = iota _csFieldIDSubsystems _csFieldIDName _csFieldCount ) // CGroupSubsys represents the data structure for entities in // `/proc/$PID/cgroup`. See also proc(5) for more information. type CGroupSubsys struct { ID int Subsystems []string Name string } // NewCGroupSubsysFromLine returns a new *CGroupSubsys by parsing a string in // the format of `/proc/$PID/cgroup` func NewCGroupSubsysFromLine(line string) (*CGroupSubsys, error) { fields := strings.SplitN(line, _cgroupSep, _csFieldCount) if len(fields) != _csFieldCount { return nil, cgroupSubsysFormatInvalidError{line} } id, err := strconv.Atoi(fields[_csFieldIDID]) if err != nil { return nil, err } cgroup := &CGroupSubsys{ ID: id, Subsystems: strings.Split(fields[_csFieldIDSubsystems], _cgroupSubsysSep), Name: fields[_csFieldIDName], } return cgroup, nil } // parseCGroupSubsystems parses procPathCGroup (usually at `/proc/$PID/cgroup`) // and returns a new map[string]*CGroupSubsys. func parseCGroupSubsystems(procPathCGroup string) (map[string]*CGroupSubsys, error) { cgroupFile, err := os.Open(filepath.Clean(procPathCGroup)) if err != nil { return nil, err } defer cgroupFile.Close() scanner := bufio.NewScanner(cgroupFile) subsystems := make(map[string]*CGroupSubsys) for scanner.Scan() { cgroup, err := NewCGroupSubsysFromLine(scanner.Text()) if err != nil { return nil, err } for _, subsys := range cgroup.Subsystems { subsystems[subsys] = cgroup } } if err := scanner.Err(); err != nil { return nil, err } return subsystems, nil } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/subsys_test.go000066400000000000000000000056731511331344600276630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups import ( "strconv" "testing" "github.com/stretchr/testify/assert" ) func TestNewCGroupSubsysFromLine(t *testing.T) { testTable := []struct { name string line string expectedSubsys *CGroupSubsys }{ { name: "single-subsys", line: "1:cpu:/", expectedSubsys: &CGroupSubsys{ ID: 1, Subsystems: []string{"cpu"}, Name: "/", }, }, { name: "multi-subsys", line: "8:cpu,cpuacct,cpuset:/docker/1234567890abcdef", expectedSubsys: &CGroupSubsys{ ID: 8, Subsystems: []string{"cpu", "cpuacct", "cpuset"}, Name: "/docker/1234567890abcdef", }, }, { name: "sophisticated-path", line: "4:pids:/example.slice:extra-path-designator", expectedSubsys: &CGroupSubsys{ ID: 4, Subsystems: []string{"pids"}, Name: "/example.slice:extra-path-designator", }, }, } for _, tt := range testTable { subsys, err := NewCGroupSubsysFromLine(tt.line) assert.Equal(t, tt.expectedSubsys, subsys, tt.name) assert.NoError(t, err, tt.name) } } func TestNewCGroupSubsysFromLineErr(t *testing.T) { lines := []string{ "1:cpu", "not-a-number:cpu:/", } _, parseError := strconv.Atoi("not-a-number") testTable := []struct { name string line string expectedError error }{ { name: "fewer-fields", line: lines[0], expectedError: cgroupSubsysFormatInvalidError{lines[0]}, }, { name: "illegal-id", line: lines[1], expectedError: parseError, }, } for _, tt := range testTable { subsys, err := NewCGroupSubsysFromLine(tt.line) assert.Nil(t, subsys, tt.name) assert.Equal(t, tt.expectedError, err, tt.name) } } opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/000077500000000000000000000000001511331344600265435ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/000077500000000000000000000000001511331344600302255ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/cpu/000077500000000000000000000000001511331344600310145ustar00rootroot00000000000000cpu.cfs_period_us000066400000000000000000000000071511331344600342670ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/cpu100000 opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/cpu/cpu.cfs_quota_us000066400000000000000000000000071511331344600342150ustar00rootroot00000000000000600000 opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/empty/000077500000000000000000000000001511331344600313635ustar00rootroot00000000000000cpu.cfs_quota_us000066400000000000000000000000001511331344600344760ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/emptyopentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/invalid/000077500000000000000000000000001511331344600316535ustar00rootroot00000000000000cpu.cfs_quota_us000066400000000000000000000000171511331344600347760ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/invalidnon-an-integer opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/memory/000077500000000000000000000000001511331344600315355ustar00rootroot00000000000000memory.limit_in_bytes000066400000000000000000000000161511331344600357170ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/memory8796093018112 opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/undefined-period/000077500000000000000000000000001511331344600334465ustar00rootroot00000000000000cpu.cfs_quota_us000066400000000000000000000000071511331344600365700ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/undefined-period800000 opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/undefined/000077500000000000000000000000001511331344600321665ustar00rootroot00000000000000cpu.cfs_period_us000066400000000000000000000000071511331344600354410ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/undefined100000 cpu.cfs_quota_us000066400000000000000000000000031511331344600353040ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/undefined-1 opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/000077500000000000000000000000001511331344600305545ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/empty/000077500000000000000000000000001511331344600317125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/empty/memory.max000066400000000000000000000000001511331344600337170ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/invalid/000077500000000000000000000000001511331344600322025ustar00rootroot00000000000000memory.max000066400000000000000000000000041511331344600341340ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/invalidngn opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/memory/000077500000000000000000000000001511331344600320645ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/memory/memory.max000066400000000000000000000000121511331344600340740ustar00rootroot00000000000000250000000 opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/undefined/000077500000000000000000000000001511331344600325155ustar00rootroot00000000000000memory.max000066400000000000000000000000041511331344600344470ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/cgroups/v2/undefinedmax opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/000077500000000000000000000000001511331344600275065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/cgroups/000077500000000000000000000000001511331344600311705ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/cgroups/cgroup000066400000000000000000000000701511331344600324070ustar00rootroot000000000000003:memory:/docker/large 2:cpu,cpuacct:/docker 1:cpuset:/ opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/cgroups/mountinfo000066400000000000000000000021251511331344600331310ustar00rootroot000000000000001 0 8:1 / / rw,noatime shared:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=reordered 2 1 0:1 / /dev rw,relatime shared:2 - devtmpfs udev rw,size=10240k,nr_inodes=16487629,mode=755 3 1 0:2 / /proc rw,nosuid,nodev,noexec,relatime shared:3 - proc proc rw 4 1 0:3 / /sys rw,nosuid,nodev,noexec,relatime shared:4 - sysfs sysfs rw 5 4 0:4 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:5 - tmpfs tmpfs ro,mode=755 6 5 0:5 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:6 - cgroup cgroup rw,cpuset 7 5 0:6 /docker /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:7 - cgroup cgroup rw,cpu,cpuacct 8 5 0:7 /docker /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:8 - cgroup cgroup rw,memory 9 1 0:8 / /var/lib/docker/overlay2/9054a95f2cf7296867089e1bd37931742a17eb3308a795d51adb2654ee2276df/merged/sys/fs/cgroup ro,nosuid,nodev,noexec,relatime - tmpfs tmpfs rw,mode=755 10 9 0:9 /docker /var/lib/docker/overlay2/9054a95f2cf7296867089e1bd37931742a17eb3308a795d51adb2654ee2276df/merged/sys/fs/cgroup/memory ro,nosuid,nodev,noexec,relatime master:17 - cgroup cgroup rw,memory opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/invalid-cgroup/000077500000000000000000000000001511331344600324315ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/invalid-cgroup/cgroup000066400000000000000000000000311511331344600336450ustar00rootroot000000000000001:cpu:/cpu invalid-line: opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/invalid-mountinfo/000077500000000000000000000000001511331344600331505ustar00rootroot00000000000000mountinfo000066400000000000000000000000611511331344600350270ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/invalid-mountinfo1 0 8:1 / / rw,noatime shared:1 - ext4 /dev/sda1 opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/untranslatable/000077500000000000000000000000001511331344600325255ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/untranslatable/cgroup000066400000000000000000000000401511331344600337410ustar00rootroot000000000000001:cpu:/docker 2:cpuacct:/docker mountinfo000066400000000000000000000003371511331344600344120ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/untranslatable31 23 0:24 / /sys/fs/cgroup/cpu rw,nosuid,nodev,noexec,relatime shared:1 - cgroup cgroup rw,cpu 32 23 0:25 /docker/0123456789abcdef /sys/fs/cgroup/cpuacct rw,nosuid,nodev,noexec,relatime shared:2 - cgroup cgroup rw,cpuacct opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/v2/000077500000000000000000000000001511331344600300355ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/v2/cgroupv1/000077500000000000000000000000001511331344600316035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/v2/cgroupv1/mountinfo000066400000000000000000000013271511331344600335470ustar00rootroot000000000000001 0 8:1 / / rw,noatime shared:1 - ext4 /dev/sda1 rw,errors=remount-ro,data=reordered 2 1 0:1 / /dev rw,relatime shared:2 - devtmpfs udev rw,size=10240k,nr_inodes=16487629,mode=755 3 1 0:2 / /proc rw,nosuid,nodev,noexec,relatime shared:3 - proc proc rw 4 1 0:3 / /sys rw,nosuid,nodev,noexec,relatime shared:4 - sysfs sysfs rw 5 4 0:4 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:5 - tmpfs tmpfs ro,mode=755 6 5 0:5 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:6 - cgroup cgroup rw,cpuset 7 5 0:6 /docker /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:7 - cgroup cgroup rw,cpu,cpuacct 8 5 0:7 /docker /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:8 - cgroup cgroup rw,memory opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/v2/cgroupv1v2/000077500000000000000000000000001511331344600320535ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/v2/cgroupv1v2/mountinfo000066400000000000000000000030621511331344600340150ustar00rootroot0000000000000033 24 0:28 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755,inode64 34 33 0:29 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup2 rw,nsdelegate 35 33 0:30 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,xattr,name=systemd 39 33 0:34 / /sys/fs/cgroup/misc rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,misc 40 33 0:35 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,net_cls,net_prio 41 33 0:36 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,rdma 42 33 0:37 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,memory 43 33 0:38 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,blkio 44 33 0:39 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,cpu,cpuacct 45 33 0:40 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,pids 46 33 0:41 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:23 - cgroup cgroup rw,hugetlb 47 33 0:42 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:24 - cgroup cgroup rw,freezer 48 33 0:43 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:25 - cgroup cgroup rw,perf_event 49 33 0:44 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:26 - cgroup cgroup rw,devices 50 33 0:45 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:27 - cgroup cgroup rw,cpuset opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/v2/cgroupv2/000077500000000000000000000000001511331344600316045ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/testdata/proc/v2/cgroupv2/mountinfo000066400000000000000000000001441511331344600335440ustar00rootroot0000000000000034 33 0:29 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup rw,nsdelegateopentelemetry-collector-0.141.0/internal/memorylimiter/cgroups/util_test.go000066400000000000000000000031271511331344600273000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Keep the original Uber license. // Copyright (c) 2017 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. //go:build linux package cgroups import ( "os" "path/filepath" ) var ( pwd = mustGetWd() testDataPath = filepath.Join(pwd, "testdata") testDataCGroupsPath = filepath.Join(testDataPath, "cgroups") testDataProcPath = filepath.Join(testDataPath, "proc") ) func mustGetWd() string { pwd, err := os.Getwd() if err != nil { panic(err) } return pwd } opentelemetry-collector-0.141.0/internal/memorylimiter/config.go000066400000000000000000000072411511331344600250500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiter // import "go.opentelemetry.io/collector/internal/memorylimiter" import ( "errors" "time" "go.opentelemetry.io/collector/component" ) var ( errCheckIntervalOutOfRange = errors.New("'check_interval' must be greater than zero") errInconsistentGCMinInterval = errors.New("'min_gc_interval_when_soft_limited' should be larger than 'min_gc_interval_when_hard_limited'") errLimitOutOfRange = errors.New("'limit_mib' or 'limit_percentage' must be greater than zero") errSpikeLimitOutOfRange = errors.New("'spike_limit_mib' must be smaller than 'limit_mib'") errSpikeLimitPercentageOutOfRange = errors.New("'spike_limit_percentage' must be smaller than 'limit_percentage'") errLimitPercentageOutOfRange = errors.New( "'limit_percentage' and 'spike_limit_percentage' must be greater than zero and less than or equal to hundred") ) // Config defines configuration for memory memoryLimiter processor. type Config struct { // CheckInterval is the time between measurements of memory usage for the // purposes of avoiding going over the limits. Defaults to zero, so no // checks will be performed. CheckInterval time.Duration `mapstructure:"check_interval"` // MinGCIntervalWhenSoftLimited minimum interval between forced GC when in soft (=limit_mib - spike_limit_mib) limited mode. // Zero value means no minimum interval. // GCs is a CPU-heavy operation and executing it too frequently may affect the recovery capabilities of the collector. MinGCIntervalWhenSoftLimited time.Duration `mapstructure:"min_gc_interval_when_soft_limited"` // MinGCIntervalWhenHardLimited minimum interval between forced GC when in hard (=limit_mib) limited mode. // Zero value means no minimum interval. // GCs is a CPU-heavy operation and executing it too frequently may affect the recovery capabilities of the collector. MinGCIntervalWhenHardLimited time.Duration `mapstructure:"min_gc_interval_when_hard_limited"` // MemoryLimitMiB is the maximum amount of memory, in MiB, targeted to be // allocated by the process. MemoryLimitMiB uint32 `mapstructure:"limit_mib"` // MemorySpikeLimitMiB is the maximum, in MiB, spike expected between the // measurements of memory usage. MemorySpikeLimitMiB uint32 `mapstructure:"spike_limit_mib"` // MemoryLimitPercentage is the maximum amount of memory, in %, targeted to be // allocated by the process. The fixed memory settings MemoryLimitMiB has a higher precedence. MemoryLimitPercentage uint32 `mapstructure:"limit_percentage"` // MemorySpikePercentage is the maximum, in percents against the total memory, // spike expected between the measurements of memory usage. MemorySpikePercentage uint32 `mapstructure:"spike_limit_percentage"` } var _ component.Config = (*Config)(nil) func NewDefaultConfig() *Config { return &Config{ MinGCIntervalWhenSoftLimited: 10 * time.Second, } } // Validate checks if the processor configuration is valid func (cfg *Config) Validate() error { if cfg.CheckInterval <= 0 { return errCheckIntervalOutOfRange } if cfg.MinGCIntervalWhenSoftLimited < cfg.MinGCIntervalWhenHardLimited { return errInconsistentGCMinInterval } if cfg.MemoryLimitMiB == 0 && cfg.MemoryLimitPercentage == 0 { return errLimitOutOfRange } if cfg.MemoryLimitPercentage > 100 || cfg.MemorySpikePercentage > 100 { return errLimitPercentageOutOfRange } if cfg.MemoryLimitMiB > 0 && cfg.MemoryLimitMiB <= cfg.MemorySpikeLimitMiB { return errSpikeLimitOutOfRange } if cfg.MemoryLimitPercentage > 0 && cfg.MemoryLimitPercentage <= cfg.MemorySpikePercentage { return errSpikeLimitPercentageOutOfRange } return nil } opentelemetry-collector-0.141.0/internal/memorylimiter/config_test.go000066400000000000000000000053131511331344600261050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiter import ( "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestUnmarshalConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) cfg := &Config{} assert.NoError(t, cm.Unmarshal(&cfg)) assert.Equal(t, &Config{ CheckInterval: 5 * time.Second, MemoryLimitMiB: 4000, MemorySpikeLimitMiB: 500, }, cfg) } func TestConfigValidate(t *testing.T) { tests := []struct { name string cfg *Config err error }{ { name: "valid", cfg: &Config{ MemoryLimitMiB: 5722, MemorySpikeLimitMiB: 1907, CheckInterval: 100 * time.Millisecond, }, err: nil, }, { name: "zero check interval", cfg: &Config{ CheckInterval: 0, }, err: errCheckIntervalOutOfRange, }, { name: "unset memory limit", cfg: &Config{ CheckInterval: 1 * time.Second, MemoryLimitMiB: 0, MemoryLimitPercentage: 0, }, err: errLimitOutOfRange, }, { name: "invalid memory spike limit", cfg: &Config{ CheckInterval: 1 * time.Second, MemoryLimitMiB: 10, MemorySpikeLimitMiB: 10, }, err: errSpikeLimitOutOfRange, }, { name: "invalid memory percentage limit", cfg: &Config{ CheckInterval: 1 * time.Second, MemoryLimitPercentage: 101, }, err: errLimitPercentageOutOfRange, }, { name: "invalid memory spike percentage limit", cfg: &Config{ CheckInterval: 1 * time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 60, }, err: errSpikeLimitPercentageOutOfRange, }, { name: "invalid gc intervals", cfg: &Config{ CheckInterval: 100 * time.Millisecond, MinGCIntervalWhenSoftLimited: 50 * time.Millisecond, MinGCIntervalWhenHardLimited: 100 * time.Millisecond, MemoryLimitMiB: 5722, MemorySpikeLimitMiB: 1907, }, err: errInconsistentGCMinInterval, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := tt.cfg.Validate() assert.Equal(t, tt.err, err) }) } } func TestUnmarshalInvalidConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "negative_unsigned_limits_config.yaml")) require.NoError(t, err) cfg := &Config{} err = cm.Unmarshal(&cfg) require.ErrorContains(t, err, "'limit_mib' cannot parse value as 'uint32': -2000 overflows uint") require.ErrorContains(t, err, "'spike_limit_mib' cannot parse value as 'uint32': -2300 overflows uint") } opentelemetry-collector-0.141.0/internal/memorylimiter/go.mod000066400000000000000000000042351511331344600243620ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/memorylimiter go 1.24.0 require ( github.com/shirou/gopsutil/v4 v4.25.10 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../testutil opentelemetry-collector-0.141.0/internal/memorylimiter/go.sum000066400000000000000000000213221511331344600244030ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= 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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/000077500000000000000000000000001511331344600251045ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/mem_info.go000066400000000000000000000006221511331344600272240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package iruntime // import "go.opentelemetry.io/collector/internal/memorylimiter/iruntime" import ( "github.com/shirou/gopsutil/v4/mem" ) // readMemInfo returns the total memory // supports in linux, darwin and windows func readMemInfo() (uint64, error) { vmStat, err := mem.VirtualMemory() return vmStat.Total, err } opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/mem_info_test.go000066400000000000000000000005001511331344600302560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package iruntime import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestReadMemInfo(t *testing.T) { vmStat, err := readMemInfo() require.NoError(t, err) assert.Positive(t, vmStat) } opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/package_test.go000066400000000000000000000003111511331344600300600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package iruntime import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/total_memory_linux.go000066400000000000000000000024561511331344600313740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build linux package iruntime // import "go.opentelemetry.io/collector/internal/memorylimiter/iruntime" import "go.opentelemetry.io/collector/internal/memorylimiter/cgroups" // unlimitedMemorySize defines the bytes size when memory limit is not set // for the container and process with cgroups const unlimitedMemorySize = 9223372036854771712 // TotalMemory returns total available memory. // This implementation is meant for linux and uses cgroups to determine available memory. func TotalMemory() (uint64, error) { var memoryQuota int64 var defined bool var err error isV2, err := cgroups.IsCGroupV2() if err != nil { return 0, err } if isV2 { memoryQuota, defined, err = cgroups.MemoryQuotaV2() if err != nil { return 0, err } } else { cgv1, err := cgroups.NewCGroupsForCurrentProcess() if err != nil { return 0, err } memoryQuota, defined, err = cgv1.MemoryQuota() if err != nil { return 0, err } } // If memory is not defined or is set to unlimitedMemorySize (v1 unset), // we fallback to /proc/meminfo. if memoryQuota == unlimitedMemorySize || !defined { totalMem, err := readMemInfo() if err != nil { return 0, err } return totalMem, nil } return uint64(memoryQuota), nil } opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/total_memory_linux_test.go000066400000000000000000000005341511331344600324260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build linux package iruntime import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestTotalMemory(t *testing.T) { totalMemory, err := TotalMemory() require.NoError(t, err) assert.Positive(t, totalMemory) } opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/total_memory_other.go000066400000000000000000000005021511331344600313440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build !linux package iruntime // import "go.opentelemetry.io/collector/internal/memorylimiter/iruntime" // TotalMemory returns total available memory for non-linux platforms. func TotalMemory() (uint64, error) { return readMemInfo() } opentelemetry-collector-0.141.0/internal/memorylimiter/iruntime/total_memory_other_test.go000066400000000000000000000005351511331344600324110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build !linux package iruntime import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestTotalMemory(t *testing.T) { totalMemory, err := TotalMemory() require.NoError(t, err) assert.Positive(t, totalMemory) } opentelemetry-collector-0.141.0/internal/memorylimiter/memorylimiter.go000066400000000000000000000161501511331344600265000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiter // import "go.opentelemetry.io/collector/internal/memorylimiter" import ( "context" "errors" "fmt" "runtime" "sync" "sync/atomic" "time" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/internal/memorylimiter/iruntime" ) const ( mibBytes = 1024 * 1024 ) var ( // ErrDataRefused will be returned to callers of ConsumeTraceData to indicate // that data is being refused due to high memory usage. ErrDataRefused = errors.New("data refused due to high memory usage") // GetMemoryFn and ReadMemStatsFn make it overridable by tests GetMemoryFn = iruntime.TotalMemory ReadMemStatsFn = runtime.ReadMemStats ) // MemoryLimiter is used to prevent out of memory situations on the collector. type MemoryLimiter struct { usageChecker memUsageChecker memCheckWait time.Duration // mustRefuse is used to indicate when data should be refused. mustRefuse *atomic.Bool ticker *time.Ticker minGCIntervalWhenSoftLimited time.Duration minGCIntervalWhenHardLimited time.Duration lastGCDone time.Time // The functions to read the mem values and run GC are set as a reference to help with // testing different values. readMemStatsFn func(m *runtime.MemStats) runGCFn func() // Fields used for logging. logger *zap.Logger refCounterLock sync.Mutex refCounter int waitGroup sync.WaitGroup closed chan struct{} } // NewMemoryLimiter returns a new memory limiter component func NewMemoryLimiter(cfg *Config, logger *zap.Logger) (*MemoryLimiter, error) { usageChecker, err := getMemUsageChecker(cfg, logger) if err != nil { return nil, err } logger.Info("Memory limiter configured", zap.Uint64("limit_mib", usageChecker.memAllocLimit/mibBytes), zap.Uint64("spike_limit_mib", usageChecker.memSpikeLimit/mibBytes), zap.Duration("check_interval", cfg.CheckInterval)) return &MemoryLimiter{ usageChecker: *usageChecker, memCheckWait: cfg.CheckInterval, ticker: time.NewTicker(cfg.CheckInterval), minGCIntervalWhenSoftLimited: cfg.MinGCIntervalWhenSoftLimited, minGCIntervalWhenHardLimited: cfg.MinGCIntervalWhenHardLimited, lastGCDone: time.Now(), readMemStatsFn: ReadMemStatsFn, runGCFn: runtime.GC, logger: logger, mustRefuse: &atomic.Bool{}, }, nil } func (ml *MemoryLimiter) Start(_ context.Context, _ component.Host) error { ml.refCounterLock.Lock() defer ml.refCounterLock.Unlock() ml.refCounter++ if ml.refCounter == 1 { ml.closed = make(chan struct{}) ml.waitGroup.Add(1) go func() { defer ml.waitGroup.Done() for { select { case <-ml.ticker.C: case <-ml.closed: return } ml.CheckMemLimits() } }() } return nil } // Shutdown resets MemoryLimiter monitoring ticker and stop monitoring func (ml *MemoryLimiter) Shutdown(context.Context) error { ml.refCounterLock.Lock() defer ml.refCounterLock.Unlock() switch ml.refCounter { case 0: return nil case 1: ml.ticker.Stop() close(ml.closed) ml.waitGroup.Wait() } ml.refCounter-- return nil } // MustRefuse returns true if memory has reached its configured limits func (ml *MemoryLimiter) MustRefuse() bool { return ml.mustRefuse.Load() } func getMemUsageChecker(cfg *Config, logger *zap.Logger) (*memUsageChecker, error) { memAllocLimit := uint64(cfg.MemoryLimitMiB) * mibBytes memSpikeLimit := uint64(cfg.MemorySpikeLimitMiB) * mibBytes if cfg.MemoryLimitMiB != 0 { return newFixedMemUsageChecker(memAllocLimit, memSpikeLimit), nil } totalMemory, err := GetMemoryFn() if err != nil { return nil, fmt.Errorf("failed to get total memory, use fixed memory settings (limit_mib): %w", err) } logger.Info("Using percentage memory limiter", zap.Uint64("total_memory_mib", totalMemory/mibBytes), zap.Uint32("limit_percentage", cfg.MemoryLimitPercentage), zap.Uint32("spike_limit_percentage", cfg.MemorySpikePercentage)) return newPercentageMemUsageChecker(totalMemory, uint64(cfg.MemoryLimitPercentage), uint64(cfg.MemorySpikePercentage)), nil } func (ml *MemoryLimiter) readMemStats() *runtime.MemStats { ms := &runtime.MemStats{} ml.readMemStatsFn(ms) return ms } func memstatToZapField(ms *runtime.MemStats) zap.Field { return zap.Uint64("cur_mem_mib", ms.Alloc/mibBytes) } func (ml *MemoryLimiter) doGCandReadMemStats() *runtime.MemStats { ml.runGCFn() ml.lastGCDone = time.Now() ms := ml.readMemStats() ml.logger.Info("Memory usage after GC.", memstatToZapField(ms)) return ms } // CheckMemLimits inspects current memory usage against threshold and toggles mustRefuse when threshold is exceeded func (ml *MemoryLimiter) CheckMemLimits() { ms := ml.readMemStats() ml.logger.Debug("Currently used memory.", memstatToZapField(ms)) // Check if we are below the soft limit. aboveSoftLimit := ml.usageChecker.aboveSoftLimit(ms) if !aboveSoftLimit { if ml.mustRefuse.Load() { // Was previously refusing but enough memory is available now, no need to limit. ml.logger.Info("Memory usage back within limits. Resuming normal operation.", memstatToZapField(ms)) } ml.mustRefuse.Store(aboveSoftLimit) return } if ml.usageChecker.aboveHardLimit(ms) { // We are above hard limit, do a GC if it wasn't done recently and see if // it brings memory usage below the soft limit. if time.Since(ml.lastGCDone) > ml.minGCIntervalWhenHardLimited { ml.logger.Warn("Memory usage is above hard limit. Forcing a GC.", memstatToZapField(ms)) ms = ml.doGCandReadMemStats() // Check the limit again to see if GC helped. aboveSoftLimit = ml.usageChecker.aboveSoftLimit(ms) } } else { // We are above soft limit, do a GC if it wasn't done recently and see if // it brings memory usage below the soft limit. if time.Since(ml.lastGCDone) > ml.minGCIntervalWhenSoftLimited { ml.logger.Info("Memory usage is above soft limit. Forcing a GC.", memstatToZapField(ms)) ms = ml.doGCandReadMemStats() // Check the limit again to see if GC helped. aboveSoftLimit = ml.usageChecker.aboveSoftLimit(ms) } } if !ml.mustRefuse.Load() && aboveSoftLimit { ml.logger.Warn("Memory usage is above soft limit. Refusing data.", memstatToZapField(ms)) } ml.mustRefuse.Store(aboveSoftLimit) } type memUsageChecker struct { memAllocLimit uint64 memSpikeLimit uint64 } func (d memUsageChecker) aboveSoftLimit(ms *runtime.MemStats) bool { return ms.Alloc >= d.memAllocLimit-d.memSpikeLimit } func (d memUsageChecker) aboveHardLimit(ms *runtime.MemStats) bool { return ms.Alloc >= d.memAllocLimit } func newFixedMemUsageChecker(memAllocLimit, memSpikeLimit uint64) *memUsageChecker { if memSpikeLimit == 0 { // If spike limit is unspecified use 20% of mem limit. memSpikeLimit = memAllocLimit / 5 } return &memUsageChecker{ memAllocLimit: memAllocLimit, memSpikeLimit: memSpikeLimit, } } func newPercentageMemUsageChecker(totalMemory, percentageLimit, percentageSpike uint64) *memUsageChecker { return newFixedMemUsageChecker(percentageLimit*totalMemory/100, percentageSpike*totalMemory/100) } opentelemetry-collector-0.141.0/internal/memorylimiter/memorylimiter_test.go000066400000000000000000000143361511331344600275430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiter import ( "runtime" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.opentelemetry.io/collector/internal/memorylimiter/iruntime" ) // TestMemoryPressureResponse manipulates results from querying memory and // check expected side effects. func TestMemoryPressureResponse(t *testing.T) { var currentMemAlloc uint64 cfg := &Config{ CheckInterval: 1 * time.Minute, MemoryLimitMiB: 1024, MemorySpikeLimitMiB: 0, } ml, err := NewMemoryLimiter(cfg, zap.NewNop()) require.NoError(t, err) ml.readMemStatsFn = func(ms *runtime.MemStats) { ms.Alloc = currentMemAlloc * mibBytes } // Below memAllocLimit. currentMemAlloc = 800 ml.CheckMemLimits() assert.False(t, ml.MustRefuse()) // Above memAllocLimit. currentMemAlloc = 1800 ml.CheckMemLimits() assert.True(t, ml.MustRefuse()) // Check spike limit ml.usageChecker.memSpikeLimit = 512 * mibBytes // Below memSpikeLimit. currentMemAlloc = 500 ml.CheckMemLimits() assert.False(t, ml.MustRefuse()) // Above memSpikeLimit. currentMemAlloc = 550 ml.CheckMemLimits() assert.True(t, ml.MustRefuse()) } func TestGetDecision(t *testing.T) { t.Run("fixed_limit", func(t *testing.T) { d, err := getMemUsageChecker(&Config{MemoryLimitMiB: 100, MemorySpikeLimitMiB: 20}, zap.NewNop()) require.NoError(t, err) assert.Equal(t, &memUsageChecker{ memAllocLimit: 100 * mibBytes, memSpikeLimit: 20 * mibBytes, }, d) }) t.Cleanup(func() { GetMemoryFn = iruntime.TotalMemory }) GetMemoryFn = func() (uint64, error) { return 100 * mibBytes, nil } t.Run("percentage_limit", func(t *testing.T) { d, err := getMemUsageChecker(&Config{MemoryLimitPercentage: 50, MemorySpikePercentage: 10}, zap.NewNop()) require.NoError(t, err) assert.Equal(t, &memUsageChecker{ memAllocLimit: 50 * mibBytes, memSpikeLimit: 10 * mibBytes, }, d) }) } func TestRefuseDecision(t *testing.T) { decision1000Limit30Spike30 := newPercentageMemUsageChecker(1000, 60, 30) decision1000Limit60Spike50 := newPercentageMemUsageChecker(1000, 60, 50) decision1000Limit40Spike20 := newPercentageMemUsageChecker(1000, 40, 20) tests := []struct { name string usageChecker memUsageChecker ms *runtime.MemStats shouldRefuse bool }{ { name: "should refuse over limit", usageChecker: *decision1000Limit30Spike30, ms: &runtime.MemStats{Alloc: 600}, shouldRefuse: true, }, { name: "should not refuse", usageChecker: *decision1000Limit30Spike30, ms: &runtime.MemStats{Alloc: 100}, shouldRefuse: false, }, { name: "should not refuse spike, fixed usageChecker", usageChecker: memUsageChecker{ memAllocLimit: 600, memSpikeLimit: 500, }, ms: &runtime.MemStats{Alloc: 300}, shouldRefuse: true, }, { name: "should refuse, spike, percentage usageChecker", usageChecker: *decision1000Limit60Spike50, ms: &runtime.MemStats{Alloc: 300}, shouldRefuse: true, }, { name: "should refuse, spike, percentage usageChecker", usageChecker: *decision1000Limit40Spike20, ms: &runtime.MemStats{Alloc: 250}, shouldRefuse: true, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { shouldRefuse := test.usageChecker.aboveSoftLimit(test.ms) assert.Equal(t, test.shouldRefuse, shouldRefuse) }) } } func TestCallGCWhenSoftLimit(t *testing.T) { tests := []struct { name string mlCfg *Config memAllocMiB [2]uint64 numGCs int }{ { name: "GC when first soft limit and not immediately", mlCfg: &Config{ CheckInterval: 1 * time.Minute, MinGCIntervalWhenSoftLimited: 10 * time.Second, MemoryLimitMiB: 50, MemorySpikeLimitMiB: 10, }, memAllocMiB: [2]uint64{45, 45}, numGCs: 1, }, { name: "GC always when soft limit min interval is 0", mlCfg: &Config{ CheckInterval: 1 * time.Minute, MinGCIntervalWhenSoftLimited: 0, MemoryLimitMiB: 50, MemorySpikeLimitMiB: 10, }, memAllocMiB: [2]uint64{45, 45}, numGCs: 2, }, { name: "GC when first hard limit and not immediately", mlCfg: &Config{ CheckInterval: 1 * time.Minute, MinGCIntervalWhenHardLimited: 10 * time.Second, MemoryLimitMiB: 50, MemorySpikeLimitMiB: 10, }, memAllocMiB: [2]uint64{55, 55}, numGCs: 1, }, { name: "GC always when hard limit min interval is 0", mlCfg: &Config{ CheckInterval: 1 * time.Minute, MinGCIntervalWhenHardLimited: 0, MemoryLimitMiB: 50, MemorySpikeLimitMiB: 10, }, memAllocMiB: [2]uint64{55, 55}, numGCs: 2, }, { name: "GC based on soft then based on hard limit", mlCfg: &Config{ CheckInterval: 1 * time.Minute, MinGCIntervalWhenSoftLimited: 10 * time.Second, MinGCIntervalWhenHardLimited: 0, MemoryLimitMiB: 50, MemorySpikeLimitMiB: 10, }, memAllocMiB: [2]uint64{45, 55}, numGCs: 2, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ml, err := NewMemoryLimiter(tt.mlCfg, zap.NewNop()) require.NoError(t, err) memAllocMiB := uint64(0) ml.readMemStatsFn = func(ms *runtime.MemStats) { ms.Alloc = memAllocMiB * mibBytes } // Mark last GC in the past so that even first call can trigger GC // Not updating the initialization code, since at the beginning of the collector no need to GC. ml.lastGCDone = ml.lastGCDone.Add(-time.Minute) numGCs := 0 ml.runGCFn = func() { numGCs++ } memAllocMiB = tt.memAllocMiB[0] ml.CheckMemLimits() assert.True(t, ml.MustRefuse()) // On windows, time has larger precision, and checking here again may return same time as "lastGCDone" // which will not trigger a new GC for 0 duration, update last GC with -1 millis. ml.lastGCDone = ml.lastGCDone.Add(-1 * time.Millisecond) memAllocMiB = tt.memAllocMiB[1] ml.CheckMemLimits() assert.True(t, ml.MustRefuse()) assert.Equal(t, tt.numGCs, numGCs) }) } } opentelemetry-collector-0.141.0/internal/memorylimiter/testdata/000077500000000000000000000000001511331344600250615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/memorylimiter/testdata/config.yaml000066400000000000000000000011161511331344600272110ustar00rootroot00000000000000# check_interval is the time between measurements of memory usage for the # purposes of avoiding going over the limits. Defaults to zero, so no # checks will be performed. Values below 1 second are not recommended since # it can result in unnecessary CPU consumption. check_interval: 5s # Maximum amount of memory, in MiB, targeted to be allocated by the process heap. # Note that typically the total memory usage of process will be about 50MiB higher # than this value. limit_mib: 4000 # The maximum, in MiB, spike expected between the measurements of memory usage. spike_limit_mib: 500 opentelemetry-collector-0.141.0/internal/memorylimiter/testdata/negative_unsigned_limits_config.yaml000066400000000000000000000011211511331344600343440ustar00rootroot00000000000000# check_interval is the time between measurements of memory usage for the # purposes of avoiding going over the limits. Defaults to zero, so no # checks will be performed. Values below 1 second are not recommended since # it can result in unnecessary CPU consumption. check_interval: 5s # Maximum amount of memory, in MiB, targeted to be allocated by the process heap. # Note that typically the total memory usage of process will be about 50MiB higher # than this value. limit_mib: -2000 # The maximum, in MiB, spike expected between the measurements of memory usage. spike_limit_mib: -2300 opentelemetry-collector-0.141.0/internal/sharedcomponent/000077500000000000000000000000001511331344600235435ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/sharedcomponent/Makefile000066400000000000000000000000361511331344600252020ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/internal/sharedcomponent/go.mod000066400000000000000000000037261511331344600246610ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/sharedcomponent go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componentstatus v0.141.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../testutil opentelemetry-collector-0.141.0/internal/sharedcomponent/go.sum000066400000000000000000000140451511331344600247020ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/internal/sharedcomponent/package_test.go000066400000000000000000000003201511331344600265170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sharedcomponent import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/internal/sharedcomponent/sharedcomponent.go000066400000000000000000000115331511331344600272660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package sharedcomponent exposes functionality for components // to register against a shared key, such as a configuration object, in order to be reused across signal types. // This is particularly useful when the component relies on a shared resource such as os.File or http.Server. package sharedcomponent // import "go.opentelemetry.io/collector/internal/sharedcomponent" import ( "container/ring" "context" "sync" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" ) func NewMap[K comparable, V component.Component]() *Map[K, V] { return &Map[K, V]{ components: map[K]*Component[V]{}, } } // Map keeps reference of all created instances for a given shared key such as a component configuration. type Map[K comparable, V component.Component] struct { lock sync.Mutex components map[K]*Component[V] } // LoadOrStore returns the already created instance if exists, otherwise creates a new instance // and adds it to the map of references. func (m *Map[K, V]) LoadOrStore(key K, create func() (V, error)) (*Component[V], error) { m.lock.Lock() defer m.lock.Unlock() if c, ok := m.components[key]; ok { return c, nil } comp, err := create() if err != nil { return nil, err } newComp := &Component[V]{ component: comp, removeFunc: func() { m.lock.Lock() defer m.lock.Unlock() delete(m.components, key) }, } m.components[key] = newComp return newComp, nil } // Component ensures that the wrapped component is started and stopped only once. // When stopped it is removed from the Map. type Component[V component.Component] struct { component V startOnce sync.Once stopOnce sync.Once removeFunc func() hostWrapper *hostWrapper } // Unwrap returns the original component. func (c *Component[V]) Unwrap() V { return c.component } // Start starts the underlying component if it never started before. func (c *Component[V]) Start(ctx context.Context, host component.Host) error { if c.hostWrapper == nil { var err error c.startOnce.Do(func() { c.hostWrapper = &hostWrapper{ host: host, sources: make([]componentstatus.Reporter, 0), previousEvents: ring.New(5), } statusReporter, isStatusReporter := host.(componentstatus.Reporter) if isStatusReporter { c.hostWrapper.addSource(statusReporter) } // It's important that status for a shared component is reported through its // telemetry settings to keep status in sync and avoid race conditions. This logic duplicates // and takes priority over the automated status reporting that happens in graph, making the // status reporting in graph a no-op. c.hostWrapper.Report(componentstatus.NewEvent(componentstatus.StatusStarting)) if err = c.component.Start(ctx, c.hostWrapper); err != nil { c.hostWrapper.Report(componentstatus.NewPermanentErrorEvent(err)) } }) return err } statusReporter, isStatusReporter := host.(componentstatus.Reporter) if isStatusReporter { c.hostWrapper.addSource(statusReporter) } return nil } var ( _ component.Host = (*hostWrapper)(nil) _ componentstatus.Reporter = (*hostWrapper)(nil) ) type hostWrapper struct { host component.Host sources []componentstatus.Reporter previousEvents *ring.Ring lock sync.Mutex } func (h *hostWrapper) GetExtensions() map[component.ID]component.Component { return h.host.GetExtensions() } func (h *hostWrapper) Report(e *componentstatus.Event) { // Only remember an event if it will be emitted and it has not been sent already. h.lock.Lock() defer h.lock.Unlock() if len(h.sources) > 0 { h.previousEvents.Value = e h.previousEvents = h.previousEvents.Next() } for _, s := range h.sources { s.Report(e) } } func (h *hostWrapper) addSource(s componentstatus.Reporter) { h.lock.Lock() defer h.lock.Unlock() h.previousEvents.Do(func(a any) { if e, ok := a.(*componentstatus.Event); ok { s.Report(e) } }) h.sources = append(h.sources, s) } // Shutdown shuts down the underlying component. func (c *Component[V]) Shutdown(ctx context.Context) error { var err error c.stopOnce.Do(func() { // It's important that status for a shared component is reported through its // telemetry settings to keep status in sync and avoid race conditions. This logic duplicates // and takes priority over the automated status reporting that happens in graph, making the // status reporting in graph a no-op. if c.hostWrapper != nil { c.hostWrapper.Report(componentstatus.NewEvent(componentstatus.StatusStopping)) } err = c.component.Shutdown(ctx) if c.hostWrapper != nil { if err != nil { c.hostWrapper.Report(componentstatus.NewPermanentErrorEvent(err)) } else { c.hostWrapper.Report(componentstatus.NewEvent(componentstatus.StatusStopped)) } } c.removeFunc() }) return err } opentelemetry-collector-0.141.0/internal/sharedcomponent/sharedcomponent_test.go000066400000000000000000000132441511331344600303260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package sharedcomponent import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/component/componenttest" ) var id = component.MustNewID("test") type baseComponent struct { component.StartFunc component.ShutdownFunc } func TestNewMap(t *testing.T) { comps := NewMap[component.ID, *baseComponent]() assert.Empty(t, comps.components) } func TestNewSharedComponentsCreateError(t *testing.T) { comps := NewMap[component.ID, *baseComponent]() assert.Empty(t, comps.components) myErr := errors.New("my error") _, err := comps.LoadOrStore( id, func() (*baseComponent, error) { return nil, myErr }, ) require.ErrorIs(t, err, myErr) assert.Empty(t, comps.components) } func TestSharedComponentsLoadOrStore(t *testing.T) { nop := &baseComponent{} comps := NewMap[component.ID, *baseComponent]() got, err := comps.LoadOrStore( id, func() (*baseComponent, error) { return nop, nil }, ) require.NoError(t, err) assert.Len(t, comps.components, 1) assert.Same(t, nop, got.Unwrap()) gotSecond, err := comps.LoadOrStore( id, func() (*baseComponent, error) { panic("should not be called") }, ) require.NoError(t, err) assert.Same(t, got, gotSecond) // Shutdown nop will remove require.NoError(t, got.Shutdown(context.Background())) assert.Empty(t, comps.components) gotThird, err := comps.LoadOrStore( id, func() (*baseComponent, error) { return nop, nil }, ) require.NoError(t, err) assert.NotSame(t, got, gotThird) } func TestSharedComponent(t *testing.T) { wantErr := errors.New("my error") calledStart := 0 calledStop := 0 comp := &baseComponent{ StartFunc: func(context.Context, component.Host) error { calledStart++ return wantErr }, ShutdownFunc: func(context.Context) error { calledStop++ return wantErr }, } comps := NewMap[component.ID, *baseComponent]() got, err := comps.LoadOrStore( id, func() (*baseComponent, error) { return comp, nil }, ) require.NoError(t, err) assert.Equal(t, wantErr, got.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, 1, calledStart) // Second time is not called anymore. require.NoError(t, got.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, 1, calledStart) // first time, shutdown is called. assert.Equal(t, wantErr, got.Shutdown(context.Background())) assert.Equal(t, 1, calledStop) // Second time is not called anymore. require.NoError(t, got.Shutdown(context.Background())) assert.Equal(t, 1, calledStop) } func TestReportStatusOnStartShutdown(t *testing.T) { for _, tc := range []struct { name string startErr error shutdownErr error expectedStatuses []componentstatus.Status expectedNumReporterInstances int }{ { name: "successful start/stop", startErr: nil, shutdownErr: nil, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, expectedNumReporterInstances: 3, }, { name: "start error", startErr: assert.AnError, shutdownErr: nil, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusPermanentError, }, expectedNumReporterInstances: 1, }, { name: "shutdown error", shutdownErr: assert.AnError, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusPermanentError, }, expectedNumReporterInstances: 3, }, } { t.Run(tc.name, func(t *testing.T) { reportedStatuses := make(map[*componentstatus.InstanceID][]componentstatus.Status) newStatusFunc := func(id *componentstatus.InstanceID, ev *componentstatus.Event) { reportedStatuses[id] = append(reportedStatuses[id], ev.Status()) } base := &baseComponent{} if tc.startErr != nil { base.StartFunc = func(context.Context, component.Host) error { return tc.startErr } } if tc.shutdownErr != nil { base.ShutdownFunc = func(context.Context) error { return tc.shutdownErr } } comps := NewMap[component.ID, *baseComponent]() var comp *Component[*baseComponent] var err error for range 3 { comp, err = comps.LoadOrStore( id, func() (*baseComponent, error) { return base, nil }, ) require.NoError(t, err) } baseHost := componenttest.NewNopHost() for range 3 { err = comp.Start(context.Background(), &testHost{Host: baseHost, InstanceID: &componentstatus.InstanceID{}, newStatusFunc: newStatusFunc}) if err != nil { break } } require.Equal(t, tc.startErr, err) if tc.startErr == nil { comp.hostWrapper.Report(componentstatus.NewEvent(componentstatus.StatusOK)) err = comp.Shutdown(context.Background()) require.Equal(t, tc.shutdownErr, err) } require.Len(t, reportedStatuses, tc.expectedNumReporterInstances) for _, actualStatuses := range reportedStatuses { require.Equal(t, tc.expectedStatuses, actualStatuses) } }) } } var ( _ component.Host = (*testHost)(nil) _ componentstatus.Reporter = (*testHost)(nil) ) type testHost struct { component.Host *componentstatus.InstanceID newStatusFunc func(id *componentstatus.InstanceID, ev *componentstatus.Event) } func (h *testHost) Report(e *componentstatus.Event) { h.newStatusFunc(h.InstanceID, e) } opentelemetry-collector-0.141.0/internal/statusutil/000077500000000000000000000000001511331344600225735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/statusutil/helper.go000066400000000000000000000027011511331344600244010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package statusutil // import "go.opentelemetry.io/collector/internal/statusutil" import ( "net/http" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) // NewStatusFromMsgAndHTTPCode returns a gRPC status based on an error message string and a http status code. // This function is shared between the http receiver and http exporter for error propagation. func NewStatusFromMsgAndHTTPCode(errMsg string, statusCode int) *status.Status { var c codes.Code // Mapping based on https://github.com/grpc/grpc/blob/master/doc/http-grpc-status-mapping.md // 429 mapping to ResourceExhausted and 400 mapping to StatusBadRequest are exceptions. switch statusCode { case http.StatusBadRequest: c = codes.InvalidArgument case http.StatusUnauthorized: c = codes.Unauthenticated case http.StatusForbidden: c = codes.PermissionDenied case http.StatusNotFound: c = codes.Unimplemented case http.StatusTooManyRequests: c = codes.ResourceExhausted case http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout: c = codes.Unavailable default: c = codes.Unknown } return status.New(c, errMsg) } func GetRetryInfo(status *status.Status) *errdetails.RetryInfo { for _, detail := range status.Details() { if t, ok := detail.(*errdetails.RetryInfo); ok { return t } } return nil } opentelemetry-collector-0.141.0/internal/statusutil/helper_test.go000066400000000000000000000071541511331344600254470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package statusutil import ( "net/http" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/genproto/googleapis/rpc/errdetails" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" ) func Test_ErrorMsgAndHTTPCodeToStatus(t *testing.T) { tests := []struct { name string errMsg string statusCode int expected *status.Status }{ { name: "Bad Request", errMsg: "test", statusCode: http.StatusBadRequest, expected: status.New(codes.InvalidArgument, "test"), }, { name: "Unauthorized", errMsg: "test", statusCode: http.StatusUnauthorized, expected: status.New(codes.Unauthenticated, "test"), }, { name: "Forbidden", errMsg: "test", statusCode: http.StatusForbidden, expected: status.New(codes.PermissionDenied, "test"), }, { name: "Not Found", errMsg: "test", statusCode: http.StatusNotFound, expected: status.New(codes.Unimplemented, "test"), }, { name: "Too Many Requests", errMsg: "test", statusCode: http.StatusTooManyRequests, expected: status.New(codes.ResourceExhausted, "test"), }, { name: "Bad Gateway", errMsg: "test", statusCode: http.StatusBadGateway, expected: status.New(codes.Unavailable, "test"), }, { name: "Service Unavailable", errMsg: "test", statusCode: http.StatusServiceUnavailable, expected: status.New(codes.Unavailable, "test"), }, { name: "Gateway Timeout", errMsg: "test", statusCode: http.StatusGatewayTimeout, expected: status.New(codes.Unavailable, "test"), }, { name: "Unsupported Media Type", errMsg: "test", statusCode: http.StatusUnsupportedMediaType, expected: status.New(codes.Unknown, "test"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := NewStatusFromMsgAndHTTPCode(tt.errMsg, tt.statusCode) assert.Equal(t, tt.expected, result) }) } } func TestGetRetryInfo(t *testing.T) { tests := []struct { name string input *status.Status expected *errdetails.RetryInfo }{ { name: "NoDetails", input: status.New(codes.InvalidArgument, "test"), expected: nil, }, { name: "WithRetryInfoDetails", input: func() *status.Status { st := status.New(codes.ResourceExhausted, "test") dt, err := st.WithDetails(&errdetails.RetryInfo{RetryDelay: durationpb.New(1 * time.Second)}) require.NoError(t, err) return dt }(), expected: &errdetails.RetryInfo{RetryDelay: durationpb.New(1 * time.Second)}, }, { name: "WithOtherDetails", input: func() *status.Status { st := status.New(codes.ResourceExhausted, "test") dt, err := st.WithDetails(&errdetails.ErrorInfo{Reason: "my reason"}) require.NoError(t, err) return dt }(), expected: nil, }, { name: "WithMultipleDetails", input: func() *status.Status { st := status.New(codes.ResourceExhausted, "test") dt, err := st.WithDetails( &errdetails.ErrorInfo{Reason: "my reason"}, &errdetails.RetryInfo{RetryDelay: durationpb.New(1 * time.Second)}) require.NoError(t, err) return dt }(), expected: &errdetails.RetryInfo{RetryDelay: durationpb.New(1 * time.Second)}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := GetRetryInfo(tt.input) assert.True(t, proto.Equal(tt.expected, result)) }) } } opentelemetry-collector-0.141.0/internal/telemetry/000077500000000000000000000000001511331344600223645ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/telemetry/Makefile000066400000000000000000000000361511331344600240230ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/internal/telemetry/attribute.go000066400000000000000000000027721511331344600247260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetry // import "go.opentelemetry.io/collector/internal/telemetry" import ( "go.opentelemetry.io/otel/attribute" "go.uber.org/zap" ) const ( ComponentKindKey = "otelcol.component.kind" ComponentIDKey = "otelcol.component.id" PipelineIDKey = "otelcol.pipeline.id" SignalKey = "otelcol.signal" SignalOutputKey = "otelcol.signal.output" ) // ToZapFields converts an OTel Go attribute set to a slice of zap fields. func ToZapFields(attrs []attribute.KeyValue) []zap.Field { zapFields := make([]zap.Field, 0, len(attrs)) for _, attr := range attrs { var zapField zap.Field key := string(attr.Key) switch attr.Value.Type() { case attribute.BOOL: zapField = zap.Bool(key, attr.Value.AsBool()) case attribute.INT64: zapField = zap.Int64(key, attr.Value.AsInt64()) case attribute.FLOAT64: zapField = zap.Float64(key, attr.Value.AsFloat64()) case attribute.STRING: zapField = zap.String(key, attr.Value.AsString()) case attribute.BOOLSLICE: zapField = zap.Bools(key, attr.Value.AsBoolSlice()) case attribute.INT64SLICE: zapField = zap.Int64s(key, attr.Value.AsInt64Slice()) case attribute.FLOAT64SLICE: zapField = zap.Float64s(key, attr.Value.AsFloat64Slice()) case attribute.STRINGSLICE: zapField = zap.Strings(key, attr.Value.AsStringSlice()) default: zapField = zap.Any(key, attr.Value.AsInterface()) } zapFields = append(zapFields, zapField) } return zapFields } opentelemetry-collector-0.141.0/internal/telemetry/attribute_test.go000066400000000000000000000041051511331344600257550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetry // import "go.opentelemetry.io/collector/internal/telemetry" import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.uber.org/zap" ) func TestToZapFields(t *testing.T) { tests := []struct { attrs attribute.Set expected []zap.Field }{ { attrs: attribute.NewSet( attribute.String("string_key", "string_value"), ), expected: []zap.Field{ zap.String("string_key", "string_value"), }, }, { attrs: attribute.NewSet( attribute.Bool("bool_key", true), ), expected: []zap.Field{ zap.Bool("bool_key", true), }, }, { attrs: attribute.NewSet( attribute.Int64("int64_key", 42), ), expected: []zap.Field{ zap.Int64("int64_key", 42), }, }, { attrs: attribute.NewSet( attribute.Float64("float64_key", 3.14), ), expected: []zap.Field{ zap.Float64("float64_key", 3.14), }, }, { attrs: attribute.NewSet( attribute.BoolSlice("bool_slice_key", []bool{true, false, true}), ), expected: []zap.Field{ zap.Bools("bool_slice_key", []bool{true, false, true}), }, }, { attrs: attribute.NewSet( attribute.Int64Slice("int64_slice_key", []int64{1, 2, 3}), ), expected: []zap.Field{ zap.Int64s("int64_slice_key", []int64{1, 2, 3}), }, }, { attrs: attribute.NewSet( attribute.Float64Slice("float64_slice_key", []float64{1.1, 2.2, 3.3}), ), expected: []zap.Field{ zap.Float64s("float64_slice_key", []float64{1.1, 2.2, 3.3}), }, }, { attrs: attribute.NewSet( attribute.StringSlice("string_slice_key", []string{"a", "b", "c"}), ), expected: []zap.Field{ zap.Strings("string_slice_key", []string{"a", "b", "c"}), }, }, } for _, tt := range tests { name := "" if tt.attrs.Len() > 0 { attr, ok := tt.attrs.Get(0) if ok { name = string(attr.Key) } } t.Run(name, func(t *testing.T) { result := ToZapFields(tt.attrs.ToSlice()) require.Equal(t, tt.expected, result) }) } } opentelemetry-collector-0.141.0/internal/telemetry/go.mod000066400000000000000000000021601511331344600234710ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/telemetry go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/internal/testutil => ../testutil opentelemetry-collector-0.141.0/internal/telemetry/go.sum000066400000000000000000000124431511331344600235230ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/internal/telemetry/telemetry.go000066400000000000000000000032531511331344600247300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetry // import "go.opentelemetry.io/collector/internal/telemetry" import ( "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/featuregate" ) var NewPipelineTelemetryGate = featuregate.GlobalRegistry().MustRegister( "telemetry.newPipelineTelemetry", featuregate.StageAlpha, featuregate.WithRegisterFromVersion("v0.123.0"), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/rfcs/component-universal-telemetry.md"), featuregate.WithRegisterDescription("Injects component-identifying scope attributes in internal Collector metrics"), ) type injectorCore interface { DropInjectedAttributes(droppedAttrs ...string) zapcore.Core } type injectorTracerProvider interface { DropInjectedAttributes(droppedAttrs ...string) trace.TracerProvider } type injectorMeterProvider interface { DropInjectedAttributes(droppedAttrs ...string) metric.MeterProvider } func DropInjectedAttributes(ts component.TelemetrySettings, attrs ...string) component.TelemetrySettings { ts.Logger = ts.Logger.WithOptions(zap.WrapCore(func(c zapcore.Core) zapcore.Core { if ic, ok := c.(injectorCore); ok { return ic.DropInjectedAttributes(attrs...) } return c })) if itp, ok := ts.TracerProvider.(injectorTracerProvider); ok { ts.TracerProvider = itp.DropInjectedAttributes(attrs...) } if imp, ok := ts.MeterProvider.(injectorMeterProvider); ok { ts.MeterProvider = imp.DropInjectedAttributes(attrs...) } return ts } opentelemetry-collector-0.141.0/internal/telemetry/telemetrytest/000077500000000000000000000000001511331344600252765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/telemetry/telemetrytest/mock.go000066400000000000000000000012601511331344600265550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetrytest // import "go.opentelemetry.io/collector/internal/telemetry/telemetrytest" import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" ) type mockInjectorCore struct { zapcore.Core dropped *[]string } func (mic mockInjectorCore) DropInjectedAttributes(droppedAttrs ...string) zapcore.Core { *mic.dropped = append(*mic.dropped, droppedAttrs...) return mic } func MockInjectorLogger(logger *zap.Logger, dropped *[]string) *zap.Logger { return logger.WithOptions(zap.WrapCore(func(c zapcore.Core) zapcore.Core { return mockInjectorCore{ Core: c, dropped: dropped, } })) } opentelemetry-collector-0.141.0/internal/testutil/000077500000000000000000000000001511331344600222275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/testutil/Makefile000066400000000000000000000000361511331344600236660ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/internal/testutil/README.md000066400000000000000000000002541511331344600235070ustar00rootroot00000000000000## Test Utilities The `go.opentelemetry.io/collector/internal/testutil` module provides utility functions, etc. for use by tests in other OpenTelemetry Collector modules.opentelemetry-collector-0.141.0/internal/testutil/benchmarks.go000066400000000000000000000006611511331344600246760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testutil // import "go.opentelemetry.io/collector/internal/testutil" import ( "os" "testing" ) // SkipMemoryBench will skip memory benchmarks on CI, as we currently only // monitor duration. func SkipMemoryBench(b *testing.B) { if os.Getenv("MEMBENCH") == "" { b.Skip("Skipping since the 'MEMBENCH' environment variable was not set") } } opentelemetry-collector-0.141.0/internal/testutil/fips.go000066400000000000000000000014271511331344600235230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testutil // import "go.opentelemetry.io/collector/internal/testutil" import ( "os" "strings" "testing" ) // SkipIfFIPSOnly will mark the passed test as skipped if GODEBUG=fips140=only is detected. // If GODEBUG=fips140=on, go may call non-compliant algorithms and the test does not need to be skipped. func SkipIfFIPSOnly(t *testing.T, msg string) { // NOTE: This only checks env var; at the time of writing fips140 can only be set via env // other GODEBUG settings can be set via embedded comments or in go.mod, we may need to account for this in the future. s := os.Getenv("GODEBUG") if strings.Contains(s, "fips140=only") { t.Skip("GODEBUG=fips140=only detected, skipping test:", msg) } } opentelemetry-collector-0.141.0/internal/testutil/go.mod000066400000000000000000000005111511331344600233320ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/testutil go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/internal/testutil/go.sum000066400000000000000000000030101511331344600233540ustar00rootroot00000000000000github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/internal/testutil/package_test.go000066400000000000000000000003111511331344600252030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testutil import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/internal/testutil/testutil.go000066400000000000000000000100001511331344600244220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testutil // import "go.opentelemetry.io/collector/internal/testutil" import ( "net" "os/exec" "runtime" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) type portpair struct { first string last string } // GetAvailableLocalAddress finds an available local port and returns an endpoint // describing it. The port is available for opening when this function returns // provided that there is no race by some other code to grab the same port // immediately. func GetAvailableLocalAddress(tb testing.TB) string { return findAvailable(tb, "tcp4") } // GetAvailableLocalIPv6Address is IPv6 version of GetAvailableLocalAddress. func GetAvailableLocalIPv6Address(tb testing.TB) string { return findAvailable(tb, "tcp6") } func findAvailable(tb testing.TB, network string) string { // Retry has been added for windows as net.Listen can return a port that is not actually available. Details can be // found in https://github.com/docker/for-win/issues/3171 but to summarize Hyper-V will reserve ranges of ports // which do not show up under the "netstat -ano" but can only be found by // "netsh interface ipv4 show excludedportrange protocol=tcp". We'll use []exclusions to hold those ranges and // retry if the port returned by GetAvailableLocalAddress falls in one of those them. var exclusions []portpair portFound := false if runtime.GOOS == "windows" { exclusions = getExclusionsList(tb, network) } var endpoint string for !portFound { endpoint = findAvailableAddress(tb, network) _, port, err := net.SplitHostPort(endpoint) require.NoError(tb, err) portFound = true if runtime.GOOS == "windows" { for _, pair := range exclusions { if port >= pair.first && port <= pair.last { portFound = false break } } } } return endpoint } func findAvailableAddress(tb testing.TB, network string) string { var host string switch network { case "tcp", "tcp4": host = "localhost" case "tcp6": host = "[::1]" } require.NotEmpty(tb, host, "network must be either of tcp, tcp4 or tcp6") ln, err := net.Listen("tcp", host+":0") require.NoError(tb, err, "Failed to get a free local port") // There is a possible race if something else takes this same port before // the test uses it, however, that is unlikely in practice. defer func() { assert.NoError(tb, ln.Close()) }() return ln.Addr().String() } // Get excluded ports on Windows from the command: netsh interface ipv4 show excludedportrange protocol=tcp func getExclusionsList(tb testing.TB, network string) []portpair { var cmdTCP *exec.Cmd switch network { case "tcp", "tcp4": cmdTCP = exec.Command("netsh", "interface", "ipv4", "show", "excludedportrange", "protocol=tcp") case "tcp6": cmdTCP = exec.Command("netsh", "interface", "ipv6", "show", "excludedportrange", "protocol=tcp") } require.NotZero(tb, cmdTCP, "network must be either of tcp, tcp4 or tcp6") outputTCP, errTCP := cmdTCP.CombinedOutput() require.NoError(tb, errTCP) exclusions := createExclusionsList(tb, string(outputTCP)) cmdUDP := exec.Command("netsh", "interface", "ipv4", "show", "excludedportrange", "protocol=udp") outputUDP, errUDP := cmdUDP.CombinedOutput() require.NoError(tb, errUDP) exclusions = append(exclusions, createExclusionsList(tb, string(outputUDP))...) return exclusions } func createExclusionsList(tb testing.TB, exclusionsText string) []portpair { var exclusions []portpair parts := strings.Split(exclusionsText, "--------") require.Len(tb, parts, 3) portsText := strings.Split(parts[2], "*") require.Greater(tb, len(portsText), 1) // original text may have a suffix like " - Administered port exclusions." lines := strings.SplitSeq(portsText[0], "\n") for line := range lines { if strings.TrimSpace(line) != "" { entries := strings.Fields(strings.TrimSpace(line)) require.Len(tb, entries, 2) pair := portpair{entries[0], entries[1]} exclusions = append(exclusions, pair) } } return exclusions } opentelemetry-collector-0.141.0/internal/testutil/testutil_test.go000066400000000000000000000033571511331344600255020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testutil import ( "net" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestGetAvailableLocalAddress(t *testing.T) { endpoint := GetAvailableLocalAddress(t) // Endpoint should be free. ln0, err := net.Listen("tcp", endpoint) require.NoError(t, err) require.NotNil(t, ln0) t.Cleanup(func() { assert.NoError(t, ln0.Close()) }) // Ensure that the endpoint wasn't something like ":0" by checking that a // second listener will fail. ln1, err := net.Listen("tcp", endpoint) require.Error(t, err) require.Nil(t, ln1) } func TestGetAvailableLocalIpv6Address(t *testing.T) { endpoint := GetAvailableLocalIPv6Address(t) // Endpoint should be free. ln0, err := net.Listen("tcp", endpoint) require.NoError(t, err) require.NotNil(t, ln0) t.Cleanup(func() { assert.NoError(t, ln0.Close()) }) // Ensure that the endpoint wasn't something like ":0" by checking that a // second listener will fail. ln1, err := net.Listen("tcp", endpoint) require.Error(t, err) require.Nil(t, ln1) } func TestCreateExclusionsList(t *testing.T) { // Test two examples of typical output from "netsh interface ipv4 show excludedportrange protocol=tcp" emptyExclusionsText := ` Protocol tcp Port Exclusion Ranges Start Port End Port ---------- -------- * - Administered port exclusions.` exclusionsText := ` Start Port End Port ---------- -------- 49697 49796 49797 49896 * - Administered port exclusions. ` exclusions := createExclusionsList(t, exclusionsText) require.Len(t, exclusions, 2) emptyExclusions := createExclusionsList(t, emptyExclusionsText) require.Empty(t, emptyExclusions) } opentelemetry-collector-0.141.0/internal/tools/000077500000000000000000000000001511331344600215125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/internal/tools/Makefile000066400000000000000000000000361511331344600231510ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/internal/tools/go.mod000066400000000000000000000340301511331344600226200ustar00rootroot00000000000000module go.opentelemetry.io/collector/internal/tools go 1.24.0 tool ( github.com/a8m/envsubst/cmd/envsubst github.com/client9/misspell/cmd/misspell github.com/golangci/golangci-lint/v2/cmd/golangci-lint github.com/google/addlicense github.com/jcchavezs/porto/cmd/porto github.com/pavius/impi/cmd/impi github.com/rhysd/actionlint/cmd/actionlint go.opentelemetry.io/build-tools/checkapi go.opentelemetry.io/build-tools/checkfile go.opentelemetry.io/build-tools/chloggen go.opentelemetry.io/build-tools/crosslink go.opentelemetry.io/build-tools/githubgen go.opentelemetry.io/build-tools/multimod golang.org/x/exp/cmd/apidiff golang.org/x/tools/cmd/goimports golang.org/x/vuln/cmd/govulncheck gotest.tools/gotestsum mvdan.cc/gofumpt ) require ( 4d63.com/gocheckcompilerdirectives v1.3.0 // indirect 4d63.com/gochecknoglobals v0.2.2 // indirect codeberg.org/chavacava/garif v0.2.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 github.com/Abirdcfly/dupword v0.1.7 // indirect github.com/AdminBenni/iota-mixing v1.0.0 // indirect github.com/AlwxSin/noinlineerr v1.0.5 // indirect 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/BurntSushi/toml v1.5.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.2.1 // indirect github.com/OpenPeeDeeP/depguard/v2 v2.2.1 // indirect github.com/ProtonMail/go-crypto v1.3.0 // indirect github.com/a8m/envsubst v1.4.3 // indirect github.com/alecthomas/chroma/v2 v2.20.0 // indirect github.com/alecthomas/go-check-sumtype v0.3.1 // indirect github.com/alexkohler/nakedret/v2 v2.0.6 // indirect github.com/alexkohler/prealloc v1.0.0 // indirect github.com/alfatraining/structtag v1.0.0 // indirect github.com/alingse/asasalint v0.0.11 // indirect github.com/alingse/nilnesserr v0.2.0 // indirect github.com/ashanbrown/forbidigo/v2 v2.3.0 // indirect github.com/ashanbrown/makezero/v2 v2.1.0 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bitfield/gotestdox v0.2.2 // indirect github.com/bkielbasa/cyclop v1.2.3 // indirect github.com/blizzy78/varnamelen v0.8.0 // indirect github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect github.com/bombsimon/wsl/v4 v4.7.0 // indirect github.com/bombsimon/wsl/v5 v5.3.0 // indirect github.com/breml/bidichk v0.3.3 // indirect github.com/breml/errchkjson v0.4.1 // indirect github.com/butuzov/ireturn v0.4.0 // indirect github.com/butuzov/mirror v1.3.0 // indirect github.com/catenacyber/perfsprint v0.10.0 // indirect github.com/ccojocar/zxcvbn-go v1.0.4 // 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 github.com/charmbracelet/lipgloss v1.1.0 // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect 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/client9/misspell v0.3.4 // indirect github.com/cloudflare/circl v1.6.1 // indirect github.com/curioswitch/go-reassign v0.3.0 // indirect github.com/cyphar/filepath-securejoin v0.5.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/dlclark/regexp2 v1.11.5 // indirect github.com/dnephin/pflag v1.0.7 // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/ettle/strcase v0.2.0 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fatih/structtag v1.2.0 // 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 github.com/ghostiam/protogetter v0.3.17 // indirect github.com/go-critic/go-critic v0.14.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.6.2 // indirect github.com/go-git/go-git/v5 v5.16.3 // indirect github.com/go-json-experiment/json v0.0.0-20250813233538-9b1f9ea2e11b // 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 github.com/go-toolsmith/astfmt v1.1.0 // indirect github.com/go-toolsmith/astp v1.1.0 // indirect github.com/go-toolsmith/strparse v1.1.0 // indirect github.com/go-toolsmith/typep v1.1.0 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/go-xmlfmt/xmlfmt v1.1.3 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-yaml v1.18.0 // indirect github.com/godoc-lint/godoc-lint v0.10.1 // indirect github.com/gofrs/flock v0.13.0 // indirect github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect github.com/golangci/asciicheck v0.5.0 // indirect github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 // indirect github.com/golangci/go-printf-func-name v0.1.1 // indirect github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d // indirect github.com/golangci/golangci-lint/v2 v2.6.2 // indirect github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 // indirect github.com/golangci/misspell v0.7.0 // indirect github.com/golangci/plugin-module-register v0.1.2 // indirect github.com/golangci/revgrep v0.8.0 // indirect github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e // indirect github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e // indirect github.com/google/addlicense v1.2.0 // indirect github.com/google/go-cmp v0.7.0 // indirect github.com/google/go-github/v76 v76.0.0 // indirect github.com/google/go-querystring v1.1.0 // 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 github.com/gostaticanalysis/comment v1.5.0 // indirect github.com/gostaticanalysis/forcetypeassert v0.2.0 // indirect github.com/gostaticanalysis/nilerr v0.1.2 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect github.com/hashicorp/go-retryablehttp v0.7.8 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/hexops/gotextdiff v1.0.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jcchavezs/porto v0.7.0 // indirect github.com/jgautheron/goconst v1.8.2 // indirect github.com/jingyugao/rowserrcheck v1.1.1 // indirect github.com/jjti/go-spancheck v0.6.5 // indirect github.com/julz/importas v0.2.0 // indirect github.com/kaptinlin/go-i18n v0.1.6 // indirect github.com/kaptinlin/jsonschema v0.4.12 // indirect github.com/kaptinlin/messageformat-go v0.4.0 // indirect github.com/karamaru-alpha/copyloopvar v1.2.2 // indirect github.com/kevinburke/ssh_config v1.4.0 // indirect github.com/kisielk/errcheck v1.9.0 // indirect github.com/kisielk/gotool v1.0.0 // indirect github.com/kkHAIKE/contextcheck v1.1.6 // indirect github.com/klauspost/cpuid/v2 v2.3.0 // 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 github.com/ldez/exptostd v0.4.5 // indirect github.com/ldez/gomoddirectives v0.7.1 // indirect github.com/ldez/grignotin v0.10.1 // indirect github.com/ldez/tagliatelle v0.7.2 // indirect 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/macabu/inamedparam v0.2.0 // 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 github.com/maratori/testpackage v1.1.2 // indirect github.com/matoous/godox v1.1.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.17 // indirect github.com/mattn/go-shellwords v1.0.12 // indirect github.com/mgechev/revive v1.12.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/moricho/tparallel v0.3.2 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/nakabonne/nestif v0.3.1 // indirect github.com/nishanths/exhaustive v0.12.0 // indirect github.com/nishanths/predeclared v0.2.2 // indirect github.com/nunnatsa/ginkgolinter v0.21.2 // indirect github.com/pavius/impi v0.0.3 // indirect github.com/pelletier/go-toml/v2 v2.2.4 // indirect github.com/pjbgf/sha1cd v0.5.0 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/polyfloyd/go-errorlint v1.8.0 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.66.1 // indirect github.com/prometheus/procfs v0.16.1 // indirect github.com/quasilyte/go-ruleguard v0.4.5 // indirect github.com/quasilyte/go-ruleguard/dsl v0.3.23 // indirect github.com/quasilyte/gogrep v0.5.0 // indirect github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 // indirect github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect github.com/raeperd/recvcheck v0.2.0 // indirect github.com/rhysd/actionlint v1.7.9 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/robfig/cron/v3 v3.0.1 // indirect github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/ryancurrah/gomodguard v1.4.1 // indirect github.com/ryanrolds/sqlclosecheck v0.5.1 // indirect github.com/sagikazarmark/locafero v0.12.0 // indirect github.com/sanposhiho/wastedassign/v2 v2.1.0 // indirect github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect github.com/sashamelentyev/interfacebloat v1.1.0 // indirect github.com/sashamelentyev/usestdlibvars v1.29.0 // indirect github.com/securego/gosec/v2 v2.22.10 // indirect github.com/sergi/go-diff v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/sivchari/containedctx v1.0.3 // indirect github.com/skeema/knownhosts v1.3.2 // indirect github.com/sonatard/noctx v0.4.0 // indirect github.com/sourcegraph/go-diff v0.7.0 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.10.0 // indirect github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.10 // indirect github.com/spf13/viper v1.21.0 // indirect github.com/ssgreg/nlreturn/v2 v2.2.1 // indirect github.com/stbenjam/no-sprintf-host-port v0.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/subosito/gotenv v1.6.0 // 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/tomarrell/wrapcheck/v2 v2.11.0 // indirect github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect github.com/ultraware/funlen v0.2.0 // indirect github.com/ultraware/whitespace v0.2.0 // indirect github.com/uudashr/gocognit v1.2.0 // indirect github.com/uudashr/iface v1.4.1 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xen0n/gosmopolitan v1.3.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/yagipy/maintidx v1.0.0 // indirect github.com/yeya24/promlinter v0.3.0 // indirect github.com/ykadowak/zerologlint v0.1.5 // 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 go.augendre.info/arangolint v0.3.1 // indirect go.augendre.info/fatcontext v0.9.0 // indirect go.opentelemetry.io/build-tools v0.29.0 // indirect go.opentelemetry.io/build-tools/checkapi v0.29.0 // indirect go.opentelemetry.io/build-tools/checkfile v0.29.0 // indirect go.opentelemetry.io/build-tools/chloggen v0.29.0 // indirect go.opentelemetry.io/build-tools/crosslink v0.29.0 // indirect go.opentelemetry.io/build-tools/githubgen v0.29.0 // indirect go.opentelemetry.io/build-tools/multimod v0.29.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/exp/typeparams v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/mod v0.30.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect golang.org/x/term v0.37.0 // indirect golang.org/x/text v0.31.0 // indirect golang.org/x/tools v0.39.0 // indirect golang.org/x/vuln v1.1.4 // indirect google.golang.org/protobuf v1.36.8 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect gotest.tools/gotestsum v1.13.0 // indirect honnef.co/go/tools v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea // indirect mvdan.cc/gofumpt v0.9.2 // indirect mvdan.cc/unparam v0.0.0-20251027182757-5beb8c8f8f15 // indirect ) retract ( v0.57.1 // Release failed, use v0.57.2 v0.57.0 // Release failed, use v0.57.2 ) opentelemetry-collector-0.141.0/internal/tools/go.sum000066400000000000000000002017571511331344600226610ustar00rootroot000000000000004d63.com/gocheckcompilerdirectives v1.3.0 h1:Ew5y5CtcAAQeTVKUVFrE7EwHMrTO6BggtEj8BZSjZ3A= 4d63.com/gocheckcompilerdirectives v1.3.0/go.mod h1:ofsJ4zx2QAuIP/NO/NAh1ig6R1Fb18/GI7RVMwz7kAY= 4d63.com/gochecknoglobals v0.2.2 h1:H1vdnwnMaZdQW/N+NrkT1SZMTBmcwHe9Vq8lJcYYTtU= 4d63.com/gochecknoglobals v0.2.2/go.mod h1:lLxwTQjL5eIesRbvnzIP3jZtG140FnTdz+AlMa+ogt0= codeberg.org/chavacava/garif v0.2.0 h1:F0tVjhYbuOCnvNcU3YSpO6b3Waw6Bimy4K0mM8y6MfY= codeberg.org/chavacava/garif v0.2.0/go.mod h1:P2BPbVbT4QcvLZrORc2T29szK3xEOlnl0GiPTJmEqBQ= 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= dev.gaijin.team/go/golib v0.6.0/go.mod h1:uY1mShx8Z/aNHWDyAkZTkX+uCi5PdX7KsG1eDQa2AVE= 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/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= github.com/AlwxSin/noinlineerr v1.0.5/go.mod h1:+QgkkoYrMH7RHvcdxdlI7vYYEdgeoFOVjU9sUhw/rQc= github.com/Antonboom/errname v1.1.1 h1:bllB7mlIbTVzO9jmSWVWLjxTEbGBVQ1Ff/ClQgtPw9Q= github.com/Antonboom/errname v1.1.1/go.mod h1:gjhe24xoxXp0ScLtHzjiXp0Exi1RFLKJb0bVBtWKCWQ= github.com/Antonboom/nilnil v1.1.1 h1:9Mdr6BYd8WHCDngQnNVV0b554xyisFioEKi30sksufQ= 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/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Djarvur/go-err113 v0.1.1 h1:eHfopDqXRwAi+YmCUas75ZE0+hoBHJ2GQNLYRSxao4g= 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.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= 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.2.1 h1:M+zdXMq84g+E1YOLa7g7ExN3dWfZQrdDSTCM7gC+m/A= github.com/MirrexOne/unqueryvet v1.2.1/go.mod h1:IWwCwMQlSWjAIteW0t+28Q5vouyktfujzYznSIWiuOg= github.com/OpenPeeDeeP/depguard/v2 v2.2.1 h1:vckeWVESWp6Qog7UZSARNqfu/cZqvki8zsuj3piCMx4= github.com/OpenPeeDeeP/depguard/v2 v2.2.1/go.mod h1:q4DKzC4UcVaAvcfd41CZh0PWpGgzrVxUYBlgKNGquUo= github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= github.com/a8m/envsubst v1.4.3 h1:kDF7paGK8QACWYaQo6KtyYBozY2jhQrTuNNuUxQkhJY= github.com/a8m/envsubst v1.4.3/go.mod h1:4jjHWQlZoaXPoLQUb7H2qT4iLkZDdmEQiOUogdUmqVU= github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw= github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA= github.com/alecthomas/go-check-sumtype v0.3.1 h1:u9aUvbGINJxLVXiFvHUlPEaD7VDULsrxJb4Aq31NLkU= github.com/alecthomas/go-check-sumtype v0.3.1/go.mod h1:A8TSiN3UPRw3laIgWEUOHHLPa6/r9MtoigdlP5h3K/E= github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg= github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= github.com/alexkohler/nakedret/v2 v2.0.6 h1:ME3Qef1/KIKr3kWX3nti3hhgNxw6aqN5pZmQiFSsuzQ= github.com/alexkohler/nakedret/v2 v2.0.6/go.mod h1:l3RKju/IzOMQHmsEvXwkqMDzHHvurNQfAgE1eVmT40Q= github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pOcUuw= github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE= github.com/alfatraining/structtag v1.0.0 h1:2qmcUqNcCoyVJ0up879K614L9PazjBSFruTB0GOFjCc= github.com/alfatraining/structtag v1.0.0/go.mod h1:p3Xi5SwzTi+Ryj64DqjLWz7XurHxbGsq6y3ubePJPus= github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw= github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I= github.com/alingse/nilnesserr v0.2.0 h1:raLem5KG7EFVb4UIDAXgrv3N2JIaffeKNtcEXkEWd/w= github.com/alingse/nilnesserr v0.2.0/go.mod h1:1xJPrXonEtX7wyTq8Dytns5P2hNzoWymVUIaKm4HNFg= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/ashanbrown/forbidigo/v2 v2.3.0 h1:OZZDOchCgsX5gvToVtEBoV2UWbFfI6RKQTir2UZzSxo= 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/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bitfield/gotestdox v0.2.2 h1:x6RcPAbBbErKLnapz1QeAlf3ospg8efBsedU93CDsnE= github.com/bitfield/gotestdox v0.2.2/go.mod h1:D+gwtS0urjBrzguAkTM2wodsTQYFHdpx8eqRJ3N+9pY= github.com/bkielbasa/cyclop v1.2.3 h1:faIVMIGDIANuGPWH031CZJTi2ymOQBULs9H21HSMa5w= github.com/bkielbasa/cyclop v1.2.3/go.mod h1:kHTwA9Q0uZqOADdupvcFJQtp/ksSnytRMe8ztxG8Fuo= github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M= github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k= github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE= github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bombsimon/wsl/v4 v4.7.0 h1:1Ilm9JBPRczjyUs6hvOPKvd7VL1Q++PL8M0SXBDf+jQ= github.com/bombsimon/wsl/v4 v4.7.0/go.mod h1:uV/+6BkffuzSAVYD+yGyld1AChO7/EuLrCF/8xTiapg= github.com/bombsimon/wsl/v5 v5.3.0 h1:nZWREJFL6U3vgW/B1lfDOigl+tEF6qgs6dGGbFeR0UM= github.com/bombsimon/wsl/v5 v5.3.0/go.mod h1:Gp8lD04z27wm3FANIUPZycXp+8huVsn0oxc+n4qfV9I= github.com/breml/bidichk v0.3.3 h1:WSM67ztRusf1sMoqH6/c4OBCUlRVTKq+CbSeo0R17sE= github.com/breml/bidichk v0.3.3/go.mod h1:ISbsut8OnjB367j5NseXEGGgO/th206dVa427kR8YTE= github.com/breml/errchkjson v0.4.1 h1:keFSS8D7A2T0haP9kzZTi7o26r7kE3vymjZNeNDRDwg= github.com/breml/errchkjson v0.4.1/go.mod h1:a23OvR6Qvcl7DG/Z4o0el6BRAjKnaReoPQFciAl9U3s= github.com/butuzov/ireturn v0.4.0 h1:+s76bF/PfeKEdbG8b54aCocxXmi0wvYdOVsWxVO7n8E= github.com/butuzov/ireturn v0.4.0/go.mod h1:ghI0FrCmap8pDWZwfPisFD1vEc56VKH4NpQUxDHta70= github.com/butuzov/mirror v1.3.0 h1:HdWCXzmwlQHdVhwvsfBb2Au0r3HyINry3bDWLYXiKoc= github.com/butuzov/mirror v1.3.0/go.mod h1:AEij0Z8YMALaq4yQj9CPPVYOyJQyiexpQEQgihajRfI= github.com/catenacyber/perfsprint v0.10.0 h1:AZj1mYyxbxLRqmnYOeguZXEQwWOgQGm2wzLI5d7Hl/0= github.com/catenacyber/perfsprint v0.10.0/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/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/charithe/durationcheck v0.0.11 h1:g1/EX1eIiKS57NTWsYtHDZ/APfeXKhye1DidBcABctk= github.com/charithe/durationcheck v0.0.11/go.mod h1:x5iZaixRNl8ctbM+3B2RrPG5t856TxRyVQEnbIEM2X4= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= github.com/ckaznocha/intrange v0.3.1 h1:j1onQyXvHUsPWujDH6WIjhyH26gkRt/txNlV7LspvJs= github.com/ckaznocha/intrange v0.3.1/go.mod h1:QVepyz1AkUoFQkpEqksSYpNpUo3c5W7nWh/s6SHIJJk= github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= 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/cyphar/filepath-securejoin v0.5.0 h1:hIAhkRBMQ8nIeuVwcAoymp7MY4oherZdAxD+m0u9zaw= github.com/cyphar/filepath-securejoin v0.5.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= github.com/daixiang0/gci v0.13.7 h1:+0bG5eK9vlI08J+J/NWGbWPTNiXPG4WhNLJOkSxWITQ= github.com/daixiang0/gci v0.13.7/go.mod h1:812WVN6JLFY9S6Tv76twqmNqevN0pa3SX3nih0brVzQ= github.com/dave/dst v0.27.3 h1:P1HPoMza3cMEquVf9kKy8yXsFirry4zEnWOdYPOoIzY= github.com/dave/dst v0.27.3/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= github.com/dave/jennifer v1.7.1 h1:B4jJJDHelWcDhlRQxWeo0Npa/pYKBLrirAQoTN45txo= github.com/dave/jennifer v1.7.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 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/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/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/ettle/strcase v0.2.0 h1:fGNiVF21fHXpX1niBgk0aROov1LagYsOwV/xqKDKR/Q= github.com/ettle/strcase v0.2.0/go.mod h1:DajmHElDSaX76ITe3/VHVyMin4LWSJN5Z909Wp+ED1A= github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/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/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.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA= github.com/ghostiam/protogetter v0.3.17 h1:sjGPErP9o7i2Ym+z3LsQzBdLCNaqbYy2iJQPxGXg04Q= github.com/ghostiam/protogetter v0.3.17/go.mod h1:AivIX1eKA/TcUmzZdzbl+Tb8tjIe8FcyG6JFyemQAH4= github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= github.com/go-critic/go-critic v0.14.2 h1:PMvP5f+LdR8p6B29npvChUXbD1vrNlKDf60NJtgMBOo= github.com/go-critic/go-critic v0.14.2/go.mod h1:xwntfW6SYAd7h1OqDzmN6hBX/JxsEKl5up/Y2bsxgVQ= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= github.com/go-git/go-git/v5 v5.16.3 h1:Z8BtvxZ09bYm/yYNgPKCzgWtaRqDTgIKRgIRHBfU6Z8= github.com/go-git/go-git/v5 v5.16.3/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= github.com/go-json-experiment/json v0.0.0-20250813233538-9b1f9ea2e11b h1:6Q4zRHXS/YLOl9Ng1b1OOOBWMidAQZR3Gel0UKPC/KU= github.com/go-json-experiment/json v0.0.0-20250813233538-9b1f9ea2e11b/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= 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-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= github.com/go-toolsmith/astcopy v1.1.0 h1:YGwBN0WM+ekI/6SS6+52zLDEf8Yvp3n2seZITCUBt5s= github.com/go-toolsmith/astcopy v1.1.0/go.mod h1:hXM6gan18VA1T/daUEHCFcYiW8Ai1tIwIzHY6srfEAw= github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4= github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ= github.com/go-toolsmith/astequal v1.2.0 h1:3Fs3CYZ1k9Vo4FzFhwwewC3CHISHDnVUPC4x0bI2+Cw= github.com/go-toolsmith/astequal v1.2.0/go.mod h1:c8NZ3+kSFtFY/8lPso4v8LuJjdJiUFVnSuU3s0qrrDY= github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco= github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4= github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus= github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/go-xmlfmt/xmlfmt v1.1.3 h1:t8Ey3Uy7jDSEisW2K3somuMKIpzktkWptA0iFCnRUWY= 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/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/godoc-lint/godoc-lint v0.10.1 h1:ZPUVzlDtJfA+P688JfPJPkI/SuzcBr/753yGIk5bOPA= github.com/godoc-lint/godoc-lint v0.10.1/go.mod h1:KleLcHu/CGSvkjUH2RvZyoK1MBC7pDQg4NxMYLcBBsw= github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw= github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= github.com/golangci/asciicheck v0.5.0 h1:jczN/BorERZwK8oiFBOGvlGPknhvq0bjnysTj4nUfo0= github.com/golangci/asciicheck v0.5.0/go.mod h1:5RMNAInbNFw2krqN6ibBxN/zfRFa9S6tA1nPdM0l8qQ= github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32 h1:WUvBfQL6EW/40l6OmeSBYQJNSif4O11+bmWEz+C7FYw= github.com/golangci/dupl v0.0.0-20250308024227-f665c8d69b32/go.mod h1:NUw9Zr2Sy7+HxzdjIULge71wI6yEg1lWQr7Evcu8K0E= github.com/golangci/go-printf-func-name v0.1.1 h1:hIYTFJqAGp1iwoIfsNTpoq1xZAarogrvjO9AfiW3B4U= github.com/golangci/go-printf-func-name v0.1.1/go.mod h1:Es64MpWEZbh0UBtTAICOZiB+miW53w/K9Or/4QogJss= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d h1:viFft9sS/dxoYY0aiOTsLKO2aZQAPT4nlQCsimGcSGE= github.com/golangci/gofmt v0.0.0-20250106114630-d62b90e6713d/go.mod h1:ivJ9QDg0XucIkmwhzCDsqcnxxlDStoTl89jDMIoNxKY= github.com/golangci/golangci-lint/v2 v2.6.2 h1:jkMSVv36JmyTENcEertckvimvjPcD5qxNM7W7qhECvI= github.com/golangci/golangci-lint/v2 v2.6.2/go.mod h1:fSIMDiBt9kzdpnvvV7GO6iWzyv5uaeZ+iPor+2uRczE= github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95 h1:AkK+w9FZBXlU/xUmBtSJN1+tAI4FIvy5WtnUnY8e4p8= github.com/golangci/golines v0.0.0-20250217134842-442fd0091d95/go.mod h1:k9mmcyWKSTMcPPvQUCfRWWQ9VHJ1U9Dc0R7kaXAgtnQ= github.com/golangci/misspell v0.7.0 h1:4GOHr/T1lTW0hhR4tgaaV1WS/lJ+ncvYCoFKmqJsj0c= github.com/golangci/misspell v0.7.0/go.mod h1:WZyyI2P3hxPY2UVHs3cS8YcllAeyfquQcKfdeE9AFVg= github.com/golangci/plugin-module-register v0.1.2 h1:e5WM6PO6NIAEcij3B053CohVp3HIYbzSuP53UAYgOpg= github.com/golangci/plugin-module-register v0.1.2/go.mod h1:1+QGTsKBvAIvPvoY/os+G5eoqxWn70HYDm2uvUyGuVw= github.com/golangci/revgrep v0.8.0 h1:EZBctwbVd0aMeRnNUsFogoyayvKHyxlV3CdUA46FX2s= github.com/golangci/revgrep v0.8.0/go.mod h1:U4R/s9dlXZsg8uJmaR1GrloUr14D7qDl8gi2iPXJH8k= github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e h1:ai0EfmVYE2bRA5htgAG9r7s3tHsfjIhN98WshBTJ9jM= github.com/golangci/swaggoswag v0.0.0-20250504205917-77f2aca3143e/go.mod h1:Vrn4B5oR9qRwM+f54koyeH3yzphlecwERs0el27Fr/s= github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e h1:gD6P7NEo7Eqtt0ssnqSJNNndxe69DOQ24A5h7+i3KpM= github.com/golangci/unconvert v0.0.0-20250410112200-a129a6e6413e/go.mod h1:h+wZwLjUTJnm/P2rwlbJdRPZXOzaT36/FwnPnY2inzc= github.com/google/addlicense v1.2.0 h1:W+DP4A639JGkcwBGMDvjSurZHvaq2FN0pP7se9czsKA= github.com/google/addlicense v1.2.0/go.mod h1:Sm/DHu7Jk+T5miFHHehdIjbi4M5+dJDRS3Cq0rncIxA= github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU= github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o= github.com/google/go-cmp v0.5.2/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.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= github.com/google/go-github/v76 v76.0.0 h1:MCa9VQn+VG5GG7Y7BAkBvSRUN3o+QpaEOuZwFPJmdFA= github.com/google/go-github/v76 v76.0.0/go.mod h1:38+d/8pYDO4fBLYfBhXF5EKO0wA3UkXBjfmQapFsNCQ= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6 h1:EEHtgt9IwisQ2AZ4pIsMjahcegHh6rmhqxzIRQIyepY= github.com/google/pprof v0.0.0-20250820193118-f64d9cf942d6/go.mod h1:I6V7YzU0XDpsHqbsyrghnFZLO1gwK6NPTNvmetQIk9U= github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/gordonklaus/ineffassign v0.2.0 h1:Uths4KnmwxNJNzq87fwQQDDnbNb7De00VOk9Nu0TySs= github.com/gordonklaus/ineffassign v0.2.0/go.mod h1:TIpymnagPSexySzs7F9FnO1XFTy8IT3a59vmZp5Y9Lw= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= github.com/gostaticanalysis/comment v1.4.2/go.mod h1:KLUTGDv6HOCotCH8h2erHKmpci2ZoR8VPu34YA2uzdM= github.com/gostaticanalysis/comment v1.5.0 h1:X82FLl+TswsUMpMh17srGRuKaaXprTaytmEpgnKIDu8= github.com/gostaticanalysis/comment v1.5.0/go.mod h1:V6eb3gpCv9GNVqb6amXzEUX3jXLVK/AdA+IrAMSqvEc= github.com/gostaticanalysis/forcetypeassert v0.2.0 h1:uSnWrrUEYDr86OCxWa4/Tp2jeYDlogZiZHzGkWFefTk= github.com/gostaticanalysis/forcetypeassert v0.2.0/go.mod h1:M5iPavzE9pPqWyeiVXSFghQjljW1+l/Uke3PXHS6ILY= github.com/gostaticanalysis/nilerr v0.1.2 h1:S6nk8a9N8g062nsx63kUkF6AzbHGw7zzyHMcpu52xQU= github.com/gostaticanalysis/nilerr v0.1.2/go.mod h1:A19UHhoY3y8ahoL7YKz6sdjDtduwTSI4CsymaC2htPA= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+3Zh0sUGqw8= github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-immutable-radix/v2 v2.1.0 h1:CUW5RYIcysz+D3B+l1mDeXrQ7fUvGGCwJfdASSzbrfo= github.com/hashicorp/go-immutable-radix/v2 v2.1.0/go.mod h1:hgdqLXA4f6NIjRVisM1TJ9aOJVNRqKZj+xDGF6m7PBw= github.com/hashicorp/go-retryablehttp v0.7.8 h1:ylXZWnqa7Lhqpk0L1P1LzDtGcCR0rPVUrx/c8Unxc48= github.com/hashicorp/go-retryablehttp v0.7.8/go.mod h1:rjiScheydd+CxvumBsIrFKlx3iS0jrZ7LvzFGFmuKbw= github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8= github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-version v1.2.1/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jcchavezs/porto v0.7.0 h1:VncK84yxV7QZD4GdvoslzjnieSuruztGxLCmFi/Eu28= github.com/jcchavezs/porto v0.7.0/go.mod h1:tQ1cJ85cNzzZg/58VuZWOLbmrjcH1wPxkWgeBjvOq5o= github.com/jgautheron/goconst v1.8.2 h1:y0XF7X8CikZ93fSNT6WBTb/NElBu9IjaY7CCYQrCMX4= github.com/jgautheron/goconst v1.8.2/go.mod h1:A0oxgBCHy55NQn6sYpO7UdnA9p+h7cPtoOZUmvNIako= github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjzq7gFzUs= github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c= github.com/jjti/go-spancheck v0.6.5 h1:lmi7pKxa37oKYIMScialXUK6hP3iY5F1gu+mLBPgYB8= github.com/jjti/go-spancheck v0.6.5/go.mod h1:aEogkeatBrbYsyW6y5TgDfihCulDYciL1B7rG2vSsrU= github.com/julz/importas v0.2.0 h1:y+MJN/UdL63QbFJHws9BVC5RpA2iq0kpjrFajTGivjQ= github.com/julz/importas v0.2.0/go.mod h1:pThlt589EnCYtMnmhmRYY/qn9lCf/frPOK+WMx3xiJY= github.com/kaptinlin/go-i18n v0.1.6 h1:XQT3qvE/xgNrAps/zXBHAKWhPlWSrFS9t1jCZ4PVnOs= github.com/kaptinlin/go-i18n v0.1.6/go.mod h1:MoHPYUYQug2jyLygIWeT9F3VDUZEP480cKotmtQjUCc= github.com/kaptinlin/jsonschema v0.4.12 h1:10cy+j2b69jyOX+F+u9suLK2dw0k63UqzUNctpxiV3A= github.com/kaptinlin/jsonschema v0.4.12/go.mod h1:zG+WOWvAxUaPUnh83QrV/a/fsfloI6L6d/YM4mtZCHw= github.com/kaptinlin/messageformat-go v0.4.0 h1:L5wPgwQZkV1Rvs19htUT2RGx8N1GCq3uQG5nB6VHRcM= github.com/kaptinlin/messageformat-go v0.4.0/go.mod h1:LrLCV49C5ms/BZlOpFPihou+cPvhOQSvVJHj2wOe6w8= github.com/karamaru-alpha/copyloopvar v1.2.2 h1:yfNQvP9YaGQR7VaWLYcfZUlRP2eo2vhExWKxD/fP6q0= github.com/karamaru-alpha/copyloopvar v1.2.2/go.mod h1:oY4rGZqZ879JkJMtX3RRkcXRkmUvH0x35ykgaKgsgJY= github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ= github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= github.com/kisielk/errcheck v1.9.0 h1:9xt1zI9EBfcYBvdU1nVrzMzzUPUtPKs9bVSIM3TAb3M= github.com/kisielk/errcheck v1.9.0/go.mod h1:kQxWMMVZgIkDq7U8xtG/n2juOjbLgZtedi0D+/VL/i8= github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kkHAIKE/contextcheck v1.1.6 h1:7HIyRcnyzxL9Lz06NGhiKvenXq7Zw6Q0UQu/ttjfJCE= github.com/kkHAIKE/contextcheck v1.1.6/go.mod h1:3dDbMRNBFaq8HFXWC1JyvDSPm43CmE6IuHam8Wr0rkg= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kulti/thelper v0.7.1 h1:fI8QITAoFVLx+y+vSyuLBP+rcVIB8jKooNSCT2EiI98= github.com/kulti/thelper v0.7.1/go.mod h1:NsMjfQEy6sd+9Kfw8kCP61W1I0nerGSYSFnGaxQkcbs= github.com/kunwardeep/paralleltest v1.0.15 h1:ZMk4Qt306tHIgKISHWFJAO1IDQJLc6uDyJMLyncOb6w= github.com/kunwardeep/paralleltest v1.0.15/go.mod h1:di4moFqtfz3ToSKxhNjhOZL+696QtJGCFe132CbBLGk= github.com/lasiar/canonicalheader v1.1.2 h1:vZ5uqwvDbyJCnMhmFYimgMZnJMjwljN5VGY0VKbMXb4= github.com/lasiar/canonicalheader v1.1.2/go.mod h1:qJCeLFS0G/QlLQ506T+Fk/fWMa2VmBUiEI2cuMK4djI= github.com/ldez/exptostd v0.4.5 h1:kv2ZGUVI6VwRfp/+bcQ6Nbx0ghFWcGIKInkG/oFn1aQ= github.com/ldez/exptostd v0.4.5/go.mod h1:QRjHRMXJrCTIm9WxVNH6VW7oN7KrGSht69bIRwvdFsM= github.com/ldez/gomoddirectives v0.7.1 h1:FaULkvUIG36hj6chpwa+FdCNGZBsD7/fO+p7CCsM6pE= github.com/ldez/gomoddirectives v0.7.1/go.mod h1:auDNtakWJR1rC+YX7ar+HmveqXATBAyEK1KYpsIRW/8= github.com/ldez/grignotin v0.10.1 h1:keYi9rYsgbvqAZGI1liek5c+jv9UUjbvdj3Tbn5fn4o= github.com/ldez/grignotin v0.10.1/go.mod h1:UlDbXFCARrXbWGNGP3S5vsysNXAPhnSuBufpTEbwOas= github.com/ldez/tagliatelle v0.7.2 h1:KuOlL70/fu9paxuxbeqlicJnCspCRjH0x8FW+NfgYUk= github.com/ldez/tagliatelle v0.7.2/go.mod h1:PtGgm163ZplJfZMZ2sf5nhUT170rSuPgBimoyYtdaSI= github.com/ldez/usetesting v0.5.0 h1:3/QtzZObBKLy1F4F8jLuKJiKBjjVFi1IavpoWbmqLwc= github.com/ldez/usetesting v0.5.0/go.mod h1:Spnb4Qppf8JTuRgblLrEWb7IE6rDmUpGvxY3iRrzvDQ= github.com/leonklingele/grouper v1.1.2 h1:o1ARBDLOmmasUaNDesWqWCIFH3u7hoFlM84YrjT3mIY= 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/macabu/inamedparam v0.2.0 h1:VyPYpOc10nkhI2qeNUdh3Zket4fcZjEWe35poddBCpE= github.com/macabu/inamedparam v0.2.0/go.mod h1:+Pee9/YfGe5LJ62pYXqB89lJ+0k5bsR8Wgz/C0Zlq3U= 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= github.com/manuelarte/funcorder v0.5.0/go.mod h1:Yt3CiUQthSBMBxjShjdXMexmzpP8YGvGLjrxJNkO2hA= github.com/maratori/testableexamples v1.0.1 h1:HfOQXs+XgfeRBJ+Wz0XfH+FHnoY9TVqL6Fcevpzy4q8= github.com/maratori/testableexamples v1.0.1/go.mod h1:XE2F/nQs7B9N08JgyRmdGjYVGqxWwClLPCGSQhXQSrQ= github.com/maratori/testpackage v1.1.2 h1:ffDSh+AgqluCLMXhM19f/cpvQAKygKAJXFl9aUjmbqs= github.com/maratori/testpackage v1.1.2/go.mod h1:8F24GdVDFW5Ew43Et02jamrVMNXLUNaOynhDssITGfc= github.com/matoous/godox v1.1.0 h1:W5mqwbyWrwZv6OQ5Z1a/DHGMOvXYCBP3+Ht7KMoJhq4= github.com/matoous/godox v1.1.0/go.mod h1:jgE/3fUXiTurkdHOLT5WEkThTSuE7yxHv5iWPa80afs= github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE= github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.17 h1:78v8ZlW0bP43XfmAfPsdXcoNCelfMHsDmd/pkENfrjQ= github.com/mattn/go-runewidth v0.0.17/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= github.com/mgechev/revive v1.12.0 h1:Q+/kkbbwerrVYPv9d9efaPGmAO/NsxwW/nE6ahpQaCU= github.com/mgechev/revive v1.12.0/go.mod h1:VXsY2LsTigk8XU9BpZauVLjVrhICMOV3k1lpB3CXrp8= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/moricho/tparallel v0.3.2 h1:odr8aZVFA3NZrNybggMkYO3rgPRcqjeQUlBBFVxKHTI= github.com/moricho/tparallel v0.3.2/go.mod h1:OQ+K3b4Ln3l2TZveGCywybl68glfLEwFGqvnjok8b+U= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81U= github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE= github.com/nishanths/exhaustive v0.12.0 h1:vIY9sALmw6T/yxiASewa4TQcFsVYZQQRUQJhKRf3Swg= github.com/nishanths/exhaustive v0.12.0/go.mod h1:mEZ95wPIZW+x8kC4TgC+9YCUgiST7ecevsVDTgc2obs= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c= github.com/nunnatsa/ginkgolinter v0.21.2 h1:khzWfm2/Br8ZemX8QM1pl72LwM+rMeW6VUbQ4rzh0Po= github.com/nunnatsa/ginkgolinter v0.21.2/go.mod h1:GItSI5fw7mCGLPmkvGYrr1kEetZe7B593jcyOpyabsY= github.com/onsi/ginkgo/v2 v2.26.0 h1:1J4Wut1IlYZNEAWIV3ALrT9NfiaGW2cDCJQSFQMs/gE= github.com/onsi/ginkgo/v2 v2.26.0/go.mod h1:qhEywmzWTBUY88kfO0BRvX4py7scov9yR+Az2oavUzw= github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/copy v1.14.1 h1:5/7E6qsUMBaH5AnQ0sSLzzTg1oTECmcCmT6lvF45Na8= github.com/otiai10/copy v1.14.1/go.mod h1:oQwrEDDOci3IM8dJF0d8+jnbfPDllW6vUjNc3DoZm9I= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs= github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.1/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/otiai10/mint v1.6.3 h1:87qsV/aw1F5as1eH1zS/yqHY85ANKVMgkDrf9rcxbQs= github.com/otiai10/mint v1.6.3/go.mod h1:MJm72SBthJjz8qhefc4z1PYEieWmy8Bku7CjcAqyUSM= github.com/pavius/impi v0.0.3 h1:DND6MzU+BLABhOZXbELR3FU8b+zDgcq4dOCNLhiTYuI= github.com/pavius/impi v0.0.3/go.mod h1:x/hU0bfdWIhuOT1SKwiJg++yvkk6EuOtJk8WtDZqgr8= github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/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/polyfloyd/go-errorlint v1.8.0 h1:DL4RestQqRLr8U4LygLw8g2DX6RN1eBJOpa2mzsrl1Q= github.com/polyfloyd/go-errorlint v1.8.0/go.mod h1:G2W0Q5roxbLCt0ZQbdoxQxXktTjwNyDbEaj3n7jvl4s= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.66.1 h1:h5E0h5/Y8niHc5DlaLlWLArTQI7tMrsfQjHV+d9ZoGs= github.com/prometheus/common v0.66.1/go.mod h1:gcaUsgf3KfRSwHY4dIMXLPV0K/Wg1oZ8+SbZk/HH/dA= github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/quasilyte/go-ruleguard v0.4.5 h1:AGY0tiOT5hJX9BTdx/xBdoCubQUAE2grkqY2lSwvZcA= github.com/quasilyte/go-ruleguard v0.4.5/go.mod h1:Vl05zJ538vcEEwu16V/Hdu7IYZWyKSwIy4c88Ro1kRE= github.com/quasilyte/go-ruleguard/dsl v0.3.23 h1:lxjt5B6ZCiBeeNO8/oQsegE6fLeCzuMRoVWSkXC4uvY= github.com/quasilyte/go-ruleguard/dsl v0.3.23/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo= github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727 h1:TCg2WBOl980XxGFEZSS6KlBGIV0diGdySzxATTWoqaU= github.com/quasilyte/regex/syntax v0.0.0-20210819130434-b3f0c404a727/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs= github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/raeperd/recvcheck v0.2.0 h1:GnU+NsbiCqdC2XX5+vMZzP+jAJC5fht7rcVTAhX74UI= github.com/raeperd/recvcheck v0.2.0/go.mod h1:n04eYkwIR0JbgD73wT8wL4JjPC3wm0nFtzBnWNocnYU= github.com/rhysd/actionlint v1.7.9 h1:oq4uFwcW6pRTk8BhAS4+RhYoUddUkbvRMcqndja0CT0= github.com/rhysd/actionlint v1.7.9/go.mod h1:H3q8YpD2es7K4c+mibw3OhTXGQQ7HkZX1u+DXaHLwfE= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.4.1 h1:eWC8eUMNZ/wM/PWuZBv7JxxqT5fiIKSIyTvjb7Elr+g= github.com/ryancurrah/gomodguard v1.4.1/go.mod h1:qnMJwV1hX9m+YJseXEBhd2s90+1Xn6x9dLz11ualI1I= github.com/ryanrolds/sqlclosecheck v0.5.1 h1:dibWW826u0P8jNLsLN+En7+RqWWTYrjCB9fJfSfdyCU= github.com/ryanrolds/sqlclosecheck v0.5.1/go.mod h1:2g3dUjoS6AL4huFdv6wn55WpLIDjY7ZgUR4J8HOO/XQ= github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4= github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI= github.com/sanposhiho/wastedassign/v2 v2.1.0 h1:crurBF7fJKIORrV85u9UUpePDYGWnwvv3+A96WvwXT0= github.com/sanposhiho/wastedassign/v2 v2.1.0/go.mod h1:+oSmSC+9bQ+VUAxA66nBb0Z7N8CK7mscKTDYC6aIek4= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ= github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU= github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw= github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ= github.com/sashamelentyev/usestdlibvars v1.29.0 h1:8J0MoRrw4/NAXtjQqTHrbW9NN+3iMf7Knkq057v4XOQ= github.com/sashamelentyev/usestdlibvars v1.29.0/go.mod h1:8PpnjHMk5VdeWlVb4wCdrB8PNbLqZ3wBZTZWkrpZZL8= github.com/securego/gosec/v2 v2.22.10 h1:ntbBqdWXnu46DUOXn+R2SvPo3PiJCDugTCgTW2g4tQg= github.com/securego/gosec/v2 v2.22.10/go.mod h1:9UNjK3tLpv/w2b0+7r82byV43wCJDNtEDQMeS+H/g2w= github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 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.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sivchari/containedctx v1.0.3 h1:x+etemjbsh2fB5ewm5FeLNi5bUjK0V8n0RB+Wwfd0XE= github.com/sivchari/containedctx v1.0.3/go.mod h1:c1RDvCbnJLtH4lLcYD/GqwiBSSf4F5Qk0xld2rBqzJ4= github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg= github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow= github.com/sonatard/noctx v0.4.0 h1:7MC/5Gg4SQ4lhLYR6mvOP6mQVSxCrdyiExo7atBs27o= github.com/sonatard/noctx v0.4.0/go.mod h1:64XdbzFb18XL4LporKXp8poqZtPKbCrqQ402CV+kJas= github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0= github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY= github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/ssgreg/nlreturn/v2 v2.2.1 h1:X4XDI7jstt3ySqGU86YGAURbxw3oTDPK9sPEi6YEwQ0= github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I= github.com/stbenjam/no-sprintf-host-port v0.2.0 h1:i8pxvGrt1+4G0czLr/WnmyH7zbZ8Bg8etvARQ1rpyl4= github.com/stbenjam/no-sprintf-host-port v0.2.0/go.mod h1:eL0bQ9PasS0hsyTyfTjjG+E80QIyPnBVQbYZyv20Jfk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.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= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= 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/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/tomarrell/wrapcheck/v2 v2.11.0 h1:BJSt36snX9+4WTIXeJ7nvHBQBcm1h2SjQMSlmQ6aFSU= github.com/tomarrell/wrapcheck/v2 v2.11.0/go.mod h1:wFL9pDWDAbXhhPZZt+nG8Fu+h29TtnZ2MW6Lx4BRXIU= github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw= github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw= github.com/ultraware/funlen v0.2.0 h1:gCHmCn+d2/1SemTdYMiKLAHFYxTYz7z9VIDRaTGyLkI= github.com/ultraware/funlen v0.2.0/go.mod h1:ZE0q4TsJ8T1SQcjmkhN/w+MceuatI6pBFSxxyteHIJA= github.com/ultraware/whitespace v0.2.0 h1:TYowo2m9Nfj1baEQBjuHzvMRbp19i+RCcRYrSWoFa+g= github.com/ultraware/whitespace v0.2.0/go.mod h1:XcP1RLD81eV4BW8UhQlpaR+SDc2givTvyI8a586WjW8= github.com/uudashr/gocognit v1.2.0 h1:3BU9aMr1xbhPlvJLSydKwdLN3tEUUrzPSSM8S4hDYRA= github.com/uudashr/gocognit v1.2.0/go.mod h1:k/DdKPI6XBZO1q7HgoV2juESI2/Ofj9AcHPZhBBdrTU= github.com/uudashr/iface v1.4.1 h1:J16Xl1wyNX9ofhpHmQ9h9gk5rnv2A6lX/2+APLTo0zU= github.com/uudashr/iface v1.4.1/go.mod h1:pbeBPlbuU2qkNDn0mmfrxP2X+wjPMIQAy+r1MBXSXtg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/xen0n/gosmopolitan v1.3.0 h1:zAZI1zefvo7gcpbCOrPSHJZJYA9ZgLfJqtKzZ5pHqQM= github.com/xen0n/gosmopolitan v1.3.0/go.mod h1:rckfr5T6o4lBtM1ga7mLGKZmLxswUoH1zxHgNXOsEt4= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= github.com/yagipy/maintidx v1.0.0 h1:h5NvIsCz+nRDapQ0exNv4aJ0yXSI0420omVANTv3GJM= github.com/yagipy/maintidx v1.0.0/go.mod h1:0qNf/I/CCZXSMhsRsrEPDZ+DkekpKLXAJfsTACwgXLk= github.com/yeya24/promlinter v0.3.0 h1:JVDbMp08lVCP7Y6NP3qHroGAO6z2yGKQtS5JsjqtoFs= github.com/yeya24/promlinter v0.3.0/go.mod h1:cDfJQQYv9uYciW60QT0eeHlFodotkYZlL+YcPQN+mW4= github.com/ykadowak/zerologlint v0.1.5 h1:Gy/fMz1dFQN9JZTPjv1hxEk+sRWm05row04Yoolgdiw= github.com/ykadowak/zerologlint v0.1.5/go.mod h1:KaUskqF3e/v59oPmdq1U1DnKcuHokl2/K1U4pmIELKg= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 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= gitlab.com/bosi/decorder v0.4.2 h1:qbQaV3zgwnBZ4zPMhGLW4KZe7A7NwxEhJx39R3shffo= gitlab.com/bosi/decorder v0.4.2/go.mod h1:muuhHoaJkA9QLcYHq4Mj8FJUwDZ+EirSHRiaTcTf6T8= go-simpler.org/assert v0.9.0 h1:PfpmcSvL7yAnWyChSjOz6Sp6m9j5lyK8Ok9pEL31YkQ= go-simpler.org/assert v0.9.0/go.mod h1:74Eqh5eI6vCK6Y5l3PI8ZYFXG4Sa+tkr70OIPJAUr28= go-simpler.org/musttag v0.14.0 h1:XGySZATqQYSEV3/YTy+iX+aofbZZllJaqwFWs+RTtSo= go-simpler.org/musttag v0.14.0/go.mod h1:uP8EymctQjJ4Z1kUnjX0u2l60WfUdQxCwSNKzE1JEOE= go-simpler.org/sloglint v0.11.1 h1:xRbPepLT/MHPTCA6TS/wNfZrDzkGvCCqUv4Bdwc3H7s= go-simpler.org/sloglint v0.11.1/go.mod h1:2PowwiCOK8mjiF+0KGifVOT8ZsCNiFzvfyJeJOIt8MQ= go.augendre.info/arangolint v0.3.1 h1:n2E6p8f+zfXSFLa2e2WqFPp4bfvcuRdd50y6cT65pSo= go.augendre.info/arangolint v0.3.1/go.mod h1:6ZKzEzIZuBQwoSvlKT+qpUfIbBfFCE5gbAoTg0/117g= go.augendre.info/fatcontext v0.9.0 h1:Gt5jGD4Zcj8CDMVzjOJITlSb9cEch54hjRRlN3qDojE= go.augendre.info/fatcontext v0.9.0/go.mod h1:L94brOAT1OOUNue6ph/2HnwxoNlds9aXDF2FcUntbNw= go.opentelemetry.io/build-tools v0.29.0 h1:dG1zmHKYTMsP0zGT34+32/U+YR+lcJ8kka7Lc4RAoT4= go.opentelemetry.io/build-tools v0.29.0/go.mod h1:jTzBit47RqVApCwStu9qw2TfGqR2Fhu5jinLHqfhghQ= go.opentelemetry.io/build-tools/checkapi v0.29.0 h1:witlcpwRObFHyNBr0XM1P21C//jIUW25gxnO0V5sls0= go.opentelemetry.io/build-tools/checkapi v0.29.0/go.mod h1:BUlDXzIK1uVJC4mcYBzeNTiRk1HbKA8kf3N44zlhx9g= go.opentelemetry.io/build-tools/checkfile v0.29.0 h1:9ue2+J4x7NL9Nugahec6A9JsV4CUd0GhDiFxN3VUufE= go.opentelemetry.io/build-tools/checkfile v0.29.0/go.mod h1:vtBRUpSPWJdfdGV3/vodhcD3wiMp8fhQ03HOwmczeJQ= go.opentelemetry.io/build-tools/chloggen v0.29.0 h1:0HnDE47uJNlst1XtCukHB7sQYtUlJjmvdhWVdJn+GBU= go.opentelemetry.io/build-tools/chloggen v0.29.0/go.mod h1:eby4AVJQF5uanGCnErZdhDYBSW/EJ0iqejBFNJMN4DQ= go.opentelemetry.io/build-tools/crosslink v0.29.0 h1:sz8if4EgUejLvfulrfLF7i2yzSUEyiY4s++aWJGVMZc= go.opentelemetry.io/build-tools/crosslink v0.29.0/go.mod h1:jWE8JLNnuAQhnISpzGsWumC4JREBHOPaxufdSeBbSWs= go.opentelemetry.io/build-tools/githubgen v0.29.0 h1:ETjvcslIftce8aARBGtCCdxIs4Le2tSUlXD5cbzhYGE= go.opentelemetry.io/build-tools/githubgen v0.29.0/go.mod h1:aTnMaP7dTUOZzFxAyS1OXmc27QHpSN9NK+3rD9irWqI= go.opentelemetry.io/build-tools/multimod v0.29.0 h1:hVXibTuNuJumtn3cpzqPOX2xmcO+KogKZcB0yygHux0= go.opentelemetry.io/build-tools/multimod v0.29.0/go.mod h1:tx762Z6RQe5Twkd04q1zzpmGQGtSljbKRy/P61EnJpo= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go= go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 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.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk= golang.org/x/exp/typeparams v0.0.0-20251023183803-a4bb9ffd2546 h1:HDjDiATsGqvuqvkDvgJjD1IgPrVekcSXVVE21JwvzGE= golang.org/x/exp/typeparams v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:4Mzdyp/6jzw9auFDJ3OMF5qksa7UvPnzKqTVGcb04ms= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/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-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-20210615035016-665e8c7367d1/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-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo= golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= 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= golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= 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-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= google.golang.org/protobuf v1.36.8 h1:xHScyCOEuuwZEc6UtSOvPbAT4zRh0xcNRYekJwfqyMc= google.golang.org/protobuf v1.36.8/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/gotestsum v1.13.0 h1:+Lh454O9mu9AMG1APV4o0y7oDYKyik/3kBOiCqiEpRo= gotest.tools/gotestsum v1.13.0/go.mod h1:7f0NS5hFb0dWr4NtcsAsF0y1kzjEFfAil0HiBQJE03Q= gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw= honnef.co/go/tools v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea/go.mod h1:EPDDhEZqVHhWuPI5zPAsjU0U7v9xNIWjoOVyZ5ZcniQ= 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= opentelemetry-collector-0.141.0/otelcol/000077500000000000000000000000001511331344600201775ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/Makefile000066400000000000000000000000331511331344600216330ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/otelcol/buffered_core.go000066400000000000000000000034231511331344600233220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // This logger implements zapcore.Core and is based on zaptest/observer. package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "errors" "sync" "go.uber.org/zap/zapcore" ) type loggedEntry struct { zapcore.Entry Context []zapcore.Field } func newBufferedCore(enab zapcore.LevelEnabler) *bufferedCore { return &bufferedCore{LevelEnabler: enab} } var _ zapcore.Core = (*bufferedCore)(nil) type bufferedCore struct { zapcore.LevelEnabler mu sync.Mutex logs []loggedEntry context []zapcore.Field logsTaken bool } func (bc *bufferedCore) Level() zapcore.Level { return zapcore.LevelOf(bc.LevelEnabler) } func (bc *bufferedCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { if bc.Enabled(ent.Level) { return ce.AddCore(ent, bc) } return ce } func (bc *bufferedCore) With(fields []zapcore.Field) zapcore.Core { return &bufferedCore{ LevelEnabler: bc.LevelEnabler, logs: bc.logs, logsTaken: bc.logsTaken, context: append(bc.context, fields...), } } func (bc *bufferedCore) Write(ent zapcore.Entry, fields []zapcore.Field) error { bc.mu.Lock() defer bc.mu.Unlock() if bc.logsTaken { return errors.New("the buffered logs have already been taken so writing is no longer supported") } all := make([]zapcore.Field, 0, len(fields)+len(bc.context)) all = append(all, bc.context...) all = append(all, fields...) bc.logs = append(bc.logs, loggedEntry{ent, all}) return nil } func (bc *bufferedCore) Sync() error { return nil } func (bc *bufferedCore) TakeLogs() []loggedEntry { bc.mu.Lock() defer bc.mu.Unlock() if bc.logsTaken { return nil } logs := bc.logs bc.logs = nil bc.logsTaken = true return logs } opentelemetry-collector-0.141.0/otelcol/buffered_core_test.go000066400000000000000000000045101511331344600243570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" ) func Test_bufferedCore_Level(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) assert.Equal(t, zapcore.InfoLevel, bc.Level()) } func Test_bufferedCore_Check(t *testing.T) { t.Run("check passed", func(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) e := zapcore.Entry{ Level: zapcore.InfoLevel, } expected := &zapcore.CheckedEntry{} expected = expected.AddCore(e, bc) ce := bc.Check(e, nil) assert.Equal(t, expected, ce) }) t.Run("check did not pass", func(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) e := zapcore.Entry{ Level: zapcore.DebugLevel, } ce := bc.Check(e, nil) assert.Nil(t, ce) }) } func Test_bufferedCore_With(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) bc.logsTaken = true bc.context = []zapcore.Field{ {Key: "original", String: "context"}, } inputs := []zapcore.Field{ {Key: "test", String: "passed"}, } expected := []zapcore.Field{ {Key: "original", String: "context"}, {Key: "test", String: "passed"}, } newBC := bc.With(inputs) assert.Equal(t, expected, newBC.(*bufferedCore).context) assert.True(t, newBC.(*bufferedCore).logsTaken) } func Test_bufferedCore_Write(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) e := zapcore.Entry{ Level: zapcore.DebugLevel, Message: "test", } fields := []zapcore.Field{ {Key: "field1", String: "value1"}, } err := bc.Write(e, fields) require.NoError(t, err) expected := loggedEntry{ e, fields, } require.Len(t, bc.logs, 1) require.Equal(t, expected, bc.logs[0]) } func Test_bufferedCore_Sync(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) assert.NoError(t, bc.Sync()) } func Test_bufferedCore_TakeLogs(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) e := zapcore.Entry{ Level: zapcore.DebugLevel, Message: "test", } fields := []zapcore.Field{ {Key: "field1", String: "value1"}, } err := bc.Write(e, fields) require.NoError(t, err) expected := []loggedEntry{ { e, fields, }, } assert.Equal(t, expected, bc.TakeLogs()) assert.Nil(t, bc.logs) require.Error(t, bc.Write(e, fields)) assert.Nil(t, bc.TakeLogs()) } opentelemetry-collector-0.141.0/otelcol/collector.go000066400000000000000000000311551511331344600225210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package otelcol handles the command-line, configuration, and runs the OpenTelemetry Collector. // It contains the main [Collector] struct and its constructor [NewCollector]. // [Collector.Run] starts the Collector and then blocks until it shuts down. package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "context" "errors" "fmt" "os" "os/signal" "sync" "sync/atomic" "syscall" "go.uber.org/multierr" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/otelcol/internal/grpclog" "go.opentelemetry.io/collector/service" ) // State defines Collector's state. type State int const ( StateStarting State = iota StateRunning StateClosing StateClosed ) func (s State) String() string { switch s { case StateStarting: return "Starting" case StateRunning: return "Running" case StateClosing: return "Closing" case StateClosed: return "Closed" } return "UNKNOWN" } // CollectorSettings holds configuration for creating a new Collector. type CollectorSettings struct { // Factories returns component factories for the collector. // // TODO(13263) This is a dangerous "bare" function value, should define an interface // following style guidelines. Factories func() (Factories, error) // BuildInfo provides collector start information. BuildInfo component.BuildInfo // DisableGracefulShutdown disables the automatic graceful shutdown // of the collector on SIGINT or SIGTERM. // Users who want to handle signals themselves can disable this behavior // and manually handle the signals to shutdown the collector. DisableGracefulShutdown bool // ConfigProviderSettings allows configuring the way the Collector retrieves its configuration // The Collector will reload based on configuration changes from the ConfigProvider if any // confmap.Providers watch for configuration changes. ConfigProviderSettings ConfigProviderSettings // ProviderModules maps provider schemes to their respective go modules. ProviderModules map[string]string // ConverterModules maps converter names to their respective go modules. ConverterModules []string // LoggingOptions provides a way to change behavior of zap logging. LoggingOptions []zap.Option // SkipSettingGRPCLogger avoids setting the grpc logger SkipSettingGRPCLogger bool } // (Internal note) Collector Lifecycle: // - New constructs a new Collector. // - Run starts the collector. // - Run calls setupConfigurationComponents to handle configuration. // If configuration parser fails, collector's config can be reloaded. // Collector can be shutdown if parser gets a shutdown error. // - Run runs runAndWaitForShutdownEvent and waits for a shutdown event. // SIGINT and SIGTERM, errors, and (*Collector).Shutdown can trigger the shutdown events. // - Upon shutdown, pipelines are notified, then pipelines and extensions are shut down. // - Users can call (*Collector).Shutdown anytime to shut down the collector. // Collector represents a server providing the OpenTelemetry Collector service. type Collector struct { set CollectorSettings configProvider *ConfigProvider serviceConfig *service.Config service *service.Service state *atomic.Int64 // shutdownChan is used to terminate the collector. shutdownChan chan struct{} shutdownOnce sync.Once // signalsChannel is used to receive termination signals from the OS. signalsChannel chan os.Signal // asyncErrorChannel is used to signal a fatal error from any component. asyncErrorChannel chan error bc *bufferedCore updateConfigProviderLogger func(core zapcore.Core) } // NewCollector creates and returns a new instance of Collector. func NewCollector(set CollectorSettings) (*Collector, error) { bc := newBufferedCore(zapcore.DebugLevel) cc := newCollectorCore(bc) options := append([]zap.Option{zap.WithCaller(true)}, set.LoggingOptions...) logger := zap.New(cc, options...) set.ConfigProviderSettings.ResolverSettings.ProviderSettings = confmap.ProviderSettings{Logger: logger} set.ConfigProviderSettings.ResolverSettings.ConverterSettings = confmap.ConverterSettings{Logger: logger} configProvider, err := NewConfigProvider(set.ConfigProviderSettings) if err != nil { return nil, err } state := new(atomic.Int64) state.Store(int64(StateStarting)) return &Collector{ set: set, state: state, shutdownChan: make(chan struct{}), // Per signal.Notify documentation, a size of the channel equaled with // the number of signals getting notified on is recommended. signalsChannel: make(chan os.Signal, 3), asyncErrorChannel: make(chan error), configProvider: configProvider, bc: bc, updateConfigProviderLogger: cc.SetCore, }, nil } // GetState returns current state of the collector server. func (col *Collector) GetState() State { return State(col.state.Load()) } // Shutdown shuts down the collector server. func (col *Collector) Shutdown() { col.shutdownOnce.Do(func() { close(col.shutdownChan) }) } func buildModuleInfo(m map[component.Type]string) map[component.Type]service.ModuleInfo { moduleInfo := make(map[component.Type]service.ModuleInfo) for k, v := range m { moduleInfo[k] = service.ModuleInfo{BuilderRef: v} } return moduleInfo } // setupConfigurationComponents loads the config, creates the graph, and starts the components. If all the steps succeeds it // sets the col.service with the service currently running. func (col *Collector) setupConfigurationComponents(ctx context.Context) error { col.setCollectorState(StateStarting) factories, err := col.set.Factories() if err != nil { return fmt.Errorf("failed to initialize factories: %w", err) } cfg, err := col.configProvider.Get(ctx, factories) if err != nil { return fmt.Errorf("failed to get config: %w", err) } if err = xconfmap.Validate(cfg); err != nil { return fmt.Errorf("invalid configuration: %w", err) } col.serviceConfig = &cfg.Service conf := confmap.New() if err = conf.Marshal(cfg); err != nil { return fmt.Errorf("could not marshal configuration: %w", err) } col.service, err = service.New(ctx, service.Settings{ BuildInfo: col.set.BuildInfo, CollectorConf: conf, ReceiversConfigs: cfg.Receivers, ReceiversFactories: factories.Receivers, ProcessorsConfigs: cfg.Processors, ProcessorsFactories: factories.Processors, ExportersConfigs: cfg.Exporters, ExportersFactories: factories.Exporters, ConnectorsConfigs: cfg.Connectors, ConnectorsFactories: factories.Connectors, ExtensionsConfigs: cfg.Extensions, ExtensionsFactories: factories.Extensions, ModuleInfos: service.ModuleInfos{ Receiver: buildModuleInfo(factories.ReceiverModules), Processor: buildModuleInfo(factories.ProcessorModules), Exporter: buildModuleInfo(factories.ExporterModules), Extension: buildModuleInfo(factories.ExtensionModules), Connector: buildModuleInfo(factories.ConnectorModules), }, AsyncErrorChannel: col.asyncErrorChannel, LoggingOptions: col.set.LoggingOptions, TelemetryFactory: factories.Telemetry, }, cfg.Service) if err != nil { return err } if col.updateConfigProviderLogger != nil { col.updateConfigProviderLogger(col.service.Logger().Core()) } if col.bc != nil { x := col.bc.TakeLogs() for _, log := range x { ce := col.service.Logger().Core().Check(log.Entry, nil) if ce != nil { ce.Write(log.Context...) } } } if !col.set.SkipSettingGRPCLogger { grpclog.SetLogger(col.service.Logger()) } if err = col.service.Start(ctx); err != nil { return multierr.Combine(err, col.service.Shutdown(ctx)) } col.setCollectorState(StateRunning) return nil } func (col *Collector) reloadConfiguration(ctx context.Context) error { col.service.Logger().Warn("Config updated, restart service") col.setCollectorState(StateClosing) if err := col.service.Shutdown(ctx); err != nil { return fmt.Errorf("failed to shutdown the retiring config: %w", err) } if err := col.setupConfigurationComponents(ctx); err != nil { return fmt.Errorf("failed to setup configuration components: %w", err) } return nil } func (col *Collector) DryRun(ctx context.Context) error { factories, err := col.set.Factories() if err != nil { return fmt.Errorf("failed to initialize factories: %w", err) } cfg, err := col.configProvider.Get(ctx, factories) if err != nil { return fmt.Errorf("failed to get config: %w", err) } if err := xconfmap.Validate(cfg); err != nil { return err } return service.Validate(ctx, service.Settings{ BuildInfo: col.set.BuildInfo, ReceiversConfigs: cfg.Receivers, ReceiversFactories: factories.Receivers, ProcessorsConfigs: cfg.Processors, ProcessorsFactories: factories.Processors, ExportersConfigs: cfg.Exporters, ExportersFactories: factories.Exporters, ConnectorsConfigs: cfg.Connectors, ConnectorsFactories: factories.Connectors, TelemetryFactory: factories.Telemetry, }, service.Config{ Pipelines: cfg.Service.Pipelines, }) } func newFallbackLogger(options []zap.Option) (*zap.Logger, error) { ec := zap.NewProductionEncoderConfig() ec.EncodeTime = zapcore.ISO8601TimeEncoder zapCfg := &zap.Config{ Level: zap.NewAtomicLevelAt(zapcore.DebugLevel), Encoding: "console", EncoderConfig: ec, OutputPaths: []string{"stderr"}, ErrorOutputPaths: []string{"stderr"}, } return zapCfg.Build(options...) } // Run starts the collector according to the given configuration, and waits for it to complete. // Consecutive calls to Run are not allowed, Run shouldn't be called once a collector is shut down. // Sets up the control logic for config reloading and shutdown. func (col *Collector) Run(ctx context.Context) error { // setupConfigurationComponents is the "main" function responsible for startup if err := col.setupConfigurationComponents(ctx); err != nil { col.setCollectorState(StateClosed) logger, loggerErr := newFallbackLogger(col.set.LoggingOptions) if loggerErr != nil { return errors.Join(err, fmt.Errorf("unable to create fallback logger: %w", loggerErr)) } if col.bc != nil { x := col.bc.TakeLogs() for _, log := range x { ce := logger.Core().Check(log.Entry, nil) if ce != nil { ce.Write(log.Context...) } } } return err } // Always notify with SIGHUP for configuration reloading. signal.Notify(col.signalsChannel, syscall.SIGHUP) defer signal.Stop(col.signalsChannel) // Only notify with SIGTERM and SIGINT if graceful shutdown is enabled. if !col.set.DisableGracefulShutdown { signal.Notify(col.signalsChannel, os.Interrupt, syscall.SIGTERM) } // Control loop: selects between channels for various interrupts - when this loop is broken, the collector exits. // If a configuration reload fails, we return without waiting for graceful shutdown. LOOP: for { select { case err := <-col.configProvider.Watch(): if err != nil { col.service.Logger().Error("Config watch failed", zap.Error(err)) break LOOP } if err := col.reloadConfiguration(ctx); err != nil { return err } case err := <-col.asyncErrorChannel: col.service.Logger().Error("Asynchronous error received, terminating process", zap.Error(err)) break LOOP case s := <-col.signalsChannel: col.service.Logger().Info("Received signal from OS", zap.String("signal", s.String())) if s != syscall.SIGHUP { break LOOP } if err := col.reloadConfiguration(ctx); err != nil { return err } case <-col.shutdownChan: col.service.Logger().Info("Received shutdown request") break LOOP case <-ctx.Done(): col.service.Logger().Info("Context done, terminating process", zap.Error(ctx.Err())) // Call shutdown with background context as the passed in context has been canceled return col.shutdown(context.Background()) //nolint:contextcheck } } return col.shutdown(ctx) } func (col *Collector) shutdown(ctx context.Context) error { col.setCollectorState(StateClosing) // Accumulate errors and proceed with shutting down remaining components. var errs error if err := col.configProvider.Shutdown(ctx); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to shutdown config provider: %w", err)) } // shutdown service if err := col.service.Shutdown(ctx); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to shutdown service after error: %w", err)) } col.setCollectorState(StateClosed) return errs } // setCollectorState provides current state of the collector func (col *Collector) setCollectorState(state State) { col.state.Store(int64(state)) } opentelemetry-collector-0.141.0/otelcol/collector_core.go000066400000000000000000000023141511331344600235240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "sync/atomic" "go.uber.org/zap/zapcore" ) var _ zapcore.Core = (*collectorCore)(nil) type collectorCore struct { delegate atomic.Pointer[zapcore.Core] } func newCollectorCore(core zapcore.Core) *collectorCore { cc := &collectorCore{} cc.SetCore(core) return cc } func (c *collectorCore) Enabled(l zapcore.Level) bool { return c.loadDelegate().Enabled(l) } func (c *collectorCore) With(f []zapcore.Field) zapcore.Core { return newCollectorCore(c.loadDelegate().With(f)) } func (c *collectorCore) Check(e zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { core := c.loadDelegate() if core.Enabled(e.Level) { return ce.AddCore(e, core) } return ce } func (c *collectorCore) Write(e zapcore.Entry, f []zapcore.Field) error { return c.loadDelegate().Write(e, f) } func (c *collectorCore) Sync() error { return c.loadDelegate().Sync() } func (c *collectorCore) SetCore(core zapcore.Core) { c.delegate.Store(&core) } // loadDelegate returns the delegate. func (c *collectorCore) loadDelegate() zapcore.Core { return *c.delegate.Load() } opentelemetry-collector-0.141.0/otelcol/collector_core_test.go000066400000000000000000000044771511331344600245770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap/zapcore" ) func Test_collectorCore_Enabled(t *testing.T) { cc := newCollectorCore(newBufferedCore(zapcore.InfoLevel)) assert.True(t, cc.Enabled(zapcore.ErrorLevel)) assert.False(t, cc.Enabled(zapcore.DebugLevel)) } func Test_collectorCore_Check(t *testing.T) { t.Run("check passed", func(t *testing.T) { bc := newBufferedCore(zapcore.InfoLevel) cc := newCollectorCore(bc) e := zapcore.Entry{ Level: zapcore.InfoLevel, } expected := &zapcore.CheckedEntry{} expected = expected.AddCore(e, bc) assert.Equal(t, expected, cc.Check(e, nil)) }) t.Run("check did not pass", func(t *testing.T) { cc := newCollectorCore(newBufferedCore(zapcore.InfoLevel)) e := zapcore.Entry{ Level: zapcore.DebugLevel, } assert.Nil(t, cc.Check(e, nil)) }) } func Test_collectorCore_With(t *testing.T) { cc := newCollectorCore(newBufferedCore(zapcore.InfoLevel)) cc.loadDelegate().(*bufferedCore).context = []zapcore.Field{ {Key: "original", String: "context"}, } inputs := []zapcore.Field{ {Key: "test", String: "passed"}, } expected := []zapcore.Field{ {Key: "original", String: "context"}, {Key: "test", String: "passed"}, } newCC := cc.With(inputs) assert.Equal(t, expected, newCC.(*collectorCore).loadDelegate().(*bufferedCore).context) } func Test_collectorCore_Write(t *testing.T) { cc := newCollectorCore(newBufferedCore(zapcore.InfoLevel)) e := zapcore.Entry{ Level: zapcore.DebugLevel, Message: "test", } fields := []zapcore.Field{ {Key: "field1", String: "value1"}, } err := cc.Write(e, fields) require.NoError(t, err) expected := loggedEntry{ e, fields, } require.Len(t, cc.loadDelegate().(*bufferedCore).logs, 1) require.Equal(t, expected, cc.loadDelegate().(*bufferedCore).logs[0]) } func Test_collectorCore_Sync(t *testing.T) { cc := newCollectorCore(newBufferedCore(zapcore.InfoLevel)) assert.NoError(t, cc.Sync()) } func Test_collectorCore_SetCore(t *testing.T) { cc := newCollectorCore(newBufferedCore(zapcore.InfoLevel)) newCore := newBufferedCore(zapcore.DebugLevel) cc.SetCore(newCore) assert.Equal(t, zapcore.DebugLevel, cc.loadDelegate().(*bufferedCore).LevelEnabler) } opentelemetry-collector-0.141.0/otelcol/collector_test.go000066400000000000000000000610531511331344600235600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package collector handles the command-line, configuration, and runs the OC collector. package otelcol import ( "context" "errors" "os" "path/filepath" "sync" "syscall" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" yaml "go.yaml.in/yaml/v3" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/service/telemetry" "go.opentelemetry.io/collector/service/telemetry/telemetrytest" ) func TestStateString(t *testing.T) { assert.Equal(t, "Starting", StateStarting.String()) assert.Equal(t, "Running", StateRunning.String()) assert.Equal(t, "Closing", StateClosing.String()) assert.Equal(t, "Closed", StateClosed.String()) assert.Equal(t, "UNKNOWN", State(13).String()) } func TestCollectorStartAsGoRoutine(t *testing.T) { set := CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), } col, err := NewCollector(set) require.NoError(t, err) wg := startCollector(context.Background(), t, col) assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 2*time.Second, 200*time.Millisecond) col.Shutdown() col.Shutdown() wg.Wait() assert.Equal(t, StateClosed, col.GetState()) } func TestCollectorCancelContext(t *testing.T) { set := CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), } col, err := NewCollector(set) require.NoError(t, err) ctx, cancel := context.WithCancel(context.Background()) wg := startCollector(ctx, t, col) assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 2*time.Second, 200*time.Millisecond) cancel() wg.Wait() assert.Equal(t, StateClosed, col.GetState()) } func TestCollectorStateAfterConfigChange(t *testing.T) { var watcher confmap.WatcherFunc fileProvider := newFakeProvider("file", func(_ context.Context, uri string, w confmap.WatcherFunc) (*confmap.Retrieved, error) { watcher = w conf := newConfFromFile(t, uri[5:]) return confmap.NewRetrieved(conf) }) shutdownRequests := make(chan chan struct{}) shutdown := func(ctx context.Context) error { unblock := make(chan struct{}) select { case <-ctx.Done(): case shutdownRequests <- unblock: select { case <-unblock: case <-ctx.Done(): } } return nil } factories, err := nopFactories() require.NoError(t, err) factories.Telemetry = telemetry.NewFactory( func() component.Config { return fakeTelemetryConfig{} }, telemetrytest.WithLogger(zap.NewNop(), shutdown), ) set := ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{filepath.Join("testdata", "otelcol-nop.yaml")}, ProviderFactories: []confmap.ProviderFactory{ fileProvider, }, }, } col, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: func() (Factories, error) { return factories, nil }, ConfigProviderSettings: set, }) require.NoError(t, err) wg := startCollector(context.Background(), t, col) assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 10*time.Second, 10*time.Millisecond) // On config change, the collector will internally close // and recreate the service. The metrics reader will try to // push to the OTLP endpoint. We block the request to check // the state of the collector during the config change event. watcher(&confmap.ChangeEvent{}) unblock := <-shutdownRequests assert.Equal(t, StateClosing, col.GetState()) close(unblock) assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 10*time.Second, 10*time.Millisecond) // Do it again, but this time call Shutdown during the // config change to make sure the internal service shutdown // does not influence collector shutdown. watcher(&confmap.ChangeEvent{}) unblock = <-shutdownRequests assert.Equal(t, StateClosing, col.GetState()) col.Shutdown() close(unblock) // After the config reload, the final shutdown should occur. close(<-shutdownRequests) wg.Wait() assert.Equal(t, StateClosed, col.GetState()) } func TestCollectorReportError(t *testing.T) { col, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), }) require.NoError(t, err) wg := startCollector(context.Background(), t, col) assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 2*time.Second, 200*time.Millisecond) col.asyncErrorChannel <- errors.New("err2") wg.Wait() assert.Equal(t, StateClosed, col.GetState()) } // NewStatusWatcherExtensionFactory returns a component.ExtensionFactory to construct a status watcher extension. func NewStatusWatcherExtensionFactory( onStatusChanged func(source *componentstatus.InstanceID, event *componentstatus.Event), ) extension.Factory { return extension.NewFactory( component.MustNewType("statuswatcher"), func() component.Config { return &struct{}{} }, func(context.Context, extension.Settings, component.Config) (extension.Extension, error) { return &statusWatcherExtension{onStatusChanged: onStatusChanged}, nil }, component.StabilityLevelStable) } // statusWatcherExtension receives status events reported via component status reporting for testing // purposes. type statusWatcherExtension struct { component.StartFunc component.ShutdownFunc onStatusChanged func(source *componentstatus.InstanceID, event *componentstatus.Event) } func (e statusWatcherExtension) ComponentStatusChanged(source *componentstatus.InstanceID, event *componentstatus.Event) { e.onStatusChanged(source, event) } func TestComponentStatusWatcher(t *testing.T) { factories, err := nopFactories() require.NoError(t, err) // Use a processor factory that creates "unhealthy" processor: one that // always reports StatusRecoverableError after successful Start. unhealthyProcessorFactory := processortest.NewUnhealthyProcessorFactory() factories.Processors[unhealthyProcessorFactory.Type()] = unhealthyProcessorFactory // Keep track of all status changes in a map. changedComponents := map[*componentstatus.InstanceID][]componentstatus.Status{} var mux sync.Mutex onStatusChanged := func(source *componentstatus.InstanceID, event *componentstatus.Event) { if source.ComponentID().Type() != unhealthyProcessorFactory.Type() { return } mux.Lock() defer mux.Unlock() changedComponents[source] = append(changedComponents[source], event.Status()) } // Add a "statuswatcher" extension that will receive notifications when processor // status changes. factory := NewStatusWatcherExtensionFactory(onStatusChanged) factories.Extensions[factory.Type()] = factory // Create a collector col, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: func() (Factories, error) { return factories, nil }, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-statuswatcher.yaml")}), }) require.NoError(t, err) // Start the newly created collector. wg := startCollector(context.Background(), t, col) // An unhealthy processor asynchronously reports a recoverable error. Depending on the Go // Scheduler the statuses reported at startup will be one of the two valid sequences below. startupStatuses1 := []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusRecoverableError, } startupStatuses2 := []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusRecoverableError, } // the modulus of the actual statuses will match the modulus of the startup statuses startupStatuses := func(actualStatuses []componentstatus.Status) []componentstatus.Status { if len(actualStatuses)%2 == 1 { return startupStatuses1 } return startupStatuses2 } // The "unhealthy" processors will now begin to asynchronously report StatusRecoverableError. // We expect to see these reports. assert.Eventually(t, func() bool { mux.Lock() defer mux.Unlock() for k, v := range changedComponents { // All processors must report a status change with the same ID assert.Equal(t, component.NewID(unhealthyProcessorFactory.Type()), k.ComponentID()) // And all must have a valid startup sequence assert.Equal(t, startupStatuses(v), v) } // We have 3 processors with exactly the same ID in otelcol-statuswatcher.yaml // We must have exactly 3 items in our map. This ensures that the "source" argument // passed to status change func is unique per instance of source component despite // components having the same IDs (having same ID for different component instances // is a normal situation for processors). return len(changedComponents) == 3 }, 2*time.Second, time.Millisecond*100) col.Shutdown() wg.Wait() // Check for additional statuses after Shutdown. for _, v := range changedComponents { expectedStatuses := append([]componentstatus.Status{}, startupStatuses(v)...) expectedStatuses = append(expectedStatuses, componentstatus.StatusStopping, componentstatus.StatusStopped) assert.Equal(t, expectedStatuses, v) } assert.Equal(t, StateClosed, col.GetState()) } func TestCollectorSendSignal(t *testing.T) { col, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), }) require.NoError(t, err) wg := startCollector(context.Background(), t, col) assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 2*time.Second, 200*time.Millisecond) col.signalsChannel <- syscall.SIGHUP assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 2*time.Second, 200*time.Millisecond) col.signalsChannel <- syscall.SIGTERM wg.Wait() assert.Equal(t, StateClosed, col.GetState()) } func TestCollectorFailedShutdown(t *testing.T) { t.Skip("This test was using telemetry shutdown failure, switch to use a component that errors on shutdown.") col, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), }) require.NoError(t, err) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.EqualError(t, col.Run(context.Background()), "failed to shutdown collector telemetry: err1") }() assert.Eventually(t, func() bool { return StateRunning == col.GetState() }, 2*time.Second, 200*time.Millisecond) col.Shutdown() wg.Wait() assert.Equal(t, StateClosed, col.GetState()) } func TestCollectorStartInvalidConfig(t *testing.T) { col, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-invalid.yaml")}), }) require.NoError(t, err) assert.EqualError(t, col.Run(context.Background()), "invalid configuration: service::pipelines::traces: references processor \"invalid\" which is not configured") } func TestNewCollectorInvalidConfigProviderSettings(t *testing.T) { _, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: ConfigProviderSettings{}, }) require.Error(t, err) } func TestNewCollectorUseConfig(t *testing.T) { set := newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}) col, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: set, }) require.NoError(t, err) require.NotNil(t, col.configProvider) } func TestNewCollectorValidatesResolverSettings(t *testing.T) { set := ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{filepath.Join("testdata", "otelcol-nop.yaml")}, }, } _, err := NewCollector(CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: set, }) require.Error(t, err) } func TestCollectorRun(t *testing.T) { tests := map[string]struct { factories func() (Factories, error) configFile string }{ "nop": { factories: nopFactories, configFile: "otelcol-nop.yaml", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { set := CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: test.factories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", test.configFile)}), } col, err := NewCollector(set) require.NoError(t, err) wg := startCollector(context.Background(), t, col) col.Shutdown() wg.Wait() assert.Equal(t, StateClosed, col.GetState()) }) } } func TestCollectorRun_AfterShutdown(t *testing.T) { set := CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), } col, err := NewCollector(set) require.NoError(t, err) // Calling shutdown before collector is running should cause it to return quickly require.NotPanics(t, func() { col.Shutdown() }) wg := startCollector(context.Background(), t, col) col.Shutdown() wg.Wait() assert.Equal(t, StateClosed, col.GetState()) } func TestCollectorRun_Errors(t *testing.T) { tests := map[string]struct { settings CollectorSettings expectedErr string }{ "factories_error": { settings: CollectorSettings{ Factories: func() (Factories, error) { return Factories{}, errors.New("no factories for you") }, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), }, expectedErr: "failed to initialize factories: no factories for you", }, "invalid_processor": { settings: CollectorSettings{ Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-invalid.yaml")}), }, expectedErr: `invalid configuration: service::pipelines::traces: references processor "invalid" which is not configured`, }, "invalid_telemetry_config": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-invalid-telemetry.yaml")}), }, expectedErr: "failed to get config: cannot unmarshal the configuration: decoding failed due to the following error(s):\n\n'service.telemetry' has invalid keys: unknown", }, "missing_telemetry_factory": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: func() (Factories, error) { factories, _ := nopFactories() factories.Telemetry = nil return factories, nil }, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-otelconftelemetry.yaml")}), }, expectedErr: "failed to get config: cannot unmarshal the configuration: otelcol.Factories.Telemetry must not be nil. For example, you can use otelconftelemetry.NewFactory to build a telemetry factory", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { col, err := NewCollector(test.settings) require.NoError(t, err) // Expect run to error err = col.Run(context.Background()) require.EqualError(t, err, test.expectedErr) // Expect state to be closed assert.Equal(t, StateClosed, col.GetState()) }) } } func TestCollectorDryRun(t *testing.T) { tests := map[string]struct { settings CollectorSettings expectedErr string }{ "factories_error": { settings: CollectorSettings{ Factories: func() (Factories, error) { return Factories{}, errors.New("no factories for you") }, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), }, expectedErr: "failed to initialize factories: no factories for you", }, "invalid_processor": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-invalid.yaml")}), }, expectedErr: `service::pipelines::traces: references processor "invalid" which is not configured`, }, "invalid_connector_use_unused_exp": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-invalid-connector-unused-exp.yaml")}), }, expectedErr: `failed to build pipelines: connector "nop/connector1" used as receiver in [logs/in2] pipeline but not used in any supported exporter pipeline`, }, "invalid_connector_use_unused_rec": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-invalid-connector-unused-rec.yaml")}), }, expectedErr: `failed to build pipelines: connector "nop/connector1" used as exporter in [logs/in2] pipeline but not used in any supported receiver pipeline`, }, "cyclic_connector": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-cyclic-connector.yaml")}), }, expectedErr: `failed to build pipelines: cycle detected: connector "nop/forward" (traces to traces) -> connector "nop/forward" (traces to traces)`, }, "invalid_telemetry_config": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-invalid-telemetry.yaml")}), }, expectedErr: "failed to get config: cannot unmarshal the configuration: decoding failed due to the following error(s):\n\n'service.telemetry' has invalid keys: unknown", }, "missing_telemetry_factory": { settings: CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: func() (Factories, error) { factories, _ := nopFactories() factories.Telemetry = nil return factories, nil }, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-otelconftelemetry.yaml")}), }, expectedErr: "failed to get config: cannot unmarshal the configuration: otelcol.Factories.Telemetry must not be nil. For example, you can use otelconftelemetry.NewFactory to build a telemetry factory", }, } for name, test := range tests { t.Run(name, func(t *testing.T) { col, err := NewCollector(test.settings) require.NoError(t, err) err = col.DryRun(context.Background()) if test.expectedErr == "" { require.NoError(t, err) } else { require.EqualError(t, err, test.expectedErr) } }) } } func startCollector(ctx context.Context, t *testing.T, col *Collector) *sync.WaitGroup { wg := &sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, col.Run(ctx)) }() return wg } type failureProvider struct{} func newFailureProvider(_ confmap.ProviderSettings) confmap.Provider { return &failureProvider{} } func (fmp *failureProvider) Retrieve(context.Context, string, confmap.WatcherFunc) (*confmap.Retrieved, error) { return nil, errors.New("a failure occurred during configuration retrieval") } func (*failureProvider) Scheme() string { return "file" } func (*failureProvider) Shutdown(context.Context) error { return nil } type fakeProvider struct { scheme string ret func(ctx context.Context, uri string, watcher confmap.WatcherFunc) (*confmap.Retrieved, error) logger *zap.Logger } func (f *fakeProvider) Retrieve(ctx context.Context, uri string, watcher confmap.WatcherFunc) (*confmap.Retrieved, error) { return f.ret(ctx, uri, watcher) } func (f *fakeProvider) Scheme() string { return f.scheme } func (f *fakeProvider) Shutdown(context.Context) error { return nil } func newFakeProvider(scheme string, ret func(ctx context.Context, uri string, watcher confmap.WatcherFunc) (*confmap.Retrieved, error)) confmap.ProviderFactory { return confmap.NewProviderFactory(func(ps confmap.ProviderSettings) confmap.Provider { return &fakeProvider{ scheme: scheme, ret: ret, logger: ps.Logger, } }) } func newEnvProvider() confmap.ProviderFactory { return newFakeProvider("env", func(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { // When using `env` as the default scheme for tests, the uri will not include `env:`. // Instead of duplicating the switch cases, the scheme is added instead. if uri[0:4] != "env:" { uri = "env:" + uri } switch uri { case "env:COMPLEX_VALUE": return confmap.NewRetrieved([]any{"localhost:3042"}) case "env:HOST": return confmap.NewRetrieved("localhost") case "env:OS": return confmap.NewRetrieved("ubuntu") case "env:PR": return confmap.NewRetrieved("amd") case "env:PORT": return confmap.NewRetrieved(3044) case "env:INT": return confmap.NewRetrieved(1) case "env:INT32": return confmap.NewRetrieved(32) case "env:INT64": return confmap.NewRetrieved(64) case "env:FLOAT32": return confmap.NewRetrieved(float32(3.25)) case "env:FLOAT64": return confmap.NewRetrieved(float64(6.4)) case "env:BOOL": return confmap.NewRetrieved(true) } return nil, errors.New("impossible") }) } func newDefaultConfigProviderSettings(tb testing.TB, uris []string) ConfigProviderSettings { fileProvider := newFakeProvider("file", func(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { return confmap.NewRetrieved(newConfFromFile(tb, uri[5:])) }) return ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: uris, ProviderFactories: []confmap.ProviderFactory{ fileProvider, newEnvProvider(), }, }, } } // newConfFromFile creates a new Conf by reading the given file. func newConfFromFile(tb testing.TB, fileName string) map[string]any { content, err := os.ReadFile(filepath.Clean(fileName)) require.NoErrorf(tb, err, "unable to read the file %v", fileName) var data map[string]any require.NoError(tb, yaml.Unmarshal(content, &data), "unable to parse yaml") return confmap.NewFromStringMap(data).ToStringMap() } func TestProviderAndConverterModules(t *testing.T) { set := CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), ProviderModules: map[string]string{ "nop": "go.opentelemetry.io/collector/confmap/provider/testprovider v1.2.3", }, ConverterModules: []string{ "go.opentelemetry.io/collector/converter/testconverter v1.2.3", }, } col, err := NewCollector(set) require.NoError(t, err) wg := startCollector(context.Background(), t, col) require.NoError(t, err) providerModules := map[string]string{ "nop": "go.opentelemetry.io/collector/confmap/provider/testprovider v1.2.3", } converterModules := []string{ "go.opentelemetry.io/collector/converter/testconverter v1.2.3", } assert.Equal(t, providerModules, col.set.ProviderModules) assert.Equal(t, converterModules, col.set.ConverterModules) col.Shutdown() wg.Wait() } opentelemetry-collector-0.141.0/otelcol/collector_windows.go000066400000000000000000000156771511331344600243060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build windows package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "context" "flag" "fmt" "os" "time" "go.uber.org/zap" "go.uber.org/zap/zapcore" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/eventlog" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" ) type windowsService struct { settings CollectorSettings col *Collector flags *flag.FlagSet } // NewSvcHandler constructs a new svc.Handler using the given CollectorSettings. func NewSvcHandler(set CollectorSettings) svc.Handler { return &windowsService{settings: set, flags: flags(featuregate.GlobalRegistry())} } // Execute implements https://godoc.org/golang.org/x/sys/windows/svc#Handler func (s *windowsService) Execute(args []string, requests <-chan svc.ChangeRequest, changes chan<- svc.Status) (ssec bool, errno uint32) { // The first argument supplied to service.Execute is the service name. If this is // not provided for some reason, raise a relevant error to the system event log if len(args) == 0 { return false, 1213 // 1213: ERROR_INVALID_SERVICENAME } elog, err := openEventLog(args[0]) if err != nil { return false, 1501 // 1501: ERROR_EVENTLOG_CANT_START } colErrorChannel := make(chan error, 1) changes <- svc.Status{State: svc.StartPending} if err = s.start(elog, colErrorChannel); err != nil { _ = elog.Error(3, fmt.Sprintf("failed to start service: %v", err)) return false, 1064 // 1064: ERROR_EXCEPTION_IN_SERVICE } changes <- svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown} for req := range requests { switch req.Cmd { case svc.Interrogate: changes <- req.CurrentStatus case svc.Stop, svc.Shutdown: changes <- svc.Status{State: svc.StopPending} if err = s.stop(colErrorChannel); err != nil { _ = elog.Error(3, fmt.Sprintf("errors occurred while shutting down the service: %v", err)) } changes <- svc.Status{State: svc.Stopped} return false, 0 default: _ = elog.Error(3, fmt.Sprintf("unexpected service control request #%d", req.Cmd)) return false, 1052 // 1052: ERROR_INVALID_SERVICE_CONTROL } } return false, 0 } func (s *windowsService) start(elog *eventlog.Log, colErrorChannel chan error) error { // Parse all the flags manually. if err := s.flags.Parse(os.Args[1:]); err != nil { return err } var err error err = updateSettingsUsingFlags(&s.settings, s.flags) if err != nil { return err } s.col, err = NewCollector(s.settings) if err != nil { return err } // The logging options need to be in place before the collector Run method is called // since the telemetry creates the logger at the time of the Run method call. // However, the zap.WrapCore function needs to read the serviceConfig to determine // if the Windows Event Log should be used, however, the serviceConfig is also // only read at the time of the Run method call. To work around this, we pass the // serviceConfig as a pointer to the logging options, and then read its value // when the zap.Logger is created by the telemetry. s.col.set.LoggingOptions = loggingOptionsWithEventLogCore(elog, &s.col.serviceConfig, s.col.set.LoggingOptions) // col.Run blocks until receiving a SIGTERM signal, so needs to be started // asynchronously, but it will exit early if an error occurs on startup go func() { colErrorChannel <- s.col.Run(context.Background()) }() // wait until the collector server is in the Running state go func() { for { state := s.col.GetState() if state == StateRunning { colErrorChannel <- nil break } time.Sleep(time.Millisecond * 200) } }() // wait until the collector server is in the Running state, or an error was returned return <-colErrorChannel } func (s *windowsService) stop(colErrorChannel chan error) error { s.col.Shutdown() // return the response of col.Start return <-colErrorChannel } func openEventLog(serviceName string) (*eventlog.Log, error) { elog, err := eventlog.Open(serviceName) if err != nil { return nil, fmt.Errorf("service failed to open event log: %w", err) } return elog, nil } func loggingOptionsWithEventLogCore( elog *eventlog.Log, serviceConfig **service.Config, userOptions []zap.Option, ) []zap.Option { return append( // The order below must be preserved - see PR #11051 // The event log core must run *after* any user provided options, so it // must be the first option in this list. []zap.Option{zap.WrapCore(withWindowsCore(elog, serviceConfig))}, userOptions..., ) } var _ zapcore.Core = (*windowsEventLogCore)(nil) type windowsEventLogCore struct { core zapcore.Core elog *eventlog.Log encoder zapcore.Encoder } func (w windowsEventLogCore) Enabled(level zapcore.Level) bool { return w.core.Enabled(level) } func (w windowsEventLogCore) With(fields []zapcore.Field) zapcore.Core { enc := w.encoder.Clone() for _, field := range fields { field.AddTo(enc) } return windowsEventLogCore{ core: w.core, elog: w.elog, encoder: enc, } } func (w windowsEventLogCore) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { if w.Enabled(ent.Level) { return ce.AddCore(ent, w) } return ce } func (w windowsEventLogCore) Write(ent zapcore.Entry, fields []zapcore.Field) error { buf, err := w.encoder.EncodeEntry(ent, fields) if err != nil { _ = w.elog.Warning(2, fmt.Sprintf("failed encoding log entry %v\r\n", err)) return err } msg := buf.String() buf.Free() switch ent.Level { case zapcore.FatalLevel, zapcore.PanicLevel, zapcore.DPanicLevel: // golang.org/x/sys/windows/svc/eventlog does not support Critical level event logs return w.elog.Error(3, msg) case zapcore.ErrorLevel: return w.elog.Error(3, msg) case zapcore.WarnLevel: return w.elog.Warning(2, msg) case zapcore.InfoLevel: return w.elog.Info(1, msg) } // We would not be here if debug were disabled so log as info to not drop. return w.elog.Info(1, msg) } func (w windowsEventLogCore) Sync() error { return w.core.Sync() } func withWindowsCore(elog *eventlog.Log, serviceConfig **service.Config) func(zapcore.Core) zapcore.Core { return func(core zapcore.Core) zapcore.Core { if serviceConfig != nil && *serviceConfig != nil { // TODO remove the dependency on otelconftelemetry // // https://github.com/open-telemetry/opentelemetry-collector/issues/14002 for _, output := range (*serviceConfig).Telemetry.(*otelconftelemetry.Config).Logs.OutputPaths { if output != "stdout" && output != "stderr" { // A log file was specified in the configuration, so we should not use the Windows Event Log return core } } } // Use the Windows Event Log encoderConfig := zap.NewProductionEncoderConfig() encoderConfig.LineEnding = "\r\n" encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder return windowsEventLogCore{core, elog, zapcore.NewConsoleEncoder(encoderConfig)} } } opentelemetry-collector-0.141.0/otelcol/collector_windows_service_test.go000066400000000000000000000133711511331344600270520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build windows && win32service package otelcol import ( "encoding/xml" "fmt" "os" "os/exec" "path/filepath" "runtime" "testing" "time" "github.com/stretchr/testify/require" "golang.org/x/sys/windows/svc" "golang.org/x/sys/windows/svc/mgr" ) const ( collectorServiceName = "otelcorecol" ) // Test the collector as a Windows service. // The test assumes that the service and respective event source are already created. // // To test locally: // * Build the binary: // - make otelcorecol // // * Install the Windows service // - New-Service -Name "otelcorecol" -StartupType "Manual" -BinaryPathName "${PWD}\bin\otelcorecol_windows_$(go env GOARCH) --config ${PWD}\examples\local\otel-config.yaml" // // * Create event log source // - eventcreate.exe /t information /id 1 /l application /d "Creating event provider for 'otelcorecol'" /so otelcorecol // // The test also must be executed with administrative privileges. func TestCollectorAsService(t *testing.T) { collector_executable, err := filepath.Abs(filepath.Join("..", "bin", fmt.Sprintf("otelcorecol_windows_%s", runtime.GOARCH))) require.NoError(t, err) _, err = os.Stat(collector_executable) require.NoError(t, err) scm, err := mgr.Connect() require.NoError(t, err) defer scm.Disconnect() service, err := scm.OpenService(collectorServiceName) require.NoError(t, err) defer service.Close() tests := []struct { name string configFile string expectStartFailure bool customSetup func(*testing.T) customValidation func(*testing.T) }{ { name: "Default", configFile: filepath.Join("..", "examples", "local", "otel-config.yaml"), }, { name: "ConfigFileNotFound", configFile: filepath.Join(".", "non", "existent", "otel-config.yaml"), expectStartFailure: true, }, { name: "LogToFile", configFile: filepath.Join(".", "testdata", "otelcol-log-to-file.yaml"), customSetup: func(t *testing.T) { // Create the folder and clean the log file if it exists programDataPath := os.Getenv("ProgramData") logsPath := filepath.Join(programDataPath, "OpenTelemetry", "Collector", "Logs") err := os.MkdirAll(logsPath, os.ModePerm) require.NoError(t, err) logFilePath := filepath.Join(logsPath, "otelcol.log") err = os.Remove(logFilePath) if err != nil && !os.IsNotExist(err) { require.NoError(t, err) } }, customValidation: func(t *testing.T) { // Check that the log file was created programDataPath := os.Getenv("ProgramData") logsPath := filepath.Join(programDataPath, "OpenTelemetry", "Collector", "Logs") logFilePath := filepath.Join(logsPath, "otelcol.log") fileinfo, err := os.Stat(logFilePath) require.NoError(t, err) require.NotEmpty(t, fileinfo.Size()) }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { serviceConfig, err := service.Config() require.NoError(t, err) // Setup the command line to launch the collector as a service fullConfigPath, err := filepath.Abs(tt.configFile) require.NoError(t, err) serviceConfig.BinaryPathName = fmt.Sprintf("\"%s\" --config \"%s\"", collector_executable, fullConfigPath) err = service.UpdateConfig(serviceConfig) require.NoError(t, err) if tt.customSetup != nil { tt.customSetup(t) } startTime := time.Now() err = service.Start() require.NoError(t, err) expectedState := svc.Running if tt.expectStartFailure { expectedState = svc.Stopped } else { defer func() { _, err = service.Control(svc.Stop) require.NoError(t, err) require.Eventually(t, func() bool { status, _ := service.Query() return status.State == svc.Stopped }, 10*time.Second, 500*time.Millisecond) }() } // Wait for the service to reach the expected state require.Eventually(t, func() bool { status, _ := service.Query() return status.State == expectedState }, 10*time.Second, 500*time.Millisecond) if tt.customValidation != nil { tt.customValidation(t) } else { // Read the events from the otelcorecol source and check that they were emitted after the service // command started. This is a simple validation that the messages are being logged on the // Windows event log. cmd := exec.Command("wevtutil.exe", "qe", "Application", "/c:1", "/rd:true", "/f:RenderedXml", "/q:*[System[Provider[@Name='otelcorecol']]]") out, err := cmd.CombinedOutput() require.NoError(t, err) var e Event require.NoError(t, xml.Unmarshal([]byte(out), &e)) eventTime, err := time.Parse("2006-01-02T15:04:05.9999999Z07:00", e.System.TimeCreated.SystemTime) require.NoError(t, err) require.True(t, eventTime.After(startTime.In(time.UTC))) } }) } } // Helper types to read the XML events from the event log using wevtutil type Event struct { XMLName xml.Name `xml:"Event"` System System `xml:"System"` Data string `xml:"EventData>Data"` } type System struct { Provider Provider `xml:"Provider"` EventID int `xml:"EventID"` Version int `xml:"Version"` Level int `xml:"Level"` Task int `xml:"Task"` Opcode int `xml:"Opcode"` Keywords string `xml:"Keywords"` TimeCreated TimeCreated `xml:"TimeCreated"` EventRecordID int `xml:"EventRecordID"` Execution Execution `xml:"Execution"` Channel string `xml:"Channel"` Computer string `xml:"Computer"` } type Provider struct { Name string `xml:"Name,attr"` } type TimeCreated struct { SystemTime string `xml:"SystemTime,attr"` } type Execution struct { ProcessID string `xml:"ProcessID,attr"` ThreadID string `xml:"ThreadID,attr"` } opentelemetry-collector-0.141.0/otelcol/collector_windows_test.go000066400000000000000000000025301511331344600253250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build windows package otelcol import ( "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "golang.org/x/sys/windows/svc" "go.opentelemetry.io/collector/component" ) func TestNewSvcHandler(t *testing.T) { oldArgs := os.Args defer func() { os.Args = oldArgs }() filePath := filepath.Join("testdata", "otelcol-nop.yaml") os.Args = []string{"otelcol", "--config", filePath} s := NewSvcHandler(CollectorSettings{BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filePath})}) colDone := make(chan struct{}) requests := make(chan svc.ChangeRequest) changes := make(chan svc.Status) go func() { defer close(colDone) ssec, errno := s.Execute([]string{"svc name"}, requests, changes) assert.Equal(t, uint32(0), errno) assert.False(t, ssec) }() assert.Equal(t, svc.StartPending, (<-changes).State) assert.Equal(t, svc.Running, (<-changes).State) requests <- svc.ChangeRequest{Cmd: svc.Interrogate, CurrentStatus: svc.Status{State: svc.Running}} assert.Equal(t, svc.Running, (<-changes).State) requests <- svc.ChangeRequest{Cmd: svc.Stop} assert.Equal(t, svc.StopPending, (<-changes).State) assert.Equal(t, svc.Stopped, (<-changes).State) <-colDone } opentelemetry-collector-0.141.0/otelcol/command.go000066400000000000000000000063461511331344600221550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "errors" "flag" "fmt" "os" "text/tabwriter" "github.com/spf13/cobra" "go.opentelemetry.io/collector/featuregate" ) // NewCommand constructs a new cobra.Command using the given CollectorSettings. // Any URIs specified in CollectorSettings.ConfigProviderSettings.ResolverSettings.URIs // are considered defaults and will be overwritten by config flags passed as // command-line arguments to the executable. // At least one Provider must be set. func NewCommand(set CollectorSettings) *cobra.Command { flagSet := flags(featuregate.GlobalRegistry()) rootCmd := &cobra.Command{ Use: set.BuildInfo.Command, Version: set.BuildInfo.Version, SilenceUsage: true, RunE: func(cmd *cobra.Command, _ []string) error { err := updateSettingsUsingFlags(&set, flagSet) if err != nil { return err } col, err := NewCollector(set) if err != nil { return err } return col.Run(cmd.Context()) }, } rootCmd.AddCommand(newFeatureGateCommand()) rootCmd.AddCommand(newComponentsCommand(set)) rootCmd.AddCommand(newValidateSubCommand(set, flagSet)) rootCmd.AddCommand(newConfigPrintSubCommand(set, flagSet)) rootCmd.Flags().AddGoFlagSet(flagSet) return rootCmd } // Puts command line flags from flags into the CollectorSettings, to be used during config resolution. func updateSettingsUsingFlags(set *CollectorSettings, flags *flag.FlagSet) error { resolverSet := &set.ConfigProviderSettings.ResolverSettings configFlags := getConfigFlag(flags) if len(configFlags) > 0 { resolverSet.URIs = configFlags } if len(resolverSet.URIs) == 0 { return errors.New("at least one config flag must be provided") } if set.ConfigProviderSettings.ResolverSettings.DefaultScheme == "" { set.ConfigProviderSettings.ResolverSettings.DefaultScheme = "env" } if len(resolverSet.ProviderFactories) == 0 { return errors.New("at least one Provider must be supplied") } return nil } func newFeatureGateCommand() *cobra.Command { return &cobra.Command{ Use: "featuregate [feature-id]", Short: "Display feature gates information", Long: "Display information about available feature gates and their status", RunE: func(_ *cobra.Command, args []string) error { if len(args) > 0 { found := false featuregate.GlobalRegistry().VisitAll(func(g *featuregate.Gate) { if g.ID() == args[0] { found = true fmt.Printf("Feature: %s\n", g.ID()) fmt.Printf("Enabled: %v\n", g.IsEnabled()) fmt.Printf("Stage: %s\n", g.Stage()) fmt.Printf("Description: %s\n", g.Description()) fmt.Printf("From Version: %s\n", g.FromVersion()) if g.ToVersion() != "" { fmt.Printf("To Version: %s\n", g.ToVersion()) } } }) if !found { return fmt.Errorf("feature %q not found", args[0]) } return nil } w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0) fmt.Fprintf(w, "ID\tEnabled\tStage\tDescription\n") featuregate.GlobalRegistry().VisitAll(func(g *featuregate.Gate) { fmt.Fprintf(w, "%s\t%v\t%s\t%s\n", g.ID(), g.IsEnabled(), g.Stage(), g.Description()) }) return w.Flush() }, } } opentelemetry-collector-0.141.0/otelcol/command_components.go000066400000000000000000000130161511331344600244120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "fmt" "sort" "github.com/spf13/cobra" yaml "go.yaml.in/yaml/v3" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" ) type componentWithStability struct { Name component.Type Module string Stability map[string]string } type componentWithoutStability struct { Scheme string `yaml:",omitempty"` Module string } type componentsOutput struct { BuildInfo component.BuildInfo Receivers []componentWithStability Processors []componentWithStability Exporters []componentWithStability Connectors []componentWithStability Extensions []componentWithStability Providers []componentWithoutStability Converters []componentWithoutStability `yaml:",omitempty"` } // newComponentsCommand constructs a new components command using the given CollectorSettings. func newComponentsCommand(set CollectorSettings) *cobra.Command { return &cobra.Command{ Use: "components", Short: "Outputs available components in this collector distribution", Long: "Outputs available components in this collector distribution including their stability levels. The output format is not stable and can change between releases.", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) error { factories, err := set.Factories() if err != nil { return fmt.Errorf("failed to initialize factories: %w", err) } components := componentsOutput{} for _, con := range sortFactoriesByType[connector.Factory](factories.Connectors) { components.Connectors = append(components.Connectors, componentWithStability{ Name: con.Type(), Module: factories.ConnectorModules[con.Type()], Stability: map[string]string{ "logs-to-logs": con.LogsToLogsStability().String(), "logs-to-metrics": con.LogsToMetricsStability().String(), "logs-to-traces": con.LogsToTracesStability().String(), "metrics-to-logs": con.MetricsToLogsStability().String(), "metrics-to-metrics": con.MetricsToMetricsStability().String(), "metrics-to-traces": con.MetricsToTracesStability().String(), "traces-to-logs": con.TracesToLogsStability().String(), "traces-to-metrics": con.TracesToMetricsStability().String(), "traces-to-traces": con.TracesToTracesStability().String(), }, }) } for _, ext := range sortFactoriesByType[extension.Factory](factories.Extensions) { components.Extensions = append(components.Extensions, componentWithStability{ Name: ext.Type(), Module: factories.ExtensionModules[ext.Type()], Stability: map[string]string{ "extension": ext.Stability().String(), }, }) } for _, prs := range sortFactoriesByType[processor.Factory](factories.Processors) { components.Processors = append(components.Processors, componentWithStability{ Name: prs.Type(), Module: factories.ProcessorModules[prs.Type()], Stability: map[string]string{ "logs": prs.LogsStability().String(), "metrics": prs.MetricsStability().String(), "traces": prs.TracesStability().String(), }, }) } for _, rcv := range sortFactoriesByType[receiver.Factory](factories.Receivers) { components.Receivers = append(components.Receivers, componentWithStability{ Name: rcv.Type(), Module: factories.ReceiverModules[rcv.Type()], Stability: map[string]string{ "logs": rcv.LogsStability().String(), "metrics": rcv.MetricsStability().String(), "traces": rcv.TracesStability().String(), }, }) } for _, exp := range sortFactoriesByType[exporter.Factory](factories.Exporters) { components.Exporters = append(components.Exporters, componentWithStability{ Name: exp.Type(), Module: factories.ExporterModules[exp.Type()], Stability: map[string]string{ "logs": exp.LogsStability().String(), "metrics": exp.MetricsStability().String(), "traces": exp.TracesStability().String(), }, }) } components.BuildInfo = set.BuildInfo for providerScheme, providerModuleModule := range set.ProviderModules { components.Providers = append(components.Providers, componentWithoutStability{ Scheme: providerScheme, Module: providerModuleModule, }) } for _, converterModule := range set.ConverterModules { components.Converters = append(components.Converters, componentWithoutStability{ Module: converterModule, }) } yamlData, err := yaml.Marshal(components) if err != nil { return err } fmt.Fprint(cmd.OutOrStdout(), string(yamlData)) return nil }, } } func sortFactoriesByType[T component.Factory](factories map[component.Type]T) []T { // Gather component types (factories map keys) componentTypes := make([]component.Type, 0, len(factories)) for componentType := range factories { componentTypes = append(componentTypes, componentType) } // Sort component types as strings sort.Slice(componentTypes, func(i, j int) bool { return componentTypes[i].String() < componentTypes[j].String() }) // Build and return list of factories, sorted by component types sortedFactories := make([]T, 0, len(factories)) for _, componentType := range componentTypes { sortedFactories = append(sortedFactories, factories[componentType]) } return sortedFactories } opentelemetry-collector-0.141.0/otelcol/command_components_test.go000066400000000000000000000025551511331344600254570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "bytes" "os" "path/filepath" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" ) func TestNewBuildSubCommand(t *testing.T) { set := CollectorSettings{ BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories, ConfigProviderSettings: newDefaultConfigProviderSettings(t, []string{filepath.Join("testdata", "otelcol-nop.yaml")}), ProviderModules: map[string]string{ "nop": "go.opentelemetry.io/collector/confmap/provider/testprovider v1.2.3", }, ConverterModules: []string{ "go.opentelemetry.io/collector/converter/testconverter v1.2.3", }, } cmd := NewCommand(set) cmd.SetArgs([]string{"components"}) ExpectedOutput, err := os.ReadFile(filepath.Join("testdata", "components-output.yaml")) require.NoError(t, err) b := bytes.NewBufferString("") cmd.SetOut(b) err = cmd.Execute() require.NoError(t, err) // Trim new line at the end of the two strings to make a better comparison as string() adds an extra new // line that makes the test fail. assert.Equal(t, strings.ReplaceAll(strings.ReplaceAll(string(ExpectedOutput), "\n", ""), "\r", ""), strings.ReplaceAll(strings.ReplaceAll(b.String(), "\n", ""), "\r", "")) } opentelemetry-collector-0.141.0/otelcol/command_print.go000066400000000000000000000134151511331344600233640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "encoding/json" "errors" "flag" "fmt" "io" "strings" "github.com/spf13/cobra" yaml "go.yaml.in/yaml/v3" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/featuregate" ) const featureGateName = "otelcol.printInitialConfig" var printCommandFeatureFlag = featuregate.GlobalRegistry().MustRegister( featureGateName, featuregate.StageBeta, featuregate.WithRegisterFromVersion("v0.120.0"), featuregate.WithRegisterDescription("if set to true, enable the print-config command"), ) // newConfigPrintSubCommand constructs a new print-config command using the given CollectorSettings. func newConfigPrintSubCommand(set CollectorSettings, flagSet *flag.FlagSet) *cobra.Command { var outputFormat string var mode string var validate bool cmd := &cobra.Command{ Use: "print-config", Aliases: []string{"print-initial-config"}, Short: "Prints the Collector's configuration in the specified mode", Long: `Prints the Collector's configuration with different levels of processing: - redacted: Shows the resolved configuration with sensitive data redacted (default) - unredacted: Shows the resolved configuration with all sensitive data visible The output prints in YAML by default. To print JSON use --format=json, however this is considered unstable. Validation is enabled by default, as a safety measure. All modes are experimental, requiring the otelcol.printInitialConfig feature gate.`, Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) error { pc := printContext{ cmd: cmd, stdout: cmd.OutOrStdout(), set: set, outputFormat: outputFormat, validate: validate, } return pc.configPrintSubCommand(flagSet, mode) }, } formatHelp := "Output format: yaml (default), json (unstable))" cmd.Flags().StringVar(&outputFormat, "format", "yaml", formatHelp) modeHelp := "Operating mode: redacted (default), unredacted" cmd.Flags().StringVar(&mode, "mode", "redacted", modeHelp) validateHelp := "Validation mode: true (default), false" cmd.Flags().BoolVar(&validate, "validate", true, validateHelp) cmd.Flags().AddGoFlagSet(flagSet) return cmd } type printContext struct { cmd *cobra.Command stdout io.Writer set CollectorSettings outputFormat string validate bool } func (pctx *printContext) configPrintSubCommand(flagSet *flag.FlagSet, mode string) error { if !printCommandFeatureFlag.IsEnabled() { return errors.New("print-config is currently experimental, use the otelcol.printInitialConfig feature gate to enable this command") } err := updateSettingsUsingFlags(&pctx.set, flagSet) if err != nil { return err } switch strings.ToLower(mode) { case "redacted": return pctx.printRedactedConfig() case "unredacted": return pctx.printUnredactedConfig() default: return fmt.Errorf("invalid mode %q: modes are: redacted, unredacted", mode) } } // printConfigData formats and prints configuration data in yaml or json format. func (pctx *printContext) printConfigData(data map[string]any) error { format := pctx.outputFormat if format == "" { format = "yaml" } switch { case strings.EqualFold(format, "yaml"): b, err := yaml.Marshal(data) if err != nil { return err } fmt.Fprintf(pctx.stdout, "%s\n", b) return nil case strings.EqualFold(format, "json"): encoder := json.NewEncoder(pctx.stdout) encoder.SetIndent("", " ") return encoder.Encode(data) } return fmt.Errorf("unrecognized print format: %s", format) } func (pctx *printContext) getPrintableConfig() (any, error) { var factories Factories if pctx.set.Factories != nil { var err error factories, err = pctx.set.Factories() if err != nil { return nil, fmt.Errorf("failed to get factories: %w", err) } } configProvider, err := NewConfigProvider(pctx.set.ConfigProviderSettings) if err != nil { return nil, fmt.Errorf("failed to create config provider: %w", err) } cfg, err := configProvider.Get(pctx.cmd.Context(), factories) if err != nil { return nil, fmt.Errorf("failed to get config: %w", err) } return cfg, nil } // printUnredactedConfig prints resolved configuration before interpreting // with the intended types for each component, thus it shows the full // configuration without considering configuopaque. Use with caution. func (pctx *printContext) printUnredactedConfig() error { if pctx.validate { // Validation serves prevent revealing invalid data. cfg, err := pctx.getPrintableConfig() if err != nil { return err } if err = xconfmap.Validate(cfg); err != nil { return fmt.Errorf("invalid configuration: %w", err) } // Note: we discard the validated configuration. } resolver, err := confmap.NewResolver(pctx.set.ConfigProviderSettings.ResolverSettings) if err != nil { return fmt.Errorf("failed to create new resolver: %w", err) } conf, err := resolver.Resolve(pctx.cmd.Context()) if err != nil { return fmt.Errorf("error while resolving config: %w", err) } return pctx.printConfigData(conf.ToStringMap()) } // printRedactedConfig prints resolved configuration with its assigned // types, but without validation. Notably, configopaque strings are printed // as "[redacted]". This is the default. func (pctx *printContext) printRedactedConfig() error { cfg, err := pctx.getPrintableConfig() if err != nil { return err } if pctx.validate { if err = xconfmap.Validate(cfg); err != nil { return fmt.Errorf("invalid configuration: %w", err) } } confMap := confmap.New() if err := confMap.Marshal(cfg); err != nil { return fmt.Errorf("failed to marshal config: %w", err) } return pctx.printConfigData(confMap.ToStringMap()) } opentelemetry-collector-0.141.0/otelcol/command_print_test.go000066400000000000000000000154701511331344600244260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "bytes" "context" "errors" "fmt" "path/filepath" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configopaque" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/fileprovider" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/xreceiver" "go.opentelemetry.io/collector/service/telemetry" ) type printExporterConfig struct { Timeout time.Duration `mapstructure:"timeout"` } type printReceiverConfig struct { Opaque configopaque.String `mapstructure:"opaque"` Other string `mapstructure:"other,omitempty"` } func (c *printExporterConfig) Validate() error { if c.Timeout < 0 { return errors.New("timeout cannot be negative") } return nil } func TestPrintCommand(t *testing.T) { const nonexistentConfig = "file:nope.yaml" validConfig := fmt.Sprint("file:", filepath.Join("testdata", "print.yaml")) invalidConfig1 := fmt.Sprint("file:", filepath.Join("testdata", "print_invalid.yaml")) invalidConfig2 := fmt.Sprint("file:", filepath.Join("testdata", "print_negative.yaml")) defaultConfig := fmt.Sprint("file:", filepath.Join("testdata", "print_default.yaml")) tests := []struct { name string ofmt string path string errString string outString map[string]string disableFF bool // disable the feature flag validate bool // add validation (even redacted) errOnlyRedacted bool // error applies only in redacted mode }{ { name: "file not found", path: nonexistentConfig, errString: "cannot retrieve the configuration: unable to read the file", }, { name: "valid yaml", path: validConfig, }, { name: "invalid syntax without validate", path: invalidConfig1, errString: "'timeout' time: invalid duration", errOnlyRedacted: true, }, { name: "validation fail", path: invalidConfig2, validate: true, errString: "timeout cannot be negative", }, { name: "no feature flag", path: validConfig, disableFF: true, errString: "use the otelcol.printInitialConfig feature gate", }, { name: "field is set yaml", path: validConfig, outString: map[string]string{ "redacted": `timeout: 5s`, "unredacted": `timeout: 5s`, }, }, { name: "default field value", path: defaultConfig, outString: map[string]string{ "redacted": `timeout: 1s`, // Since the structure is empty before // interpretation, no default is expanded. "unredacted": `e: null`, }, }, { name: "field is set json", ofmt: "json", path: validConfig, outString: map[string]string{ // Note: JSON does not format as a time.Duration "redacted": `"timeout": 5000000000`, // Note: the original input is "5s" "unredacted": `"timeout": "5s"`, }, }, { name: "opaque field", path: validConfig, outString: map[string]string{ "redacted": `opaque: '[REDACTED]'`, "unredacted": `opaque: OOO`, }, }, { name: "opaque default", path: defaultConfig, outString: map[string]string{ "redacted": `opaque: '[REDACTED]'`, // Note: the default opaque value does not print, // the other value is set in defaultConfig so that // the whole component config is not defaulted. "unredacted": `other: lala`, }, }, } for _, test := range tests { testModes := []string{"redacted", "unredacted", "unrecognized"} for _, mode := range testModes { t.Run(fmt.Sprint(test.name, "_", mode), func(t *testing.T) { // Save current feature flag state and restore after test fg := featuregate.GlobalRegistry() fg.VisitAll(func(g *featuregate.Gate) { if g.ID() == featureGateName { defer func() { _ = fg.Set(featureGateName, g.IsEnabled()) }() } }) if test.disableFF { require.NoError(t, fg.Set(featureGateName, false)) } else { require.NoError(t, fg.Set(featureGateName, true)) } testR := component.MustNewType("r") testE := component.MustNewType("e") testReceiver := xreceiver.NewFactory( testR, func() component.Config { return printReceiverConfig{ Opaque: "1234", Other: "", } }, xreceiver.WithLogs(func(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { return nil, nil }, component.StabilityLevelStable), ) testExporter := xexporter.NewFactory( testE, func() component.Config { return printExporterConfig{ Timeout: time.Second, } }, xexporter.WithLogs(func(context.Context, exporter.Settings, component.Config) (exporter.Logs, error) { return nil, nil }, component.StabilityLevelStable), ) var stdout bytes.Buffer set := confmap.ResolverSettings{} set.ProviderFactories = []confmap.ProviderFactory{ fileprovider.NewFactory(), } set.DefaultScheme = "file" set.URIs = []string{test.path} cmd := newConfigPrintSubCommand(CollectorSettings{ Factories: func() (Factories, error) { return Factories{ Receivers: map[component.Type]receiver.Factory{ testR: testReceiver, }, Exporters: map[component.Type]exporter.Factory{ testE: testExporter, }, Telemetry: telemetry.NewFactory(func() component.Config { return fakeTelemetryConfig{} }), }, nil }, ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: set, }, }, flags(featuregate.GlobalRegistry())) cmd.SetOut(&stdout) args := []string{ "--mode", mode, "--format", test.ofmt, } if test.validate { args = append(args, "--validate=true") } else { args = append(args, "--validate=false") } cmd.SetArgs(args) err := cmd.Execute() expectErr := test.errString != "" expectErrMsg := test.errString switch mode { case "redacted": case "unredacted": if test.errOnlyRedacted { expectErr = false expectErrMsg = "" } default: expectErr = true if test.disableFF { expectErrMsg = "feature gate" } else { expectErrMsg = "unrecognized" } } if expectErr { require.Error(t, err) require.ErrorContains(t, err, expectErrMsg) } else { require.NoError(t, err) } if test.outString[mode] != "" { require.Contains(t, stdout.String(), test.outString[mode]) } }) } } } opentelemetry-collector-0.141.0/otelcol/command_test.go000066400000000000000000000146101511331344600232050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "context" "io" "os" "path/filepath" "testing" "github.com/spf13/cobra" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/featuregate" ) func TestNewCommandVersion(t *testing.T) { cmd := NewCommand(CollectorSettings{BuildInfo: component.BuildInfo{Version: "test_version"}}) assert.Equal(t, "test_version", cmd.Version) } func TestNewCommandNoConfigURI(t *testing.T) { cmd := NewCommand(CollectorSettings{Factories: nopFactories}) require.Error(t, cmd.Execute()) } // This test emulates usage of Collector in Jaeger all-in-one, which // allows running the binary with no explicit configuration. func TestNewCommandProgrammaticallyPassedConfig(t *testing.T) { cmd := NewCommand(CollectorSettings{Factories: nopFactories, ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ ProviderFactories: []confmap.ProviderFactory{confmap.NewProviderFactory(newFailureProvider)}, DefaultScheme: "file", }, }}) otelRunE := cmd.RunE cmd.RunE = func(c *cobra.Command, args []string) error { configFlag := c.Flag("config") cfg := ` service: extensions: [invalid_component_name] receivers: invalid_component_name: ` require.NoError(t, configFlag.Value.Set("yaml:"+cfg)) return otelRunE(cmd, args) } // verify that cmd.Execute was run with the implicitly provided config. require.ErrorContains(t, cmd.Execute(), "invalid_component_name") } func TestAddFlagToSettings(t *testing.T) { filePath := filepath.Join("testdata", "otelcol-invalid.yaml") fileProvider := newFakeProvider("file", func(_ context.Context, _ string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { return confmap.NewRetrieved(newConfFromFile(t, filePath)) }) set := CollectorSettings{ ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{filePath}, ProviderFactories: []confmap.ProviderFactory{fileProvider}, }, }, } flgs := flags(featuregate.NewRegistry()) err := flgs.Parse([]string{"--config=otelcol-nop.yaml"}) require.NoError(t, err) err = updateSettingsUsingFlags(&set, flgs) require.NoError(t, err) require.Len(t, set.ConfigProviderSettings.ResolverSettings.URIs, 1) } func TestInvalidCollectorSettings(t *testing.T) { set := CollectorSettings{ ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{"--config=otelcol-nop.yaml"}, }, }, } cmd := NewCommand(set) require.Error(t, cmd.Execute()) } func TestNewCommandInvalidComponent(t *testing.T) { filePath := filepath.Join("testdata", "otelcol-invalid.yaml") fileProvider := newFakeProvider("file", func(_ context.Context, _ string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { return confmap.NewRetrieved(newConfFromFile(t, filePath)) }) set := ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{filePath}, ProviderFactories: []confmap.ProviderFactory{fileProvider}, }, } cmd := NewCommand(CollectorSettings{Factories: nopFactories, ConfigProviderSettings: set}) require.Error(t, cmd.Execute()) } func TestNoProvidersReturnsError(t *testing.T) { set := CollectorSettings{ ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{filepath.Join("testdata", "otelcol-invalid.yaml")}, }, }, } flgs := flags(featuregate.NewRegistry()) err := flgs.Parse([]string{"--config=otelcol-nop.yaml"}) require.NoError(t, err) err = updateSettingsUsingFlags(&set, flgs) require.ErrorContains(t, err, "at least one Provider must be supplied") } func Test_UseUnifiedEnvVarExpansionRules(t *testing.T) { tests := []struct { name string input string expected string }{ { name: "default scheme set", input: "file", expected: "file", }, { name: "default scheme not set", input: "", expected: "env", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { fileProvider := newFakeProvider("file", func(_ context.Context, _ string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { return &confmap.Retrieved{}, nil }) set := CollectorSettings{ ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ ProviderFactories: []confmap.ProviderFactory{fileProvider}, DefaultScheme: tt.input, }, }, } flgs := flags(featuregate.NewRegistry()) err := flgs.Parse([]string{"--config=otelcol-nop.yaml"}) require.NoError(t, err) err = updateSettingsUsingFlags(&set, flgs) require.NoError(t, err) require.Equal(t, tt.expected, set.ConfigProviderSettings.ResolverSettings.DefaultScheme) }) } } func TestNewFeatureGateCommand(t *testing.T) { t.Run("list all featuregates", func(t *testing.T) { cmd := newFeatureGateCommand() require.NotNil(t, cmd) // Capture stdout oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w err := cmd.RunE(cmd, []string{}) require.NoError(t, err) w.Close() out, _ := io.ReadAll(r) os.Stdout = oldStdout output := string(out) assert.Contains(t, output, "ID") assert.Contains(t, output, "Enabled") assert.Contains(t, output, "Stage") assert.Contains(t, output, "Description") }) t.Run("specific featuregate details", func(t *testing.T) { cmd := newFeatureGateCommand() // Register a test feature gate in the global registry featuregate.GlobalRegistry().MustRegister("test.feature", featuregate.StageBeta, featuregate.WithRegisterDescription("Test feature description")) // Capture stdout oldStdout := os.Stdout r, w, _ := os.Pipe() os.Stdout = w err := cmd.RunE(cmd, []string{"test.feature"}) require.NoError(t, err) w.Close() out, _ := io.ReadAll(r) os.Stdout = oldStdout output := string(out) assert.Contains(t, output, "Feature: test.feature") assert.Contains(t, output, "Description: Test feature description") assert.Contains(t, output, "Stage: Beta") }) t.Run("non-existent featuregate", func(t *testing.T) { cmd := newFeatureGateCommand() err := cmd.RunE(cmd, []string{"non.existent.feature"}) require.Error(t, err) assert.Contains(t, err.Error(), "feature \"non.existent.feature\" not found") }) } opentelemetry-collector-0.141.0/otelcol/command_validate.go000066400000000000000000000015171511331344600240210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "flag" "github.com/spf13/cobra" ) // newValidateSubCommand constructs a new validate sub command using the given CollectorSettings. func newValidateSubCommand(set CollectorSettings, flagSet *flag.FlagSet) *cobra.Command { validateCmd := &cobra.Command{ Use: "validate", Short: "Validates the config without running the collector", Args: cobra.ExactArgs(0), RunE: func(cmd *cobra.Command, _ []string) error { if err := updateSettingsUsingFlags(&set, flagSet); err != nil { return err } col, err := NewCollector(set) if err != nil { return err } return col.DryRun(cmd.Context()) }, } validateCmd.Flags().AddGoFlagSet(flagSet) return validateCmd } opentelemetry-collector-0.141.0/otelcol/command_validate_test.go000066400000000000000000000024321511331344600250550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "context" "path/filepath" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/featuregate" ) func TestValidateSubCommandNoConfig(t *testing.T) { cmd := newValidateSubCommand(CollectorSettings{Factories: nopFactories}, flags(featuregate.GlobalRegistry())) err := cmd.Execute() require.ErrorContains(t, err, "at least one config flag must be provided") } func TestValidateSubCommandInvalidComponents(t *testing.T) { filePath := filepath.Join("testdata", "otelcol-invalid-components.yaml") fileProvider := newFakeProvider("file", func(_ context.Context, _ string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { return confmap.NewRetrieved(newConfFromFile(t, filePath)) }) cmd := newValidateSubCommand(CollectorSettings{Factories: nopFactories, ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{filePath}, ProviderFactories: []confmap.ProviderFactory{fileProvider}, DefaultScheme: "file", }, }}, flags(featuregate.GlobalRegistry())) err := cmd.Execute() require.ErrorContains(t, err, "unknown type: \"nosuchprocessor\"") } opentelemetry-collector-0.141.0/otelcol/config.go000066400000000000000000000114351511331344600217770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "errors" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/pipelines" ) var ( errMissingExporters = errors.New("no exporter configuration specified in config") errMissingReceivers = errors.New("no receiver configuration specified in config") errEmptyConfigurationFile = errors.New("empty configuration file") ) // Config defines the configuration for the various elements of collector or agent. type Config struct { // Receivers is a map of ComponentID to Receivers. Receivers map[component.ID]component.Config `mapstructure:"receivers"` // Exporters is a map of ComponentID to Exporters. Exporters map[component.ID]component.Config `mapstructure:"exporters"` // Processors is a map of ComponentID to Processors. Processors map[component.ID]component.Config `mapstructure:"processors"` // Connectors is a map of ComponentID to connectors. Connectors map[component.ID]component.Config `mapstructure:"connectors"` // Extensions is a map of ComponentID to extensions. Extensions map[component.ID]component.Config `mapstructure:"extensions"` Service service.Config `mapstructure:"service"` // prevent unkeyed literal initialization _ struct{} } // Validate returns an error if the config is invalid. // // This function performs basic validation of configuration. There may be more subtle // invalid cases that we currently don't check for but which we may want to add in // the future (e.g. disallowing receiving and exporting on the same endpoint). func (cfg *Config) Validate() error { // There must be at least one property set in the configuration file. if len(cfg.Receivers) == 0 && len(cfg.Exporters) == 0 && len(cfg.Processors) == 0 && len(cfg.Connectors) == 0 && len(cfg.Extensions) == 0 { return errEmptyConfigurationFile } // Currently, there is no default receiver enabled. // The configuration must specify at least one receiver to be valid. if !pipelines.AllowNoPipelines.IsEnabled() && len(cfg.Receivers) == 0 { return errMissingReceivers } // Currently, there is no default exporter enabled. // The configuration must specify at least one exporter to be valid. if !pipelines.AllowNoPipelines.IsEnabled() && len(cfg.Exporters) == 0 { return errMissingExporters } // Validate the connector configuration. for connID := range cfg.Connectors { if _, ok := cfg.Exporters[connID]; ok { return fmt.Errorf("connectors::%s: ambiguous ID: Found both %q exporter and %q connector. "+ "Change one of the components' IDs to eliminate ambiguity (e.g. rename %q connector to %q)", connID, connID, connID, connID, connID.String()+"/connector") } if _, ok := cfg.Receivers[connID]; ok { return fmt.Errorf("connectors::%s: ambiguous ID: Found both %q receiver and %q connector. "+ "Change one of the components' IDs to eliminate ambiguity (e.g. rename %q connector to %q)", connID, connID, connID, connID, connID.String()+"/connector") } } // Check that all enabled extensions in the service are configured. for _, ref := range cfg.Service.Extensions { // Check that the name referenced in the Service extensions exists in the top-level extensions. if cfg.Extensions[ref] == nil { return fmt.Errorf("service::extensions: references extension %q which is not configured", ref) } } // Check that all pipelines reference only configured components. for pipelineID, pipeline := range cfg.Service.Pipelines { // Validate pipeline receiver name references. for _, ref := range pipeline.Receivers { // Check that the name referenced in the pipeline's receivers exists in the top-level receivers. if _, ok := cfg.Receivers[ref]; ok { continue } if _, ok := cfg.Connectors[ref]; ok { continue } return fmt.Errorf("service::pipelines::%s: references receiver %q which is not configured", pipelineID.String(), ref) } // Validate pipeline processor name references. for _, ref := range pipeline.Processors { // Check that the name referenced in the pipeline's processors exists in the top-level processors. if cfg.Processors[ref] == nil { return fmt.Errorf("service::pipelines::%s: references processor %q which is not configured", pipelineID.String(), ref) } } // Validate pipeline exporter name references. for _, ref := range pipeline.Exporters { // Check that the name referenced in the pipeline's Exporters exists in the top-level Exporters. if _, ok := cfg.Exporters[ref]; ok { continue } if _, ok := cfg.Connectors[ref]; ok { continue } return fmt.Errorf("service::pipelines::%s: references exporter %q which is not configured", pipelineID.String(), ref) } } return nil } opentelemetry-collector-0.141.0/otelcol/config_test.go000066400000000000000000000226241511331344600230400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "errors" "fmt" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/pipelines" ) var ( errInvalidRecvConfig = errors.New("invalid receiver config") errInvalidExpConfig = errors.New("invalid exporter config") errInvalidProcConfig = errors.New("invalid processor config") errInvalidConnConfig = errors.New("invalid connector config") errInvalidExtConfig = errors.New("invalid extension config") ) type errConfig struct { validateErr error } func (c *errConfig) Validate() error { return c.validateErr } func TestConfigValidate(t *testing.T) { testCases := []struct { name string // test case name (also file name containing config yaml) cfgFn func() *Config expected error }{ { name: "valid", cfgFn: generateConfig, expected: nil, }, { name: "valid-telemetry-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Service.Telemetry = fakeTelemetryConfig{} return cfg }, expected: nil, }, { name: "empty configuration file", cfgFn: func() *Config { cfg := generateConfig() cfg.Receivers = nil cfg.Connectors = nil cfg.Processors = nil cfg.Exporters = nil cfg.Extensions = nil return cfg }, expected: errEmptyConfigurationFile, }, { name: "missing-exporters", cfgFn: func() *Config { cfg := generateConfig() cfg.Exporters = nil return cfg }, expected: errMissingExporters, }, { name: "missing-receivers", cfgFn: func() *Config { cfg := generateConfig() cfg.Receivers = nil return cfg }, expected: errMissingReceivers, }, { name: "invalid-telemetry-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Service.Telemetry = fakeTelemetryConfig{Invalid: true} return cfg }, expected: errors.New("service::telemetry: invalid config"), }, { name: "invalid-extension-reference", cfgFn: func() *Config { cfg := generateConfig() cfg.Service.Extensions = append(cfg.Service.Extensions, component.MustNewIDWithName("nop", "2")) return cfg }, expected: errors.New(`service::extensions: references extension "nop/2" which is not configured`), }, { name: "invalid-receiver-reference", cfgFn: func() *Config { cfg := generateConfig() pipe := cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Receivers = append(pipe.Receivers, component.MustNewIDWithName("nop", "2")) return cfg }, expected: errors.New(`service::pipelines::traces: references receiver "nop/2" which is not configured`), }, { name: "invalid-processor-reference", cfgFn: func() *Config { cfg := generateConfig() pipe := cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Processors = append(pipe.Processors, component.MustNewIDWithName("nop", "2")) return cfg }, expected: errors.New(`service::pipelines::traces: references processor "nop/2" which is not configured`), }, { name: "invalid-exporter-reference", cfgFn: func() *Config { cfg := generateConfig() pipe := cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Exporters = append(pipe.Exporters, component.MustNewIDWithName("nop", "2")) return cfg }, expected: errors.New(`service::pipelines::traces: references exporter "nop/2" which is not configured`), }, { name: "invalid-receiver-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Receivers[component.MustNewID("nop")] = &errConfig{ validateErr: errInvalidRecvConfig, } return cfg }, expected: fmt.Errorf(`receivers::nop: %w`, errInvalidRecvConfig), }, { name: "invalid-exporter-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Exporters[component.MustNewID("nop")] = &errConfig{ validateErr: errInvalidExpConfig, } return cfg }, expected: fmt.Errorf(`exporters::nop: %w`, errInvalidExpConfig), }, { name: "invalid-processor-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Processors[component.MustNewID("nop")] = &errConfig{ validateErr: errInvalidProcConfig, } return cfg }, expected: fmt.Errorf(`processors::nop: %w`, errInvalidProcConfig), }, { name: "invalid-extension-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Extensions[component.MustNewID("nop")] = &errConfig{ validateErr: errInvalidExtConfig, } return cfg }, expected: fmt.Errorf(`extensions::nop: %w`, errInvalidExtConfig), }, { name: "invalid-connector-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Connectors[component.MustNewIDWithName("nop", "conn")] = &errConfig{ validateErr: errInvalidConnConfig, } return cfg }, expected: fmt.Errorf(`connectors::nop/conn: %w`, errInvalidConnConfig), }, { name: "ambiguous-connector-name-as-receiver", cfgFn: func() *Config { cfg := generateConfig() cfg.Receivers[component.MustNewID("nop2")] = &errConfig{} cfg.Connectors[component.MustNewID("nop2")] = &errConfig{} pipe := cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Receivers = append(pipe.Receivers, component.MustNewIDWithName("nop", "2")) pipe.Exporters = append(pipe.Exporters, component.MustNewIDWithName("nop", "2")) return cfg }, expected: errors.New(`connectors::nop2: ambiguous ID: Found both "nop2" receiver and "nop2" connector. Change one of the components' IDs to eliminate ambiguity (e.g. rename "nop2" connector to "nop2/connector")`), }, { name: "ambiguous-connector-name-as-exporter", cfgFn: func() *Config { cfg := generateConfig() cfg.Exporters[component.MustNewID("nop2")] = &errConfig{} cfg.Connectors[component.MustNewID("nop2")] = &errConfig{} pipe := cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Receivers = append(pipe.Receivers, component.MustNewIDWithName("nop", "2")) pipe.Exporters = append(pipe.Exporters, component.MustNewIDWithName("nop", "2")) return cfg }, expected: errors.New(`connectors::nop2: ambiguous ID: Found both "nop2" exporter and "nop2" connector. Change one of the components' IDs to eliminate ambiguity (e.g. rename "nop2" connector to "nop2/connector")`), }, { name: "invalid-connector-reference-as-receiver", cfgFn: func() *Config { cfg := generateConfig() pipe := cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Receivers = append(pipe.Receivers, component.MustNewIDWithName("nop", "conn2")) return cfg }, expected: errors.New(`service::pipelines::traces: references receiver "nop/conn2" which is not configured`), }, { name: "invalid-connector-reference-as-receiver", cfgFn: func() *Config { cfg := generateConfig() pipe := cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Exporters = append(pipe.Exporters, component.MustNewIDWithName("nop", "conn2")) return cfg }, expected: errors.New(`service::pipelines::traces: references exporter "nop/conn2" which is not configured`), }, { name: "invalid-service-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Service.Pipelines = nil return cfg }, expected: fmt.Errorf(`service::pipelines: %w`, errors.New(`service must have at least one pipeline`)), }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn() err := xconfmap.Validate(cfg) if tt.expected != nil { require.EqualError(t, err, tt.expected.Error()) } else { require.NoError(t, err) } }) } } func TestNoPipelinesFeatureGate(t *testing.T) { cfg := generateConfig() cfg.Receivers = nil cfg.Exporters = nil cfg.Service.Pipelines = pipelines.Config{} require.Error(t, xconfmap.Validate(cfg)) gate := pipelines.AllowNoPipelines require.NoError(t, featuregate.GlobalRegistry().Set(gate.ID(), true)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(gate.ID(), false)) }() require.NoError(t, xconfmap.Validate(cfg)) } func generateConfig() *Config { return &Config{ Receivers: map[component.ID]component.Config{ component.MustNewID("nop"): &errConfig{}, }, Exporters: map[component.ID]component.Config{ component.MustNewID("nop"): &errConfig{}, }, Processors: map[component.ID]component.Config{ component.MustNewID("nop"): &errConfig{}, }, Connectors: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): &errConfig{}, }, Extensions: map[component.ID]component.Config{ component.MustNewID("nop"): &errConfig{}, }, Service: service.Config{ Telemetry: fakeTelemetryConfig{}, Extensions: []component.ID{component.MustNewID("nop")}, Pipelines: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, }, } } type fakeTelemetryConfig struct { Invalid bool `mapstructure:"invalid"` } func (cfg fakeTelemetryConfig) Validate() error { if cfg.Invalid { return errors.New("invalid config") } return nil } opentelemetry-collector-0.141.0/otelcol/configprovider.go000066400000000000000000000060741511331344600235550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "context" "fmt" "go.opentelemetry.io/collector/confmap" ) // ConfigProvider provides the service configuration. // // The typical usage is the following: // // cfgProvider.Get(...) // cfgProvider.Watch() // wait for an event. // cfgProvider.Get(...) // cfgProvider.Watch() // wait for an event. // // repeat Get/Watch cycle until it is time to shut down the Collector process. // cfgProvider.Shutdown() type ConfigProvider struct { mapResolver *confmap.Resolver } // ConfigProviderSettings are the settings to configure the behavior of the ConfigProvider. type ConfigProviderSettings struct { // ResolverSettings are the settings to configure the behavior of the confmap.Resolver. ResolverSettings confmap.ResolverSettings // prevent unkeyed literal initialization _ struct{} } // NewConfigProvider returns a new ConfigProvider that provides the service configuration: // * Initially it resolves the "configuration map": // - Retrieve the confmap.Conf by merging all retrieved maps from the given `locations` in order. // - Then applies all the confmap.Converter in the given order. // // * Then unmarshalls the confmap.Conf into the service Config. func NewConfigProvider(set ConfigProviderSettings) (*ConfigProvider, error) { mr, err := confmap.NewResolver(set.ResolverSettings) if err != nil { return nil, err } return &ConfigProvider{ mapResolver: mr, }, nil } // Get returns the service configuration, or error otherwise. // // Should never be called concurrently with itself, Watch or Shutdown. func (cm *ConfigProvider) Get(ctx context.Context, factories Factories) (*Config, error) { conf, err := cm.mapResolver.Resolve(ctx) if err != nil { return nil, fmt.Errorf("cannot resolve the configuration: %w", err) } var cfg *configSettings if cfg, err = unmarshal(conf, factories); err != nil { return nil, fmt.Errorf("cannot unmarshal the configuration: %w", err) } return &Config{ Receivers: cfg.Receivers.Configs(), Processors: cfg.Processors.Configs(), Exporters: cfg.Exporters.Configs(), Connectors: cfg.Connectors.Configs(), Extensions: cfg.Extensions.Configs(), Service: cfg.Service, }, nil } // Watch blocks until any configuration change was detected or an unrecoverable error // happened during monitoring the configuration changes. // // Error is nil if the configuration is changed and needs to be re-fetched. Any non-nil // error indicates that there was a problem with watching the config changes. // // Should never be called concurrently with itself or Get. func (cm *ConfigProvider) Watch() <-chan error { return cm.mapResolver.Watch() } // Shutdown signals that the provider is no longer in use and the that should close // and release any resources that it may have created. // // This function must terminate the Watch channel. // // Should never be called concurrently with itself or Get. func (cm *ConfigProvider) Shutdown(ctx context.Context) error { return cm.mapResolver.Shutdown(ctx) } opentelemetry-collector-0.141.0/otelcol/configprovider_test.go000066400000000000000000000070501511331344600246070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "context" "os" "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" yaml "go.yaml.in/yaml/v3" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/pipelines" ) func TestConfigProvider(t *testing.T) { nopComponentID := component.MustNewID("nop") nopConComponentID := component.MustNewIDWithName("nop", "con") tests := map[string]struct { filename string factories func() (Factories, error) expectedConfig *Config }{ "nop": { filename: "otelcol-nop.yaml", factories: nopFactories, expectedConfig: &Config{ Connectors: map[component.ID]component.Config{ nopConComponentID: connectortest.NewNopFactory().CreateDefaultConfig(), }, Exporters: map[component.ID]component.Config{ nopComponentID: exportertest.NewNopFactory().CreateDefaultConfig(), }, Extensions: map[component.ID]component.Config{ nopComponentID: extensiontest.NewNopFactory().CreateDefaultConfig(), }, Processors: map[component.ID]component.Config{ nopComponentID: processortest.NewNopFactory().CreateDefaultConfig(), }, Receivers: map[component.ID]component.Config{ nopComponentID: receivertest.NewNopFactory().CreateDefaultConfig(), }, Service: service.Config{ Telemetry: fakeTelemetryConfig{}, Extensions: []component.ID{nopComponentID}, Pipelines: map[pipeline.ID]*pipelines.PipelineConfig{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{nopComponentID}, Processors: []component.ID{nopComponentID}, Exporters: []component.ID{nopComponentID, nopConComponentID}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{nopComponentID}, Processors: []component.ID{nopComponentID}, Exporters: []component.ID{nopComponentID}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{nopComponentID, nopConComponentID}, Processors: []component.ID{nopComponentID}, Exporters: []component.ID{nopComponentID}, }, }, }, }, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { yamlBytes, err := os.ReadFile(filepath.Join("testdata", test.filename)) require.NoError(t, err) yamlProvider := newFakeProvider("yaml", func(context.Context, string, confmap.WatcherFunc) (*confmap.Retrieved, error) { var rawConf any if yamlErr := yaml.Unmarshal(yamlBytes, &rawConf); yamlErr != nil { return nil, yamlErr } return confmap.NewRetrieved(rawConf) }) set := ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{"yaml:" + string(yamlBytes)}, ProviderFactories: []confmap.ProviderFactory{yamlProvider}, }, } cp, err := NewConfigProvider(set) require.NoError(t, err) factories, err := test.factories() require.NoError(t, err) cfg, err := cp.Get(context.Background(), factories) require.NoError(t, err) assert.Equal(t, test.expectedConfig, cfg) }) } } opentelemetry-collector-0.141.0/otelcol/factories.go000066400000000000000000000045721511331344600225150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service/telemetry" ) // Factories struct holds in a single type all component factories that // can be handled by the Config. type Factories struct { // Receivers maps receiver type names in the config to the respective factory. Receivers map[component.Type]receiver.Factory // Processors maps processor type names in the config to the respective factory. Processors map[component.Type]processor.Factory // Exporters maps exporter type names in the config to the respective factory. Exporters map[component.Type]exporter.Factory // Extensions maps extension type names in the config to the respective factory. Extensions map[component.Type]extension.Factory // Connectors maps connector type names in the config to the respective factory. Connectors map[component.Type]connector.Factory // Telemetry is the factory to create the telemetry providers for the service. Telemetry telemetry.Factory // ReceiverModules maps receiver types to their respective go modules. ReceiverModules map[component.Type]string // ProcessorModules maps processor types to their respective go modules. ProcessorModules map[component.Type]string // ExporterModules maps exporter types to their respective go modules. ExporterModules map[component.Type]string // ExtensionModules maps extension types to their respective go modules. ExtensionModules map[component.Type]string // ConnectorModules maps connector types to their respective go modules. ConnectorModules map[component.Type]string } // MakeFactoryMap takes a list of factories and returns a map with Factory type as keys. // It returns a non-nil error when there are factories with duplicate type. func MakeFactoryMap[T component.Factory](factories ...T) (map[component.Type]T, error) { fMap := map[component.Type]T{} for _, f := range factories { if _, ok := fMap[f.Type()]; ok { return fMap, fmt.Errorf("duplicate component factory %q", f.Type()) } fMap[f.Type()] = f } return fMap, nil } opentelemetry-collector-0.141.0/otelcol/factories_test.go000066400000000000000000000076651511331344600235620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/service/telemetry" ) func nopFactories() (Factories, error) { var factories Factories var err error if factories.Connectors, err = MakeFactoryMap(connectortest.NewNopFactory()); err != nil { return Factories{}, err } factories.ConnectorModules = make(map[component.Type]string, len(factories.Connectors)) for _, con := range factories.Connectors { factories.ConnectorModules[con.Type()] = "go.opentelemetry.io/collector/connector/connectortest v1.2.3" } if factories.Extensions, err = MakeFactoryMap(extensiontest.NewNopFactory()); err != nil { return Factories{}, err } factories.ExtensionModules = make(map[component.Type]string, len(factories.Extensions)) for _, ext := range factories.Extensions { factories.ExtensionModules[ext.Type()] = "go.opentelemetry.io/collector/extension/extensiontest v1.2.3" } if factories.Receivers, err = MakeFactoryMap(receivertest.NewNopFactory()); err != nil { return Factories{}, err } factories.ReceiverModules = make(map[component.Type]string, len(factories.Receivers)) for _, rec := range factories.Receivers { factories.ReceiverModules[rec.Type()] = "go.opentelemetry.io/collector/receiver/receivertest v1.2.3" } if factories.Exporters, err = MakeFactoryMap(exportertest.NewNopFactory()); err != nil { return Factories{}, err } factories.ExporterModules = make(map[component.Type]string, len(factories.Exporters)) for _, exp := range factories.Exporters { factories.ExporterModules[exp.Type()] = "go.opentelemetry.io/collector/exporter/exportertest v1.2.3" } if factories.Processors, err = MakeFactoryMap(processortest.NewNopFactory()); err != nil { return Factories{}, err } factories.ProcessorModules = make(map[component.Type]string, len(factories.Processors)) for _, proc := range factories.Processors { factories.ProcessorModules[proc.Type()] = "go.opentelemetry.io/collector/processor/processortest v1.2.3" } factories.Telemetry = telemetry.NewFactory(func() component.Config { return fakeTelemetryConfig{} }) return factories, err } func TestMakeFactoryMap(t *testing.T) { type testCase struct { name string in []component.Factory out map[component.Type]component.Factory } fRec := receiver.NewFactory(component.MustNewType("rec"), nil) fRec2 := receiver.NewFactory(component.MustNewType("rec"), nil) fPro := processor.NewFactory(component.MustNewType("pro"), nil) fCon := connector.NewFactory(component.MustNewType("con"), nil) fExp := exporter.NewFactory(component.MustNewType("exp"), nil) fExt := extension.NewFactory(component.MustNewType("ext"), nil, nil, component.StabilityLevelUndefined) testCases := []testCase{ { name: "different names", in: []component.Factory{fRec, fPro, fCon, fExp, fExt}, out: map[component.Type]component.Factory{ fRec.Type(): fRec, fPro.Type(): fPro, fCon.Type(): fCon, fExp.Type(): fExp, fExt.Type(): fExt, }, }, { name: "same name", in: []component.Factory{fRec, fPro, fCon, fExp, fExt, fRec2}, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { out, err := MakeFactoryMap(tt.in...) if tt.out == nil { assert.Error(t, err) return } require.NoError(t, err) assert.Equal(t, tt.out, out) }) } } opentelemetry-collector-0.141.0/otelcol/flags.go000066400000000000000000000031631511331344600216250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "errors" "flag" "strings" "go.opentelemetry.io/collector/featuregate" ) const ( configFlag = "config" ) type configFlagValue struct { values []string sets []string } func (s *configFlagValue) Set(val string) error { s.values = append(s.values, val) return nil } func (s *configFlagValue) String() string { return "[" + strings.Join(s.values, ", ") + "]" } func flags(reg *featuregate.Registry) *flag.FlagSet { flagSet := new(flag.FlagSet) cfgs := new(configFlagValue) flagSet.Var(cfgs, configFlag, "Locations to the config file(s), note that only a"+ " single location can be set per flag entry e.g. `--config=file:/path/to/first --config=file:path/to/second`.") flagSet.Func("set", "Set arbitrary component config property. The component has to be defined in the config file and the flag"+ " has a higher precedence. Array config properties are overridden and maps are joined. Example --set=processors.batch.timeout=2s", func(s string) error { before, after, ok := strings.Cut(s, "=") if !ok { // No need for more context, see TestSetFlag/invalid_set. return errors.New("missing equal sign") } cfgs.sets = append(cfgs.sets, "yaml:"+strings.TrimSpace(strings.ReplaceAll(before, ".", "::"))+": "+strings.TrimSpace(after)) return nil }) reg.RegisterFlags(flagSet) return flagSet } func getConfigFlag(flagSet *flag.FlagSet) []string { cfv := flagSet.Lookup(configFlag).Value.(*configFlagValue) return append(cfv.values, cfv.sets...) } opentelemetry-collector-0.141.0/otelcol/flags_test.go000066400000000000000000000036221511331344600226640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/featuregate" ) func TestSetFlag(t *testing.T) { tests := []struct { name string args []string expectedConfigs []string expectedErr string }{ { name: "simple set", args: []string{"--set=key=value"}, expectedConfigs: []string{"yaml:key: value"}, }, { name: "complex nested key", args: []string{"--set=outer.inner=value"}, expectedConfigs: []string{"yaml:outer::inner: value"}, }, { name: "set array", args: []string{"--set=key=[a, b, c]"}, expectedConfigs: []string{"yaml:key: [a, b, c]"}, }, { name: "set map", args: []string{"--set=key={a: c}"}, expectedConfigs: []string{"yaml:key: {a: c}"}, }, { name: "set and config", args: []string{"--set=key=value", "--config=file:testdata/otelcol-nop.yaml"}, expectedConfigs: []string{"file:testdata/otelcol-nop.yaml", "yaml:key: value"}, }, { name: "config and set", args: []string{"--config=file:testdata/otelcol-nop.yaml", "--set=key=value"}, expectedConfigs: []string{"file:testdata/otelcol-nop.yaml", "yaml:key: value"}, }, { name: "invalid set", args: []string{"--set=key:name"}, expectedErr: `invalid value "key:name" for flag -set: missing equal sign`, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { flgs := flags(featuregate.NewRegistry()) err := flgs.Parse(tt.args) if tt.expectedErr != "" { assert.EqualError(t, err, tt.expectedErr) return } require.NoError(t, err) assert.Equal(t, tt.expectedConfigs, getConfigFlag(flgs)) }) } } opentelemetry-collector-0.141.0/otelcol/go.mod000066400000000000000000000262651511331344600213200ustar00rootroot00000000000000module go.opentelemetry.io/collector/otelcol go 1.24.0 require ( github.com/spf13/cobra v1.10.1 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componentstatus v0.141.0 go.opentelemetry.io/collector/config/configopaque v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/connector/connectortest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/exporter/xexporter v0.141.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensiontest v0.141.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 go.opentelemetry.io/collector/service v0.141.0 go.opentelemetry.io/collector/service/telemetry/telemetrytest v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.1 go.yaml.in/yaml/v3 v3.0.4 golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 golang.org/x/sys v0.38.0 google.golang.org/grpc v1.77.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // 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-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/shirou/gopsutil/v4 v4.25.10 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.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.141.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.141.0 // indirect go.opentelemetry.io/collector/connector/xconnector v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumertest v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/extension/extensioncapabilities v0.141.0 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 // indirect go.opentelemetry.io/collector/internal/telemetry v0.141.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.141.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.141.0 // indirect go.opentelemetry.io/collector/service/hostcapabilities v0.141.0 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.38.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/text v0.31.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/service => ../service replace go.opentelemetry.io/collector/service/telemetry/telemetrytest => ../service/telemetry/telemetrytest replace go.opentelemetry.io/collector/service/hostcapabilities => ../service/hostcapabilities replace go.opentelemetry.io/collector/connector => ../connector replace go.opentelemetry.io/collector/connector/connectortest => ../connector/connectortest replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/component/componenttest => ../component/componenttest replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../pdata/pprofile replace go.opentelemetry.io/collector/extension/zpagesextension => ../extension/zpagesextension replace go.opentelemetry.io/collector/extension => ../extension replace go.opentelemetry.io/collector/exporter => ../exporter replace go.opentelemetry.io/collector/confmap => ../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../confmap/xconfmap replace go.opentelemetry.io/collector/config/configtelemetry => ../config/configtelemetry replace go.opentelemetry.io/collector/processor => ../processor replace go.opentelemetry.io/collector/consumer => ../consumer replace go.opentelemetry.io/collector/receiver => ../receiver replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/config/configretry => ../config/configretry replace go.opentelemetry.io/collector/config/confighttp => ../config/confighttp replace go.opentelemetry.io/collector/config/configauth => ../config/configauth replace go.opentelemetry.io/collector/extension/extensionauth => ../extension/extensionauth replace go.opentelemetry.io/collector/config/configcompression => ../config/configcompression replace go.opentelemetry.io/collector/config/configtls => ../config/configtls replace go.opentelemetry.io/collector/config/configopaque => ../config/configopaque replace go.opentelemetry.io/collector/consumer/xconsumer => ../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../consumer/consumertest replace go.opentelemetry.io/collector/client => ../client replace go.opentelemetry.io/collector/component/componentstatus => ../component/componentstatus replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../extension/extensioncapabilities replace go.opentelemetry.io/collector/receiver/xreceiver => ../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../receiver/receivertest replace go.opentelemetry.io/collector/processor/xprocessor => ../processor/xprocessor replace go.opentelemetry.io/collector/connector/xconnector => ../connector/xconnector replace go.opentelemetry.io/collector/exporter/xexporter => ../exporter/xexporter replace go.opentelemetry.io/collector/pipeline => ../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../pipeline/xpipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../exporter/exportertest replace go.opentelemetry.io/collector/processor/processortest => ../processor/processortest replace go.opentelemetry.io/collector/consumer/consumererror => ../consumer/consumererror replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../internal/fanoutconsumer replace go.opentelemetry.io/collector/extension/extensiontest => ../extension/extensiontest replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/xextension => ../extension/xextension replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../confmap/provider/fileprovider replace go.opentelemetry.io/collector/internal/telemetry => ../internal/telemetry replace go.opentelemetry.io/collector/config/configmiddleware => ../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../extension/extensionmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/config/configoptional => ../config/configoptional replace go.opentelemetry.io/collector/pdata/xpdata => ../pdata/xpdata replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporter/exporterhelper replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/otelcol/go.sum000066400000000000000000000475731511331344600213520ustar00rootroot00000000000000github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 h1:aBKdhLVieqvwWe9A79UHI/0vgp2t/s2euY8X59pGRlw= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0/go.mod h1:SYqtxLQE7iINgh6WFuVi2AI70148B8EI35DSk0Wr8m4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo= go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU= go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLImUqiTPGnX4= go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= 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= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/otelcol/internal/000077500000000000000000000000001511331344600220135ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/internal/configunmarshaler/000077500000000000000000000000001511331344600255225ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/internal/configunmarshaler/configs.go000066400000000000000000000042021511331344600274770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configunmarshaler // import "go.opentelemetry.io/collector/otelcol/internal/configunmarshaler" import ( "errors" "fmt" "golang.org/x/exp/maps" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" ) type Configs[F component.Factory] struct { cfgs map[component.ID]component.Config factories map[component.Type]F } func NewConfigs[F component.Factory](factories map[component.Type]F) *Configs[F] { return &Configs[F]{factories: factories} } func (c *Configs[F]) Unmarshal(conf *confmap.Conf) error { rawCfgs := make(map[component.ID]map[string]any) if err := conf.Unmarshal(&rawCfgs); err != nil { return err } // Prepare resulting map. c.cfgs = make(map[component.ID]component.Config) // Iterate over raw configs and create a config for each. for id := range rawCfgs { // Find factory based on component kind and type that we read from config source. factory, ok := c.factories[id.Type()] if !ok { return errorUnknownType(id, maps.Keys(c.factories)) } // Get the configuration from the confmap.Conf to preserve internal representation. sub, err := conf.Sub(id.String()) if err != nil { return errorUnmarshalError(id, err) } // Create the default config for this component. cfg := factory.CreateDefaultConfig() // Now that the default config struct is created we can Unmarshal into it, // and it will apply user-defined config on top of the default. if err := sub.Unmarshal(&cfg); err != nil { return errorUnmarshalError(id, err) } c.cfgs[id] = cfg } return nil } func (c *Configs[F]) Configs() map[component.ID]component.Config { return c.cfgs } func errorUnknownType(id component.ID, factories []component.Type) error { if id.Type().String() == "logging" { return errors.New("the logging exporter has been deprecated, use the debug exporter instead") } return fmt.Errorf("unknown type: %q for id: %q (valid values: %v)", id.Type(), id, factories) } func errorUnmarshalError(id component.ID, err error) error { return fmt.Errorf("error reading configuration for %q: %w", id, err) } opentelemetry-collector-0.141.0/otelcol/internal/configunmarshaler/configs_test.go000066400000000000000000000100641511331344600305410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configunmarshaler import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/receiver/receivertest" ) var nopType = component.MustNewType("nop") var testKinds = []struct { kind string factories map[component.Type]component.Factory }{ { kind: "receiver", factories: map[component.Type]component.Factory{ nopType: receivertest.NewNopFactory(), }, }, { kind: "processor", factories: map[component.Type]component.Factory{ nopType: processortest.NewNopFactory(), }, }, { kind: "exporter", factories: map[component.Type]component.Factory{ nopType: exportertest.NewNopFactory(), }, }, { kind: "connector", factories: map[component.Type]component.Factory{ nopType: connectortest.NewNopFactory(), }, }, { kind: "extension", factories: map[component.Type]component.Factory{ nopType: extensiontest.NewNopFactory(), }, }, } func TestUnmarshal(t *testing.T) { for _, tk := range testKinds { t.Run(tk.kind, func(t *testing.T) { cfgs := NewConfigs(tk.factories) conf := confmap.NewFromStringMap(map[string]any{ "nop": nil, "nop/my" + tk.kind: nil, }) require.NoError(t, cfgs.Unmarshal(conf)) assert.Equal(t, map[component.ID]component.Config{ component.NewID(nopType): tk.factories[nopType].CreateDefaultConfig(), component.NewIDWithName(nopType, "my"+tk.kind): tk.factories[nopType].CreateDefaultConfig(), }, cfgs.Configs()) }) } } func TestUnmarshalError(t *testing.T) { for _, tk := range testKinds { t.Run(tk.kind, func(t *testing.T) { testCases := []struct { name string conf *confmap.Conf // string that the error must contain expectedError string }{ { name: "invalid-type", conf: confmap.NewFromStringMap(map[string]any{ "nop": nil, "/custom": nil, }), expectedError: "the part before / should not be empty", }, { name: "invalid-name-after-slash", conf: confmap.NewFromStringMap(map[string]any{ "nop": nil, "nop/": nil, }), expectedError: "the part after / should not be empty", }, { name: "unknown-type", conf: confmap.NewFromStringMap(map[string]any{ "nosuch" + tk.kind: nil, }), expectedError: "unknown type: \"nosuch" + tk.kind + "\" for id: \"nosuch" + tk.kind + "\" (valid values: [nop])", }, { name: "duplicate", conf: confmap.NewFromStringMap(map[string]any{ "nop /my" + tk.kind + " ": nil, " nop/ my" + tk.kind: nil, }), expectedError: "duplicate name", }, { name: "invalid-section", conf: confmap.NewFromStringMap(map[string]any{ "nop": map[string]any{ "unknown_section": tk.kind, }, }), expectedError: "error reading configuration for \"nop\"", }, { name: "invalid-sub-config", conf: confmap.NewFromStringMap(map[string]any{ "nop": "tests", }), expectedError: "'[nop]' expected type 'map[string]interface {}', got unconvertible type 'string'", }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfgs := NewConfigs(tk.factories) err := cfgs.Unmarshal(tt.conf) assert.ErrorContains(t, err, tt.expectedError) }) } }) } } func TestUnmarshal_LoggingExporter(t *testing.T) { conf := confmap.NewFromStringMap(map[string]any{ "logging": nil, }) factories := map[component.Type]component.Factory{ nopType: exportertest.NewNopFactory(), } cfgs := NewConfigs(factories) err := cfgs.Unmarshal(conf) assert.ErrorContains(t, err, "the logging exporter has been deprecated, use the debug exporter instead") } opentelemetry-collector-0.141.0/otelcol/internal/configunmarshaler/package_test.go000066400000000000000000000003221511331344600305000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package configunmarshaler import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/otelcol/internal/grpclog/000077500000000000000000000000001511331344600234505ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/internal/grpclog/logger.go000066400000000000000000000024001511331344600252520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package grpclog // import "go.opentelemetry.io/collector/otelcol/internal/grpclog" import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zapgrpc" "google.golang.org/grpc/grpclog" ) // SetLogger constructs a zapgrpc.Logger instance, and installs it as grpc logger, cloned from baseLogger with // exact configuration. The minimum level of gRPC logs is set to WARN should the loglevel of the collector is set to // INFO to avoid copious logging from grpc framework. func SetLogger(baseLogger *zap.Logger) *zapgrpc.Logger { logger := zapgrpc.NewLogger(baseLogger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { var c zapcore.Core var err error loglevel := baseLogger.Level() if loglevel == zapcore.InfoLevel { loglevel = zapcore.WarnLevel } // NewIncreaseLevelCore errors only if the new log level is less than the initial core level. c, err = zapcore.NewIncreaseLevelCore(core, loglevel) // In case of an error changing the level, move on, this happens when using the NopCore if err != nil { c = core } return c.With([]zapcore.Field{zap.Bool("grpc_log", true)}) }), zap.AddCallerSkip(5))) grpclog.SetLoggerV2(logger) return logger } opentelemetry-collector-0.141.0/otelcol/internal/grpclog/logger_test.go000066400000000000000000000043131511331344600263160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package grpclog import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/zap" "go.uber.org/zap/zapcore" "google.golang.org/grpc/grpclog" ) func TestGRPCLogger(t *testing.T) { tests := []struct { name string cfg zap.Config infoLogged bool warnLogged bool }{ { "collector_info_level_grpc_log_warn", zap.Config{ Level: zap.NewAtomicLevelAt(zapcore.InfoLevel), Encoding: "console", }, false, true, }, { "collector_debug_level_grpc_log_debug", zap.Config{ Level: zap.NewAtomicLevelAt(zapcore.DebugLevel), Encoding: "console", }, true, true, }, { "collector_warn_level_grpc_log_warn", zap.Config{ Development: false, // this must set the grpc loggerV2 to loggerV2 Level: zap.NewAtomicLevelAt(zapcore.WarnLevel), Encoding: "console", }, false, true, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { obsInfo, obsWarn := false, false callerInfo := "" hook := zap.Hooks(func(entry zapcore.Entry) error { switch entry.Level { case zapcore.InfoLevel: obsInfo = true case zapcore.WarnLevel: obsWarn = true } callerInfo = entry.Caller.String() return nil }) // create new collector zap logger logger, err := test.cfg.Build(hook) require.NoError(t, err) // create GRPCLogger glogger := SetLogger(logger) assert.NotNil(t, glogger) // grpc does not usually call the logger directly, but through various wrappers that add extra depth component := &mockComponent{logger: grpclog.Component("channelz")} component.Info(test.name) component.Warning(test.name) assert.Equal(t, obsInfo, test.infoLogged) assert.Equal(t, obsWarn, test.warnLogged) // match the file name and line number of Warning() call above assert.Contains(t, callerInfo, "internal/grpclog/logger_test.go:77") }) } } type mockComponent struct { logger grpclog.DepthLoggerV2 } func (c *mockComponent) Info(args ...any) { c.logger.Info(args...) } func (c *mockComponent) Warning(args ...any) { c.logger.Warning(args...) } opentelemetry-collector-0.141.0/otelcol/internal/grpclog/package_test.go000066400000000000000000000003101511331344600264230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package grpclog import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/otelcol/metadata.yaml000066400000000000000000000002321511331344600226400ustar00rootroot00000000000000type: otelcol github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg distributions: [core, contrib] opentelemetry-collector-0.141.0/otelcol/otelcoltest/000077500000000000000000000000001511331344600225405ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/otelcoltest/Makefile000066400000000000000000000000361511331344600241770ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/otelcol/otelcoltest/config.go000066400000000000000000000033061511331344600243360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcoltest // import "go.opentelemetry.io/collector/otelcol/otelcoltest" import ( "context" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/provider/envprovider" "go.opentelemetry.io/collector/confmap/provider/fileprovider" "go.opentelemetry.io/collector/confmap/provider/httpprovider" "go.opentelemetry.io/collector/confmap/provider/yamlprovider" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/otelcol" ) // LoadConfig loads a config.Config from file, and does NOT validate the configuration. // // If factories.Telemetry is nil, a no-op telemetry factory will be used. This // factory does not support any telemetry configuration. func LoadConfig(fileName string, factories otelcol.Factories) (*otelcol.Config, error) { if factories.Telemetry == nil { factories.Telemetry = nopTelemetryFactory() } provider, err := otelcol.NewConfigProvider(otelcol.ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{fileName}, ProviderFactories: []confmap.ProviderFactory{ fileprovider.NewFactory(), envprovider.NewFactory(), yamlprovider.NewFactory(), httpprovider.NewFactory(), }, DefaultScheme: "env", }, }) if err != nil { return nil, err } return provider.Get(context.Background(), factories) } // LoadConfigAndValidate loads a config from the file, and validates the configuration. func LoadConfigAndValidate(fileName string, factories otelcol.Factories) (*otelcol.Config, error) { cfg, err := LoadConfig(fileName, factories) if err != nil { return nil, err } return cfg, xconfmap.Validate(cfg) } opentelemetry-collector-0.141.0/otelcol/otelcoltest/config_test.go000066400000000000000000000064651511331344600254060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcoltest import ( "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/pipelines" ) func TestLoadConfig(t *testing.T) { factories, err := NopFactories() require.NoError(t, err) cfg, err := LoadConfig(filepath.Join("testdata", "config.yaml"), factories) require.NoError(t, err) // Verify extensions. require.Len(t, cfg.Extensions, 2) assert.Contains(t, cfg.Extensions, component.MustNewID("nop")) assert.Contains(t, cfg.Extensions, component.MustNewIDWithName("nop", "myextension")) // Verify receivers require.Len(t, cfg.Receivers, 2) assert.Contains(t, cfg.Receivers, component.MustNewID("nop")) assert.Contains(t, cfg.Receivers, component.MustNewIDWithName("nop", "myreceiver")) // Verify exporters assert.Len(t, cfg.Exporters, 2) assert.Contains(t, cfg.Exporters, component.MustNewID("nop")) assert.Contains(t, cfg.Exporters, component.MustNewIDWithName("nop", "myexporter")) // Verify procs assert.Len(t, cfg.Processors, 2) assert.Contains(t, cfg.Processors, component.MustNewID("nop")) assert.Contains(t, cfg.Processors, component.MustNewIDWithName("nop", "myprocessor")) // Verify connectors assert.Len(t, cfg.Connectors, 1) assert.Contains(t, cfg.Connectors, component.MustNewIDWithName("nop", "myconnector")) // Verify service. require.Len(t, cfg.Service.Extensions, 1) assert.Contains(t, cfg.Service.Extensions, component.MustNewID("nop")) require.Len(t, cfg.Service.Pipelines, 1) assert.Equal(t, &pipelines.PipelineConfig{ Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)], "Did not load pipeline config correctly") // Verify telemetry assert.Equal(t, struct{}{}, cfg.Service.Telemetry) } func TestLoadConfig_DefaultNopTelemetry(t *testing.T) { factories, err := NopFactories() require.NoError(t, err) factories.Telemetry = nil cfg, err := LoadConfig(filepath.Join("testdata", "config.yaml"), factories) require.NoError(t, err) assert.Equal(t, struct{}{}, cfg.Service.Telemetry) } func TestLoadConfigAndValidate(t *testing.T) { factories, err := NopFactories() require.NoError(t, err) cfgValidate, errValidate := LoadConfigAndValidate(filepath.Join("testdata", "config.yaml"), factories) require.NoError(t, errValidate) cfg, errLoad := LoadConfig(filepath.Join("testdata", "config.yaml"), factories) require.NoError(t, errLoad) assert.Equal(t, cfg, cfgValidate) } func TestLoadConfigEnv(t *testing.T) { factories, err := NopFactories() require.NoError(t, err) for _, tt := range []struct { file string }{ {file: filepath.Join("testdata", "config_env.yaml")}, {file: filepath.Join("testdata", "config_default_scheme.yaml")}, } { t.Run(tt.file, func(t *testing.T) { t.Setenv("RECEIVERS", "[nop]") cfg, err := LoadConfigAndValidate(tt.file, factories) require.NoError(t, err) assert.Equal(t, []component.ID{component.MustNewID("nop")}, cfg.Service.Pipelines[pipeline.NewID(pipeline.SignalTraces)].Receivers) }) } } opentelemetry-collector-0.141.0/otelcol/otelcoltest/go.mod000066400000000000000000000300451511331344600236500ustar00rootroot00000000000000module go.opentelemetry.io/collector/otelcol/otelcoltest go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/provider/envprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/fileprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/httpprovider v1.47.0 go.opentelemetry.io/collector/confmap/provider/yamlprovider v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/connector/connectortest v0.141.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/extension/extensiontest v0.141.0 go.opentelemetry.io/collector/otelcol v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.opentelemetry.io/collector/service v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // 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-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/shirou/gopsutil/v4 v4.25.10 // indirect github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/component/componentstatus v0.141.0 // indirect go.opentelemetry.io/collector/component/componenttest v0.141.0 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.141.0 // indirect go.opentelemetry.io/collector/connector v0.141.0 // indirect go.opentelemetry.io/collector/connector/xconnector v0.141.0 // indirect go.opentelemetry.io/collector/consumer v1.47.0 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/consumertest v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/exporter v1.47.0 // indirect go.opentelemetry.io/collector/exporter/xexporter v0.141.0 // indirect go.opentelemetry.io/collector/extension v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensioncapabilities v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 // indirect go.opentelemetry.io/collector/internal/telemetry v0.141.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.141.0 // indirect go.opentelemetry.io/collector/pdata/xpdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 // indirect go.opentelemetry.io/collector/processor v1.47.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.141.0 // indirect go.opentelemetry.io/collector/receiver v1.47.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/collector/service/hostcapabilities v0.141.0 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/contrib/propagators/b3 v1.38.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect gonum.org/v1/gonum v0.16.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/confmap/provider/httpprovider => ../../confmap/provider/httpprovider replace go.opentelemetry.io/collector/confmap/provider/yamlprovider => ../../confmap/provider/yamlprovider replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry replace go.opentelemetry.io/collector/processor => ../../processor replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/connector => ../../connector replace go.opentelemetry.io/collector/connector/connectortest => ../../connector/connectortest replace go.opentelemetry.io/collector/config/configretry => ../../config/configretry replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider replace go.opentelemetry.io/collector/confmap/provider/envprovider => ../../confmap/provider/envprovider replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/exporter => ../../exporter replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../../extension/extensioncapabilities replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/processor/xprocessor => ../../processor/xprocessor replace go.opentelemetry.io/collector/connector/xconnector => ../../connector/xconnector replace go.opentelemetry.io/collector/exporter/xexporter => ../../exporter/xexporter replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../../exporter/exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/otelcol => ../ replace go.opentelemetry.io/collector/extension/zpagesextension => ../../extension/zpagesextension replace go.opentelemetry.io/collector/service => ../../service replace go.opentelemetry.io/collector/service/telemetry/telemetrytest => ../../service/telemetry/telemetrytest replace go.opentelemetry.io/collector/service/hostcapabilities => ../../service/hostcapabilities replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer replace go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/processor/processortest => ../../processor/processortest replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/exporter/exporterhelper => ../../exporter/exporterhelper replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/otelcol/otelcoltest/go.sum000066400000000000000000000475731511331344600237130ustar00rootroot00000000000000github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 h1:aBKdhLVieqvwWe9A79UHI/0vgp2t/s2euY8X59pGRlw= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0/go.mod h1:SYqtxLQE7iINgh6WFuVi2AI70148B8EI35DSk0Wr8m4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo= go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU= go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLImUqiTPGnX4= go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= 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= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/otelcol/otelcoltest/nop_factories.go000066400000000000000000000026041511331344600257240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcoltest // import "go.opentelemetry.io/collector/otelcol/otelcoltest" import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/service/telemetry" ) // NopFactories returns a otelcol.Factories with all nop factories. func NopFactories() (otelcol.Factories, error) { var factories otelcol.Factories // MakeFactoryMap can never return an error with a single Factory factories.Extensions, _ = otelcol.MakeFactoryMap(extensiontest.NewNopFactory()) factories.Receivers, _ = otelcol.MakeFactoryMap(receivertest.NewNopFactory()) factories.Exporters, _ = otelcol.MakeFactoryMap(exportertest.NewNopFactory()) factories.Processors, _ = otelcol.MakeFactoryMap(processortest.NewNopFactory()) factories.Connectors, _ = otelcol.MakeFactoryMap(connectortest.NewNopFactory()) factories.Telemetry = nopTelemetryFactory() return factories, nil } func nopTelemetryFactory() telemetry.Factory { return telemetry.NewFactory( func() component.Config { return struct{}{} }, ) } opentelemetry-collector-0.141.0/otelcol/otelcoltest/nop_factories_test.go000066400000000000000000000023471511331344600267670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcoltest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" ) var nopType = component.MustNewType("nop") func TestNopFactories(t *testing.T) { nopFactories, err := NopFactories() require.NoError(t, err) require.Len(t, nopFactories.Receivers, 1) nopReceiverFactory, ok := nopFactories.Receivers[nopType] require.True(t, ok) require.Equal(t, nopType, nopReceiverFactory.Type()) require.Len(t, nopFactories.Processors, 1) nopProcessorFactory, ok := nopFactories.Processors[nopType] require.True(t, ok) require.Equal(t, nopType, nopProcessorFactory.Type()) require.Len(t, nopFactories.Exporters, 1) nopExporterFactory, ok := nopFactories.Exporters[nopType] require.True(t, ok) require.Equal(t, nopType, nopExporterFactory.Type()) require.Len(t, nopFactories.Extensions, 1) nopExtensionFactory, ok := nopFactories.Extensions[nopType] require.True(t, ok) require.Equal(t, nopType, nopExtensionFactory.Type()) require.Len(t, nopFactories.Connectors, 1) nopConnectorFactory, ok := nopFactories.Connectors[nopType] require.True(t, ok) require.Equal(t, nopType, nopConnectorFactory.Type()) } opentelemetry-collector-0.141.0/otelcol/otelcoltest/package_test.go000066400000000000000000000003141511331344600255170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcoltest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/otelcol/otelcoltest/testdata/000077500000000000000000000000001511331344600243515ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/otelcoltest/testdata/config.yaml000066400000000000000000000005401511331344600265010ustar00rootroot00000000000000receivers: nop: nop/myreceiver: processors: nop: nop/myprocessor: exporters: nop: nop/myexporter: connectors: nop/myconnector: extensions: nop: nop/myextension: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/otelcoltest/testdata/config_default_scheme.yaml000066400000000000000000000002231511331344600315270ustar00rootroot00000000000000receivers: nop: exporters: nop: service: pipelines: traces: receivers: ${RECEIVERS} exporters: [nop] opentelemetry-collector-0.141.0/otelcol/otelcoltest/testdata/config_env.yaml000066400000000000000000000002271511331344600273530ustar00rootroot00000000000000receivers: nop: exporters: nop: service: pipelines: traces: receivers: ${env:RECEIVERS} exporters: [nop] opentelemetry-collector-0.141.0/otelcol/package_test.go000066400000000000000000000003101511331344600231520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/otelcol/testdata/000077500000000000000000000000001511331344600220105ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/testdata/components-output.yaml000066400000000000000000000026521511331344600264240ustar00rootroot00000000000000buildinfo: command: otelcol description: OpenTelemetry Collector version: latest receivers: - name: nop module: go.opentelemetry.io/collector/receiver/receivertest v1.2.3 stability: logs: Stable metrics: Stable traces: Stable processors: - name: nop module: go.opentelemetry.io/collector/processor/processortest v1.2.3 stability: logs: Stable metrics: Stable traces: Stable exporters: - name: nop module: go.opentelemetry.io/collector/exporter/exportertest v1.2.3 stability: logs: Stable metrics: Stable traces: Stable connectors: - name: nop module: go.opentelemetry.io/collector/connector/connectortest v1.2.3 stability: logs-to-logs: Development logs-to-metrics: Development logs-to-traces: Development metrics-to-logs: Development metrics-to-metrics: Development metrics-to-traces: Development traces-to-logs: Development traces-to-metrics: Development traces-to-traces: Development extensions: - name: nop module: go.opentelemetry.io/collector/extension/extensiontest v1.2.3 stability: extension: Stable providers: - scheme: nop module: go.opentelemetry.io/collector/confmap/provider/testprovider v1.2.3 converters: - module: go.opentelemetry.io/collector/converter/testconverter v1.2.3 opentelemetry-collector-0.141.0/otelcol/testdata/configs/000077500000000000000000000000001511331344600234405ustar00rootroot00000000000000opentelemetry-collector-0.141.0/otelcol/testdata/configs/1-config-first.yaml000066400000000000000000000001121511331344600270460ustar00rootroot00000000000000receivers: bar: key: val exporters: bar: key: val opentelemetry-collector-0.141.0/otelcol/testdata/configs/1-config-output.yaml000066400000000000000000000001761511331344600272710ustar00rootroot00000000000000exporters: bar: key: val foo: key: val receivers: bar: key: val foo: key: val opentelemetry-collector-0.141.0/otelcol/testdata/configs/1-config-second.yaml000066400000000000000000000001121511331344600271720ustar00rootroot00000000000000receivers: foo: key: val exporters: foo: key: val opentelemetry-collector-0.141.0/otelcol/testdata/configs/2-config-output.yaml000066400000000000000000000004521511331344600272670ustar00rootroot00000000000000exporters: bar: key: val foo: key: val receivers: bar: key: val foo: key: val service: pipelines: logs: exporters: - foo - bar receivers: - foo - bar opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-cyclic-connector.yaml000066400000000000000000000004361511331344600275740ustar00rootroot00000000000000receivers: nop: exporters: nop: connectors: nop/forward: service: pipelines: traces/in: receivers: [nop/forward] processors: [ ] exporters: [nop/forward] traces/out: receivers: [nop/forward] processors: [ ] exporters: [nop/forward]opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-invalid-components.yaml000066400000000000000000000002531511331344600301440ustar00rootroot00000000000000receivers: nop: exporters: nop: processors: nosuchprocessor: service: pipelines: traces: receivers: [nop] exporters: [nop] processors: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-invalid-connector-unused-exp.yaml000066400000000000000000000005341511331344600320460ustar00rootroot00000000000000receivers: nop: exporters: nop: connectors: nop/connector1: service: pipelines: logs/in1: receivers: [nop] processors: [ ] exporters: [nop] logs/in2: receivers: [nop/connector1] processors: [ ] exporters: [nop] logs/out: receivers: [nop] processors: [ ] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-invalid-connector-unused-rec.yaml000066400000000000000000000005341511331344600320230ustar00rootroot00000000000000receivers: nop: exporters: nop: connectors: nop/connector1: service: pipelines: logs/in1: receivers: [nop] processors: [ ] exporters: [nop] logs/in2: receivers: [nop] processors: [ ] exporters: [nop/connector1] logs/out: receivers: [nop] processors: [ ] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-invalid-receiver-type.yaml000066400000000000000000000002541511331344600305430ustar00rootroot00000000000000receivers: nop_logs: processors: nop: exporters: nop: service: pipelines: traces: receivers: [nop_logs] processors: [nop] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-invalid-telemetry.yaml000066400000000000000000000002251511331344600277700ustar00rootroot00000000000000receivers: nop: exporters: nop: service: telemetry: unknown: key pipelines: metrics: receivers: [nop] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-invalid.yaml000066400000000000000000000002461511331344600257630ustar00rootroot00000000000000receivers: nop: processors: nop: exporters: nop: service: pipelines: traces: receivers: [nop] processors: [invalid] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-log-to-file.yaml000066400000000000000000000007601511331344600264540ustar00rootroot00000000000000extensions: zpages: receivers: otlp: protocols: grpc: http: exporters: debug: verbosity: detailed service: telemetry: logs: level: info output_paths: # The folder need to be created prior to starting the collector - ${ProgramData}\OpenTelemetry\Collector\Logs\otelcol.log pipelines: traces: receivers: [otlp] exporters: [debug] metrics: receivers: [otlp] exporters: [debug] extensions: [zpages] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-nop.yaml000066400000000000000000000006271511331344600251340ustar00rootroot00000000000000receivers: nop: processors: nop: exporters: nop: extensions: nop: connectors: nop/con: service: extensions: [nop] pipelines: traces: receivers: [nop] processors: [nop] exporters: [nop, nop/con] metrics: receivers: [nop] processors: [nop] exporters: [nop] logs: receivers: [nop, nop/con] processors: [nop] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-otelconftelemetry.yaml000066400000000000000000000003321511331344600300750ustar00rootroot00000000000000receivers: nop: exporters: nop: service: telemetry: # Set configuration understood by otelconftelemetry metrics: level: none pipelines: metrics: receivers: [nop] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-statuswatcher.yaml000066400000000000000000000006541511331344600272410ustar00rootroot00000000000000receivers: nop: processors: nop: unhealthy: exporters: nop: extensions: statuswatcher: service: extensions: [statuswatcher] pipelines: traces: receivers: [nop] processors: [nop,unhealthy] exporters: [nop] metrics: receivers: [nop] processors: [nop,unhealthy] exporters: [nop] logs: receivers: [nop] processors: [nop,unhealthy] exporters: [nop] opentelemetry-collector-0.141.0/otelcol/testdata/otelcol-valid-connector-use.yaml000066400000000000000000000005461511331344600302210ustar00rootroot00000000000000receivers: nop: exporters: nop: connectors: nop/connector1: service: pipelines: logs/in1: receivers: [nop] processors: [ ] exporters: [nop] logs/in2: receivers: [nop] processors: [ ] exporters: [nop/connector1] logs/out: receivers: [nop/connector1] processors: [ ] exporters: [nop]opentelemetry-collector-0.141.0/otelcol/testdata/print.yaml000066400000000000000000000002141511331344600240250ustar00rootroot00000000000000receivers: r: opaque: "OOO" exporters: e: timeout: 5s service: pipelines: logs: receivers: [r] exporters: [e] opentelemetry-collector-0.141.0/otelcol/testdata/print_default.yaml000066400000000000000000000001721511331344600255340ustar00rootroot00000000000000receivers: r: other: lala exporters: e: service: pipelines: logs: receivers: [r] exporters: [e] opentelemetry-collector-0.141.0/otelcol/testdata/print_invalid.yaml000066400000000000000000000001771511331344600255430ustar00rootroot00000000000000receivers: r: exporters: e: timeout: invalid service: pipelines: logs: receivers: [r] exporters: [e] opentelemetry-collector-0.141.0/otelcol/testdata/print_negative.yaml000066400000000000000000000001721511331344600257120ustar00rootroot00000000000000receivers: r: exporters: e: timeout: -1 service: pipelines: logs: receivers: [r] exporters: [e] opentelemetry-collector-0.141.0/otelcol/unmarshal_dry_run_test.go000066400000000000000000000051451511331344600253260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/receiver" ) var _ component.Config = (*Config)(nil) type ValidateTestConfig struct { Number int `mapstructure:"number"` String string `mapstructure:"string"` } var genericType component.Type = component.MustNewType("generic") func NewFactories(_ *testing.T) func() (Factories, error) { return func() (Factories, error) { factories, err := nopFactories() if err != nil { return Factories{}, err } factories.Receivers[genericType] = receiver.NewFactory( genericType, func() component.Config { return &ValidateTestConfig{ Number: 1, String: "default", } }) return factories, nil } } var sampleYAMLConfig = ` receivers: generic: number: ${mock:number} string: ${mock:number} exporters: nop: service: pipelines: traces: receivers: [generic] exporters: [nop] ` func TestDryRunWithExpandedValues(t *testing.T) { tests := []struct { name string yamlConfig string mockMap map[string]string expectErr bool }{ { name: "string that looks like an integer", yamlConfig: sampleYAMLConfig, mockMap: map[string]string{ "number": "123", }, expectErr: true, }, { name: "string that looks like a bool", yamlConfig: sampleYAMLConfig, mockMap: map[string]string{ "number": "true", }, expectErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { collector, err := NewCollector(CollectorSettings{ Factories: NewFactories(t), ConfigProviderSettings: ConfigProviderSettings{ ResolverSettings: confmap.ResolverSettings{ URIs: []string{"file:file"}, DefaultScheme: "mock", ProviderFactories: []confmap.ProviderFactory{ newFakeProvider("mock", func(_ context.Context, uri string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { return confmap.NewRetrievedFromYAML([]byte(tt.mockMap[uri[len("mock:"):]])) }), newFakeProvider("file", func(_ context.Context, _ string, _ confmap.WatcherFunc) (*confmap.Retrieved, error) { return confmap.NewRetrievedFromYAML([]byte(tt.yamlConfig)) }), }, }, }, SkipSettingGRPCLogger: true, }) require.NoError(t, err) err = collector.DryRun(context.Background()) if tt.expectErr { require.Error(t, err) return } require.NoError(t, err) }) } } opentelemetry-collector-0.141.0/otelcol/unmarshaler.go000066400000000000000000000041531511331344600230520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol // import "go.opentelemetry.io/collector/otelcol" import ( "errors" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/otelcol/internal/configunmarshaler" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service" ) var errNilTelemetryFactory = errors.New("otelcol.Factories.Telemetry must not be nil. For example, you can use otelconftelemetry.NewFactory to build a telemetry factory") type configSettings struct { Receivers *configunmarshaler.Configs[receiver.Factory] `mapstructure:"receivers"` Processors *configunmarshaler.Configs[processor.Factory] `mapstructure:"processors"` Exporters *configunmarshaler.Configs[exporter.Factory] `mapstructure:"exporters"` Connectors *configunmarshaler.Configs[connector.Factory] `mapstructure:"connectors"` Extensions *configunmarshaler.Configs[extension.Factory] `mapstructure:"extensions"` Service service.Config `mapstructure:"service"` } // unmarshal the configSettings from a confmap.Conf. // After the config is unmarshalled, `Validate()` must be called to validate. func unmarshal(v *confmap.Conf, factories Factories) (*configSettings, error) { if factories.Telemetry == nil { return nil, errNilTelemetryFactory } // Unmarshal top level sections and validate. cfg := &configSettings{ Receivers: configunmarshaler.NewConfigs(factories.Receivers), Processors: configunmarshaler.NewConfigs(factories.Processors), Exporters: configunmarshaler.NewConfigs(factories.Exporters), Connectors: configunmarshaler.NewConfigs(factories.Connectors), Extensions: configunmarshaler.NewConfigs(factories.Extensions), // TODO: Add a component.ServiceFactory to allow this to be defined by the Service. Service: service.Config{ Telemetry: factories.Telemetry.CreateDefaultConfig(), }, } err := v.Unmarshal(&cfg) return cfg, err } opentelemetry-collector-0.141.0/otelcol/unmarshaler_test.go000066400000000000000000000105571511331344600241160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelcol import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/service" "go.opentelemetry.io/collector/service/pipelines" ) func TestUnmarshalEmpty(t *testing.T) { factories, err := nopFactories() require.NoError(t, err) _, err = unmarshal(confmap.New(), factories) assert.NoError(t, err) } func TestUnmarshalEmptyAllSections(t *testing.T) { factories, err := nopFactories() require.NoError(t, err) conf := confmap.NewFromStringMap(map[string]any{ "receivers": nil, "processors": nil, "exporters": nil, "connectors": nil, "extensions": nil, "service": nil, }) cfg, err := unmarshal(conf, factories) require.NoError(t, err) assert.Equal(t, fakeTelemetryConfig{}, cfg.Service.Telemetry) } func TestUnmarshalUnknownTopLevel(t *testing.T) { factories, err := nopFactories() require.NoError(t, err) conf := confmap.NewFromStringMap(map[string]any{ "unknown_section": nil, }) _, err = unmarshal(conf, factories) assert.ErrorContains(t, err, "'' has invalid keys: unknown_section") } func TestPipelineConfigUnmarshalError(t *testing.T) { testCases := []struct { // test case name (also file name containing config yaml) name string conf *confmap.Conf // string that the error must contain expectError string }{ { name: "duplicate-pipeline", conf: confmap.NewFromStringMap(map[string]any{ "traces/ pipe": nil, "traces /pipe": nil, }), expectError: "duplicate name", }, { name: "invalid-pipeline-name-after-slash", conf: confmap.NewFromStringMap(map[string]any{ "metrics/": nil, }), expectError: "in \"metrics/\" id: the part after / should not be empty", }, { name: "invalid-pipeline-section", conf: confmap.NewFromStringMap(map[string]any{ "traces": map[string]any{ "unknown_section": nil, }, }), expectError: "'[traces]' has invalid keys: unknown_section", }, { name: "invalid-pipeline-sub-config", conf: confmap.NewFromStringMap(map[string]any{ "traces": "string", }), expectError: "'[traces]' expected a map or struct, got \"string\"", }, { name: "invalid-pipeline-type", conf: confmap.NewFromStringMap(map[string]any{ "/metrics": nil, }), expectError: "in \"/metrics\" id: the part before / should not be empty", }, { name: "invalid-sequence-value", conf: confmap.NewFromStringMap(map[string]any{ "traces": map[string]any{ "receivers": map[string]any{ "nop": map[string]any{ "some": "config", }, }, }, }), expectError: "'[traces].receivers' source data must be an array or slice, got map", }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { pips := new(pipelines.Config) err := tt.conf.Unmarshal(&pips) assert.ErrorContains(t, err, tt.expectError) }) } } func TestServiceUnmarshalError(t *testing.T) { testCases := []struct { // test case name (also file name containing config yaml) name string conf *confmap.Conf // string that the error must contain expectError string }{ { name: "invalid-telemetry-unknown-key", conf: confmap.NewFromStringMap(map[string]any{ "telemetry": map[string]any{ "unknown": "key", }, }), expectError: "decoding failed due to the following error(s):\n\n'telemetry' has invalid keys: unknown", }, { name: "invalid-service-extensions-section", conf: confmap.NewFromStringMap(map[string]any{ "extensions": []any{ map[string]any{ "nop": map[string]any{ "some": "config", }, }, }, }), expectError: "'extensions[0]' has invalid keys: nop", }, { name: "invalid-service-section", conf: confmap.NewFromStringMap(map[string]any{ "unknown_section": "string", }), expectError: "'' has invalid keys: unknown_section", }, { name: "invalid-pipelines-config", conf: confmap.NewFromStringMap(map[string]any{ "pipelines": "string", }), expectError: "'pipelines' expected type 'pipelines.Config', got unconvertible type 'string'", }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { err := tt.conf.Unmarshal(&service.Config{ Telemetry: fakeTelemetryConfig{}, }) require.ErrorContains(t, err, tt.expectError) }) } } opentelemetry-collector-0.141.0/pdata/000077500000000000000000000000001511331344600176275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/Makefile000066400000000000000000000000331511331344600212630ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/pdata/README.md000066400000000000000000000303461511331344600211140ustar00rootroot00000000000000# Pipeline data (pdata) | Status | | | ------------- |-----------| | Stability | [stable]: traces, metrics, logs | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Apkg%2Fpdata%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Apkg%2Fpdata) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Apkg%2Fpdata%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Apkg%2Fpdata) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@bogdandrutu](https://www.github.com/bogdandrutu), [@dmitryax](https://www.github.com/dmitryax) | [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable Pipeline data (pdata) implements data structures that represent telemetry data in-memory. All data received is converted into this format, travels through the pipeline in this format, and is converted from this format by exporters when sending. Current implementation primarily uses OTLP protobuf structs as the underlying data structures for many of the declared structs. We keep a pointer to OTLP protobuf in the "orig" member field. This allows efficient translation to/from OTLP wire protocol. The underlying data structure is kept private so that we are free to make changes to it in the future. The pdata API is designed to avoid mutable data sharing and bugs that stem from that. Each pdata instance cannot contain a reference to an object that is used in another pdata instance. ## API naming convention ### Package names Names of pdata packages don't follow names of the protobuf packages. The pdata has a package per telemetry type starting with `p`, e.g. `ptrace`, and `pcommon` package which includes pdata API for protobuf definitions from `common` and `resource` protobuf packages. ### Protobuf message representation in pdata Pipeline data structs SHOULD be based on the names of the underlying OTLP protobuf messages. Data types for protobuf messages defined as part of another message SHOULD include the owner's name as a prefix. The following examples are two pdata structs based on protobuf messages defined at the package level and as part of another message: - `pmetric.NumberDataPoint` based on a `NumberDataPoint` protobuf message defined in [metrics.proto](https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto) package. - `pmetric.ExponentialHistogramDataPointBuckets` based on a `Buckets` protobuf message defined in `ExponentialHistogramDataPoint` message of [metrics.proto](https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto) package. Exceptions to the naming rules are possible, but not encouraged. Another name can be chosen for brevity or if the struct provides a different interface to manipulate the underlying data. The following exceptions are currently accepted: - `plog.Logs` based on `LogsData` protobuf message. - `pmetric.Metrics` based on `MetricsData` protobuf message. - `ptrace.Traces` based on `TracesData` protobuf message. - `pcommon.Slice` based on `ArrayValue` protobuf message. - `pcommon.Map` based on `KeyValueList` protobuf message. - `pcommon.Value` based on `AnyValue` protobuf message. Each pdata struct MUST have an initialization function starting with `New` prefix. Usage of zero-initialized values is prohibited and can cause a panic. Each pdata struct MUST provide the following methods: - `MoveTo()`: moves all the data from one struct instance to another. The destination instance is overwritten and the source instance is re-initialized as a new empty instance. - `CopyTo()`: deep copies all the data from one struct instance to another. The destination instance is overwritten and the source instance is not modified. Each pdata struct based on a protobuf message SHOULD have getter methods for every protobuf field. Exceptions to this rule are allowed if exposing a field is not desirable in pdata. For example, a deprecated protobuf field MAY not be exposed in pdata. Also, pdata MAY provide a different interface to manipulate protobuf fields without exposing them explicitly as is done with `pcommon.Map`. ### Protobuf fields representation in pdata #### Singular fields Name of a pdata getter methods representing singular protobuf fields SHOULD match the name the protobuf field but written in CamelCase aligned with Go naming conventions. If a protobuf field is of scalar or enum type, the corresponding pdata struct MUST provide a setter method with `Set` prefix. Some fields of scalar type in a protobuf message MAY be represented by another pdata type providing an additional interface, for example `pcommon.Timestamp` is another type that wraps `uint64` value and provides an additional interface to work with timestamps. pdata fields returning `pcommon.Timestamp` don't follow the recommended naming schema, `Timestamp` word is used instead of `TimeUnixNano` to represent protobuf fields that contain `time_unix_nano`, for example `StartTimestamp` pdata field is used for `start_time_unix_nano` protobuf fields. #### Optional fields Each optional field in a protobuf message exposed in pdata MUST have the following additional methods: - A method starting with `Has` to determine if the field is set. For example, `func (ms HistogramDataPoint) HasMin() bool`. - A method starting with `Remove` prefix to remove a value associated with the optional field. For example, `func (ms HistogramDataPoint) RemoveMin()`. #### OneOf fields A pdata struct representing a protobuf message with an exposed oneof field MUST provide getter and setter methods for each option of the oneof field. Name of each setter and getter SHOULD be called the same as the protobuf oneof field options. The following exception is adopted in pdata for numeric oneof protobuf fields for brevity: ```protobuf oneof value { double as_double = 4; sfixed64 as_int = 6; } ``` is represented in pdata in a shorter form of the following methods: ```golang DoubleValue() float64 SetDoubleValue(float64) IntValue() int64 SetIntValue(v int64) ``` If a oneof field option is another protobuf message, the setter name MUST include `Empty` in its name. Such setter MUST set the oneof field to an empty initialized struct and return it. The following conditions define whether the name of the oneof field must be included in the setter and getter method names: 1. If a oneof field represents the whole protobuf message, name of the oneof field itself MAY be omitted in setter and getter methods. For example: ```go func (ms Metric) Sum() Sum func (ms Metric) SetEmptySum() Sum ``` 2. If a oneof field is relevant only to a particular field of the message, the pdata getter and setter methods MUST include name of the oneof field along with name of the option. For example: ```go func (ms NumberDataPoint) IntValue() int64 func (ms NumberDataPoint) SetIntValue(v int64) ``` Additionally, the pdata struct MUST provide a type getter for every exposed oneof protobuf field. Name of the getter MUST be `Type` for oneof fields representing the whole protobuf message (1), or `Type` for oneof fields relevant only to a particular field. The function MUST return an `int32` enum type called `Type` for (1) and `Type` for (2). For example: - `func (ms Metric) Type() MetricType` (1) - `func (ms NumberDataPoint) ValueType() NumberDataPointValueType` (2) The enum constants MUST be called the same as the type with a suffix named after the oneof option, e.g.: - `MetricTypeSum` (1) - `NumberDataPointValueTypeString` (2) An unset oneof protobuf value MUST be represented by a pdata constant with `Empty` suffix, e.g.: - `MetricTypeEmpty` (1) - `NumberDataPointValueTypeEmpty` (2) The pdata enum type SHOULD have `String()` method returning a string value of the corresponding oneof field option. #### Repeated protobuf fields Each repeated protobuf message field exposed in pdata MUST be represented as another pdata struct that SHOULD be called the same as the underlying protobuf field with `Slice` suffix. An exception example is `pdata.Map` that provides a different interface to manipulate the underlying protobuf data. #### Repeated scalar fields Each repeated scalar protobuf field exposed in pdata MUST be represented as another pdata type wrapping a native go slice. Name of the type SHOULD include name of the primitive data type ending with `Slice` suffix, e.g. `UInt64Slice`. #### Enum fields Each protobuf enum field exposed in pdata MUST have a type declared with underlying `int64` type. Name of the type SHOULD follow the same rules as for struct type names representing protobuf messages: - If a protobuf enum is defined on the package level, pdata type SHOULD have the same name. - If a protobuf enum is defined as part of another message, pdata type SHOULD include the protobuf message name as a prefix. Constants defined for the pdata int64 type MUST have the same names and numeric values defined in protobuf. Names of the constants must be translated from ALL_CAPS_SNAKE_CASE to CamelCase. The pdata enum type SHOULD have `String()` method returning a string value for each constant. Example of a protobuf enum definition in pdata: ```golang type AggregationTemporality int32 const ( AggregationTemporalityUnspecified = AggregationTemporality(otlpmetrics.AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED) AggregationTemporalityDelta = AggregationTemporality(otlpmetrics.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA) AggregationTemporalityCumulative = AggregationTemporality(otlpmetrics.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE) ) ``` ### Flags Flags fields are typically defined in protobuf as `uint32` fields representing 32 distinct boolean flags. The exposed protobuf flags fields MUST be defined as new types with `uint32` underlying type and called according to the same rules as struct names representing protobuf messages and other enum types. Each pdata flags type MUST have an empty variable of the fields type with `Default` prefix. Each flag MUST have a getter method returning a particular flag and a setter method with `With` prefix returning a new instance of the pdata flags type. Any instance of the pdata type is immutable since it's just a wrapper over `uint32`. The following pdata type is used for log record flags field: ```golang type LogRecordFlags uint32 var DefaultLogRecordFlags = LogRecordFlags(0) func (ms LogRecordFlags) IsSampled() bool func (ms LogRecordFlags) WithIsSampled(b bool) LogRecordFlags ``` ### Examples The following protobuf message: ```protobuf message NumberDataPoint { reserved 1; repeated opentelemetry.proto.common.v1.KeyValue attributes = 7; fixed64 start_time_unix_nano = 2; fixed64 time_unix_nano = 3; oneof value { double as_double = 4; sfixed64 as_int = 6; } repeated Exemplar exemplars = 5; uint32 flags = 8; } ``` is represented by the following pdata API ```go type NumberDataPoint func NewNumberDataPoint() NumberDataPoint func (ms NumberDataPoint) MoveTo(dest NumberDataPoint) func (ms NumberDataPoint) CopyTo(dest NumberDataPoint) func (ms NumberDataPoint) Attributes() pcommon.Map func (ms NumberDataPoint) StartTimestamp() pcommon.Timestamp func (ms NumberDataPoint) SetStartTimestamp(v pcommon.Timestamp) func (ms NumberDataPoint) Timestamp() pcommon.Timestamp func (ms NumberDataPoint) SetTimestamp(v pcommon.Timestamp) func (ms NumberDataPoint) ValueType() NumberDataPointValueType func (ms NumberDataPoint) DoubleValue() float64 func (ms NumberDataPoint) SetDoubleValue(v float64) func (ms NumberDataPoint) IntValue() int64 func (ms NumberDataPoint) SetIntValue(v int64) func (ms NumberDataPoint) Exemplars() ExemplarSlice func (ms NumberDataPoint) Flags() DataPointFlags func (ms NumberDataPoint) SetFlags(v DataPointFlags) ``` opentelemetry-collector-0.141.0/pdata/doc.go000066400000000000000000000004111511331344600207170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package pdata provides the data model definitions for all supported pipeline data. package pdata // import "go.opentelemetry.io/collector/pdata" opentelemetry-collector-0.141.0/pdata/generated_package_test.go000066400000000000000000000002441511331344600246260ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package pdata import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/go.mod000066400000000000000000000027251511331344600207430ustar00rootroot00000000000000module go.opentelemetry.io/collector/pdata go 1.24.0 require ( github.com/json-iterator/go v1.1.12 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/proto/slim/otlp v1.9.0 go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.10 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // 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/pmezard/go-difflib v1.0.0 // indirect golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) retract ( v1.0.0-rc10 // RC version scheme discovered to be alphabetical, use v1.0.0-rcv0011 instead v0.57.1 // Release failed, use v0.57.2 v0.57.0 // Release failed, use v0.57.2 ) replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/pdata/go.sum000066400000000000000000000156261511331344600207740ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/pdata/internal/000077500000000000000000000000001511331344600214435ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal/.gitignore000066400000000000000000000000501511331344600234260ustar00rootroot00000000000000.patched-otlp-proto opentelemetry-proto opentelemetry-collector-0.141.0/pdata/internal/bytesid.go000066400000000000000000000013161511331344600234360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" import ( "encoding/hex" "go.opentelemetry.io/collector/pdata/internal/json" ) // unmarshalJSON inflates trace id from hex string, possibly enclosed in quotes. // Called by Protobuf JSON deserialization. func unmarshalJSON(dst []byte, iter *json.Iterator) { src := iter.ReadStringAsSlice() if len(src) == 0 { return } if len(dst) != hex.DecodedLen(len(src)) { iter.ReportError("ID.UnmarshalJSONIter", "length mismatch") return } _, err := hex.Decode(dst, src) if err != nil { iter.ReportError("ID.UnmarshalJSONIter", err.Error()) return } } opentelemetry-collector-0.141.0/pdata/internal/bytesid_test.go000066400000000000000000000021371511331344600244770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestUnmarshalJSON(t *testing.T) { iter := json.BorrowIterator(nil) defer json.ReturnIterator(iter) id := [16]byte{} unmarshalJSON(id[:], iter.ResetBytes([]byte(`""`))) require.NoError(t, iter.Error()) assert.Equal(t, [16]byte{}, id) idBytes := [16]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} unmarshalJSON(id[:], iter.ResetBytes([]byte(`"12345678123456781234567812345678"`))) require.NoError(t, iter.Error()) assert.Equal(t, idBytes, id) unmarshalJSON(id[:], iter.ResetBytes([]byte(`"nothex"`))) require.Error(t, iter.Error()) unmarshalJSON(id[:], iter.ResetBytes([]byte(`"1"`))) require.Error(t, iter.Error()) unmarshalJSON(id[:], iter.ResetBytes([]byte(`"123"`))) require.Error(t, iter.Error()) unmarshalJSON(id[:], iter.ResetBytes([]byte(`"`))) require.Error(t, iter.Error()) } opentelemetry-collector-0.141.0/pdata/internal/generated_enum_aggregationtemporality.go000066400000000000000000000020461511331344600316170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal const ( AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED = AggregationTemporality(0) AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA = AggregationTemporality(1) AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE = AggregationTemporality(2) ) // AggregationTemporality defines how a metric aggregator reports aggregated values. // It describes how those values relate to the time interval over which they are aggregated. type AggregationTemporality int32 var AggregationTemporality_name = map[int32]string{ 0: "AGGREGATION_TEMPORALITY_UNSPECIFIED", 1: "AGGREGATION_TEMPORALITY_DELTA", 2: "AGGREGATION_TEMPORALITY_CUMULATIVE", } var AggregationTemporality_value = map[string]int32{ "AGGREGATION_TEMPORALITY_UNSPECIFIED": 0, "AGGREGATION_TEMPORALITY_DELTA": 1, "AGGREGATION_TEMPORALITY_CUMULATIVE": 2, } opentelemetry-collector-0.141.0/pdata/internal/generated_enum_severitynumber.go000066400000000000000000000071521511331344600301240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal const ( SeverityNumber_SEVERITY_NUMBER_UNSPECIFIED = SeverityNumber(0) SeverityNumber_SEVERITY_NUMBER_TRACE = SeverityNumber(1) SeverityNumber_SEVERITY_NUMBER_TRACE2 = SeverityNumber(2) SeverityNumber_SEVERITY_NUMBER_TRACE3 = SeverityNumber(3) SeverityNumber_SEVERITY_NUMBER_TRACE4 = SeverityNumber(4) SeverityNumber_SEVERITY_NUMBER_DEBUG = SeverityNumber(5) SeverityNumber_SEVERITY_NUMBER_DEBUG2 = SeverityNumber(6) SeverityNumber_SEVERITY_NUMBER_DEBUG3 = SeverityNumber(7) SeverityNumber_SEVERITY_NUMBER_DEBUG4 = SeverityNumber(8) SeverityNumber_SEVERITY_NUMBER_INFO = SeverityNumber(9) SeverityNumber_SEVERITY_NUMBER_INFO2 = SeverityNumber(10) SeverityNumber_SEVERITY_NUMBER_INFO3 = SeverityNumber(11) SeverityNumber_SEVERITY_NUMBER_INFO4 = SeverityNumber(12) SeverityNumber_SEVERITY_NUMBER_WARN = SeverityNumber(13) SeverityNumber_SEVERITY_NUMBER_WARN2 = SeverityNumber(14) SeverityNumber_SEVERITY_NUMBER_WARN3 = SeverityNumber(15) SeverityNumber_SEVERITY_NUMBER_WARN4 = SeverityNumber(16) SeverityNumber_SEVERITY_NUMBER_ERROR = SeverityNumber(17) SeverityNumber_SEVERITY_NUMBER_ERROR2 = SeverityNumber(18) SeverityNumber_SEVERITY_NUMBER_ERROR3 = SeverityNumber(19) SeverityNumber_SEVERITY_NUMBER_ERROR4 = SeverityNumber(20) SeverityNumber_SEVERITY_NUMBER_FATAL = SeverityNumber(21) SeverityNumber_SEVERITY_NUMBER_FATAL2 = SeverityNumber(22) SeverityNumber_SEVERITY_NUMBER_FATAL3 = SeverityNumber(23) SeverityNumber_SEVERITY_NUMBER_FATAL4 = SeverityNumber(24) ) // SeverityNumber represent possible values for LogRecord.SeverityNumber type SeverityNumber int32 var SeverityNumber_name = map[int32]string{ 0: "SEVERITY_NUMBER_UNSPECIFIED", 1: "SEVERITY_NUMBER_TRACE ", 2: "SEVERITY_NUMBER_TRACE2", 3: "SEVERITY_NUMBER_TRACE3", 4: "SEVERITY_NUMBER_TRACE4", 5: "SEVERITY_NUMBER_DEBUG", 6: "SEVERITY_NUMBER_DEBUG2", 7: "SEVERITY_NUMBER_DEBUG3", 8: "SEVERITY_NUMBER_DEBUG4", 9: "SEVERITY_NUMBER_INFO", 10: "SEVERITY_NUMBER_INFO2", 11: "SEVERITY_NUMBER_INFO3", 12: "SEVERITY_NUMBER_INFO4", 13: "SEVERITY_NUMBER_WARN", 14: "SEVERITY_NUMBER_WARN2", 15: "SEVERITY_NUMBER_WARN3", 16: "SEVERITY_NUMBER_WARN4", 17: "SEVERITY_NUMBER_ERROR", 18: "SEVERITY_NUMBER_ERROR2", 19: "SEVERITY_NUMBER_ERROR3", 20: "SEVERITY_NUMBER_ERROR4", 21: "SEVERITY_NUMBER_FATAL", 22: "SEVERITY_NUMBER_FATAL2", 23: "SEVERITY_NUMBER_FATAL3", 24: "SEVERITY_NUMBER_FATAL4", } var SeverityNumber_value = map[string]int32{ "SEVERITY_NUMBER_UNSPECIFIED": 0, "SEVERITY_NUMBER_TRACE ": 1, "SEVERITY_NUMBER_TRACE2": 2, "SEVERITY_NUMBER_TRACE3": 3, "SEVERITY_NUMBER_TRACE4": 4, "SEVERITY_NUMBER_DEBUG": 5, "SEVERITY_NUMBER_DEBUG2": 6, "SEVERITY_NUMBER_DEBUG3": 7, "SEVERITY_NUMBER_DEBUG4": 8, "SEVERITY_NUMBER_INFO": 9, "SEVERITY_NUMBER_INFO2": 10, "SEVERITY_NUMBER_INFO3": 11, "SEVERITY_NUMBER_INFO4": 12, "SEVERITY_NUMBER_WARN": 13, "SEVERITY_NUMBER_WARN2": 14, "SEVERITY_NUMBER_WARN3": 15, "SEVERITY_NUMBER_WARN4": 16, "SEVERITY_NUMBER_ERROR": 17, "SEVERITY_NUMBER_ERROR2": 18, "SEVERITY_NUMBER_ERROR3": 19, "SEVERITY_NUMBER_ERROR4": 20, "SEVERITY_NUMBER_FATAL": 21, "SEVERITY_NUMBER_FATAL2": 22, "SEVERITY_NUMBER_FATAL3": 23, "SEVERITY_NUMBER_FATAL4": 24, } opentelemetry-collector-0.141.0/pdata/internal/generated_enum_spankind.go000066400000000000000000000020621511331344600266430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal const ( SpanKind_SPAN_KIND_UNSPECIFIED = SpanKind(0) SpanKind_SPAN_KIND_INTERNAL = SpanKind(1) SpanKind_SPAN_KIND_SERVER = SpanKind(2) SpanKind_SPAN_KIND_CLIENT = SpanKind(3) SpanKind_SPAN_KIND_PRODUCER = SpanKind(4) SpanKind_SPAN_KIND_CONSUMER = SpanKind(5) ) // SpanKind is the type of span. // Can be used to specify additional relationships between spans in addition to a parent/child relationship. type SpanKind int32 var SpanKind_name = map[int32]string{ 0: "SPAN_KIND_UNSPECIFIED", 1: "SPAN_KIND_INTERNAL", 2: "SPAN_KIND_SERVER", 3: "SPAN_KIND_CLIENT", 4: "SPAN_KIND_PRODUCER", 5: "SPAN_KIND_CONSUMER", } var SpanKind_value = map[string]int32{ "SPAN_KIND_UNSPECIFIED": 0, "SPAN_KIND_INTERNAL": 1, "SPAN_KIND_SERVER": 2, "SPAN_KIND_CLIENT": 3, "SPAN_KIND_PRODUCER": 4, "SPAN_KIND_CONSUMER": 5, } opentelemetry-collector-0.141.0/pdata/internal/generated_enum_statuscode.go000066400000000000000000000014431511331344600272140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal const ( StatusCode_STATUS_CODE_UNSET = StatusCode(0) StatusCode_STATUS_CODE_OK = StatusCode(1) StatusCode_STATUS_CODE_ERROR = StatusCode(2) ) // StatusCode is the status of the span, for the semantics of codes see // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status type StatusCode int32 var StatusCode_name = map[int32]string{ 0: "STATUS_CODE_UNSET", 1: "STATUS_CODE_OK", 2: "STATUS_CODE_ERROR", } var StatusCode_value = map[string]int32{ "STATUS_CODE_UNSET": 0, "STATUS_CODE_OK": 1, "STATUS_CODE_ERROR": 2, } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_anyvalue.go000066400000000000000000000426311511331344600270650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "math" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) func (m *AnyValue) GetValue() any { if m != nil { return m.Value } return nil } type AnyValue_StringValue struct { StringValue string } func (m *AnyValue) GetStringValue() string { if v, ok := m.GetValue().(*AnyValue_StringValue); ok { return v.StringValue } return "" } type AnyValue_BoolValue struct { BoolValue bool } func (m *AnyValue) GetBoolValue() bool { if v, ok := m.GetValue().(*AnyValue_BoolValue); ok { return v.BoolValue } return false } type AnyValue_IntValue struct { IntValue int64 } func (m *AnyValue) GetIntValue() int64 { if v, ok := m.GetValue().(*AnyValue_IntValue); ok { return v.IntValue } return int64(0) } type AnyValue_DoubleValue struct { DoubleValue float64 } func (m *AnyValue) GetDoubleValue() float64 { if v, ok := m.GetValue().(*AnyValue_DoubleValue); ok { return v.DoubleValue } return float64(0) } type AnyValue_ArrayValue struct { ArrayValue *ArrayValue } func (m *AnyValue) GetArrayValue() *ArrayValue { if v, ok := m.GetValue().(*AnyValue_ArrayValue); ok { return v.ArrayValue } return nil } type AnyValue_KvlistValue struct { KvlistValue *KeyValueList } func (m *AnyValue) GetKvlistValue() *KeyValueList { if v, ok := m.GetValue().(*AnyValue_KvlistValue); ok { return v.KvlistValue } return nil } type AnyValue_BytesValue struct { BytesValue []byte } func (m *AnyValue) GetBytesValue() []byte { if v, ok := m.GetValue().(*AnyValue_BytesValue); ok { return v.BytesValue } return nil } type AnyValue struct { Value any } var ( protoPoolAnyValue = sync.Pool{ New: func() any { return &AnyValue{} }, } ProtoPoolAnyValue_StringValue = sync.Pool{ New: func() any { return &AnyValue_StringValue{} }, } ProtoPoolAnyValue_BoolValue = sync.Pool{ New: func() any { return &AnyValue_BoolValue{} }, } ProtoPoolAnyValue_IntValue = sync.Pool{ New: func() any { return &AnyValue_IntValue{} }, } ProtoPoolAnyValue_DoubleValue = sync.Pool{ New: func() any { return &AnyValue_DoubleValue{} }, } ProtoPoolAnyValue_ArrayValue = sync.Pool{ New: func() any { return &AnyValue_ArrayValue{} }, } ProtoPoolAnyValue_KvlistValue = sync.Pool{ New: func() any { return &AnyValue_KvlistValue{} }, } ProtoPoolAnyValue_BytesValue = sync.Pool{ New: func() any { return &AnyValue_BytesValue{} }, } ) func NewAnyValue() *AnyValue { if !UseProtoPooling.IsEnabled() { return &AnyValue{} } return protoPoolAnyValue.Get().(*AnyValue) } func DeleteAnyValue(orig *AnyValue, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } switch ov := orig.Value.(type) { case *AnyValue_StringValue: if UseProtoPooling.IsEnabled() { ov.StringValue = "" ProtoPoolAnyValue_StringValue.Put(ov) } case *AnyValue_BoolValue: if UseProtoPooling.IsEnabled() { ov.BoolValue = false ProtoPoolAnyValue_BoolValue.Put(ov) } case *AnyValue_IntValue: if UseProtoPooling.IsEnabled() { ov.IntValue = int64(0) ProtoPoolAnyValue_IntValue.Put(ov) } case *AnyValue_DoubleValue: if UseProtoPooling.IsEnabled() { ov.DoubleValue = float64(0) ProtoPoolAnyValue_DoubleValue.Put(ov) } case *AnyValue_ArrayValue: DeleteArrayValue(ov.ArrayValue, true) ov.ArrayValue = nil ProtoPoolAnyValue_ArrayValue.Put(ov) case *AnyValue_KvlistValue: DeleteKeyValueList(ov.KvlistValue, true) ov.KvlistValue = nil ProtoPoolAnyValue_KvlistValue.Put(ov) case *AnyValue_BytesValue: if UseProtoPooling.IsEnabled() { ov.BytesValue = nil ProtoPoolAnyValue_BytesValue.Put(ov) } } orig.Reset() if nullable { protoPoolAnyValue.Put(orig) } } func CopyAnyValue(dest, src *AnyValue) *AnyValue { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewAnyValue() } switch t := src.Value.(type) { case *AnyValue_StringValue: var ov *AnyValue_StringValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_StringValue{} } else { ov = ProtoPoolAnyValue_StringValue.Get().(*AnyValue_StringValue) } ov.StringValue = t.StringValue dest.Value = ov case *AnyValue_BoolValue: var ov *AnyValue_BoolValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_BoolValue{} } else { ov = ProtoPoolAnyValue_BoolValue.Get().(*AnyValue_BoolValue) } ov.BoolValue = t.BoolValue dest.Value = ov case *AnyValue_IntValue: var ov *AnyValue_IntValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_IntValue{} } else { ov = ProtoPoolAnyValue_IntValue.Get().(*AnyValue_IntValue) } ov.IntValue = t.IntValue dest.Value = ov case *AnyValue_DoubleValue: var ov *AnyValue_DoubleValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_DoubleValue{} } else { ov = ProtoPoolAnyValue_DoubleValue.Get().(*AnyValue_DoubleValue) } ov.DoubleValue = t.DoubleValue dest.Value = ov case *AnyValue_ArrayValue: var ov *AnyValue_ArrayValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_ArrayValue{} } else { ov = ProtoPoolAnyValue_ArrayValue.Get().(*AnyValue_ArrayValue) } ov.ArrayValue = NewArrayValue() CopyArrayValue(ov.ArrayValue, t.ArrayValue) dest.Value = ov case *AnyValue_KvlistValue: var ov *AnyValue_KvlistValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_KvlistValue{} } else { ov = ProtoPoolAnyValue_KvlistValue.Get().(*AnyValue_KvlistValue) } ov.KvlistValue = NewKeyValueList() CopyKeyValueList(ov.KvlistValue, t.KvlistValue) dest.Value = ov case *AnyValue_BytesValue: var ov *AnyValue_BytesValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_BytesValue{} } else { ov = ProtoPoolAnyValue_BytesValue.Get().(*AnyValue_BytesValue) } ov.BytesValue = t.BytesValue dest.Value = ov default: dest.Value = nil } return dest } func CopyAnyValueSlice(dest, src []AnyValue) []AnyValue { var newDest []AnyValue if cap(dest) < len(src) { newDest = make([]AnyValue, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteAnyValue(&dest[i], false) } } for i := range src { CopyAnyValue(&newDest[i], &src[i]) } return newDest } func CopyAnyValuePtrSlice(dest, src []*AnyValue) []*AnyValue { var newDest []*AnyValue if cap(dest) < len(src) { newDest = make([]*AnyValue, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewAnyValue() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteAnyValue(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewAnyValue() } } for i := range src { CopyAnyValue(newDest[i], src[i]) } return newDest } func (orig *AnyValue) Reset() { *orig = AnyValue{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *AnyValue) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() switch orig := orig.Value.(type) { case *AnyValue_StringValue: dest.WriteObjectField("stringValue") dest.WriteString(orig.StringValue) case *AnyValue_BoolValue: dest.WriteObjectField("boolValue") dest.WriteBool(orig.BoolValue) case *AnyValue_IntValue: dest.WriteObjectField("intValue") dest.WriteInt64(orig.IntValue) case *AnyValue_DoubleValue: dest.WriteObjectField("doubleValue") dest.WriteFloat64(orig.DoubleValue) case *AnyValue_ArrayValue: if orig.ArrayValue != nil { dest.WriteObjectField("arrayValue") orig.ArrayValue.MarshalJSON(dest) } case *AnyValue_KvlistValue: if orig.KvlistValue != nil { dest.WriteObjectField("kvlistValue") orig.KvlistValue.MarshalJSON(dest) } case *AnyValue_BytesValue: dest.WriteObjectField("bytesValue") dest.WriteBytes(orig.BytesValue) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *AnyValue) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "stringValue", "string_value": { var ov *AnyValue_StringValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_StringValue{} } else { ov = ProtoPoolAnyValue_StringValue.Get().(*AnyValue_StringValue) } ov.StringValue = iter.ReadString() orig.Value = ov } case "boolValue", "bool_value": { var ov *AnyValue_BoolValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_BoolValue{} } else { ov = ProtoPoolAnyValue_BoolValue.Get().(*AnyValue_BoolValue) } ov.BoolValue = iter.ReadBool() orig.Value = ov } case "intValue", "int_value": { var ov *AnyValue_IntValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_IntValue{} } else { ov = ProtoPoolAnyValue_IntValue.Get().(*AnyValue_IntValue) } ov.IntValue = iter.ReadInt64() orig.Value = ov } case "doubleValue", "double_value": { var ov *AnyValue_DoubleValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_DoubleValue{} } else { ov = ProtoPoolAnyValue_DoubleValue.Get().(*AnyValue_DoubleValue) } ov.DoubleValue = iter.ReadFloat64() orig.Value = ov } case "arrayValue", "array_value": { var ov *AnyValue_ArrayValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_ArrayValue{} } else { ov = ProtoPoolAnyValue_ArrayValue.Get().(*AnyValue_ArrayValue) } ov.ArrayValue = NewArrayValue() ov.ArrayValue.UnmarshalJSON(iter) orig.Value = ov } case "kvlistValue", "kvlist_value": { var ov *AnyValue_KvlistValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_KvlistValue{} } else { ov = ProtoPoolAnyValue_KvlistValue.Get().(*AnyValue_KvlistValue) } ov.KvlistValue = NewKeyValueList() ov.KvlistValue.UnmarshalJSON(iter) orig.Value = ov } case "bytesValue", "bytes_value": { var ov *AnyValue_BytesValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_BytesValue{} } else { ov = ProtoPoolAnyValue_BytesValue.Get().(*AnyValue_BytesValue) } ov.BytesValue = iter.ReadBytes() orig.Value = ov } default: iter.Skip() } } } func (orig *AnyValue) SizeProto() int { var n int var l int _ = l switch orig := orig.Value.(type) { case nil: _ = orig break case *AnyValue_StringValue: l = len(orig.StringValue) n += 1 + proto.Sov(uint64(l)) + l case *AnyValue_BoolValue: n += 2 case *AnyValue_IntValue: n += 1 + proto.Sov(uint64(orig.IntValue)) case *AnyValue_DoubleValue: n += 9 case *AnyValue_ArrayValue: if orig.ArrayValue != nil { l = orig.ArrayValue.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *AnyValue_KvlistValue: if orig.KvlistValue != nil { l = orig.KvlistValue.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *AnyValue_BytesValue: l = len(orig.BytesValue) n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *AnyValue) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l switch orig := orig.Value.(type) { case *AnyValue_StringValue: l = len(orig.StringValue) pos -= l copy(buf[pos:], orig.StringValue) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa case *AnyValue_BoolValue: pos-- if orig.BoolValue { buf[pos] = 1 } else { buf[pos] = 0 } pos-- buf[pos] = 0x10 case *AnyValue_IntValue: pos = proto.EncodeVarint(buf, pos, uint64(orig.IntValue)) pos-- buf[pos] = 0x18 case *AnyValue_DoubleValue: pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.DoubleValue)) pos-- buf[pos] = 0x21 case *AnyValue_ArrayValue: if orig.ArrayValue != nil { l = orig.ArrayValue.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a } case *AnyValue_KvlistValue: if orig.KvlistValue != nil { l = orig.KvlistValue.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x32 } case *AnyValue_BytesValue: l = len(orig.BytesValue) pos -= l copy(buf[pos:], orig.BytesValue) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3a } return len(buf) - pos } func (orig *AnyValue) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field StringValue", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *AnyValue_StringValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_StringValue{} } else { ov = ProtoPoolAnyValue_StringValue.Get().(*AnyValue_StringValue) } ov.StringValue = string(buf[startPos:pos]) orig.Value = ov case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field BoolValue", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } var ov *AnyValue_BoolValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_BoolValue{} } else { ov = ProtoPoolAnyValue_BoolValue.Get().(*AnyValue_BoolValue) } ov.BoolValue = num != 0 orig.Value = ov case 3: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field IntValue", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } var ov *AnyValue_IntValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_IntValue{} } else { ov = ProtoPoolAnyValue_IntValue.Get().(*AnyValue_IntValue) } ov.IntValue = int64(num) orig.Value = ov case 4: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field DoubleValue", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *AnyValue_DoubleValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_DoubleValue{} } else { ov = ProtoPoolAnyValue_DoubleValue.Get().(*AnyValue_DoubleValue) } ov.DoubleValue = math.Float64frombits(num) orig.Value = ov case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ArrayValue", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *AnyValue_ArrayValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_ArrayValue{} } else { ov = ProtoPoolAnyValue_ArrayValue.Get().(*AnyValue_ArrayValue) } ov.ArrayValue = NewArrayValue() err = ov.ArrayValue.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.Value = ov case 6: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field KvlistValue", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *AnyValue_KvlistValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_KvlistValue{} } else { ov = ProtoPoolAnyValue_KvlistValue.Get().(*AnyValue_KvlistValue) } ov.KvlistValue = NewKeyValueList() err = ov.KvlistValue.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.Value = ov case 7: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field BytesValue", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *AnyValue_BytesValue if !UseProtoPooling.IsEnabled() { ov = &AnyValue_BytesValue{} } else { ov = ProtoPoolAnyValue_BytesValue.Get().(*AnyValue_BytesValue) } if length != 0 { ov.BytesValue = make([]byte, length) copy(ov.BytesValue, buf[startPos:pos]) } orig.Value = ov default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestAnyValue() *AnyValue { orig := NewAnyValue() orig.Value = &AnyValue_StringValue{StringValue: "test_stringvalue"} return orig } func GenTestAnyValuePtrSlice() []*AnyValue { orig := make([]*AnyValue, 5) orig[0] = NewAnyValue() orig[1] = GenTestAnyValue() orig[2] = NewAnyValue() orig[3] = GenTestAnyValue() orig[4] = NewAnyValue() return orig } func GenTestAnyValueSlice() []AnyValue { orig := make([]AnyValue, 5) orig[1] = *GenTestAnyValue() orig[3] = *GenTestAnyValue() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_anyvalue_test.go000066400000000000000000000166151511331344600301270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyAnyValue(t *testing.T) { for name, src := range genTestEncodingValuesAnyValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewAnyValue() CopyAnyValue(dest, src) assert.Equal(t, src, dest) CopyAnyValue(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyAnyValueSlice(t *testing.T) { src := []AnyValue{} dest := []AnyValue{} // Test CopyTo empty dest = CopyAnyValueSlice(dest, src) assert.Equal(t, []AnyValue{}, dest) // Test CopyTo larger slice src = GenTestAnyValueSlice() dest = CopyAnyValueSlice(dest, src) assert.Equal(t, GenTestAnyValueSlice(), dest) // Test CopyTo same size slice dest = CopyAnyValueSlice(dest, src) assert.Equal(t, GenTestAnyValueSlice(), dest) // Test CopyTo smaller size slice dest = CopyAnyValueSlice(dest, []AnyValue{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyAnyValueSlice(dest, src) assert.Equal(t, GenTestAnyValueSlice(), dest) } func TestCopyAnyValuePtrSlice(t *testing.T) { src := []*AnyValue{} dest := []*AnyValue{} // Test CopyTo empty dest = CopyAnyValuePtrSlice(dest, src) assert.Equal(t, []*AnyValue{}, dest) // Test CopyTo larger slice src = GenTestAnyValuePtrSlice() dest = CopyAnyValuePtrSlice(dest, src) assert.Equal(t, GenTestAnyValuePtrSlice(), dest) // Test CopyTo same size slice dest = CopyAnyValuePtrSlice(dest, src) assert.Equal(t, GenTestAnyValuePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyAnyValuePtrSlice(dest, []*AnyValue{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyAnyValuePtrSlice(dest, src) assert.Equal(t, GenTestAnyValuePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONAnyValueUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewAnyValue() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewAnyValue(), dest) } func TestMarshalAndUnmarshalJSONAnyValue(t *testing.T) { for name, src := range genTestEncodingValuesAnyValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewAnyValue() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteAnyValue(dest, true) }) } } } func TestMarshalAndUnmarshalProtoAnyValueFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesAnyValue() { t.Run(name, func(t *testing.T) { dest := NewAnyValue() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoAnyValueUnknown(t *testing.T) { dest := NewAnyValue() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewAnyValue(), dest) } func TestMarshalAndUnmarshalProtoAnyValue(t *testing.T) { for name, src := range genTestEncodingValuesAnyValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewAnyValue() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteAnyValue(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufAnyValue(t *testing.T) { for name, src := range genTestEncodingValuesAnyValue() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcommon.AnyValue{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewAnyValue() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesAnyValue() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "StringValue/wrong_wire_type": {0xc}, "StringValue/missing_value": {0xa}, "BoolValue/wrong_wire_type": {0x14}, "BoolValue/missing_value": {0x10}, "IntValue/wrong_wire_type": {0x1c}, "IntValue/missing_value": {0x18}, "DoubleValue/wrong_wire_type": {0x24}, "DoubleValue/missing_value": {0x21}, "ArrayValue/wrong_wire_type": {0x2c}, "ArrayValue/missing_value": {0x2a}, "KvlistValue/wrong_wire_type": {0x34}, "KvlistValue/missing_value": {0x32}, "BytesValue/wrong_wire_type": {0x3c}, "BytesValue/missing_value": {0x3a}, } } func genTestEncodingValuesAnyValue() map[string]*AnyValue { return map[string]*AnyValue{ "empty": NewAnyValue(), "StringValue/default": {Value: &AnyValue_StringValue{StringValue: ""}}, "StringValue/test": {Value: &AnyValue_StringValue{StringValue: "test_stringvalue"}}, "BoolValue/default": {Value: &AnyValue_BoolValue{BoolValue: false}}, "BoolValue/test": {Value: &AnyValue_BoolValue{BoolValue: true}}, "IntValue/default": {Value: &AnyValue_IntValue{IntValue: int64(0)}}, "IntValue/test": {Value: &AnyValue_IntValue{IntValue: int64(13)}}, "DoubleValue/default": {Value: &AnyValue_DoubleValue{DoubleValue: float64(0)}}, "DoubleValue/test": {Value: &AnyValue_DoubleValue{DoubleValue: float64(3.1415926)}}, "ArrayValue/default": {Value: &AnyValue_ArrayValue{ArrayValue: &ArrayValue{}}}, "ArrayValue/test": {Value: &AnyValue_ArrayValue{ArrayValue: GenTestArrayValue()}}, "KvlistValue/default": {Value: &AnyValue_KvlistValue{KvlistValue: &KeyValueList{}}}, "KvlistValue/test": {Value: &AnyValue_KvlistValue{KvlistValue: GenTestKeyValueList()}}, "BytesValue/default": {Value: &AnyValue_BytesValue{BytesValue: nil}}, "BytesValue/test": {Value: &AnyValue_BytesValue{BytesValue: []byte{1, 2, 3}}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_arrayvalue.go000066400000000000000000000126711511331344600274150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ArrayValue is a list of AnyValue messages. We need ArrayValue as a message since oneof in AnyValue does not allow repeated fields. type ArrayValue struct { Values []AnyValue } var ( protoPoolArrayValue = sync.Pool{ New: func() any { return &ArrayValue{} }, } ) func NewArrayValue() *ArrayValue { if !UseProtoPooling.IsEnabled() { return &ArrayValue{} } return protoPoolArrayValue.Get().(*ArrayValue) } func DeleteArrayValue(orig *ArrayValue, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Values { DeleteAnyValue(&orig.Values[i], false) } orig.Reset() if nullable { protoPoolArrayValue.Put(orig) } } func CopyArrayValue(dest, src *ArrayValue) *ArrayValue { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewArrayValue() } dest.Values = CopyAnyValueSlice(dest.Values, src.Values) return dest } func CopyArrayValueSlice(dest, src []ArrayValue) []ArrayValue { var newDest []ArrayValue if cap(dest) < len(src) { newDest = make([]ArrayValue, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteArrayValue(&dest[i], false) } } for i := range src { CopyArrayValue(&newDest[i], &src[i]) } return newDest } func CopyArrayValuePtrSlice(dest, src []*ArrayValue) []*ArrayValue { var newDest []*ArrayValue if cap(dest) < len(src) { newDest = make([]*ArrayValue, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewArrayValue() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteArrayValue(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewArrayValue() } } for i := range src { CopyArrayValue(newDest[i], src[i]) } return newDest } func (orig *ArrayValue) Reset() { *orig = ArrayValue{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ArrayValue) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.Values) > 0 { dest.WriteObjectField("values") dest.WriteArrayStart() orig.Values[0].MarshalJSON(dest) for i := 1; i < len(orig.Values); i++ { dest.WriteMore() orig.Values[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ArrayValue) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "values": for iter.ReadArray() { orig.Values = append(orig.Values, AnyValue{}) orig.Values[len(orig.Values)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ArrayValue) SizeProto() int { var n int var l int _ = l for i := range orig.Values { l = orig.Values[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ArrayValue) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.Values) - 1; i >= 0; i-- { l = orig.Values[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *ArrayValue) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Values = append(orig.Values, AnyValue{}) err = orig.Values[len(orig.Values)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestArrayValue() *ArrayValue { orig := NewArrayValue() orig.Values = []AnyValue{{}, *GenTestAnyValue()} return orig } func GenTestArrayValuePtrSlice() []*ArrayValue { orig := make([]*ArrayValue, 5) orig[0] = NewArrayValue() orig[1] = GenTestArrayValue() orig[2] = NewArrayValue() orig[3] = GenTestArrayValue() orig[4] = NewArrayValue() return orig } func GenTestArrayValueSlice() []ArrayValue { orig := make([]ArrayValue, 5) orig[1] = *GenTestArrayValue() orig[3] = *GenTestArrayValue() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_arrayvalue_test.go000066400000000000000000000137401511331344600304520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyArrayValue(t *testing.T) { for name, src := range genTestEncodingValuesArrayValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewArrayValue() CopyArrayValue(dest, src) assert.Equal(t, src, dest) CopyArrayValue(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyArrayValueSlice(t *testing.T) { src := []ArrayValue{} dest := []ArrayValue{} // Test CopyTo empty dest = CopyArrayValueSlice(dest, src) assert.Equal(t, []ArrayValue{}, dest) // Test CopyTo larger slice src = GenTestArrayValueSlice() dest = CopyArrayValueSlice(dest, src) assert.Equal(t, GenTestArrayValueSlice(), dest) // Test CopyTo same size slice dest = CopyArrayValueSlice(dest, src) assert.Equal(t, GenTestArrayValueSlice(), dest) // Test CopyTo smaller size slice dest = CopyArrayValueSlice(dest, []ArrayValue{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyArrayValueSlice(dest, src) assert.Equal(t, GenTestArrayValueSlice(), dest) } func TestCopyArrayValuePtrSlice(t *testing.T) { src := []*ArrayValue{} dest := []*ArrayValue{} // Test CopyTo empty dest = CopyArrayValuePtrSlice(dest, src) assert.Equal(t, []*ArrayValue{}, dest) // Test CopyTo larger slice src = GenTestArrayValuePtrSlice() dest = CopyArrayValuePtrSlice(dest, src) assert.Equal(t, GenTestArrayValuePtrSlice(), dest) // Test CopyTo same size slice dest = CopyArrayValuePtrSlice(dest, src) assert.Equal(t, GenTestArrayValuePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyArrayValuePtrSlice(dest, []*ArrayValue{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyArrayValuePtrSlice(dest, src) assert.Equal(t, GenTestArrayValuePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONArrayValueUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewArrayValue() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewArrayValue(), dest) } func TestMarshalAndUnmarshalJSONArrayValue(t *testing.T) { for name, src := range genTestEncodingValuesArrayValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewArrayValue() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteArrayValue(dest, true) }) } } } func TestMarshalAndUnmarshalProtoArrayValueFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesArrayValue() { t.Run(name, func(t *testing.T) { dest := NewArrayValue() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoArrayValueUnknown(t *testing.T) { dest := NewArrayValue() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewArrayValue(), dest) } func TestMarshalAndUnmarshalProtoArrayValue(t *testing.T) { for name, src := range genTestEncodingValuesArrayValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewArrayValue() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteArrayValue(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufArrayValue(t *testing.T) { for name, src := range genTestEncodingValuesArrayValue() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcommon.ArrayValue{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewArrayValue() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesArrayValue() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Values/wrong_wire_type": {0xc}, "Values/missing_value": {0xa}, } } func genTestEncodingValuesArrayValue() map[string]*ArrayValue { return map[string]*ArrayValue{ "empty": NewArrayValue(), "Values/test": {Values: []AnyValue{{}, *GenTestAnyValue()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_entityref.go000066400000000000000000000174711511331344600272560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type EntityRef struct { SchemaUrl string Type string IdKeys []string DescriptionKeys []string } var ( protoPoolEntityRef = sync.Pool{ New: func() any { return &EntityRef{} }, } ) func NewEntityRef() *EntityRef { if !UseProtoPooling.IsEnabled() { return &EntityRef{} } return protoPoolEntityRef.Get().(*EntityRef) } func DeleteEntityRef(orig *EntityRef, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolEntityRef.Put(orig) } } func CopyEntityRef(dest, src *EntityRef) *EntityRef { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewEntityRef() } dest.SchemaUrl = src.SchemaUrl dest.Type = src.Type dest.IdKeys = append(dest.IdKeys[:0], src.IdKeys...) dest.DescriptionKeys = append(dest.DescriptionKeys[:0], src.DescriptionKeys...) return dest } func CopyEntityRefSlice(dest, src []EntityRef) []EntityRef { var newDest []EntityRef if cap(dest) < len(src) { newDest = make([]EntityRef, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteEntityRef(&dest[i], false) } } for i := range src { CopyEntityRef(&newDest[i], &src[i]) } return newDest } func CopyEntityRefPtrSlice(dest, src []*EntityRef) []*EntityRef { var newDest []*EntityRef if cap(dest) < len(src) { newDest = make([]*EntityRef, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewEntityRef() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteEntityRef(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewEntityRef() } } for i := range src { CopyEntityRef(newDest[i], src[i]) } return newDest } func (orig *EntityRef) Reset() { *orig = EntityRef{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *EntityRef) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } if orig.Type != "" { dest.WriteObjectField("type") dest.WriteString(orig.Type) } if len(orig.IdKeys) > 0 { dest.WriteObjectField("idKeys") dest.WriteArrayStart() dest.WriteString(orig.IdKeys[0]) for i := 1; i < len(orig.IdKeys); i++ { dest.WriteMore() dest.WriteString(orig.IdKeys[i]) } dest.WriteArrayEnd() } if len(orig.DescriptionKeys) > 0 { dest.WriteObjectField("descriptionKeys") dest.WriteArrayStart() dest.WriteString(orig.DescriptionKeys[0]) for i := 1; i < len(orig.DescriptionKeys); i++ { dest.WriteMore() dest.WriteString(orig.DescriptionKeys[i]) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *EntityRef) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() case "type": orig.Type = iter.ReadString() case "idKeys", "id_keys": for iter.ReadArray() { orig.IdKeys = append(orig.IdKeys, iter.ReadString()) } case "descriptionKeys", "description_keys": for iter.ReadArray() { orig.DescriptionKeys = append(orig.DescriptionKeys, iter.ReadString()) } default: iter.Skip() } } } func (orig *EntityRef) SizeProto() int { var n int var l int _ = l l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.Type) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } for _, s := range orig.IdKeys { l = len(s) n += 1 + proto.Sov(uint64(l)) + l } for _, s := range orig.DescriptionKeys { l = len(s) n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *EntityRef) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = len(orig.Type) if l > 0 { pos -= l copy(buf[pos:], orig.Type) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } for i := len(orig.IdKeys) - 1; i >= 0; i-- { l = len(orig.IdKeys[i]) pos -= l copy(buf[pos:], orig.IdKeys[i]) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } for i := len(orig.DescriptionKeys) - 1; i >= 0; i-- { l = len(orig.DescriptionKeys[i]) pos -= l copy(buf[pos:], orig.DescriptionKeys[i]) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x22 } return len(buf) - pos } func (orig *EntityRef) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Type", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Type = string(buf[startPos:pos]) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field IdKeys", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.IdKeys = append(orig.IdKeys, string(buf[startPos:pos])) case 4: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DescriptionKeys", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DescriptionKeys = append(orig.DescriptionKeys, string(buf[startPos:pos])) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestEntityRef() *EntityRef { orig := NewEntityRef() orig.SchemaUrl = "test_schemaurl" orig.Type = "test_type" orig.IdKeys = []string{"", "test_idkeys"} orig.DescriptionKeys = []string{"", "test_descriptionkeys"} return orig } func GenTestEntityRefPtrSlice() []*EntityRef { orig := make([]*EntityRef, 5) orig[0] = NewEntityRef() orig[1] = GenTestEntityRef() orig[2] = NewEntityRef() orig[3] = GenTestEntityRef() orig[4] = NewEntityRef() return orig } func GenTestEntityRefSlice() []EntityRef { orig := make([]EntityRef, 5) orig[1] = *GenTestEntityRef() orig[3] = *GenTestEntityRef() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_entityref_test.go000066400000000000000000000146241511331344600303120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyEntityRef(t *testing.T) { for name, src := range genTestEncodingValuesEntityRef() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewEntityRef() CopyEntityRef(dest, src) assert.Equal(t, src, dest) CopyEntityRef(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyEntityRefSlice(t *testing.T) { src := []EntityRef{} dest := []EntityRef{} // Test CopyTo empty dest = CopyEntityRefSlice(dest, src) assert.Equal(t, []EntityRef{}, dest) // Test CopyTo larger slice src = GenTestEntityRefSlice() dest = CopyEntityRefSlice(dest, src) assert.Equal(t, GenTestEntityRefSlice(), dest) // Test CopyTo same size slice dest = CopyEntityRefSlice(dest, src) assert.Equal(t, GenTestEntityRefSlice(), dest) // Test CopyTo smaller size slice dest = CopyEntityRefSlice(dest, []EntityRef{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyEntityRefSlice(dest, src) assert.Equal(t, GenTestEntityRefSlice(), dest) } func TestCopyEntityRefPtrSlice(t *testing.T) { src := []*EntityRef{} dest := []*EntityRef{} // Test CopyTo empty dest = CopyEntityRefPtrSlice(dest, src) assert.Equal(t, []*EntityRef{}, dest) // Test CopyTo larger slice src = GenTestEntityRefPtrSlice() dest = CopyEntityRefPtrSlice(dest, src) assert.Equal(t, GenTestEntityRefPtrSlice(), dest) // Test CopyTo same size slice dest = CopyEntityRefPtrSlice(dest, src) assert.Equal(t, GenTestEntityRefPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyEntityRefPtrSlice(dest, []*EntityRef{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyEntityRefPtrSlice(dest, src) assert.Equal(t, GenTestEntityRefPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONEntityRefUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewEntityRef() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewEntityRef(), dest) } func TestMarshalAndUnmarshalJSONEntityRef(t *testing.T) { for name, src := range genTestEncodingValuesEntityRef() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewEntityRef() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteEntityRef(dest, true) }) } } } func TestMarshalAndUnmarshalProtoEntityRefFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesEntityRef() { t.Run(name, func(t *testing.T) { dest := NewEntityRef() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoEntityRefUnknown(t *testing.T) { dest := NewEntityRef() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewEntityRef(), dest) } func TestMarshalAndUnmarshalProtoEntityRef(t *testing.T) { for name, src := range genTestEncodingValuesEntityRef() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewEntityRef() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteEntityRef(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufEntityRef(t *testing.T) { for name, src := range genTestEncodingValuesEntityRef() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcommon.EntityRef{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewEntityRef() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesEntityRef() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "SchemaUrl/wrong_wire_type": {0xc}, "SchemaUrl/missing_value": {0xa}, "Type/wrong_wire_type": {0x14}, "Type/missing_value": {0x12}, "IdKeys/wrong_wire_type": {0x1c}, "IdKeys/missing_value": {0x1a}, "DescriptionKeys/wrong_wire_type": {0x24}, "DescriptionKeys/missing_value": {0x22}, } } func genTestEncodingValuesEntityRef() map[string]*EntityRef { return map[string]*EntityRef{ "empty": NewEntityRef(), "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, "Type/test": {Type: "test_type"}, "IdKeys/test": {IdKeys: []string{"", "test_idkeys"}}, "DescriptionKeys/test": {DescriptionKeys: []string{"", "test_descriptionkeys"}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exemplar.go000066400000000000000000000274231511331344600270600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "math" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) func (m *Exemplar) GetValue() any { if m != nil { return m.Value } return nil } type Exemplar_AsDouble struct { AsDouble float64 } func (m *Exemplar) GetAsDouble() float64 { if v, ok := m.GetValue().(*Exemplar_AsDouble); ok { return v.AsDouble } return float64(0) } type Exemplar_AsInt struct { AsInt int64 } func (m *Exemplar) GetAsInt() int64 { if v, ok := m.GetValue().(*Exemplar_AsInt); ok { return v.AsInt } return int64(0) } // Exemplar is a sample input double measurement. // // Exemplars also hold information about the environment when the measurement was recorded, // for example the span and trace ID of the active span when the exemplar was recorded. type Exemplar struct { FilteredAttributes []KeyValue TimeUnixNano uint64 Value any TraceId TraceID SpanId SpanID } var ( protoPoolExemplar = sync.Pool{ New: func() any { return &Exemplar{} }, } ProtoPoolExemplar_AsDouble = sync.Pool{ New: func() any { return &Exemplar_AsDouble{} }, } ProtoPoolExemplar_AsInt = sync.Pool{ New: func() any { return &Exemplar_AsInt{} }, } ) func NewExemplar() *Exemplar { if !UseProtoPooling.IsEnabled() { return &Exemplar{} } return protoPoolExemplar.Get().(*Exemplar) } func DeleteExemplar(orig *Exemplar, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.FilteredAttributes { DeleteKeyValue(&orig.FilteredAttributes[i], false) } switch ov := orig.Value.(type) { case *Exemplar_AsDouble: if UseProtoPooling.IsEnabled() { ov.AsDouble = float64(0) ProtoPoolExemplar_AsDouble.Put(ov) } case *Exemplar_AsInt: if UseProtoPooling.IsEnabled() { ov.AsInt = int64(0) ProtoPoolExemplar_AsInt.Put(ov) } } DeleteTraceID(&orig.TraceId, false) DeleteSpanID(&orig.SpanId, false) orig.Reset() if nullable { protoPoolExemplar.Put(orig) } } func CopyExemplar(dest, src *Exemplar) *Exemplar { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExemplar() } dest.FilteredAttributes = CopyKeyValueSlice(dest.FilteredAttributes, src.FilteredAttributes) dest.TimeUnixNano = src.TimeUnixNano switch t := src.Value.(type) { case *Exemplar_AsDouble: var ov *Exemplar_AsDouble if !UseProtoPooling.IsEnabled() { ov = &Exemplar_AsDouble{} } else { ov = ProtoPoolExemplar_AsDouble.Get().(*Exemplar_AsDouble) } ov.AsDouble = t.AsDouble dest.Value = ov case *Exemplar_AsInt: var ov *Exemplar_AsInt if !UseProtoPooling.IsEnabled() { ov = &Exemplar_AsInt{} } else { ov = ProtoPoolExemplar_AsInt.Get().(*Exemplar_AsInt) } ov.AsInt = t.AsInt dest.Value = ov default: dest.Value = nil } CopyTraceID(&dest.TraceId, &src.TraceId) CopySpanID(&dest.SpanId, &src.SpanId) return dest } func CopyExemplarSlice(dest, src []Exemplar) []Exemplar { var newDest []Exemplar if cap(dest) < len(src) { newDest = make([]Exemplar, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExemplar(&dest[i], false) } } for i := range src { CopyExemplar(&newDest[i], &src[i]) } return newDest } func CopyExemplarPtrSlice(dest, src []*Exemplar) []*Exemplar { var newDest []*Exemplar if cap(dest) < len(src) { newDest = make([]*Exemplar, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExemplar() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExemplar(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExemplar() } } for i := range src { CopyExemplar(newDest[i], src[i]) } return newDest } func (orig *Exemplar) Reset() { *orig = Exemplar{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Exemplar) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.FilteredAttributes) > 0 { dest.WriteObjectField("filteredAttributes") dest.WriteArrayStart() orig.FilteredAttributes[0].MarshalJSON(dest) for i := 1; i < len(orig.FilteredAttributes); i++ { dest.WriteMore() orig.FilteredAttributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } switch orig := orig.Value.(type) { case *Exemplar_AsDouble: dest.WriteObjectField("asDouble") dest.WriteFloat64(orig.AsDouble) case *Exemplar_AsInt: dest.WriteObjectField("asInt") dest.WriteInt64(orig.AsInt) } if !orig.TraceId.IsEmpty() { dest.WriteObjectField("traceId") orig.TraceId.MarshalJSON(dest) } if !orig.SpanId.IsEmpty() { dest.WriteObjectField("spanId") orig.SpanId.MarshalJSON(dest) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Exemplar) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "filteredAttributes", "filtered_attributes": for iter.ReadArray() { orig.FilteredAttributes = append(orig.FilteredAttributes, KeyValue{}) orig.FilteredAttributes[len(orig.FilteredAttributes)-1].UnmarshalJSON(iter) } case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "asDouble", "as_double": { var ov *Exemplar_AsDouble if !UseProtoPooling.IsEnabled() { ov = &Exemplar_AsDouble{} } else { ov = ProtoPoolExemplar_AsDouble.Get().(*Exemplar_AsDouble) } ov.AsDouble = iter.ReadFloat64() orig.Value = ov } case "asInt", "as_int": { var ov *Exemplar_AsInt if !UseProtoPooling.IsEnabled() { ov = &Exemplar_AsInt{} } else { ov = ProtoPoolExemplar_AsInt.Get().(*Exemplar_AsInt) } ov.AsInt = iter.ReadInt64() orig.Value = ov } case "traceId", "trace_id": orig.TraceId.UnmarshalJSON(iter) case "spanId", "span_id": orig.SpanId.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *Exemplar) SizeProto() int { var n int var l int _ = l for i := range orig.FilteredAttributes { l = orig.FilteredAttributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.TimeUnixNano != 0 { n += 9 } switch orig := orig.Value.(type) { case nil: _ = orig break case *Exemplar_AsDouble: n += 9 case *Exemplar_AsInt: n += 9 } l = orig.TraceId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = orig.SpanId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *Exemplar) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.FilteredAttributes) - 1; i >= 0; i-- { l = orig.FilteredAttributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3a } if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x11 } switch orig := orig.Value.(type) { case *Exemplar_AsDouble: pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.AsDouble)) pos-- buf[pos] = 0x19 case *Exemplar_AsInt: pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.AsInt)) pos-- buf[pos] = 0x31 } l = orig.TraceId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a l = orig.SpanId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x22 return len(buf) - pos } func (orig *Exemplar) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 7: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field FilteredAttributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.FilteredAttributes = append(orig.FilteredAttributes, KeyValue{}) err = orig.FilteredAttributes[len(orig.FilteredAttributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 3: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field AsDouble", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *Exemplar_AsDouble if !UseProtoPooling.IsEnabled() { ov = &Exemplar_AsDouble{} } else { ov = ProtoPoolExemplar_AsDouble.Get().(*Exemplar_AsDouble) } ov.AsDouble = math.Float64frombits(num) orig.Value = ov case 6: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field AsInt", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *Exemplar_AsInt if !UseProtoPooling.IsEnabled() { ov = &Exemplar_AsInt{} } else { ov = ProtoPoolExemplar_AsInt.Get().(*Exemplar_AsInt) } ov.AsInt = int64(num) orig.Value = ov case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.TraceId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 4: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.SpanId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExemplar() *Exemplar { orig := NewExemplar() orig.FilteredAttributes = []KeyValue{{}, *GenTestKeyValue()} orig.TimeUnixNano = uint64(13) orig.Value = &Exemplar_AsDouble{AsDouble: float64(3.1415926)} orig.TraceId = *GenTestTraceID() orig.SpanId = *GenTestSpanID() return orig } func GenTestExemplarPtrSlice() []*Exemplar { orig := make([]*Exemplar, 5) orig[0] = NewExemplar() orig[1] = GenTestExemplar() orig[2] = NewExemplar() orig[3] = GenTestExemplar() orig[4] = NewExemplar() return orig } func GenTestExemplarSlice() []Exemplar { orig := make([]Exemplar, 5) orig[1] = *GenTestExemplar() orig[3] = *GenTestExemplar() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exemplar_test.go000066400000000000000000000154511511331344600301150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExemplar(t *testing.T) { for name, src := range genTestEncodingValuesExemplar() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExemplar() CopyExemplar(dest, src) assert.Equal(t, src, dest) CopyExemplar(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExemplarSlice(t *testing.T) { src := []Exemplar{} dest := []Exemplar{} // Test CopyTo empty dest = CopyExemplarSlice(dest, src) assert.Equal(t, []Exemplar{}, dest) // Test CopyTo larger slice src = GenTestExemplarSlice() dest = CopyExemplarSlice(dest, src) assert.Equal(t, GenTestExemplarSlice(), dest) // Test CopyTo same size slice dest = CopyExemplarSlice(dest, src) assert.Equal(t, GenTestExemplarSlice(), dest) // Test CopyTo smaller size slice dest = CopyExemplarSlice(dest, []Exemplar{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExemplarSlice(dest, src) assert.Equal(t, GenTestExemplarSlice(), dest) } func TestCopyExemplarPtrSlice(t *testing.T) { src := []*Exemplar{} dest := []*Exemplar{} // Test CopyTo empty dest = CopyExemplarPtrSlice(dest, src) assert.Equal(t, []*Exemplar{}, dest) // Test CopyTo larger slice src = GenTestExemplarPtrSlice() dest = CopyExemplarPtrSlice(dest, src) assert.Equal(t, GenTestExemplarPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExemplarPtrSlice(dest, src) assert.Equal(t, GenTestExemplarPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExemplarPtrSlice(dest, []*Exemplar{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExemplarPtrSlice(dest, src) assert.Equal(t, GenTestExemplarPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExemplarUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExemplar() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExemplar(), dest) } func TestMarshalAndUnmarshalJSONExemplar(t *testing.T) { for name, src := range genTestEncodingValuesExemplar() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExemplar() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExemplar(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExemplarFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExemplar() { t.Run(name, func(t *testing.T) { dest := NewExemplar() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExemplarUnknown(t *testing.T) { dest := NewExemplar() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExemplar(), dest) } func TestMarshalAndUnmarshalProtoExemplar(t *testing.T) { for name, src := range genTestEncodingValuesExemplar() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExemplar() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExemplar(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExemplar(t *testing.T) { for name, src := range genTestEncodingValuesExemplar() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.Exemplar{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExemplar() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExemplar() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "FilteredAttributes/wrong_wire_type": {0x3c}, "FilteredAttributes/missing_value": {0x3a}, "TimeUnixNano/wrong_wire_type": {0x14}, "TimeUnixNano/missing_value": {0x11}, "AsDouble/wrong_wire_type": {0x1c}, "AsDouble/missing_value": {0x19}, "AsInt/wrong_wire_type": {0x34}, "AsInt/missing_value": {0x31}, "TraceId/wrong_wire_type": {0x2c}, "TraceId/missing_value": {0x2a}, "SpanId/wrong_wire_type": {0x24}, "SpanId/missing_value": {0x22}, } } func genTestEncodingValuesExemplar() map[string]*Exemplar { return map[string]*Exemplar{ "empty": NewExemplar(), "FilteredAttributes/test": {FilteredAttributes: []KeyValue{{}, *GenTestKeyValue()}}, "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "AsDouble/default": {Value: &Exemplar_AsDouble{AsDouble: float64(0)}}, "AsDouble/test": {Value: &Exemplar_AsDouble{AsDouble: float64(3.1415926)}}, "AsInt/default": {Value: &Exemplar_AsInt{AsInt: int64(0)}}, "AsInt/test": {Value: &Exemplar_AsInt{AsInt: int64(13)}}, "TraceId/test": {TraceId: *GenTestTraceID()}, "SpanId/test": {SpanId: *GenTestSpanID()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exponentialhistogram.go000066400000000000000000000164641511331344600315120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExponentialHistogram represents the type of a metric that is calculated by aggregating // as a ExponentialHistogram of all reported double measurements over a time interval. type ExponentialHistogram struct { DataPoints []*ExponentialHistogramDataPoint AggregationTemporality AggregationTemporality } var ( protoPoolExponentialHistogram = sync.Pool{ New: func() any { return &ExponentialHistogram{} }, } ) func NewExponentialHistogram() *ExponentialHistogram { if !UseProtoPooling.IsEnabled() { return &ExponentialHistogram{} } return protoPoolExponentialHistogram.Get().(*ExponentialHistogram) } func DeleteExponentialHistogram(orig *ExponentialHistogram, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.DataPoints { DeleteExponentialHistogramDataPoint(orig.DataPoints[i], true) } orig.Reset() if nullable { protoPoolExponentialHistogram.Put(orig) } } func CopyExponentialHistogram(dest, src *ExponentialHistogram) *ExponentialHistogram { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExponentialHistogram() } dest.DataPoints = CopyExponentialHistogramDataPointPtrSlice(dest.DataPoints, src.DataPoints) dest.AggregationTemporality = src.AggregationTemporality return dest } func CopyExponentialHistogramSlice(dest, src []ExponentialHistogram) []ExponentialHistogram { var newDest []ExponentialHistogram if cap(dest) < len(src) { newDest = make([]ExponentialHistogram, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExponentialHistogram(&dest[i], false) } } for i := range src { CopyExponentialHistogram(&newDest[i], &src[i]) } return newDest } func CopyExponentialHistogramPtrSlice(dest, src []*ExponentialHistogram) []*ExponentialHistogram { var newDest []*ExponentialHistogram if cap(dest) < len(src) { newDest = make([]*ExponentialHistogram, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExponentialHistogram() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExponentialHistogram(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExponentialHistogram() } } for i := range src { CopyExponentialHistogram(newDest[i], src[i]) } return newDest } func (orig *ExponentialHistogram) Reset() { *orig = ExponentialHistogram{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExponentialHistogram) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.DataPoints) > 0 { dest.WriteObjectField("dataPoints") dest.WriteArrayStart() orig.DataPoints[0].MarshalJSON(dest) for i := 1; i < len(orig.DataPoints); i++ { dest.WriteMore() orig.DataPoints[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if int32(orig.AggregationTemporality) != 0 { dest.WriteObjectField("aggregationTemporality") dest.WriteInt32(int32(orig.AggregationTemporality)) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExponentialHistogram) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "dataPoints", "data_points": for iter.ReadArray() { orig.DataPoints = append(orig.DataPoints, NewExponentialHistogramDataPoint()) orig.DataPoints[len(orig.DataPoints)-1].UnmarshalJSON(iter) } case "aggregationTemporality", "aggregation_temporality": orig.AggregationTemporality = AggregationTemporality(iter.ReadEnumValue(AggregationTemporality_value)) default: iter.Skip() } } } func (orig *ExponentialHistogram) SizeProto() int { var n int var l int _ = l for i := range orig.DataPoints { l = orig.DataPoints[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.AggregationTemporality != 0 { n += 1 + proto.Sov(uint64(orig.AggregationTemporality)) } return n } func (orig *ExponentialHistogram) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.DataPoints) - 1; i >= 0; i-- { l = orig.DataPoints[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } if orig.AggregationTemporality != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.AggregationTemporality)) pos-- buf[pos] = 0x10 } return len(buf) - pos } func (orig *ExponentialHistogram) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DataPoints", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DataPoints = append(orig.DataPoints, NewExponentialHistogramDataPoint()) err = orig.DataPoints[len(orig.DataPoints)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field AggregationTemporality", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.AggregationTemporality = AggregationTemporality(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExponentialHistogram() *ExponentialHistogram { orig := NewExponentialHistogram() orig.DataPoints = []*ExponentialHistogramDataPoint{{}, GenTestExponentialHistogramDataPoint()} orig.AggregationTemporality = AggregationTemporality(13) return orig } func GenTestExponentialHistogramPtrSlice() []*ExponentialHistogram { orig := make([]*ExponentialHistogram, 5) orig[0] = NewExponentialHistogram() orig[1] = GenTestExponentialHistogram() orig[2] = NewExponentialHistogram() orig[3] = GenTestExponentialHistogram() orig[4] = NewExponentialHistogram() return orig } func GenTestExponentialHistogramSlice() []ExponentialHistogram { orig := make([]ExponentialHistogram, 5) orig[1] = *GenTestExponentialHistogram() orig[3] = *GenTestExponentialHistogram() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exponentialhistogram_test.go000066400000000000000000000155561511331344600325520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExponentialHistogram(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogram() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExponentialHistogram() CopyExponentialHistogram(dest, src) assert.Equal(t, src, dest) CopyExponentialHistogram(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExponentialHistogramSlice(t *testing.T) { src := []ExponentialHistogram{} dest := []ExponentialHistogram{} // Test CopyTo empty dest = CopyExponentialHistogramSlice(dest, src) assert.Equal(t, []ExponentialHistogram{}, dest) // Test CopyTo larger slice src = GenTestExponentialHistogramSlice() dest = CopyExponentialHistogramSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramSlice(), dest) // Test CopyTo same size slice dest = CopyExponentialHistogramSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramSlice(), dest) // Test CopyTo smaller size slice dest = CopyExponentialHistogramSlice(dest, []ExponentialHistogram{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExponentialHistogramSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramSlice(), dest) } func TestCopyExponentialHistogramPtrSlice(t *testing.T) { src := []*ExponentialHistogram{} dest := []*ExponentialHistogram{} // Test CopyTo empty dest = CopyExponentialHistogramPtrSlice(dest, src) assert.Equal(t, []*ExponentialHistogram{}, dest) // Test CopyTo larger slice src = GenTestExponentialHistogramPtrSlice() dest = CopyExponentialHistogramPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExponentialHistogramPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExponentialHistogramPtrSlice(dest, []*ExponentialHistogram{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExponentialHistogramPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExponentialHistogramUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExponentialHistogram() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExponentialHistogram(), dest) } func TestMarshalAndUnmarshalJSONExponentialHistogram(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogram() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExponentialHistogram() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExponentialHistogram(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExponentialHistogramFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExponentialHistogram() { t.Run(name, func(t *testing.T) { dest := NewExponentialHistogram() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExponentialHistogramUnknown(t *testing.T) { dest := NewExponentialHistogram() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExponentialHistogram(), dest) } func TestMarshalAndUnmarshalProtoExponentialHistogram(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogram() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExponentialHistogram() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExponentialHistogram(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExponentialHistogram(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogram() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.ExponentialHistogram{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExponentialHistogram() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExponentialHistogram() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "DataPoints/wrong_wire_type": {0xc}, "DataPoints/missing_value": {0xa}, "AggregationTemporality/wrong_wire_type": {0x14}, "AggregationTemporality/missing_value": {0x10}, } } func genTestEncodingValuesExponentialHistogram() map[string]*ExponentialHistogram { return map[string]*ExponentialHistogram{ "empty": NewExponentialHistogram(), "DataPoints/test": {DataPoints: []*ExponentialHistogramDataPoint{{}, GenTestExponentialHistogramDataPoint()}}, "AggregationTemporality/test": {AggregationTemporality: AggregationTemporality(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exponentialhistogramdatapoint.go000066400000000000000000000540011511331344600334030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "math" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) func (m *ExponentialHistogramDataPoint) GetSum_() any { if m != nil { return m.Sum_ } return nil } type ExponentialHistogramDataPoint_Sum struct { Sum float64 } func (m *ExponentialHistogramDataPoint) GetSum() float64 { if v, ok := m.GetSum_().(*ExponentialHistogramDataPoint_Sum); ok { return v.Sum } return float64(0) } func (m *ExponentialHistogramDataPoint) GetMin_() any { if m != nil { return m.Min_ } return nil } type ExponentialHistogramDataPoint_Min struct { Min float64 } func (m *ExponentialHistogramDataPoint) GetMin() float64 { if v, ok := m.GetMin_().(*ExponentialHistogramDataPoint_Min); ok { return v.Min } return float64(0) } func (m *ExponentialHistogramDataPoint) GetMax_() any { if m != nil { return m.Max_ } return nil } type ExponentialHistogramDataPoint_Max struct { Max float64 } func (m *ExponentialHistogramDataPoint) GetMax() float64 { if v, ok := m.GetMax_().(*ExponentialHistogramDataPoint_Max); ok { return v.Max } return float64(0) } // ExponentialHistogramDataPoint is a single data point in a timeseries that describes the // time-varying values of a ExponentialHistogram of double values. A ExponentialHistogram contains // summary statistics for a population of values, it may optionally contain the // distribution of those values across a set of buckets. type ExponentialHistogramDataPoint struct { Attributes []KeyValue StartTimeUnixNano uint64 TimeUnixNano uint64 Count uint64 Sum_ any Scale int32 ZeroCount uint64 Positive ExponentialHistogramDataPointBuckets Negative ExponentialHistogramDataPointBuckets Flags uint32 Exemplars []Exemplar Min_ any Max_ any ZeroThreshold float64 } var ( protoPoolExponentialHistogramDataPoint = sync.Pool{ New: func() any { return &ExponentialHistogramDataPoint{} }, } ProtoPoolExponentialHistogramDataPoint_Sum = sync.Pool{ New: func() any { return &ExponentialHistogramDataPoint_Sum{} }, } ProtoPoolExponentialHistogramDataPoint_Min = sync.Pool{ New: func() any { return &ExponentialHistogramDataPoint_Min{} }, } ProtoPoolExponentialHistogramDataPoint_Max = sync.Pool{ New: func() any { return &ExponentialHistogramDataPoint_Max{} }, } ) func NewExponentialHistogramDataPoint() *ExponentialHistogramDataPoint { if !UseProtoPooling.IsEnabled() { return &ExponentialHistogramDataPoint{} } return protoPoolExponentialHistogramDataPoint.Get().(*ExponentialHistogramDataPoint) } func DeleteExponentialHistogramDataPoint(orig *ExponentialHistogramDataPoint, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } switch ov := orig.Sum_.(type) { case *ExponentialHistogramDataPoint_Sum: if UseProtoPooling.IsEnabled() { ov.Sum = float64(0) ProtoPoolExponentialHistogramDataPoint_Sum.Put(ov) } } DeleteExponentialHistogramDataPointBuckets(&orig.Positive, false) DeleteExponentialHistogramDataPointBuckets(&orig.Negative, false) for i := range orig.Exemplars { DeleteExemplar(&orig.Exemplars[i], false) } switch ov := orig.Min_.(type) { case *ExponentialHistogramDataPoint_Min: if UseProtoPooling.IsEnabled() { ov.Min = float64(0) ProtoPoolExponentialHistogramDataPoint_Min.Put(ov) } } switch ov := orig.Max_.(type) { case *ExponentialHistogramDataPoint_Max: if UseProtoPooling.IsEnabled() { ov.Max = float64(0) ProtoPoolExponentialHistogramDataPoint_Max.Put(ov) } } orig.Reset() if nullable { protoPoolExponentialHistogramDataPoint.Put(orig) } } func CopyExponentialHistogramDataPoint(dest, src *ExponentialHistogramDataPoint) *ExponentialHistogramDataPoint { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExponentialHistogramDataPoint() } dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.StartTimeUnixNano = src.StartTimeUnixNano dest.TimeUnixNano = src.TimeUnixNano dest.Count = src.Count switch t := src.Sum_.(type) { case *ExponentialHistogramDataPoint_Sum: var ov *ExponentialHistogramDataPoint_Sum if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Sum{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Sum.Get().(*ExponentialHistogramDataPoint_Sum) } ov.Sum = t.Sum dest.Sum_ = ov default: dest.Sum_ = nil } dest.Scale = src.Scale dest.ZeroCount = src.ZeroCount CopyExponentialHistogramDataPointBuckets(&dest.Positive, &src.Positive) CopyExponentialHistogramDataPointBuckets(&dest.Negative, &src.Negative) dest.Flags = src.Flags dest.Exemplars = CopyExemplarSlice(dest.Exemplars, src.Exemplars) switch t := src.Min_.(type) { case *ExponentialHistogramDataPoint_Min: var ov *ExponentialHistogramDataPoint_Min if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Min{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Min.Get().(*ExponentialHistogramDataPoint_Min) } ov.Min = t.Min dest.Min_ = ov default: dest.Min_ = nil } switch t := src.Max_.(type) { case *ExponentialHistogramDataPoint_Max: var ov *ExponentialHistogramDataPoint_Max if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Max{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Max.Get().(*ExponentialHistogramDataPoint_Max) } ov.Max = t.Max dest.Max_ = ov default: dest.Max_ = nil } dest.ZeroThreshold = src.ZeroThreshold return dest } func CopyExponentialHistogramDataPointSlice(dest, src []ExponentialHistogramDataPoint) []ExponentialHistogramDataPoint { var newDest []ExponentialHistogramDataPoint if cap(dest) < len(src) { newDest = make([]ExponentialHistogramDataPoint, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExponentialHistogramDataPoint(&dest[i], false) } } for i := range src { CopyExponentialHistogramDataPoint(&newDest[i], &src[i]) } return newDest } func CopyExponentialHistogramDataPointPtrSlice(dest, src []*ExponentialHistogramDataPoint) []*ExponentialHistogramDataPoint { var newDest []*ExponentialHistogramDataPoint if cap(dest) < len(src) { newDest = make([]*ExponentialHistogramDataPoint, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExponentialHistogramDataPoint() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExponentialHistogramDataPoint(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExponentialHistogramDataPoint() } } for i := range src { CopyExponentialHistogramDataPoint(newDest[i], src[i]) } return newDest } func (orig *ExponentialHistogramDataPoint) Reset() { *orig = ExponentialHistogramDataPoint{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExponentialHistogramDataPoint) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.StartTimeUnixNano != uint64(0) { dest.WriteObjectField("startTimeUnixNano") dest.WriteUint64(orig.StartTimeUnixNano) } if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } if orig.Count != uint64(0) { dest.WriteObjectField("count") dest.WriteUint64(orig.Count) } if orig, ok := orig.Sum_.(*ExponentialHistogramDataPoint_Sum); ok { dest.WriteObjectField("sum") dest.WriteFloat64(orig.Sum) } if orig.Scale != int32(0) { dest.WriteObjectField("scale") dest.WriteInt32(orig.Scale) } if orig.ZeroCount != uint64(0) { dest.WriteObjectField("zeroCount") dest.WriteUint64(orig.ZeroCount) } dest.WriteObjectField("positive") orig.Positive.MarshalJSON(dest) dest.WriteObjectField("negative") orig.Negative.MarshalJSON(dest) if orig.Flags != uint32(0) { dest.WriteObjectField("flags") dest.WriteUint32(orig.Flags) } if len(orig.Exemplars) > 0 { dest.WriteObjectField("exemplars") dest.WriteArrayStart() orig.Exemplars[0].MarshalJSON(dest) for i := 1; i < len(orig.Exemplars); i++ { dest.WriteMore() orig.Exemplars[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig, ok := orig.Min_.(*ExponentialHistogramDataPoint_Min); ok { dest.WriteObjectField("min") dest.WriteFloat64(orig.Min) } if orig, ok := orig.Max_.(*ExponentialHistogramDataPoint_Max); ok { dest.WriteObjectField("max") dest.WriteFloat64(orig.Max) } if orig.ZeroThreshold != float64(0) { dest.WriteObjectField("zeroThreshold") dest.WriteFloat64(orig.ZeroThreshold) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExponentialHistogramDataPoint) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "startTimeUnixNano", "start_time_unix_nano": orig.StartTimeUnixNano = iter.ReadUint64() case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "count": orig.Count = iter.ReadUint64() case "sum": { var ov *ExponentialHistogramDataPoint_Sum if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Sum{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Sum.Get().(*ExponentialHistogramDataPoint_Sum) } ov.Sum = iter.ReadFloat64() orig.Sum_ = ov } case "scale": orig.Scale = iter.ReadInt32() case "zeroCount", "zero_count": orig.ZeroCount = iter.ReadUint64() case "positive": orig.Positive.UnmarshalJSON(iter) case "negative": orig.Negative.UnmarshalJSON(iter) case "flags": orig.Flags = iter.ReadUint32() case "exemplars": for iter.ReadArray() { orig.Exemplars = append(orig.Exemplars, Exemplar{}) orig.Exemplars[len(orig.Exemplars)-1].UnmarshalJSON(iter) } case "min": { var ov *ExponentialHistogramDataPoint_Min if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Min{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Min.Get().(*ExponentialHistogramDataPoint_Min) } ov.Min = iter.ReadFloat64() orig.Min_ = ov } case "max": { var ov *ExponentialHistogramDataPoint_Max if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Max{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Max.Get().(*ExponentialHistogramDataPoint_Max) } ov.Max = iter.ReadFloat64() orig.Max_ = ov } case "zeroThreshold", "zero_threshold": orig.ZeroThreshold = iter.ReadFloat64() default: iter.Skip() } } } func (orig *ExponentialHistogramDataPoint) SizeProto() int { var n int var l int _ = l for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.StartTimeUnixNano != 0 { n += 9 } if orig.TimeUnixNano != 0 { n += 9 } if orig.Count != 0 { n += 9 } if orig, ok := orig.Sum_.(*ExponentialHistogramDataPoint_Sum); ok { _ = orig n += 9 } if orig.Scale != 0 { n += 1 + proto.Soz(uint64(orig.Scale)) } if orig.ZeroCount != 0 { n += 9 } l = orig.Positive.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = orig.Negative.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.Flags != 0 { n += 1 + proto.Sov(uint64(orig.Flags)) } for i := range orig.Exemplars { l = orig.Exemplars[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig, ok := orig.Min_.(*ExponentialHistogramDataPoint_Min); ok { _ = orig n += 9 } if orig, ok := orig.Max_.(*ExponentialHistogramDataPoint_Max); ok { _ = orig n += 9 } if orig.ZeroThreshold != 0 { n += 9 } return n } func (orig *ExponentialHistogramDataPoint) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } if orig.StartTimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.StartTimeUnixNano)) pos-- buf[pos] = 0x11 } if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x19 } if orig.Count != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.Count)) pos-- buf[pos] = 0x21 } if orig, ok := orig.Sum_.(*ExponentialHistogramDataPoint_Sum); ok { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Sum)) pos-- buf[pos] = 0x29 } if orig.Scale != 0 { pos = proto.EncodeVarint(buf, pos, uint64((uint32(orig.Scale)<<1)^uint32(orig.Scale>>31))) pos-- buf[pos] = 0x30 } if orig.ZeroCount != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.ZeroCount)) pos-- buf[pos] = 0x39 } l = orig.Positive.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x42 l = orig.Negative.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x4a if orig.Flags != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Flags)) pos-- buf[pos] = 0x50 } for i := len(orig.Exemplars) - 1; i >= 0; i-- { l = orig.Exemplars[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x5a } if orig, ok := orig.Min_.(*ExponentialHistogramDataPoint_Min); ok { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Min)) pos-- buf[pos] = 0x61 } if orig, ok := orig.Max_.(*ExponentialHistogramDataPoint_Max); ok { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Max)) pos-- buf[pos] = 0x69 } if orig.ZeroThreshold != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.ZeroThreshold)) pos-- buf[pos] = 0x71 } return len(buf) - pos } func (orig *ExponentialHistogramDataPoint) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field StartTimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.StartTimeUnixNano = uint64(num) case 3: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 4: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.Count = uint64(num) case 5: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Sum", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *ExponentialHistogramDataPoint_Sum if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Sum{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Sum.Get().(*ExponentialHistogramDataPoint_Sum) } ov.Sum = math.Float64frombits(num) orig.Sum_ = ov case 6: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Scale", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Scale = int32(uint32(num>>1) ^ uint32(int32((num&1)<<31)>>31)) case 7: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field ZeroCount", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.ZeroCount = uint64(num) case 8: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Positive", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Positive.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 9: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Negative", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Negative.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 10: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Flags = uint32(num) case 11: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Exemplars", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Exemplars = append(orig.Exemplars, Exemplar{}) err = orig.Exemplars[len(orig.Exemplars)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 12: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Min", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *ExponentialHistogramDataPoint_Min if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Min{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Min.Get().(*ExponentialHistogramDataPoint_Min) } ov.Min = math.Float64frombits(num) orig.Min_ = ov case 13: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *ExponentialHistogramDataPoint_Max if !UseProtoPooling.IsEnabled() { ov = &ExponentialHistogramDataPoint_Max{} } else { ov = ProtoPoolExponentialHistogramDataPoint_Max.Get().(*ExponentialHistogramDataPoint_Max) } ov.Max = math.Float64frombits(num) orig.Max_ = ov case 14: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field ZeroThreshold", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.ZeroThreshold = math.Float64frombits(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExponentialHistogramDataPoint() *ExponentialHistogramDataPoint { orig := NewExponentialHistogramDataPoint() orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.StartTimeUnixNano = uint64(13) orig.TimeUnixNano = uint64(13) orig.Count = uint64(13) orig.Sum_ = &ExponentialHistogramDataPoint_Sum{Sum: float64(3.1415926)} orig.Scale = int32(13) orig.ZeroCount = uint64(13) orig.Positive = *GenTestExponentialHistogramDataPointBuckets() orig.Negative = *GenTestExponentialHistogramDataPointBuckets() orig.Flags = uint32(13) orig.Exemplars = []Exemplar{{}, *GenTestExemplar()} orig.Min_ = &ExponentialHistogramDataPoint_Min{Min: float64(3.1415926)} orig.Max_ = &ExponentialHistogramDataPoint_Max{Max: float64(3.1415926)} orig.ZeroThreshold = float64(3.1415926) return orig } func GenTestExponentialHistogramDataPointPtrSlice() []*ExponentialHistogramDataPoint { orig := make([]*ExponentialHistogramDataPoint, 5) orig[0] = NewExponentialHistogramDataPoint() orig[1] = GenTestExponentialHistogramDataPoint() orig[2] = NewExponentialHistogramDataPoint() orig[3] = GenTestExponentialHistogramDataPoint() orig[4] = NewExponentialHistogramDataPoint() return orig } func GenTestExponentialHistogramDataPointSlice() []ExponentialHistogramDataPoint { orig := make([]ExponentialHistogramDataPoint, 5) orig[1] = *GenTestExponentialHistogramDataPoint() orig[3] = *GenTestExponentialHistogramDataPoint() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exponentialhistogramdatapoint_test.go000066400000000000000000000225701511331344600344500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExponentialHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExponentialHistogramDataPoint() CopyExponentialHistogramDataPoint(dest, src) assert.Equal(t, src, dest) CopyExponentialHistogramDataPoint(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExponentialHistogramDataPointSlice(t *testing.T) { src := []ExponentialHistogramDataPoint{} dest := []ExponentialHistogramDataPoint{} // Test CopyTo empty dest = CopyExponentialHistogramDataPointSlice(dest, src) assert.Equal(t, []ExponentialHistogramDataPoint{}, dest) // Test CopyTo larger slice src = GenTestExponentialHistogramDataPointSlice() dest = CopyExponentialHistogramDataPointSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointSlice(), dest) // Test CopyTo same size slice dest = CopyExponentialHistogramDataPointSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointSlice(), dest) // Test CopyTo smaller size slice dest = CopyExponentialHistogramDataPointSlice(dest, []ExponentialHistogramDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExponentialHistogramDataPointSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointSlice(), dest) } func TestCopyExponentialHistogramDataPointPtrSlice(t *testing.T) { src := []*ExponentialHistogramDataPoint{} dest := []*ExponentialHistogramDataPoint{} // Test CopyTo empty dest = CopyExponentialHistogramDataPointPtrSlice(dest, src) assert.Equal(t, []*ExponentialHistogramDataPoint{}, dest) // Test CopyTo larger slice src = GenTestExponentialHistogramDataPointPtrSlice() dest = CopyExponentialHistogramDataPointPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExponentialHistogramDataPointPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExponentialHistogramDataPointPtrSlice(dest, []*ExponentialHistogramDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExponentialHistogramDataPointPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExponentialHistogramDataPointUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExponentialHistogramDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExponentialHistogramDataPoint(), dest) } func TestMarshalAndUnmarshalJSONExponentialHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExponentialHistogramDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExponentialHistogramDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExponentialHistogramDataPointFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExponentialHistogramDataPoint() { t.Run(name, func(t *testing.T) { dest := NewExponentialHistogramDataPoint() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExponentialHistogramDataPointUnknown(t *testing.T) { dest := NewExponentialHistogramDataPoint() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExponentialHistogramDataPoint(), dest) } func TestMarshalAndUnmarshalProtoExponentialHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExponentialHistogramDataPoint() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExponentialHistogramDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExponentialHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPoint() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.ExponentialHistogramDataPoint{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExponentialHistogramDataPoint() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExponentialHistogramDataPoint() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Attributes/wrong_wire_type": {0xc}, "Attributes/missing_value": {0xa}, "StartTimeUnixNano/wrong_wire_type": {0x14}, "StartTimeUnixNano/missing_value": {0x11}, "TimeUnixNano/wrong_wire_type": {0x1c}, "TimeUnixNano/missing_value": {0x19}, "Count/wrong_wire_type": {0x24}, "Count/missing_value": {0x21}, "Sum/wrong_wire_type": {0x2c}, "Sum/missing_value": {0x29}, "Scale/wrong_wire_type": {0x34}, "Scale/missing_value": {0x30}, "ZeroCount/wrong_wire_type": {0x3c}, "ZeroCount/missing_value": {0x39}, "Positive/wrong_wire_type": {0x44}, "Positive/missing_value": {0x42}, "Negative/wrong_wire_type": {0x4c}, "Negative/missing_value": {0x4a}, "Flags/wrong_wire_type": {0x54}, "Flags/missing_value": {0x50}, "Exemplars/wrong_wire_type": {0x5c}, "Exemplars/missing_value": {0x5a}, "Min/wrong_wire_type": {0x64}, "Min/missing_value": {0x61}, "Max/wrong_wire_type": {0x6c}, "Max/missing_value": {0x69}, "ZeroThreshold/wrong_wire_type": {0x74}, "ZeroThreshold/missing_value": {0x71}, } } func genTestEncodingValuesExponentialHistogramDataPoint() map[string]*ExponentialHistogramDataPoint { return map[string]*ExponentialHistogramDataPoint{ "empty": NewExponentialHistogramDataPoint(), "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "StartTimeUnixNano/test": {StartTimeUnixNano: uint64(13)}, "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "Count/test": {Count: uint64(13)}, "Sum/default": {Sum_: &ExponentialHistogramDataPoint_Sum{Sum: float64(0)}}, "Sum/test": {Sum_: &ExponentialHistogramDataPoint_Sum{Sum: float64(3.1415926)}}, "Scale/test": {Scale: int32(13)}, "ZeroCount/test": {ZeroCount: uint64(13)}, "Positive/test": {Positive: *GenTestExponentialHistogramDataPointBuckets()}, "Negative/test": {Negative: *GenTestExponentialHistogramDataPointBuckets()}, "Flags/test": {Flags: uint32(13)}, "Exemplars/test": {Exemplars: []Exemplar{{}, *GenTestExemplar()}}, "Min/default": {Min_: &ExponentialHistogramDataPoint_Min{Min: float64(0)}}, "Min/test": {Min_: &ExponentialHistogramDataPoint_Min{Min: float64(3.1415926)}}, "Max/default": {Max_: &ExponentialHistogramDataPoint_Max{Max: float64(0)}}, "Max/test": {Max_: &ExponentialHistogramDataPoint_Max{Max: float64(3.1415926)}}, "ZeroThreshold/test": {ZeroThreshold: float64(3.1415926)}, } } generated_proto_exponentialhistogramdatapointbuckets.go000066400000000000000000000200031511331344600347000ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExponentialHistogramDataPointBuckets are a set of bucket counts, encoded in a contiguous array of counts. type ExponentialHistogramDataPointBuckets struct { Offset int32 BucketCounts []uint64 } var ( protoPoolExponentialHistogramDataPointBuckets = sync.Pool{ New: func() any { return &ExponentialHistogramDataPointBuckets{} }, } ) func NewExponentialHistogramDataPointBuckets() *ExponentialHistogramDataPointBuckets { if !UseProtoPooling.IsEnabled() { return &ExponentialHistogramDataPointBuckets{} } return protoPoolExponentialHistogramDataPointBuckets.Get().(*ExponentialHistogramDataPointBuckets) } func DeleteExponentialHistogramDataPointBuckets(orig *ExponentialHistogramDataPointBuckets, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolExponentialHistogramDataPointBuckets.Put(orig) } } func CopyExponentialHistogramDataPointBuckets(dest, src *ExponentialHistogramDataPointBuckets) *ExponentialHistogramDataPointBuckets { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExponentialHistogramDataPointBuckets() } dest.Offset = src.Offset dest.BucketCounts = append(dest.BucketCounts[:0], src.BucketCounts...) return dest } func CopyExponentialHistogramDataPointBucketsSlice(dest, src []ExponentialHistogramDataPointBuckets) []ExponentialHistogramDataPointBuckets { var newDest []ExponentialHistogramDataPointBuckets if cap(dest) < len(src) { newDest = make([]ExponentialHistogramDataPointBuckets, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExponentialHistogramDataPointBuckets(&dest[i], false) } } for i := range src { CopyExponentialHistogramDataPointBuckets(&newDest[i], &src[i]) } return newDest } func CopyExponentialHistogramDataPointBucketsPtrSlice(dest, src []*ExponentialHistogramDataPointBuckets) []*ExponentialHistogramDataPointBuckets { var newDest []*ExponentialHistogramDataPointBuckets if cap(dest) < len(src) { newDest = make([]*ExponentialHistogramDataPointBuckets, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExponentialHistogramDataPointBuckets() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExponentialHistogramDataPointBuckets(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExponentialHistogramDataPointBuckets() } } for i := range src { CopyExponentialHistogramDataPointBuckets(newDest[i], src[i]) } return newDest } func (orig *ExponentialHistogramDataPointBuckets) Reset() { *orig = ExponentialHistogramDataPointBuckets{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExponentialHistogramDataPointBuckets) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.Offset != int32(0) { dest.WriteObjectField("offset") dest.WriteInt32(orig.Offset) } if len(orig.BucketCounts) > 0 { dest.WriteObjectField("bucketCounts") dest.WriteArrayStart() dest.WriteUint64(orig.BucketCounts[0]) for i := 1; i < len(orig.BucketCounts); i++ { dest.WriteMore() dest.WriteUint64(orig.BucketCounts[i]) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExponentialHistogramDataPointBuckets) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "offset": orig.Offset = iter.ReadInt32() case "bucketCounts", "bucket_counts": for iter.ReadArray() { orig.BucketCounts = append(orig.BucketCounts, iter.ReadUint64()) } default: iter.Skip() } } } func (orig *ExponentialHistogramDataPointBuckets) SizeProto() int { var n int var l int _ = l if orig.Offset != 0 { n += 1 + proto.Soz(uint64(orig.Offset)) } if len(orig.BucketCounts) > 0 { l = 0 for _, e := range orig.BucketCounts { l += proto.Sov(uint64(e)) } n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExponentialHistogramDataPointBuckets) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.Offset != 0 { pos = proto.EncodeVarint(buf, pos, uint64((uint32(orig.Offset)<<1)^uint32(orig.Offset>>31))) pos-- buf[pos] = 0x8 } l = len(orig.BucketCounts) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.BucketCounts[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) pos-- buf[pos] = 0x12 } return len(buf) - pos } func (orig *ExponentialHistogramDataPointBuckets) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Offset", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Offset = int32(uint32(num>>1) ^ uint32(int32((num&1)<<31)>>31)) case 2: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.BucketCounts = append(orig.BucketCounts, uint64(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field BucketCounts", pos-startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.BucketCounts = append(orig.BucketCounts, uint64(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field BucketCounts", wireType) } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExponentialHistogramDataPointBuckets() *ExponentialHistogramDataPointBuckets { orig := NewExponentialHistogramDataPointBuckets() orig.Offset = int32(13) orig.BucketCounts = []uint64{uint64(0), uint64(13)} return orig } func GenTestExponentialHistogramDataPointBucketsPtrSlice() []*ExponentialHistogramDataPointBuckets { orig := make([]*ExponentialHistogramDataPointBuckets, 5) orig[0] = NewExponentialHistogramDataPointBuckets() orig[1] = GenTestExponentialHistogramDataPointBuckets() orig[2] = NewExponentialHistogramDataPointBuckets() orig[3] = GenTestExponentialHistogramDataPointBuckets() orig[4] = NewExponentialHistogramDataPointBuckets() return orig } func GenTestExponentialHistogramDataPointBucketsSlice() []ExponentialHistogramDataPointBuckets { orig := make([]ExponentialHistogramDataPointBuckets, 5) orig[1] = *GenTestExponentialHistogramDataPointBuckets() orig[3] = *GenTestExponentialHistogramDataPointBuckets() return orig } generated_proto_exponentialhistogramdatapointbuckets_test.go000066400000000000000000000172031511331344600357470ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExponentialHistogramDataPointBuckets(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPointBuckets() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExponentialHistogramDataPointBuckets() CopyExponentialHistogramDataPointBuckets(dest, src) assert.Equal(t, src, dest) CopyExponentialHistogramDataPointBuckets(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExponentialHistogramDataPointBucketsSlice(t *testing.T) { src := []ExponentialHistogramDataPointBuckets{} dest := []ExponentialHistogramDataPointBuckets{} // Test CopyTo empty dest = CopyExponentialHistogramDataPointBucketsSlice(dest, src) assert.Equal(t, []ExponentialHistogramDataPointBuckets{}, dest) // Test CopyTo larger slice src = GenTestExponentialHistogramDataPointBucketsSlice() dest = CopyExponentialHistogramDataPointBucketsSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointBucketsSlice(), dest) // Test CopyTo same size slice dest = CopyExponentialHistogramDataPointBucketsSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointBucketsSlice(), dest) // Test CopyTo smaller size slice dest = CopyExponentialHistogramDataPointBucketsSlice(dest, []ExponentialHistogramDataPointBuckets{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExponentialHistogramDataPointBucketsSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointBucketsSlice(), dest) } func TestCopyExponentialHistogramDataPointBucketsPtrSlice(t *testing.T) { src := []*ExponentialHistogramDataPointBuckets{} dest := []*ExponentialHistogramDataPointBuckets{} // Test CopyTo empty dest = CopyExponentialHistogramDataPointBucketsPtrSlice(dest, src) assert.Equal(t, []*ExponentialHistogramDataPointBuckets{}, dest) // Test CopyTo larger slice src = GenTestExponentialHistogramDataPointBucketsPtrSlice() dest = CopyExponentialHistogramDataPointBucketsPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointBucketsPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExponentialHistogramDataPointBucketsPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointBucketsPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExponentialHistogramDataPointBucketsPtrSlice(dest, []*ExponentialHistogramDataPointBuckets{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExponentialHistogramDataPointBucketsPtrSlice(dest, src) assert.Equal(t, GenTestExponentialHistogramDataPointBucketsPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExponentialHistogramDataPointBucketsUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExponentialHistogramDataPointBuckets() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExponentialHistogramDataPointBuckets(), dest) } func TestMarshalAndUnmarshalJSONExponentialHistogramDataPointBuckets(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPointBuckets() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExponentialHistogramDataPointBuckets() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExponentialHistogramDataPointBuckets(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExponentialHistogramDataPointBucketsFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExponentialHistogramDataPointBuckets() { t.Run(name, func(t *testing.T) { dest := NewExponentialHistogramDataPointBuckets() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExponentialHistogramDataPointBucketsUnknown(t *testing.T) { dest := NewExponentialHistogramDataPointBuckets() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExponentialHistogramDataPointBuckets(), dest) } func TestMarshalAndUnmarshalProtoExponentialHistogramDataPointBuckets(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPointBuckets() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExponentialHistogramDataPointBuckets() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExponentialHistogramDataPointBuckets(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExponentialHistogramDataPointBuckets(t *testing.T) { for name, src := range genTestEncodingValuesExponentialHistogramDataPointBuckets() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.ExponentialHistogramDataPoint_Buckets{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExponentialHistogramDataPointBuckets() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExponentialHistogramDataPointBuckets() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Offset/wrong_wire_type": {0xc}, "Offset/missing_value": {0x8}, "BucketCounts/wrong_wire_type": {0x14}, "BucketCounts/missing_value": {0x12}, } } func genTestEncodingValuesExponentialHistogramDataPointBuckets() map[string]*ExponentialHistogramDataPointBuckets { return map[string]*ExponentialHistogramDataPointBuckets{ "empty": NewExponentialHistogramDataPointBuckets(), "Offset/test": {Offset: int32(13)}, "BucketCounts/test": {BucketCounts: []uint64{uint64(0), uint64(13)}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportlogspartialsuccess.go000066400000000000000000000150371511331344600324150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportPartialSuccess represents the details of a partially successful export request. type ExportLogsPartialSuccess struct { RejectedLogRecords int64 ErrorMessage string } var ( protoPoolExportLogsPartialSuccess = sync.Pool{ New: func() any { return &ExportLogsPartialSuccess{} }, } ) func NewExportLogsPartialSuccess() *ExportLogsPartialSuccess { if !UseProtoPooling.IsEnabled() { return &ExportLogsPartialSuccess{} } return protoPoolExportLogsPartialSuccess.Get().(*ExportLogsPartialSuccess) } func DeleteExportLogsPartialSuccess(orig *ExportLogsPartialSuccess, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolExportLogsPartialSuccess.Put(orig) } } func CopyExportLogsPartialSuccess(dest, src *ExportLogsPartialSuccess) *ExportLogsPartialSuccess { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportLogsPartialSuccess() } dest.RejectedLogRecords = src.RejectedLogRecords dest.ErrorMessage = src.ErrorMessage return dest } func CopyExportLogsPartialSuccessSlice(dest, src []ExportLogsPartialSuccess) []ExportLogsPartialSuccess { var newDest []ExportLogsPartialSuccess if cap(dest) < len(src) { newDest = make([]ExportLogsPartialSuccess, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportLogsPartialSuccess(&dest[i], false) } } for i := range src { CopyExportLogsPartialSuccess(&newDest[i], &src[i]) } return newDest } func CopyExportLogsPartialSuccessPtrSlice(dest, src []*ExportLogsPartialSuccess) []*ExportLogsPartialSuccess { var newDest []*ExportLogsPartialSuccess if cap(dest) < len(src) { newDest = make([]*ExportLogsPartialSuccess, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportLogsPartialSuccess() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportLogsPartialSuccess(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportLogsPartialSuccess() } } for i := range src { CopyExportLogsPartialSuccess(newDest[i], src[i]) } return newDest } func (orig *ExportLogsPartialSuccess) Reset() { *orig = ExportLogsPartialSuccess{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportLogsPartialSuccess) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RejectedLogRecords != int64(0) { dest.WriteObjectField("rejectedLogRecords") dest.WriteInt64(orig.RejectedLogRecords) } if orig.ErrorMessage != "" { dest.WriteObjectField("errorMessage") dest.WriteString(orig.ErrorMessage) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportLogsPartialSuccess) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "rejectedLogRecords", "rejected_log_records": orig.RejectedLogRecords = iter.ReadInt64() case "errorMessage", "error_message": orig.ErrorMessage = iter.ReadString() default: iter.Skip() } } } func (orig *ExportLogsPartialSuccess) SizeProto() int { var n int var l int _ = l if orig.RejectedLogRecords != 0 { n += 1 + proto.Sov(uint64(orig.RejectedLogRecords)) } l = len(orig.ErrorMessage) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExportLogsPartialSuccess) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RejectedLogRecords != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.RejectedLogRecords)) pos-- buf[pos] = 0x8 } l = len(orig.ErrorMessage) if l > 0 { pos -= l copy(buf[pos:], orig.ErrorMessage) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } return len(buf) - pos } func (orig *ExportLogsPartialSuccess) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field RejectedLogRecords", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.RejectedLogRecords = int64(num) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ErrorMessage = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportLogsPartialSuccess() *ExportLogsPartialSuccess { orig := NewExportLogsPartialSuccess() orig.RejectedLogRecords = int64(13) orig.ErrorMessage = "test_errormessage" return orig } func GenTestExportLogsPartialSuccessPtrSlice() []*ExportLogsPartialSuccess { orig := make([]*ExportLogsPartialSuccess, 5) orig[0] = NewExportLogsPartialSuccess() orig[1] = GenTestExportLogsPartialSuccess() orig[2] = NewExportLogsPartialSuccess() orig[3] = GenTestExportLogsPartialSuccess() orig[4] = NewExportLogsPartialSuccess() return orig } func GenTestExportLogsPartialSuccessSlice() []ExportLogsPartialSuccess { orig := make([]ExportLogsPartialSuccess, 5) orig[1] = *GenTestExportLogsPartialSuccess() orig[3] = *GenTestExportLogsPartialSuccess() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportlogspartialsuccess_test.go000066400000000000000000000160011511331344600334440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorlogs "go.opentelemetry.io/proto/slim/otlp/collector/logs/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportLogsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportLogsPartialSuccess() CopyExportLogsPartialSuccess(dest, src) assert.Equal(t, src, dest) CopyExportLogsPartialSuccess(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportLogsPartialSuccessSlice(t *testing.T) { src := []ExportLogsPartialSuccess{} dest := []ExportLogsPartialSuccess{} // Test CopyTo empty dest = CopyExportLogsPartialSuccessSlice(dest, src) assert.Equal(t, []ExportLogsPartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportLogsPartialSuccessSlice() dest = CopyExportLogsPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportLogsPartialSuccessSlice(), dest) // Test CopyTo same size slice dest = CopyExportLogsPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportLogsPartialSuccessSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportLogsPartialSuccessSlice(dest, []ExportLogsPartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportLogsPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportLogsPartialSuccessSlice(), dest) } func TestCopyExportLogsPartialSuccessPtrSlice(t *testing.T) { src := []*ExportLogsPartialSuccess{} dest := []*ExportLogsPartialSuccess{} // Test CopyTo empty dest = CopyExportLogsPartialSuccessPtrSlice(dest, src) assert.Equal(t, []*ExportLogsPartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportLogsPartialSuccessPtrSlice() dest = CopyExportLogsPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportLogsPartialSuccessPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportLogsPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportLogsPartialSuccessPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportLogsPartialSuccessPtrSlice(dest, []*ExportLogsPartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportLogsPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportLogsPartialSuccessPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportLogsPartialSuccessUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportLogsPartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportLogsPartialSuccess(), dest) } func TestMarshalAndUnmarshalJSONExportLogsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportLogsPartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportLogsPartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportLogsPartialSuccessFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportLogsPartialSuccess() { t.Run(name, func(t *testing.T) { dest := NewExportLogsPartialSuccess() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportLogsPartialSuccessUnknown(t *testing.T) { dest := NewExportLogsPartialSuccess() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportLogsPartialSuccess(), dest) } func TestMarshalAndUnmarshalProtoExportLogsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportLogsPartialSuccess() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportLogsPartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportLogsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsPartialSuccess() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectorlogs.ExportLogsPartialSuccess{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportLogsPartialSuccess() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportLogsPartialSuccess() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RejectedLogRecords/wrong_wire_type": {0xc}, "RejectedLogRecords/missing_value": {0x8}, "ErrorMessage/wrong_wire_type": {0x14}, "ErrorMessage/missing_value": {0x12}, } } func genTestEncodingValuesExportLogsPartialSuccess() map[string]*ExportLogsPartialSuccess { return map[string]*ExportLogsPartialSuccess{ "empty": NewExportLogsPartialSuccess(), "RejectedLogRecords/test": {RejectedLogRecords: int64(13)}, "ErrorMessage/test": {ErrorMessage: "test_errormessage"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportlogsservicerequest.go000066400000000000000000000146351511331344600324440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Logs is the top-level struct that is propagated through the logs pipeline. // Use NewLogs to create new instance, zero-initialized instance is not valid for use. type ExportLogsServiceRequest struct { ResourceLogs []*ResourceLogs } var ( protoPoolExportLogsServiceRequest = sync.Pool{ New: func() any { return &ExportLogsServiceRequest{} }, } ) func NewExportLogsServiceRequest() *ExportLogsServiceRequest { if !UseProtoPooling.IsEnabled() { return &ExportLogsServiceRequest{} } return protoPoolExportLogsServiceRequest.Get().(*ExportLogsServiceRequest) } func DeleteExportLogsServiceRequest(orig *ExportLogsServiceRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceLogs { DeleteResourceLogs(orig.ResourceLogs[i], true) } orig.Reset() if nullable { protoPoolExportLogsServiceRequest.Put(orig) } } func CopyExportLogsServiceRequest(dest, src *ExportLogsServiceRequest) *ExportLogsServiceRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportLogsServiceRequest() } dest.ResourceLogs = CopyResourceLogsPtrSlice(dest.ResourceLogs, src.ResourceLogs) return dest } func CopyExportLogsServiceRequestSlice(dest, src []ExportLogsServiceRequest) []ExportLogsServiceRequest { var newDest []ExportLogsServiceRequest if cap(dest) < len(src) { newDest = make([]ExportLogsServiceRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportLogsServiceRequest(&dest[i], false) } } for i := range src { CopyExportLogsServiceRequest(&newDest[i], &src[i]) } return newDest } func CopyExportLogsServiceRequestPtrSlice(dest, src []*ExportLogsServiceRequest) []*ExportLogsServiceRequest { var newDest []*ExportLogsServiceRequest if cap(dest) < len(src) { newDest = make([]*ExportLogsServiceRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportLogsServiceRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportLogsServiceRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportLogsServiceRequest() } } for i := range src { CopyExportLogsServiceRequest(newDest[i], src[i]) } return newDest } func (orig *ExportLogsServiceRequest) Reset() { *orig = ExportLogsServiceRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportLogsServiceRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceLogs) > 0 { dest.WriteObjectField("resourceLogs") dest.WriteArrayStart() orig.ResourceLogs[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceLogs); i++ { dest.WriteMore() orig.ResourceLogs[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportLogsServiceRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceLogs", "resource_logs": for iter.ReadArray() { orig.ResourceLogs = append(orig.ResourceLogs, NewResourceLogs()) orig.ResourceLogs[len(orig.ResourceLogs)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ExportLogsServiceRequest) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceLogs { l = orig.ResourceLogs[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExportLogsServiceRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceLogs) - 1; i >= 0; i-- { l = orig.ResourceLogs[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *ExportLogsServiceRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceLogs", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceLogs = append(orig.ResourceLogs, NewResourceLogs()) err = orig.ResourceLogs[len(orig.ResourceLogs)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportLogsServiceRequest() *ExportLogsServiceRequest { orig := NewExportLogsServiceRequest() orig.ResourceLogs = []*ResourceLogs{{}, GenTestResourceLogs()} return orig } func GenTestExportLogsServiceRequestPtrSlice() []*ExportLogsServiceRequest { orig := make([]*ExportLogsServiceRequest, 5) orig[0] = NewExportLogsServiceRequest() orig[1] = GenTestExportLogsServiceRequest() orig[2] = NewExportLogsServiceRequest() orig[3] = GenTestExportLogsServiceRequest() orig[4] = NewExportLogsServiceRequest() return orig } func GenTestExportLogsServiceRequestSlice() []ExportLogsServiceRequest { orig := make([]ExportLogsServiceRequest, 5) orig[1] = *GenTestExportLogsServiceRequest() orig[3] = *GenTestExportLogsServiceRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportlogsservicerequest_test.go000066400000000000000000000155341511331344600335020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorlogs "go.opentelemetry.io/proto/slim/otlp/collector/logs/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportLogsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportLogsServiceRequest() CopyExportLogsServiceRequest(dest, src) assert.Equal(t, src, dest) CopyExportLogsServiceRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportLogsServiceRequestSlice(t *testing.T) { src := []ExportLogsServiceRequest{} dest := []ExportLogsServiceRequest{} // Test CopyTo empty dest = CopyExportLogsServiceRequestSlice(dest, src) assert.Equal(t, []ExportLogsServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportLogsServiceRequestSlice() dest = CopyExportLogsServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceRequestSlice(), dest) // Test CopyTo same size slice dest = CopyExportLogsServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportLogsServiceRequestSlice(dest, []ExportLogsServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportLogsServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceRequestSlice(), dest) } func TestCopyExportLogsServiceRequestPtrSlice(t *testing.T) { src := []*ExportLogsServiceRequest{} dest := []*ExportLogsServiceRequest{} // Test CopyTo empty dest = CopyExportLogsServiceRequestPtrSlice(dest, src) assert.Equal(t, []*ExportLogsServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportLogsServiceRequestPtrSlice() dest = CopyExportLogsServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportLogsServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportLogsServiceRequestPtrSlice(dest, []*ExportLogsServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportLogsServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportLogsServiceRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportLogsServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportLogsServiceRequest(), dest) } func TestMarshalAndUnmarshalJSONExportLogsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportLogsServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportLogsServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportLogsServiceRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportLogsServiceRequest() { t.Run(name, func(t *testing.T) { dest := NewExportLogsServiceRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportLogsServiceRequestUnknown(t *testing.T) { dest := NewExportLogsServiceRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportLogsServiceRequest(), dest) } func TestMarshalAndUnmarshalProtoExportLogsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportLogsServiceRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportLogsServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportLogsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectorlogs.ExportLogsServiceRequest{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportLogsServiceRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportLogsServiceRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceLogs/wrong_wire_type": {0xc}, "ResourceLogs/missing_value": {0xa}, } } func genTestEncodingValuesExportLogsServiceRequest() map[string]*ExportLogsServiceRequest { return map[string]*ExportLogsServiceRequest{ "empty": NewExportLogsServiceRequest(), "ResourceLogs/test": {ResourceLogs: []*ResourceLogs{{}, GenTestResourceLogs()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportlogsserviceresponse.go000066400000000000000000000135261511331344600326100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportResponse represents the response for gRPC/HTTP client/server. type ExportLogsServiceResponse struct { PartialSuccess ExportLogsPartialSuccess } var ( protoPoolExportLogsServiceResponse = sync.Pool{ New: func() any { return &ExportLogsServiceResponse{} }, } ) func NewExportLogsServiceResponse() *ExportLogsServiceResponse { if !UseProtoPooling.IsEnabled() { return &ExportLogsServiceResponse{} } return protoPoolExportLogsServiceResponse.Get().(*ExportLogsServiceResponse) } func DeleteExportLogsServiceResponse(orig *ExportLogsServiceResponse, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteExportLogsPartialSuccess(&orig.PartialSuccess, false) orig.Reset() if nullable { protoPoolExportLogsServiceResponse.Put(orig) } } func CopyExportLogsServiceResponse(dest, src *ExportLogsServiceResponse) *ExportLogsServiceResponse { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportLogsServiceResponse() } CopyExportLogsPartialSuccess(&dest.PartialSuccess, &src.PartialSuccess) return dest } func CopyExportLogsServiceResponseSlice(dest, src []ExportLogsServiceResponse) []ExportLogsServiceResponse { var newDest []ExportLogsServiceResponse if cap(dest) < len(src) { newDest = make([]ExportLogsServiceResponse, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportLogsServiceResponse(&dest[i], false) } } for i := range src { CopyExportLogsServiceResponse(&newDest[i], &src[i]) } return newDest } func CopyExportLogsServiceResponsePtrSlice(dest, src []*ExportLogsServiceResponse) []*ExportLogsServiceResponse { var newDest []*ExportLogsServiceResponse if cap(dest) < len(src) { newDest = make([]*ExportLogsServiceResponse, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportLogsServiceResponse() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportLogsServiceResponse(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportLogsServiceResponse() } } for i := range src { CopyExportLogsServiceResponse(newDest[i], src[i]) } return newDest } func (orig *ExportLogsServiceResponse) Reset() { *orig = ExportLogsServiceResponse{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportLogsServiceResponse) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("partialSuccess") orig.PartialSuccess.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportLogsServiceResponse) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "partialSuccess", "partial_success": orig.PartialSuccess.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *ExportLogsServiceResponse) SizeProto() int { var n int var l int _ = l l = orig.PartialSuccess.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *ExportLogsServiceResponse) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.PartialSuccess.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa return len(buf) - pos } func (orig *ExportLogsServiceResponse) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field PartialSuccess", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.PartialSuccess.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportLogsServiceResponse() *ExportLogsServiceResponse { orig := NewExportLogsServiceResponse() orig.PartialSuccess = *GenTestExportLogsPartialSuccess() return orig } func GenTestExportLogsServiceResponsePtrSlice() []*ExportLogsServiceResponse { orig := make([]*ExportLogsServiceResponse, 5) orig[0] = NewExportLogsServiceResponse() orig[1] = GenTestExportLogsServiceResponse() orig[2] = NewExportLogsServiceResponse() orig[3] = GenTestExportLogsServiceResponse() orig[4] = NewExportLogsServiceResponse() return orig } func GenTestExportLogsServiceResponseSlice() []ExportLogsServiceResponse { orig := make([]ExportLogsServiceResponse, 5) orig[1] = *GenTestExportLogsServiceResponse() orig[3] = *GenTestExportLogsServiceResponse() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportlogsserviceresponse_test.go000066400000000000000000000156331511331344600336500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorlogs "go.opentelemetry.io/proto/slim/otlp/collector/logs/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportLogsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportLogsServiceResponse() CopyExportLogsServiceResponse(dest, src) assert.Equal(t, src, dest) CopyExportLogsServiceResponse(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportLogsServiceResponseSlice(t *testing.T) { src := []ExportLogsServiceResponse{} dest := []ExportLogsServiceResponse{} // Test CopyTo empty dest = CopyExportLogsServiceResponseSlice(dest, src) assert.Equal(t, []ExportLogsServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportLogsServiceResponseSlice() dest = CopyExportLogsServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceResponseSlice(), dest) // Test CopyTo same size slice dest = CopyExportLogsServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceResponseSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportLogsServiceResponseSlice(dest, []ExportLogsServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportLogsServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceResponseSlice(), dest) } func TestCopyExportLogsServiceResponsePtrSlice(t *testing.T) { src := []*ExportLogsServiceResponse{} dest := []*ExportLogsServiceResponse{} // Test CopyTo empty dest = CopyExportLogsServiceResponsePtrSlice(dest, src) assert.Equal(t, []*ExportLogsServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportLogsServiceResponsePtrSlice() dest = CopyExportLogsServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceResponsePtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportLogsServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceResponsePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportLogsServiceResponsePtrSlice(dest, []*ExportLogsServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportLogsServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportLogsServiceResponsePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportLogsServiceResponseUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportLogsServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportLogsServiceResponse(), dest) } func TestMarshalAndUnmarshalJSONExportLogsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportLogsServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportLogsServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportLogsServiceResponseFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportLogsServiceResponse() { t.Run(name, func(t *testing.T) { dest := NewExportLogsServiceResponse() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportLogsServiceResponseUnknown(t *testing.T) { dest := NewExportLogsServiceResponse() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportLogsServiceResponse(), dest) } func TestMarshalAndUnmarshalProtoExportLogsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportLogsServiceResponse() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportLogsServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportLogsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportLogsServiceResponse() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectorlogs.ExportLogsServiceResponse{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportLogsServiceResponse() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportLogsServiceResponse() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "PartialSuccess/wrong_wire_type": {0xc}, "PartialSuccess/missing_value": {0xa}, } } func genTestEncodingValuesExportLogsServiceResponse() map[string]*ExportLogsServiceResponse { return map[string]*ExportLogsServiceResponse{ "empty": NewExportLogsServiceResponse(), "PartialSuccess/test": {PartialSuccess: *GenTestExportLogsPartialSuccess()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportmetricspartialsuccess.go000066400000000000000000000153011511331344600331110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportPartialSuccess represents the details of a partially successful export request. type ExportMetricsPartialSuccess struct { RejectedDataPoints int64 ErrorMessage string } var ( protoPoolExportMetricsPartialSuccess = sync.Pool{ New: func() any { return &ExportMetricsPartialSuccess{} }, } ) func NewExportMetricsPartialSuccess() *ExportMetricsPartialSuccess { if !UseProtoPooling.IsEnabled() { return &ExportMetricsPartialSuccess{} } return protoPoolExportMetricsPartialSuccess.Get().(*ExportMetricsPartialSuccess) } func DeleteExportMetricsPartialSuccess(orig *ExportMetricsPartialSuccess, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolExportMetricsPartialSuccess.Put(orig) } } func CopyExportMetricsPartialSuccess(dest, src *ExportMetricsPartialSuccess) *ExportMetricsPartialSuccess { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportMetricsPartialSuccess() } dest.RejectedDataPoints = src.RejectedDataPoints dest.ErrorMessage = src.ErrorMessage return dest } func CopyExportMetricsPartialSuccessSlice(dest, src []ExportMetricsPartialSuccess) []ExportMetricsPartialSuccess { var newDest []ExportMetricsPartialSuccess if cap(dest) < len(src) { newDest = make([]ExportMetricsPartialSuccess, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportMetricsPartialSuccess(&dest[i], false) } } for i := range src { CopyExportMetricsPartialSuccess(&newDest[i], &src[i]) } return newDest } func CopyExportMetricsPartialSuccessPtrSlice(dest, src []*ExportMetricsPartialSuccess) []*ExportMetricsPartialSuccess { var newDest []*ExportMetricsPartialSuccess if cap(dest) < len(src) { newDest = make([]*ExportMetricsPartialSuccess, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportMetricsPartialSuccess() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportMetricsPartialSuccess(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportMetricsPartialSuccess() } } for i := range src { CopyExportMetricsPartialSuccess(newDest[i], src[i]) } return newDest } func (orig *ExportMetricsPartialSuccess) Reset() { *orig = ExportMetricsPartialSuccess{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportMetricsPartialSuccess) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RejectedDataPoints != int64(0) { dest.WriteObjectField("rejectedDataPoints") dest.WriteInt64(orig.RejectedDataPoints) } if orig.ErrorMessage != "" { dest.WriteObjectField("errorMessage") dest.WriteString(orig.ErrorMessage) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportMetricsPartialSuccess) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "rejectedDataPoints", "rejected_data_points": orig.RejectedDataPoints = iter.ReadInt64() case "errorMessage", "error_message": orig.ErrorMessage = iter.ReadString() default: iter.Skip() } } } func (orig *ExportMetricsPartialSuccess) SizeProto() int { var n int var l int _ = l if orig.RejectedDataPoints != 0 { n += 1 + proto.Sov(uint64(orig.RejectedDataPoints)) } l = len(orig.ErrorMessage) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExportMetricsPartialSuccess) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RejectedDataPoints != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.RejectedDataPoints)) pos-- buf[pos] = 0x8 } l = len(orig.ErrorMessage) if l > 0 { pos -= l copy(buf[pos:], orig.ErrorMessage) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } return len(buf) - pos } func (orig *ExportMetricsPartialSuccess) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field RejectedDataPoints", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.RejectedDataPoints = int64(num) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ErrorMessage = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportMetricsPartialSuccess() *ExportMetricsPartialSuccess { orig := NewExportMetricsPartialSuccess() orig.RejectedDataPoints = int64(13) orig.ErrorMessage = "test_errormessage" return orig } func GenTestExportMetricsPartialSuccessPtrSlice() []*ExportMetricsPartialSuccess { orig := make([]*ExportMetricsPartialSuccess, 5) orig[0] = NewExportMetricsPartialSuccess() orig[1] = GenTestExportMetricsPartialSuccess() orig[2] = NewExportMetricsPartialSuccess() orig[3] = GenTestExportMetricsPartialSuccess() orig[4] = NewExportMetricsPartialSuccess() return orig } func GenTestExportMetricsPartialSuccessSlice() []ExportMetricsPartialSuccess { orig := make([]ExportMetricsPartialSuccess, 5) orig[1] = *GenTestExportMetricsPartialSuccess() orig[3] = *GenTestExportMetricsPartialSuccess() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportmetricspartialsuccess_test.go000066400000000000000000000162731511331344600341610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectormetrics "go.opentelemetry.io/proto/slim/otlp/collector/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportMetricsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportMetricsPartialSuccess() CopyExportMetricsPartialSuccess(dest, src) assert.Equal(t, src, dest) CopyExportMetricsPartialSuccess(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportMetricsPartialSuccessSlice(t *testing.T) { src := []ExportMetricsPartialSuccess{} dest := []ExportMetricsPartialSuccess{} // Test CopyTo empty dest = CopyExportMetricsPartialSuccessSlice(dest, src) assert.Equal(t, []ExportMetricsPartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportMetricsPartialSuccessSlice() dest = CopyExportMetricsPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportMetricsPartialSuccessSlice(), dest) // Test CopyTo same size slice dest = CopyExportMetricsPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportMetricsPartialSuccessSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportMetricsPartialSuccessSlice(dest, []ExportMetricsPartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportMetricsPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportMetricsPartialSuccessSlice(), dest) } func TestCopyExportMetricsPartialSuccessPtrSlice(t *testing.T) { src := []*ExportMetricsPartialSuccess{} dest := []*ExportMetricsPartialSuccess{} // Test CopyTo empty dest = CopyExportMetricsPartialSuccessPtrSlice(dest, src) assert.Equal(t, []*ExportMetricsPartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportMetricsPartialSuccessPtrSlice() dest = CopyExportMetricsPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsPartialSuccessPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportMetricsPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsPartialSuccessPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportMetricsPartialSuccessPtrSlice(dest, []*ExportMetricsPartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportMetricsPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsPartialSuccessPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportMetricsPartialSuccessUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportMetricsPartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportMetricsPartialSuccess(), dest) } func TestMarshalAndUnmarshalJSONExportMetricsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportMetricsPartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportMetricsPartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportMetricsPartialSuccessFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportMetricsPartialSuccess() { t.Run(name, func(t *testing.T) { dest := NewExportMetricsPartialSuccess() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportMetricsPartialSuccessUnknown(t *testing.T) { dest := NewExportMetricsPartialSuccess() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportMetricsPartialSuccess(), dest) } func TestMarshalAndUnmarshalProtoExportMetricsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportMetricsPartialSuccess() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportMetricsPartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportMetricsPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsPartialSuccess() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectormetrics.ExportMetricsPartialSuccess{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportMetricsPartialSuccess() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportMetricsPartialSuccess() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RejectedDataPoints/wrong_wire_type": {0xc}, "RejectedDataPoints/missing_value": {0x8}, "ErrorMessage/wrong_wire_type": {0x14}, "ErrorMessage/missing_value": {0x12}, } } func genTestEncodingValuesExportMetricsPartialSuccess() map[string]*ExportMetricsPartialSuccess { return map[string]*ExportMetricsPartialSuccess{ "empty": NewExportMetricsPartialSuccess(), "RejectedDataPoints/test": {RejectedDataPoints: int64(13)}, "ErrorMessage/test": {ErrorMessage: "test_errormessage"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportmetricsservicerequest.go000066400000000000000000000152561511331344600331460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Metrics is the top-level struct that is propagated through the metrics pipeline. // Use NewMetrics to create new instance, zero-initialized instance is not valid for use. type ExportMetricsServiceRequest struct { ResourceMetrics []*ResourceMetrics } var ( protoPoolExportMetricsServiceRequest = sync.Pool{ New: func() any { return &ExportMetricsServiceRequest{} }, } ) func NewExportMetricsServiceRequest() *ExportMetricsServiceRequest { if !UseProtoPooling.IsEnabled() { return &ExportMetricsServiceRequest{} } return protoPoolExportMetricsServiceRequest.Get().(*ExportMetricsServiceRequest) } func DeleteExportMetricsServiceRequest(orig *ExportMetricsServiceRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceMetrics { DeleteResourceMetrics(orig.ResourceMetrics[i], true) } orig.Reset() if nullable { protoPoolExportMetricsServiceRequest.Put(orig) } } func CopyExportMetricsServiceRequest(dest, src *ExportMetricsServiceRequest) *ExportMetricsServiceRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportMetricsServiceRequest() } dest.ResourceMetrics = CopyResourceMetricsPtrSlice(dest.ResourceMetrics, src.ResourceMetrics) return dest } func CopyExportMetricsServiceRequestSlice(dest, src []ExportMetricsServiceRequest) []ExportMetricsServiceRequest { var newDest []ExportMetricsServiceRequest if cap(dest) < len(src) { newDest = make([]ExportMetricsServiceRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportMetricsServiceRequest(&dest[i], false) } } for i := range src { CopyExportMetricsServiceRequest(&newDest[i], &src[i]) } return newDest } func CopyExportMetricsServiceRequestPtrSlice(dest, src []*ExportMetricsServiceRequest) []*ExportMetricsServiceRequest { var newDest []*ExportMetricsServiceRequest if cap(dest) < len(src) { newDest = make([]*ExportMetricsServiceRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportMetricsServiceRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportMetricsServiceRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportMetricsServiceRequest() } } for i := range src { CopyExportMetricsServiceRequest(newDest[i], src[i]) } return newDest } func (orig *ExportMetricsServiceRequest) Reset() { *orig = ExportMetricsServiceRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportMetricsServiceRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceMetrics) > 0 { dest.WriteObjectField("resourceMetrics") dest.WriteArrayStart() orig.ResourceMetrics[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceMetrics); i++ { dest.WriteMore() orig.ResourceMetrics[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportMetricsServiceRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceMetrics", "resource_metrics": for iter.ReadArray() { orig.ResourceMetrics = append(orig.ResourceMetrics, NewResourceMetrics()) orig.ResourceMetrics[len(orig.ResourceMetrics)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ExportMetricsServiceRequest) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceMetrics { l = orig.ResourceMetrics[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExportMetricsServiceRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceMetrics) - 1; i >= 0; i-- { l = orig.ResourceMetrics[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *ExportMetricsServiceRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceMetrics", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceMetrics = append(orig.ResourceMetrics, NewResourceMetrics()) err = orig.ResourceMetrics[len(orig.ResourceMetrics)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportMetricsServiceRequest() *ExportMetricsServiceRequest { orig := NewExportMetricsServiceRequest() orig.ResourceMetrics = []*ResourceMetrics{{}, GenTestResourceMetrics()} return orig } func GenTestExportMetricsServiceRequestPtrSlice() []*ExportMetricsServiceRequest { orig := make([]*ExportMetricsServiceRequest, 5) orig[0] = NewExportMetricsServiceRequest() orig[1] = GenTestExportMetricsServiceRequest() orig[2] = NewExportMetricsServiceRequest() orig[3] = GenTestExportMetricsServiceRequest() orig[4] = NewExportMetricsServiceRequest() return orig } func GenTestExportMetricsServiceRequestSlice() []ExportMetricsServiceRequest { orig := make([]ExportMetricsServiceRequest, 5) orig[1] = *GenTestExportMetricsServiceRequest() orig[3] = *GenTestExportMetricsServiceRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportmetricsservicerequest_test.go000066400000000000000000000160561511331344600342040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectormetrics "go.opentelemetry.io/proto/slim/otlp/collector/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportMetricsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportMetricsServiceRequest() CopyExportMetricsServiceRequest(dest, src) assert.Equal(t, src, dest) CopyExportMetricsServiceRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportMetricsServiceRequestSlice(t *testing.T) { src := []ExportMetricsServiceRequest{} dest := []ExportMetricsServiceRequest{} // Test CopyTo empty dest = CopyExportMetricsServiceRequestSlice(dest, src) assert.Equal(t, []ExportMetricsServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportMetricsServiceRequestSlice() dest = CopyExportMetricsServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceRequestSlice(), dest) // Test CopyTo same size slice dest = CopyExportMetricsServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportMetricsServiceRequestSlice(dest, []ExportMetricsServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportMetricsServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceRequestSlice(), dest) } func TestCopyExportMetricsServiceRequestPtrSlice(t *testing.T) { src := []*ExportMetricsServiceRequest{} dest := []*ExportMetricsServiceRequest{} // Test CopyTo empty dest = CopyExportMetricsServiceRequestPtrSlice(dest, src) assert.Equal(t, []*ExportMetricsServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportMetricsServiceRequestPtrSlice() dest = CopyExportMetricsServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportMetricsServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportMetricsServiceRequestPtrSlice(dest, []*ExportMetricsServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportMetricsServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportMetricsServiceRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportMetricsServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportMetricsServiceRequest(), dest) } func TestMarshalAndUnmarshalJSONExportMetricsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportMetricsServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportMetricsServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportMetricsServiceRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportMetricsServiceRequest() { t.Run(name, func(t *testing.T) { dest := NewExportMetricsServiceRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportMetricsServiceRequestUnknown(t *testing.T) { dest := NewExportMetricsServiceRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportMetricsServiceRequest(), dest) } func TestMarshalAndUnmarshalProtoExportMetricsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportMetricsServiceRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportMetricsServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportMetricsServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectormetrics.ExportMetricsServiceRequest{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportMetricsServiceRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportMetricsServiceRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceMetrics/wrong_wire_type": {0xc}, "ResourceMetrics/missing_value": {0xa}, } } func genTestEncodingValuesExportMetricsServiceRequest() map[string]*ExportMetricsServiceRequest { return map[string]*ExportMetricsServiceRequest{ "empty": NewExportMetricsServiceRequest(), "ResourceMetrics/test": {ResourceMetrics: []*ResourceMetrics{{}, GenTestResourceMetrics()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportmetricsserviceresponse.go000066400000000000000000000140041511331344600333020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportResponse represents the response for gRPC/HTTP client/server. type ExportMetricsServiceResponse struct { PartialSuccess ExportMetricsPartialSuccess } var ( protoPoolExportMetricsServiceResponse = sync.Pool{ New: func() any { return &ExportMetricsServiceResponse{} }, } ) func NewExportMetricsServiceResponse() *ExportMetricsServiceResponse { if !UseProtoPooling.IsEnabled() { return &ExportMetricsServiceResponse{} } return protoPoolExportMetricsServiceResponse.Get().(*ExportMetricsServiceResponse) } func DeleteExportMetricsServiceResponse(orig *ExportMetricsServiceResponse, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteExportMetricsPartialSuccess(&orig.PartialSuccess, false) orig.Reset() if nullable { protoPoolExportMetricsServiceResponse.Put(orig) } } func CopyExportMetricsServiceResponse(dest, src *ExportMetricsServiceResponse) *ExportMetricsServiceResponse { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportMetricsServiceResponse() } CopyExportMetricsPartialSuccess(&dest.PartialSuccess, &src.PartialSuccess) return dest } func CopyExportMetricsServiceResponseSlice(dest, src []ExportMetricsServiceResponse) []ExportMetricsServiceResponse { var newDest []ExportMetricsServiceResponse if cap(dest) < len(src) { newDest = make([]ExportMetricsServiceResponse, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportMetricsServiceResponse(&dest[i], false) } } for i := range src { CopyExportMetricsServiceResponse(&newDest[i], &src[i]) } return newDest } func CopyExportMetricsServiceResponsePtrSlice(dest, src []*ExportMetricsServiceResponse) []*ExportMetricsServiceResponse { var newDest []*ExportMetricsServiceResponse if cap(dest) < len(src) { newDest = make([]*ExportMetricsServiceResponse, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportMetricsServiceResponse() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportMetricsServiceResponse(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportMetricsServiceResponse() } } for i := range src { CopyExportMetricsServiceResponse(newDest[i], src[i]) } return newDest } func (orig *ExportMetricsServiceResponse) Reset() { *orig = ExportMetricsServiceResponse{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportMetricsServiceResponse) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("partialSuccess") orig.PartialSuccess.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportMetricsServiceResponse) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "partialSuccess", "partial_success": orig.PartialSuccess.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *ExportMetricsServiceResponse) SizeProto() int { var n int var l int _ = l l = orig.PartialSuccess.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *ExportMetricsServiceResponse) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.PartialSuccess.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa return len(buf) - pos } func (orig *ExportMetricsServiceResponse) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field PartialSuccess", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.PartialSuccess.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportMetricsServiceResponse() *ExportMetricsServiceResponse { orig := NewExportMetricsServiceResponse() orig.PartialSuccess = *GenTestExportMetricsPartialSuccess() return orig } func GenTestExportMetricsServiceResponsePtrSlice() []*ExportMetricsServiceResponse { orig := make([]*ExportMetricsServiceResponse, 5) orig[0] = NewExportMetricsServiceResponse() orig[1] = GenTestExportMetricsServiceResponse() orig[2] = NewExportMetricsServiceResponse() orig[3] = GenTestExportMetricsServiceResponse() orig[4] = NewExportMetricsServiceResponse() return orig } func GenTestExportMetricsServiceResponseSlice() []ExportMetricsServiceResponse { orig := make([]ExportMetricsServiceResponse, 5) orig[1] = *GenTestExportMetricsServiceResponse() orig[3] = *GenTestExportMetricsServiceResponse() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportmetricsserviceresponse_test.go000066400000000000000000000161301511331344600343430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectormetrics "go.opentelemetry.io/proto/slim/otlp/collector/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportMetricsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportMetricsServiceResponse() CopyExportMetricsServiceResponse(dest, src) assert.Equal(t, src, dest) CopyExportMetricsServiceResponse(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportMetricsServiceResponseSlice(t *testing.T) { src := []ExportMetricsServiceResponse{} dest := []ExportMetricsServiceResponse{} // Test CopyTo empty dest = CopyExportMetricsServiceResponseSlice(dest, src) assert.Equal(t, []ExportMetricsServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportMetricsServiceResponseSlice() dest = CopyExportMetricsServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceResponseSlice(), dest) // Test CopyTo same size slice dest = CopyExportMetricsServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceResponseSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportMetricsServiceResponseSlice(dest, []ExportMetricsServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportMetricsServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceResponseSlice(), dest) } func TestCopyExportMetricsServiceResponsePtrSlice(t *testing.T) { src := []*ExportMetricsServiceResponse{} dest := []*ExportMetricsServiceResponse{} // Test CopyTo empty dest = CopyExportMetricsServiceResponsePtrSlice(dest, src) assert.Equal(t, []*ExportMetricsServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportMetricsServiceResponsePtrSlice() dest = CopyExportMetricsServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceResponsePtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportMetricsServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceResponsePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportMetricsServiceResponsePtrSlice(dest, []*ExportMetricsServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportMetricsServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportMetricsServiceResponsePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportMetricsServiceResponseUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportMetricsServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportMetricsServiceResponse(), dest) } func TestMarshalAndUnmarshalJSONExportMetricsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportMetricsServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportMetricsServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportMetricsServiceResponseFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportMetricsServiceResponse() { t.Run(name, func(t *testing.T) { dest := NewExportMetricsServiceResponse() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportMetricsServiceResponseUnknown(t *testing.T) { dest := NewExportMetricsServiceResponse() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportMetricsServiceResponse(), dest) } func TestMarshalAndUnmarshalProtoExportMetricsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportMetricsServiceResponse() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportMetricsServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportMetricsServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportMetricsServiceResponse() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectormetrics.ExportMetricsServiceResponse{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportMetricsServiceResponse() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportMetricsServiceResponse() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "PartialSuccess/wrong_wire_type": {0xc}, "PartialSuccess/missing_value": {0xa}, } } func genTestEncodingValuesExportMetricsServiceResponse() map[string]*ExportMetricsServiceResponse { return map[string]*ExportMetricsServiceResponse{ "empty": NewExportMetricsServiceResponse(), "PartialSuccess/test": {PartialSuccess: *GenTestExportMetricsPartialSuccess()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportprofilespartialsuccess.go000066400000000000000000000153241511331344600332730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportPartialSuccess represents the details of a partially successful export request. type ExportProfilesPartialSuccess struct { RejectedProfiles int64 ErrorMessage string } var ( protoPoolExportProfilesPartialSuccess = sync.Pool{ New: func() any { return &ExportProfilesPartialSuccess{} }, } ) func NewExportProfilesPartialSuccess() *ExportProfilesPartialSuccess { if !UseProtoPooling.IsEnabled() { return &ExportProfilesPartialSuccess{} } return protoPoolExportProfilesPartialSuccess.Get().(*ExportProfilesPartialSuccess) } func DeleteExportProfilesPartialSuccess(orig *ExportProfilesPartialSuccess, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolExportProfilesPartialSuccess.Put(orig) } } func CopyExportProfilesPartialSuccess(dest, src *ExportProfilesPartialSuccess) *ExportProfilesPartialSuccess { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportProfilesPartialSuccess() } dest.RejectedProfiles = src.RejectedProfiles dest.ErrorMessage = src.ErrorMessage return dest } func CopyExportProfilesPartialSuccessSlice(dest, src []ExportProfilesPartialSuccess) []ExportProfilesPartialSuccess { var newDest []ExportProfilesPartialSuccess if cap(dest) < len(src) { newDest = make([]ExportProfilesPartialSuccess, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportProfilesPartialSuccess(&dest[i], false) } } for i := range src { CopyExportProfilesPartialSuccess(&newDest[i], &src[i]) } return newDest } func CopyExportProfilesPartialSuccessPtrSlice(dest, src []*ExportProfilesPartialSuccess) []*ExportProfilesPartialSuccess { var newDest []*ExportProfilesPartialSuccess if cap(dest) < len(src) { newDest = make([]*ExportProfilesPartialSuccess, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportProfilesPartialSuccess() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportProfilesPartialSuccess(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportProfilesPartialSuccess() } } for i := range src { CopyExportProfilesPartialSuccess(newDest[i], src[i]) } return newDest } func (orig *ExportProfilesPartialSuccess) Reset() { *orig = ExportProfilesPartialSuccess{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportProfilesPartialSuccess) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RejectedProfiles != int64(0) { dest.WriteObjectField("rejectedProfiles") dest.WriteInt64(orig.RejectedProfiles) } if orig.ErrorMessage != "" { dest.WriteObjectField("errorMessage") dest.WriteString(orig.ErrorMessage) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportProfilesPartialSuccess) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "rejectedProfiles", "rejected_profiles": orig.RejectedProfiles = iter.ReadInt64() case "errorMessage", "error_message": orig.ErrorMessage = iter.ReadString() default: iter.Skip() } } } func (orig *ExportProfilesPartialSuccess) SizeProto() int { var n int var l int _ = l if orig.RejectedProfiles != 0 { n += 1 + proto.Sov(uint64(orig.RejectedProfiles)) } l = len(orig.ErrorMessage) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExportProfilesPartialSuccess) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RejectedProfiles != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.RejectedProfiles)) pos-- buf[pos] = 0x8 } l = len(orig.ErrorMessage) if l > 0 { pos -= l copy(buf[pos:], orig.ErrorMessage) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } return len(buf) - pos } func (orig *ExportProfilesPartialSuccess) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field RejectedProfiles", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.RejectedProfiles = int64(num) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ErrorMessage = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportProfilesPartialSuccess() *ExportProfilesPartialSuccess { orig := NewExportProfilesPartialSuccess() orig.RejectedProfiles = int64(13) orig.ErrorMessage = "test_errormessage" return orig } func GenTestExportProfilesPartialSuccessPtrSlice() []*ExportProfilesPartialSuccess { orig := make([]*ExportProfilesPartialSuccess, 5) orig[0] = NewExportProfilesPartialSuccess() orig[1] = GenTestExportProfilesPartialSuccess() orig[2] = NewExportProfilesPartialSuccess() orig[3] = GenTestExportProfilesPartialSuccess() orig[4] = NewExportProfilesPartialSuccess() return orig } func GenTestExportProfilesPartialSuccessSlice() []ExportProfilesPartialSuccess { orig := make([]ExportProfilesPartialSuccess, 5) orig[1] = *GenTestExportProfilesPartialSuccess() orig[3] = *GenTestExportProfilesPartialSuccess() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportprofilespartialsuccess_test.go000066400000000000000000000163621511331344600343350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorprofiles "go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportProfilesPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportProfilesPartialSuccess() CopyExportProfilesPartialSuccess(dest, src) assert.Equal(t, src, dest) CopyExportProfilesPartialSuccess(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportProfilesPartialSuccessSlice(t *testing.T) { src := []ExportProfilesPartialSuccess{} dest := []ExportProfilesPartialSuccess{} // Test CopyTo empty dest = CopyExportProfilesPartialSuccessSlice(dest, src) assert.Equal(t, []ExportProfilesPartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportProfilesPartialSuccessSlice() dest = CopyExportProfilesPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportProfilesPartialSuccessSlice(), dest) // Test CopyTo same size slice dest = CopyExportProfilesPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportProfilesPartialSuccessSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportProfilesPartialSuccessSlice(dest, []ExportProfilesPartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportProfilesPartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportProfilesPartialSuccessSlice(), dest) } func TestCopyExportProfilesPartialSuccessPtrSlice(t *testing.T) { src := []*ExportProfilesPartialSuccess{} dest := []*ExportProfilesPartialSuccess{} // Test CopyTo empty dest = CopyExportProfilesPartialSuccessPtrSlice(dest, src) assert.Equal(t, []*ExportProfilesPartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportProfilesPartialSuccessPtrSlice() dest = CopyExportProfilesPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesPartialSuccessPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportProfilesPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesPartialSuccessPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportProfilesPartialSuccessPtrSlice(dest, []*ExportProfilesPartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportProfilesPartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesPartialSuccessPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportProfilesPartialSuccessUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportProfilesPartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportProfilesPartialSuccess(), dest) } func TestMarshalAndUnmarshalJSONExportProfilesPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportProfilesPartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportProfilesPartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportProfilesPartialSuccessFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportProfilesPartialSuccess() { t.Run(name, func(t *testing.T) { dest := NewExportProfilesPartialSuccess() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportProfilesPartialSuccessUnknown(t *testing.T) { dest := NewExportProfilesPartialSuccess() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportProfilesPartialSuccess(), dest) } func TestMarshalAndUnmarshalProtoExportProfilesPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesPartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportProfilesPartialSuccess() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportProfilesPartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportProfilesPartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesPartialSuccess() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectorprofiles.ExportProfilesPartialSuccess{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportProfilesPartialSuccess() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportProfilesPartialSuccess() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RejectedProfiles/wrong_wire_type": {0xc}, "RejectedProfiles/missing_value": {0x8}, "ErrorMessage/wrong_wire_type": {0x14}, "ErrorMessage/missing_value": {0x12}, } } func genTestEncodingValuesExportProfilesPartialSuccess() map[string]*ExportProfilesPartialSuccess { return map[string]*ExportProfilesPartialSuccess{ "empty": NewExportProfilesPartialSuccess(), "RejectedProfiles/test": {RejectedProfiles: int64(13)}, "ErrorMessage/test": {ErrorMessage: "test_errormessage"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportprofilesservicerequest.go000066400000000000000000000172071511331344600333210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Profiles is the top-level struct that is propagated through the profiles pipeline. // Use NewProfiles to create new instance, zero-initialized instance is not valid for use. type ExportProfilesServiceRequest struct { ResourceProfiles []*ResourceProfiles Dictionary ProfilesDictionary } var ( protoPoolExportProfilesServiceRequest = sync.Pool{ New: func() any { return &ExportProfilesServiceRequest{} }, } ) func NewExportProfilesServiceRequest() *ExportProfilesServiceRequest { if !UseProtoPooling.IsEnabled() { return &ExportProfilesServiceRequest{} } return protoPoolExportProfilesServiceRequest.Get().(*ExportProfilesServiceRequest) } func DeleteExportProfilesServiceRequest(orig *ExportProfilesServiceRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceProfiles { DeleteResourceProfiles(orig.ResourceProfiles[i], true) } DeleteProfilesDictionary(&orig.Dictionary, false) orig.Reset() if nullable { protoPoolExportProfilesServiceRequest.Put(orig) } } func CopyExportProfilesServiceRequest(dest, src *ExportProfilesServiceRequest) *ExportProfilesServiceRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportProfilesServiceRequest() } dest.ResourceProfiles = CopyResourceProfilesPtrSlice(dest.ResourceProfiles, src.ResourceProfiles) CopyProfilesDictionary(&dest.Dictionary, &src.Dictionary) return dest } func CopyExportProfilesServiceRequestSlice(dest, src []ExportProfilesServiceRequest) []ExportProfilesServiceRequest { var newDest []ExportProfilesServiceRequest if cap(dest) < len(src) { newDest = make([]ExportProfilesServiceRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportProfilesServiceRequest(&dest[i], false) } } for i := range src { CopyExportProfilesServiceRequest(&newDest[i], &src[i]) } return newDest } func CopyExportProfilesServiceRequestPtrSlice(dest, src []*ExportProfilesServiceRequest) []*ExportProfilesServiceRequest { var newDest []*ExportProfilesServiceRequest if cap(dest) < len(src) { newDest = make([]*ExportProfilesServiceRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportProfilesServiceRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportProfilesServiceRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportProfilesServiceRequest() } } for i := range src { CopyExportProfilesServiceRequest(newDest[i], src[i]) } return newDest } func (orig *ExportProfilesServiceRequest) Reset() { *orig = ExportProfilesServiceRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportProfilesServiceRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceProfiles) > 0 { dest.WriteObjectField("resourceProfiles") dest.WriteArrayStart() orig.ResourceProfiles[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceProfiles); i++ { dest.WriteMore() orig.ResourceProfiles[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectField("dictionary") orig.Dictionary.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportProfilesServiceRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceProfiles", "resource_profiles": for iter.ReadArray() { orig.ResourceProfiles = append(orig.ResourceProfiles, NewResourceProfiles()) orig.ResourceProfiles[len(orig.ResourceProfiles)-1].UnmarshalJSON(iter) } case "dictionary": orig.Dictionary.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *ExportProfilesServiceRequest) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceProfiles { l = orig.ResourceProfiles[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = orig.Dictionary.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *ExportProfilesServiceRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceProfiles) - 1; i >= 0; i-- { l = orig.ResourceProfiles[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = orig.Dictionary.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 return len(buf) - pos } func (orig *ExportProfilesServiceRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceProfiles", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceProfiles = append(orig.ResourceProfiles, NewResourceProfiles()) err = orig.ResourceProfiles[len(orig.ResourceProfiles)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Dictionary", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Dictionary.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportProfilesServiceRequest() *ExportProfilesServiceRequest { orig := NewExportProfilesServiceRequest() orig.ResourceProfiles = []*ResourceProfiles{{}, GenTestResourceProfiles()} orig.Dictionary = *GenTestProfilesDictionary() return orig } func GenTestExportProfilesServiceRequestPtrSlice() []*ExportProfilesServiceRequest { orig := make([]*ExportProfilesServiceRequest, 5) orig[0] = NewExportProfilesServiceRequest() orig[1] = GenTestExportProfilesServiceRequest() orig[2] = NewExportProfilesServiceRequest() orig[3] = GenTestExportProfilesServiceRequest() orig[4] = NewExportProfilesServiceRequest() return orig } func GenTestExportProfilesServiceRequestSlice() []ExportProfilesServiceRequest { orig := make([]ExportProfilesServiceRequest, 5) orig[1] = *GenTestExportProfilesServiceRequest() orig[3] = *GenTestExportProfilesServiceRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportprofilesservicerequest_test.go000066400000000000000000000164421511331344600343600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorprofiles "go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportProfilesServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportProfilesServiceRequest() CopyExportProfilesServiceRequest(dest, src) assert.Equal(t, src, dest) CopyExportProfilesServiceRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportProfilesServiceRequestSlice(t *testing.T) { src := []ExportProfilesServiceRequest{} dest := []ExportProfilesServiceRequest{} // Test CopyTo empty dest = CopyExportProfilesServiceRequestSlice(dest, src) assert.Equal(t, []ExportProfilesServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportProfilesServiceRequestSlice() dest = CopyExportProfilesServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceRequestSlice(), dest) // Test CopyTo same size slice dest = CopyExportProfilesServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportProfilesServiceRequestSlice(dest, []ExportProfilesServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportProfilesServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceRequestSlice(), dest) } func TestCopyExportProfilesServiceRequestPtrSlice(t *testing.T) { src := []*ExportProfilesServiceRequest{} dest := []*ExportProfilesServiceRequest{} // Test CopyTo empty dest = CopyExportProfilesServiceRequestPtrSlice(dest, src) assert.Equal(t, []*ExportProfilesServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportProfilesServiceRequestPtrSlice() dest = CopyExportProfilesServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportProfilesServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportProfilesServiceRequestPtrSlice(dest, []*ExportProfilesServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportProfilesServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportProfilesServiceRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportProfilesServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportProfilesServiceRequest(), dest) } func TestMarshalAndUnmarshalJSONExportProfilesServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportProfilesServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportProfilesServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportProfilesServiceRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportProfilesServiceRequest() { t.Run(name, func(t *testing.T) { dest := NewExportProfilesServiceRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportProfilesServiceRequestUnknown(t *testing.T) { dest := NewExportProfilesServiceRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportProfilesServiceRequest(), dest) } func TestMarshalAndUnmarshalProtoExportProfilesServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportProfilesServiceRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportProfilesServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportProfilesServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectorprofiles.ExportProfilesServiceRequest{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportProfilesServiceRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportProfilesServiceRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceProfiles/wrong_wire_type": {0xc}, "ResourceProfiles/missing_value": {0xa}, "Dictionary/wrong_wire_type": {0x14}, "Dictionary/missing_value": {0x12}, } } func genTestEncodingValuesExportProfilesServiceRequest() map[string]*ExportProfilesServiceRequest { return map[string]*ExportProfilesServiceRequest{ "empty": NewExportProfilesServiceRequest(), "ResourceProfiles/test": {ResourceProfiles: []*ResourceProfiles{{}, GenTestResourceProfiles()}}, "Dictionary/test": {Dictionary: *GenTestProfilesDictionary()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportprofilesserviceresponse.go000066400000000000000000000140761511331344600334700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportResponse represents the response for gRPC/HTTP client/server. type ExportProfilesServiceResponse struct { PartialSuccess ExportProfilesPartialSuccess } var ( protoPoolExportProfilesServiceResponse = sync.Pool{ New: func() any { return &ExportProfilesServiceResponse{} }, } ) func NewExportProfilesServiceResponse() *ExportProfilesServiceResponse { if !UseProtoPooling.IsEnabled() { return &ExportProfilesServiceResponse{} } return protoPoolExportProfilesServiceResponse.Get().(*ExportProfilesServiceResponse) } func DeleteExportProfilesServiceResponse(orig *ExportProfilesServiceResponse, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteExportProfilesPartialSuccess(&orig.PartialSuccess, false) orig.Reset() if nullable { protoPoolExportProfilesServiceResponse.Put(orig) } } func CopyExportProfilesServiceResponse(dest, src *ExportProfilesServiceResponse) *ExportProfilesServiceResponse { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportProfilesServiceResponse() } CopyExportProfilesPartialSuccess(&dest.PartialSuccess, &src.PartialSuccess) return dest } func CopyExportProfilesServiceResponseSlice(dest, src []ExportProfilesServiceResponse) []ExportProfilesServiceResponse { var newDest []ExportProfilesServiceResponse if cap(dest) < len(src) { newDest = make([]ExportProfilesServiceResponse, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportProfilesServiceResponse(&dest[i], false) } } for i := range src { CopyExportProfilesServiceResponse(&newDest[i], &src[i]) } return newDest } func CopyExportProfilesServiceResponsePtrSlice(dest, src []*ExportProfilesServiceResponse) []*ExportProfilesServiceResponse { var newDest []*ExportProfilesServiceResponse if cap(dest) < len(src) { newDest = make([]*ExportProfilesServiceResponse, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportProfilesServiceResponse() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportProfilesServiceResponse(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportProfilesServiceResponse() } } for i := range src { CopyExportProfilesServiceResponse(newDest[i], src[i]) } return newDest } func (orig *ExportProfilesServiceResponse) Reset() { *orig = ExportProfilesServiceResponse{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportProfilesServiceResponse) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("partialSuccess") orig.PartialSuccess.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportProfilesServiceResponse) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "partialSuccess", "partial_success": orig.PartialSuccess.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *ExportProfilesServiceResponse) SizeProto() int { var n int var l int _ = l l = orig.PartialSuccess.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *ExportProfilesServiceResponse) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.PartialSuccess.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa return len(buf) - pos } func (orig *ExportProfilesServiceResponse) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field PartialSuccess", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.PartialSuccess.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportProfilesServiceResponse() *ExportProfilesServiceResponse { orig := NewExportProfilesServiceResponse() orig.PartialSuccess = *GenTestExportProfilesPartialSuccess() return orig } func GenTestExportProfilesServiceResponsePtrSlice() []*ExportProfilesServiceResponse { orig := make([]*ExportProfilesServiceResponse, 5) orig[0] = NewExportProfilesServiceResponse() orig[1] = GenTestExportProfilesServiceResponse() orig[2] = NewExportProfilesServiceResponse() orig[3] = GenTestExportProfilesServiceResponse() orig[4] = NewExportProfilesServiceResponse() return orig } func GenTestExportProfilesServiceResponseSlice() []ExportProfilesServiceResponse { orig := make([]ExportProfilesServiceResponse, 5) orig[1] = *GenTestExportProfilesServiceResponse() orig[3] = *GenTestExportProfilesServiceResponse() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exportprofilesserviceresponse_test.go000066400000000000000000000162421511331344600345240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorprofiles "go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportProfilesServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportProfilesServiceResponse() CopyExportProfilesServiceResponse(dest, src) assert.Equal(t, src, dest) CopyExportProfilesServiceResponse(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportProfilesServiceResponseSlice(t *testing.T) { src := []ExportProfilesServiceResponse{} dest := []ExportProfilesServiceResponse{} // Test CopyTo empty dest = CopyExportProfilesServiceResponseSlice(dest, src) assert.Equal(t, []ExportProfilesServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportProfilesServiceResponseSlice() dest = CopyExportProfilesServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceResponseSlice(), dest) // Test CopyTo same size slice dest = CopyExportProfilesServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceResponseSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportProfilesServiceResponseSlice(dest, []ExportProfilesServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportProfilesServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceResponseSlice(), dest) } func TestCopyExportProfilesServiceResponsePtrSlice(t *testing.T) { src := []*ExportProfilesServiceResponse{} dest := []*ExportProfilesServiceResponse{} // Test CopyTo empty dest = CopyExportProfilesServiceResponsePtrSlice(dest, src) assert.Equal(t, []*ExportProfilesServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportProfilesServiceResponsePtrSlice() dest = CopyExportProfilesServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceResponsePtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportProfilesServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceResponsePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportProfilesServiceResponsePtrSlice(dest, []*ExportProfilesServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportProfilesServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportProfilesServiceResponsePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportProfilesServiceResponseUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportProfilesServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportProfilesServiceResponse(), dest) } func TestMarshalAndUnmarshalJSONExportProfilesServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportProfilesServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportProfilesServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportProfilesServiceResponseFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportProfilesServiceResponse() { t.Run(name, func(t *testing.T) { dest := NewExportProfilesServiceResponse() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportProfilesServiceResponseUnknown(t *testing.T) { dest := NewExportProfilesServiceResponse() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportProfilesServiceResponse(), dest) } func TestMarshalAndUnmarshalProtoExportProfilesServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportProfilesServiceResponse() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportProfilesServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportProfilesServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportProfilesServiceResponse() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectorprofiles.ExportProfilesServiceResponse{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportProfilesServiceResponse() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportProfilesServiceResponse() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "PartialSuccess/wrong_wire_type": {0xc}, "PartialSuccess/missing_value": {0xa}, } } func genTestEncodingValuesExportProfilesServiceResponse() map[string]*ExportProfilesServiceResponse { return map[string]*ExportProfilesServiceResponse{ "empty": NewExportProfilesServiceResponse(), "PartialSuccess/test": {PartialSuccess: *GenTestExportProfilesPartialSuccess()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exporttracepartialsuccess.go000066400000000000000000000147771511331344600325610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportPartialSuccess represents the details of a partially successful export request. type ExportTracePartialSuccess struct { RejectedSpans int64 ErrorMessage string } var ( protoPoolExportTracePartialSuccess = sync.Pool{ New: func() any { return &ExportTracePartialSuccess{} }, } ) func NewExportTracePartialSuccess() *ExportTracePartialSuccess { if !UseProtoPooling.IsEnabled() { return &ExportTracePartialSuccess{} } return protoPoolExportTracePartialSuccess.Get().(*ExportTracePartialSuccess) } func DeleteExportTracePartialSuccess(orig *ExportTracePartialSuccess, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolExportTracePartialSuccess.Put(orig) } } func CopyExportTracePartialSuccess(dest, src *ExportTracePartialSuccess) *ExportTracePartialSuccess { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportTracePartialSuccess() } dest.RejectedSpans = src.RejectedSpans dest.ErrorMessage = src.ErrorMessage return dest } func CopyExportTracePartialSuccessSlice(dest, src []ExportTracePartialSuccess) []ExportTracePartialSuccess { var newDest []ExportTracePartialSuccess if cap(dest) < len(src) { newDest = make([]ExportTracePartialSuccess, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportTracePartialSuccess(&dest[i], false) } } for i := range src { CopyExportTracePartialSuccess(&newDest[i], &src[i]) } return newDest } func CopyExportTracePartialSuccessPtrSlice(dest, src []*ExportTracePartialSuccess) []*ExportTracePartialSuccess { var newDest []*ExportTracePartialSuccess if cap(dest) < len(src) { newDest = make([]*ExportTracePartialSuccess, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportTracePartialSuccess() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportTracePartialSuccess(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportTracePartialSuccess() } } for i := range src { CopyExportTracePartialSuccess(newDest[i], src[i]) } return newDest } func (orig *ExportTracePartialSuccess) Reset() { *orig = ExportTracePartialSuccess{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportTracePartialSuccess) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RejectedSpans != int64(0) { dest.WriteObjectField("rejectedSpans") dest.WriteInt64(orig.RejectedSpans) } if orig.ErrorMessage != "" { dest.WriteObjectField("errorMessage") dest.WriteString(orig.ErrorMessage) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportTracePartialSuccess) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "rejectedSpans", "rejected_spans": orig.RejectedSpans = iter.ReadInt64() case "errorMessage", "error_message": orig.ErrorMessage = iter.ReadString() default: iter.Skip() } } } func (orig *ExportTracePartialSuccess) SizeProto() int { var n int var l int _ = l if orig.RejectedSpans != 0 { n += 1 + proto.Sov(uint64(orig.RejectedSpans)) } l = len(orig.ErrorMessage) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExportTracePartialSuccess) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RejectedSpans != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.RejectedSpans)) pos-- buf[pos] = 0x8 } l = len(orig.ErrorMessage) if l > 0 { pos -= l copy(buf[pos:], orig.ErrorMessage) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } return len(buf) - pos } func (orig *ExportTracePartialSuccess) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field RejectedSpans", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.RejectedSpans = int64(num) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ErrorMessage", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ErrorMessage = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportTracePartialSuccess() *ExportTracePartialSuccess { orig := NewExportTracePartialSuccess() orig.RejectedSpans = int64(13) orig.ErrorMessage = "test_errormessage" return orig } func GenTestExportTracePartialSuccessPtrSlice() []*ExportTracePartialSuccess { orig := make([]*ExportTracePartialSuccess, 5) orig[0] = NewExportTracePartialSuccess() orig[1] = GenTestExportTracePartialSuccess() orig[2] = NewExportTracePartialSuccess() orig[3] = GenTestExportTracePartialSuccess() orig[4] = NewExportTracePartialSuccess() return orig } func GenTestExportTracePartialSuccessSlice() []ExportTracePartialSuccess { orig := make([]ExportTracePartialSuccess, 5) orig[1] = *GenTestExportTracePartialSuccess() orig[3] = *GenTestExportTracePartialSuccess() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exporttracepartialsuccess_test.go000066400000000000000000000160221511331344600336010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectortrace "go.opentelemetry.io/proto/slim/otlp/collector/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportTracePartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportTracePartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportTracePartialSuccess() CopyExportTracePartialSuccess(dest, src) assert.Equal(t, src, dest) CopyExportTracePartialSuccess(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportTracePartialSuccessSlice(t *testing.T) { src := []ExportTracePartialSuccess{} dest := []ExportTracePartialSuccess{} // Test CopyTo empty dest = CopyExportTracePartialSuccessSlice(dest, src) assert.Equal(t, []ExportTracePartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportTracePartialSuccessSlice() dest = CopyExportTracePartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportTracePartialSuccessSlice(), dest) // Test CopyTo same size slice dest = CopyExportTracePartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportTracePartialSuccessSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportTracePartialSuccessSlice(dest, []ExportTracePartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportTracePartialSuccessSlice(dest, src) assert.Equal(t, GenTestExportTracePartialSuccessSlice(), dest) } func TestCopyExportTracePartialSuccessPtrSlice(t *testing.T) { src := []*ExportTracePartialSuccess{} dest := []*ExportTracePartialSuccess{} // Test CopyTo empty dest = CopyExportTracePartialSuccessPtrSlice(dest, src) assert.Equal(t, []*ExportTracePartialSuccess{}, dest) // Test CopyTo larger slice src = GenTestExportTracePartialSuccessPtrSlice() dest = CopyExportTracePartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportTracePartialSuccessPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportTracePartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportTracePartialSuccessPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportTracePartialSuccessPtrSlice(dest, []*ExportTracePartialSuccess{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportTracePartialSuccessPtrSlice(dest, src) assert.Equal(t, GenTestExportTracePartialSuccessPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportTracePartialSuccessUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportTracePartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportTracePartialSuccess(), dest) } func TestMarshalAndUnmarshalJSONExportTracePartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportTracePartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportTracePartialSuccess() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportTracePartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportTracePartialSuccessFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportTracePartialSuccess() { t.Run(name, func(t *testing.T) { dest := NewExportTracePartialSuccess() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportTracePartialSuccessUnknown(t *testing.T) { dest := NewExportTracePartialSuccess() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportTracePartialSuccess(), dest) } func TestMarshalAndUnmarshalProtoExportTracePartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportTracePartialSuccess() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportTracePartialSuccess() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportTracePartialSuccess(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportTracePartialSuccess(t *testing.T) { for name, src := range genTestEncodingValuesExportTracePartialSuccess() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectortrace.ExportTracePartialSuccess{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportTracePartialSuccess() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportTracePartialSuccess() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RejectedSpans/wrong_wire_type": {0xc}, "RejectedSpans/missing_value": {0x8}, "ErrorMessage/wrong_wire_type": {0x14}, "ErrorMessage/missing_value": {0x12}, } } func genTestEncodingValuesExportTracePartialSuccess() map[string]*ExportTracePartialSuccess { return map[string]*ExportTracePartialSuccess{ "empty": NewExportTracePartialSuccess(), "RejectedSpans/test": {RejectedSpans: int64(13)}, "ErrorMessage/test": {ErrorMessage: "test_errormessage"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exporttraceservicerequest.go000066400000000000000000000147731511331344600326010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Traces is the top-level struct that is propagated through the traces pipeline. // Use NewTraces to create new instance, zero-initialized instance is not valid for use. type ExportTraceServiceRequest struct { ResourceSpans []*ResourceSpans } var ( protoPoolExportTraceServiceRequest = sync.Pool{ New: func() any { return &ExportTraceServiceRequest{} }, } ) func NewExportTraceServiceRequest() *ExportTraceServiceRequest { if !UseProtoPooling.IsEnabled() { return &ExportTraceServiceRequest{} } return protoPoolExportTraceServiceRequest.Get().(*ExportTraceServiceRequest) } func DeleteExportTraceServiceRequest(orig *ExportTraceServiceRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceSpans { DeleteResourceSpans(orig.ResourceSpans[i], true) } orig.Reset() if nullable { protoPoolExportTraceServiceRequest.Put(orig) } } func CopyExportTraceServiceRequest(dest, src *ExportTraceServiceRequest) *ExportTraceServiceRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportTraceServiceRequest() } dest.ResourceSpans = CopyResourceSpansPtrSlice(dest.ResourceSpans, src.ResourceSpans) return dest } func CopyExportTraceServiceRequestSlice(dest, src []ExportTraceServiceRequest) []ExportTraceServiceRequest { var newDest []ExportTraceServiceRequest if cap(dest) < len(src) { newDest = make([]ExportTraceServiceRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportTraceServiceRequest(&dest[i], false) } } for i := range src { CopyExportTraceServiceRequest(&newDest[i], &src[i]) } return newDest } func CopyExportTraceServiceRequestPtrSlice(dest, src []*ExportTraceServiceRequest) []*ExportTraceServiceRequest { var newDest []*ExportTraceServiceRequest if cap(dest) < len(src) { newDest = make([]*ExportTraceServiceRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportTraceServiceRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportTraceServiceRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportTraceServiceRequest() } } for i := range src { CopyExportTraceServiceRequest(newDest[i], src[i]) } return newDest } func (orig *ExportTraceServiceRequest) Reset() { *orig = ExportTraceServiceRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportTraceServiceRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceSpans) > 0 { dest.WriteObjectField("resourceSpans") dest.WriteArrayStart() orig.ResourceSpans[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceSpans); i++ { dest.WriteMore() orig.ResourceSpans[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportTraceServiceRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceSpans", "resource_spans": for iter.ReadArray() { orig.ResourceSpans = append(orig.ResourceSpans, NewResourceSpans()) orig.ResourceSpans[len(orig.ResourceSpans)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ExportTraceServiceRequest) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceSpans { l = orig.ResourceSpans[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ExportTraceServiceRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceSpans) - 1; i >= 0; i-- { l = orig.ResourceSpans[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *ExportTraceServiceRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceSpans", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceSpans = append(orig.ResourceSpans, NewResourceSpans()) err = orig.ResourceSpans[len(orig.ResourceSpans)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportTraceServiceRequest() *ExportTraceServiceRequest { orig := NewExportTraceServiceRequest() orig.ResourceSpans = []*ResourceSpans{{}, GenTestResourceSpans()} return orig } func GenTestExportTraceServiceRequestPtrSlice() []*ExportTraceServiceRequest { orig := make([]*ExportTraceServiceRequest, 5) orig[0] = NewExportTraceServiceRequest() orig[1] = GenTestExportTraceServiceRequest() orig[2] = NewExportTraceServiceRequest() orig[3] = GenTestExportTraceServiceRequest() orig[4] = NewExportTraceServiceRequest() return orig } func GenTestExportTraceServiceRequestSlice() []ExportTraceServiceRequest { orig := make([]ExportTraceServiceRequest, 5) orig[1] = *GenTestExportTraceServiceRequest() orig[3] = *GenTestExportTraceServiceRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exporttraceservicerequest_test.go000066400000000000000000000156421511331344600336340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectortrace "go.opentelemetry.io/proto/slim/otlp/collector/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportTraceServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportTraceServiceRequest() CopyExportTraceServiceRequest(dest, src) assert.Equal(t, src, dest) CopyExportTraceServiceRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportTraceServiceRequestSlice(t *testing.T) { src := []ExportTraceServiceRequest{} dest := []ExportTraceServiceRequest{} // Test CopyTo empty dest = CopyExportTraceServiceRequestSlice(dest, src) assert.Equal(t, []ExportTraceServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportTraceServiceRequestSlice() dest = CopyExportTraceServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceRequestSlice(), dest) // Test CopyTo same size slice dest = CopyExportTraceServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportTraceServiceRequestSlice(dest, []ExportTraceServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportTraceServiceRequestSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceRequestSlice(), dest) } func TestCopyExportTraceServiceRequestPtrSlice(t *testing.T) { src := []*ExportTraceServiceRequest{} dest := []*ExportTraceServiceRequest{} // Test CopyTo empty dest = CopyExportTraceServiceRequestPtrSlice(dest, src) assert.Equal(t, []*ExportTraceServiceRequest{}, dest) // Test CopyTo larger slice src = GenTestExportTraceServiceRequestPtrSlice() dest = CopyExportTraceServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportTraceServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportTraceServiceRequestPtrSlice(dest, []*ExportTraceServiceRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportTraceServiceRequestPtrSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportTraceServiceRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportTraceServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportTraceServiceRequest(), dest) } func TestMarshalAndUnmarshalJSONExportTraceServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportTraceServiceRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportTraceServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportTraceServiceRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportTraceServiceRequest() { t.Run(name, func(t *testing.T) { dest := NewExportTraceServiceRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportTraceServiceRequestUnknown(t *testing.T) { dest := NewExportTraceServiceRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportTraceServiceRequest(), dest) } func TestMarshalAndUnmarshalProtoExportTraceServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportTraceServiceRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportTraceServiceRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportTraceServiceRequest(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectortrace.ExportTraceServiceRequest{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportTraceServiceRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportTraceServiceRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceSpans/wrong_wire_type": {0xc}, "ResourceSpans/missing_value": {0xa}, } } func genTestEncodingValuesExportTraceServiceRequest() map[string]*ExportTraceServiceRequest { return map[string]*ExportTraceServiceRequest{ "empty": NewExportTraceServiceRequest(), "ResourceSpans/test": {ResourceSpans: []*ResourceSpans{{}, GenTestResourceSpans()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exporttraceserviceresponse.go000066400000000000000000000136201511331344600327350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ExportResponse represents the response for gRPC/HTTP client/server. type ExportTraceServiceResponse struct { PartialSuccess ExportTracePartialSuccess } var ( protoPoolExportTraceServiceResponse = sync.Pool{ New: func() any { return &ExportTraceServiceResponse{} }, } ) func NewExportTraceServiceResponse() *ExportTraceServiceResponse { if !UseProtoPooling.IsEnabled() { return &ExportTraceServiceResponse{} } return protoPoolExportTraceServiceResponse.Get().(*ExportTraceServiceResponse) } func DeleteExportTraceServiceResponse(orig *ExportTraceServiceResponse, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteExportTracePartialSuccess(&orig.PartialSuccess, false) orig.Reset() if nullable { protoPoolExportTraceServiceResponse.Put(orig) } } func CopyExportTraceServiceResponse(dest, src *ExportTraceServiceResponse) *ExportTraceServiceResponse { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewExportTraceServiceResponse() } CopyExportTracePartialSuccess(&dest.PartialSuccess, &src.PartialSuccess) return dest } func CopyExportTraceServiceResponseSlice(dest, src []ExportTraceServiceResponse) []ExportTraceServiceResponse { var newDest []ExportTraceServiceResponse if cap(dest) < len(src) { newDest = make([]ExportTraceServiceResponse, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportTraceServiceResponse(&dest[i], false) } } for i := range src { CopyExportTraceServiceResponse(&newDest[i], &src[i]) } return newDest } func CopyExportTraceServiceResponsePtrSlice(dest, src []*ExportTraceServiceResponse) []*ExportTraceServiceResponse { var newDest []*ExportTraceServiceResponse if cap(dest) < len(src) { newDest = make([]*ExportTraceServiceResponse, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportTraceServiceResponse() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteExportTraceServiceResponse(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewExportTraceServiceResponse() } } for i := range src { CopyExportTraceServiceResponse(newDest[i], src[i]) } return newDest } func (orig *ExportTraceServiceResponse) Reset() { *orig = ExportTraceServiceResponse{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ExportTraceServiceResponse) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("partialSuccess") orig.PartialSuccess.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ExportTraceServiceResponse) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "partialSuccess", "partial_success": orig.PartialSuccess.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *ExportTraceServiceResponse) SizeProto() int { var n int var l int _ = l l = orig.PartialSuccess.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *ExportTraceServiceResponse) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.PartialSuccess.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa return len(buf) - pos } func (orig *ExportTraceServiceResponse) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field PartialSuccess", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.PartialSuccess.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestExportTraceServiceResponse() *ExportTraceServiceResponse { orig := NewExportTraceServiceResponse() orig.PartialSuccess = *GenTestExportTracePartialSuccess() return orig } func GenTestExportTraceServiceResponsePtrSlice() []*ExportTraceServiceResponse { orig := make([]*ExportTraceServiceResponse, 5) orig[0] = NewExportTraceServiceResponse() orig[1] = GenTestExportTraceServiceResponse() orig[2] = NewExportTraceServiceResponse() orig[3] = GenTestExportTraceServiceResponse() orig[4] = NewExportTraceServiceResponse() return orig } func GenTestExportTraceServiceResponseSlice() []ExportTraceServiceResponse { orig := make([]ExportTraceServiceResponse, 5) orig[1] = *GenTestExportTraceServiceResponse() orig[3] = *GenTestExportTraceServiceResponse() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_exporttraceserviceresponse_test.go000066400000000000000000000157321511331344600340020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectortrace "go.opentelemetry.io/proto/slim/otlp/collector/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyExportTraceServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewExportTraceServiceResponse() CopyExportTraceServiceResponse(dest, src) assert.Equal(t, src, dest) CopyExportTraceServiceResponse(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyExportTraceServiceResponseSlice(t *testing.T) { src := []ExportTraceServiceResponse{} dest := []ExportTraceServiceResponse{} // Test CopyTo empty dest = CopyExportTraceServiceResponseSlice(dest, src) assert.Equal(t, []ExportTraceServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportTraceServiceResponseSlice() dest = CopyExportTraceServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceResponseSlice(), dest) // Test CopyTo same size slice dest = CopyExportTraceServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceResponseSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportTraceServiceResponseSlice(dest, []ExportTraceServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportTraceServiceResponseSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceResponseSlice(), dest) } func TestCopyExportTraceServiceResponsePtrSlice(t *testing.T) { src := []*ExportTraceServiceResponse{} dest := []*ExportTraceServiceResponse{} // Test CopyTo empty dest = CopyExportTraceServiceResponsePtrSlice(dest, src) assert.Equal(t, []*ExportTraceServiceResponse{}, dest) // Test CopyTo larger slice src = GenTestExportTraceServiceResponsePtrSlice() dest = CopyExportTraceServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceResponsePtrSlice(), dest) // Test CopyTo same size slice dest = CopyExportTraceServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceResponsePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyExportTraceServiceResponsePtrSlice(dest, []*ExportTraceServiceResponse{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyExportTraceServiceResponsePtrSlice(dest, src) assert.Equal(t, GenTestExportTraceServiceResponsePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONExportTraceServiceResponseUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewExportTraceServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewExportTraceServiceResponse(), dest) } func TestMarshalAndUnmarshalJSONExportTraceServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewExportTraceServiceResponse() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteExportTraceServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoExportTraceServiceResponseFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesExportTraceServiceResponse() { t.Run(name, func(t *testing.T) { dest := NewExportTraceServiceResponse() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoExportTraceServiceResponseUnknown(t *testing.T) { dest := NewExportTraceServiceResponse() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewExportTraceServiceResponse(), dest) } func TestMarshalAndUnmarshalProtoExportTraceServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceResponse() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewExportTraceServiceResponse() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteExportTraceServiceResponse(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufExportTraceServiceResponse(t *testing.T) { for name, src := range genTestEncodingValuesExportTraceServiceResponse() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcollectortrace.ExportTraceServiceResponse{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewExportTraceServiceResponse() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesExportTraceServiceResponse() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "PartialSuccess/wrong_wire_type": {0xc}, "PartialSuccess/missing_value": {0xa}, } } func genTestEncodingValuesExportTraceServiceResponse() map[string]*ExportTraceServiceResponse { return map[string]*ExportTraceServiceResponse{ "empty": NewExportTraceServiceResponse(), "PartialSuccess/test": {PartialSuccess: *GenTestExportTracePartialSuccess()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_function.go000066400000000000000000000162661511331344600270730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Function describes a function, including its human-readable name, system name, source file, and starting line number in the source. type Function struct { NameStrindex int32 SystemNameStrindex int32 FilenameStrindex int32 StartLine int64 } var ( protoPoolFunction = sync.Pool{ New: func() any { return &Function{} }, } ) func NewFunction() *Function { if !UseProtoPooling.IsEnabled() { return &Function{} } return protoPoolFunction.Get().(*Function) } func DeleteFunction(orig *Function, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolFunction.Put(orig) } } func CopyFunction(dest, src *Function) *Function { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewFunction() } dest.NameStrindex = src.NameStrindex dest.SystemNameStrindex = src.SystemNameStrindex dest.FilenameStrindex = src.FilenameStrindex dest.StartLine = src.StartLine return dest } func CopyFunctionSlice(dest, src []Function) []Function { var newDest []Function if cap(dest) < len(src) { newDest = make([]Function, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteFunction(&dest[i], false) } } for i := range src { CopyFunction(&newDest[i], &src[i]) } return newDest } func CopyFunctionPtrSlice(dest, src []*Function) []*Function { var newDest []*Function if cap(dest) < len(src) { newDest = make([]*Function, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewFunction() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteFunction(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewFunction() } } for i := range src { CopyFunction(newDest[i], src[i]) } return newDest } func (orig *Function) Reset() { *orig = Function{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Function) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.NameStrindex != int32(0) { dest.WriteObjectField("nameStrindex") dest.WriteInt32(orig.NameStrindex) } if orig.SystemNameStrindex != int32(0) { dest.WriteObjectField("systemNameStrindex") dest.WriteInt32(orig.SystemNameStrindex) } if orig.FilenameStrindex != int32(0) { dest.WriteObjectField("filenameStrindex") dest.WriteInt32(orig.FilenameStrindex) } if orig.StartLine != int64(0) { dest.WriteObjectField("startLine") dest.WriteInt64(orig.StartLine) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Function) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "nameStrindex", "name_strindex": orig.NameStrindex = iter.ReadInt32() case "systemNameStrindex", "system_name_strindex": orig.SystemNameStrindex = iter.ReadInt32() case "filenameStrindex", "filename_strindex": orig.FilenameStrindex = iter.ReadInt32() case "startLine", "start_line": orig.StartLine = iter.ReadInt64() default: iter.Skip() } } } func (orig *Function) SizeProto() int { var n int var l int _ = l if orig.NameStrindex != 0 { n += 1 + proto.Sov(uint64(orig.NameStrindex)) } if orig.SystemNameStrindex != 0 { n += 1 + proto.Sov(uint64(orig.SystemNameStrindex)) } if orig.FilenameStrindex != 0 { n += 1 + proto.Sov(uint64(orig.FilenameStrindex)) } if orig.StartLine != 0 { n += 1 + proto.Sov(uint64(orig.StartLine)) } return n } func (orig *Function) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.NameStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.NameStrindex)) pos-- buf[pos] = 0x8 } if orig.SystemNameStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.SystemNameStrindex)) pos-- buf[pos] = 0x10 } if orig.FilenameStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.FilenameStrindex)) pos-- buf[pos] = 0x18 } if orig.StartLine != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.StartLine)) pos-- buf[pos] = 0x20 } return len(buf) - pos } func (orig *Function) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field NameStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.NameStrindex = int32(num) case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field SystemNameStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.SystemNameStrindex = int32(num) case 3: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field FilenameStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.FilenameStrindex = int32(num) case 4: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field StartLine", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.StartLine = int64(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestFunction() *Function { orig := NewFunction() orig.NameStrindex = int32(13) orig.SystemNameStrindex = int32(13) orig.FilenameStrindex = int32(13) orig.StartLine = int64(13) return orig } func GenTestFunctionPtrSlice() []*Function { orig := make([]*Function, 5) orig[0] = NewFunction() orig[1] = GenTestFunction() orig[2] = NewFunction() orig[3] = GenTestFunction() orig[4] = NewFunction() return orig } func GenTestFunctionSlice() []Function { orig := make([]Function, 5) orig[1] = *GenTestFunction() orig[3] = *GenTestFunction() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_function_test.go000066400000000000000000000145631511331344600301300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyFunction(t *testing.T) { for name, src := range genTestEncodingValuesFunction() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewFunction() CopyFunction(dest, src) assert.Equal(t, src, dest) CopyFunction(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyFunctionSlice(t *testing.T) { src := []Function{} dest := []Function{} // Test CopyTo empty dest = CopyFunctionSlice(dest, src) assert.Equal(t, []Function{}, dest) // Test CopyTo larger slice src = GenTestFunctionSlice() dest = CopyFunctionSlice(dest, src) assert.Equal(t, GenTestFunctionSlice(), dest) // Test CopyTo same size slice dest = CopyFunctionSlice(dest, src) assert.Equal(t, GenTestFunctionSlice(), dest) // Test CopyTo smaller size slice dest = CopyFunctionSlice(dest, []Function{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyFunctionSlice(dest, src) assert.Equal(t, GenTestFunctionSlice(), dest) } func TestCopyFunctionPtrSlice(t *testing.T) { src := []*Function{} dest := []*Function{} // Test CopyTo empty dest = CopyFunctionPtrSlice(dest, src) assert.Equal(t, []*Function{}, dest) // Test CopyTo larger slice src = GenTestFunctionPtrSlice() dest = CopyFunctionPtrSlice(dest, src) assert.Equal(t, GenTestFunctionPtrSlice(), dest) // Test CopyTo same size slice dest = CopyFunctionPtrSlice(dest, src) assert.Equal(t, GenTestFunctionPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyFunctionPtrSlice(dest, []*Function{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyFunctionPtrSlice(dest, src) assert.Equal(t, GenTestFunctionPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONFunctionUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewFunction() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewFunction(), dest) } func TestMarshalAndUnmarshalJSONFunction(t *testing.T) { for name, src := range genTestEncodingValuesFunction() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewFunction() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteFunction(dest, true) }) } } } func TestMarshalAndUnmarshalProtoFunctionFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesFunction() { t.Run(name, func(t *testing.T) { dest := NewFunction() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoFunctionUnknown(t *testing.T) { dest := NewFunction() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewFunction(), dest) } func TestMarshalAndUnmarshalProtoFunction(t *testing.T) { for name, src := range genTestEncodingValuesFunction() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewFunction() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteFunction(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufFunction(t *testing.T) { for name, src := range genTestEncodingValuesFunction() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Function{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewFunction() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesFunction() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "NameStrindex/wrong_wire_type": {0xc}, "NameStrindex/missing_value": {0x8}, "SystemNameStrindex/wrong_wire_type": {0x14}, "SystemNameStrindex/missing_value": {0x10}, "FilenameStrindex/wrong_wire_type": {0x1c}, "FilenameStrindex/missing_value": {0x18}, "StartLine/wrong_wire_type": {0x24}, "StartLine/missing_value": {0x20}, } } func genTestEncodingValuesFunction() map[string]*Function { return map[string]*Function{ "empty": NewFunction(), "NameStrindex/test": {NameStrindex: int32(13)}, "SystemNameStrindex/test": {SystemNameStrindex: int32(13)}, "FilenameStrindex/test": {FilenameStrindex: int32(13)}, "StartLine/test": {StartLine: int64(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_gauge.go000066400000000000000000000125041511331344600263250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Gauge represents the type of a numeric metric that always exports the "current value" for every data point. type Gauge struct { DataPoints []*NumberDataPoint } var ( protoPoolGauge = sync.Pool{ New: func() any { return &Gauge{} }, } ) func NewGauge() *Gauge { if !UseProtoPooling.IsEnabled() { return &Gauge{} } return protoPoolGauge.Get().(*Gauge) } func DeleteGauge(orig *Gauge, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.DataPoints { DeleteNumberDataPoint(orig.DataPoints[i], true) } orig.Reset() if nullable { protoPoolGauge.Put(orig) } } func CopyGauge(dest, src *Gauge) *Gauge { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewGauge() } dest.DataPoints = CopyNumberDataPointPtrSlice(dest.DataPoints, src.DataPoints) return dest } func CopyGaugeSlice(dest, src []Gauge) []Gauge { var newDest []Gauge if cap(dest) < len(src) { newDest = make([]Gauge, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteGauge(&dest[i], false) } } for i := range src { CopyGauge(&newDest[i], &src[i]) } return newDest } func CopyGaugePtrSlice(dest, src []*Gauge) []*Gauge { var newDest []*Gauge if cap(dest) < len(src) { newDest = make([]*Gauge, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewGauge() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteGauge(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewGauge() } } for i := range src { CopyGauge(newDest[i], src[i]) } return newDest } func (orig *Gauge) Reset() { *orig = Gauge{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Gauge) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.DataPoints) > 0 { dest.WriteObjectField("dataPoints") dest.WriteArrayStart() orig.DataPoints[0].MarshalJSON(dest) for i := 1; i < len(orig.DataPoints); i++ { dest.WriteMore() orig.DataPoints[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Gauge) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "dataPoints", "data_points": for iter.ReadArray() { orig.DataPoints = append(orig.DataPoints, NewNumberDataPoint()) orig.DataPoints[len(orig.DataPoints)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *Gauge) SizeProto() int { var n int var l int _ = l for i := range orig.DataPoints { l = orig.DataPoints[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Gauge) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.DataPoints) - 1; i >= 0; i-- { l = orig.DataPoints[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *Gauge) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DataPoints", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DataPoints = append(orig.DataPoints, NewNumberDataPoint()) err = orig.DataPoints[len(orig.DataPoints)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestGauge() *Gauge { orig := NewGauge() orig.DataPoints = []*NumberDataPoint{{}, GenTestNumberDataPoint()} return orig } func GenTestGaugePtrSlice() []*Gauge { orig := make([]*Gauge, 5) orig[0] = NewGauge() orig[1] = GenTestGauge() orig[2] = NewGauge() orig[3] = GenTestGauge() orig[4] = NewGauge() return orig } func GenTestGaugeSlice() []Gauge { orig := make([]Gauge, 5) orig[1] = *GenTestGauge() orig[3] = *GenTestGauge() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_gauge_test.go000066400000000000000000000133421511331344600273650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyGauge(t *testing.T) { for name, src := range genTestEncodingValuesGauge() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewGauge() CopyGauge(dest, src) assert.Equal(t, src, dest) CopyGauge(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyGaugeSlice(t *testing.T) { src := []Gauge{} dest := []Gauge{} // Test CopyTo empty dest = CopyGaugeSlice(dest, src) assert.Equal(t, []Gauge{}, dest) // Test CopyTo larger slice src = GenTestGaugeSlice() dest = CopyGaugeSlice(dest, src) assert.Equal(t, GenTestGaugeSlice(), dest) // Test CopyTo same size slice dest = CopyGaugeSlice(dest, src) assert.Equal(t, GenTestGaugeSlice(), dest) // Test CopyTo smaller size slice dest = CopyGaugeSlice(dest, []Gauge{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyGaugeSlice(dest, src) assert.Equal(t, GenTestGaugeSlice(), dest) } func TestCopyGaugePtrSlice(t *testing.T) { src := []*Gauge{} dest := []*Gauge{} // Test CopyTo empty dest = CopyGaugePtrSlice(dest, src) assert.Equal(t, []*Gauge{}, dest) // Test CopyTo larger slice src = GenTestGaugePtrSlice() dest = CopyGaugePtrSlice(dest, src) assert.Equal(t, GenTestGaugePtrSlice(), dest) // Test CopyTo same size slice dest = CopyGaugePtrSlice(dest, src) assert.Equal(t, GenTestGaugePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyGaugePtrSlice(dest, []*Gauge{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyGaugePtrSlice(dest, src) assert.Equal(t, GenTestGaugePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONGaugeUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewGauge() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewGauge(), dest) } func TestMarshalAndUnmarshalJSONGauge(t *testing.T) { for name, src := range genTestEncodingValuesGauge() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewGauge() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteGauge(dest, true) }) } } } func TestMarshalAndUnmarshalProtoGaugeFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesGauge() { t.Run(name, func(t *testing.T) { dest := NewGauge() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoGaugeUnknown(t *testing.T) { dest := NewGauge() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewGauge(), dest) } func TestMarshalAndUnmarshalProtoGauge(t *testing.T) { for name, src := range genTestEncodingValuesGauge() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewGauge() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteGauge(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufGauge(t *testing.T) { for name, src := range genTestEncodingValuesGauge() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.Gauge{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewGauge() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesGauge() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "DataPoints/wrong_wire_type": {0xc}, "DataPoints/missing_value": {0xa}, } } func genTestEncodingValuesGauge() map[string]*Gauge { return map[string]*Gauge{ "empty": NewGauge(), "DataPoints/test": {DataPoints: []*NumberDataPoint{{}, GenTestNumberDataPoint()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_histogram.go000066400000000000000000000151651511331344600272400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Histogram represents the type of a metric that is calculated by aggregating as a Histogram of all reported measurements over a time interval. type Histogram struct { DataPoints []*HistogramDataPoint AggregationTemporality AggregationTemporality } var ( protoPoolHistogram = sync.Pool{ New: func() any { return &Histogram{} }, } ) func NewHistogram() *Histogram { if !UseProtoPooling.IsEnabled() { return &Histogram{} } return protoPoolHistogram.Get().(*Histogram) } func DeleteHistogram(orig *Histogram, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.DataPoints { DeleteHistogramDataPoint(orig.DataPoints[i], true) } orig.Reset() if nullable { protoPoolHistogram.Put(orig) } } func CopyHistogram(dest, src *Histogram) *Histogram { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewHistogram() } dest.DataPoints = CopyHistogramDataPointPtrSlice(dest.DataPoints, src.DataPoints) dest.AggregationTemporality = src.AggregationTemporality return dest } func CopyHistogramSlice(dest, src []Histogram) []Histogram { var newDest []Histogram if cap(dest) < len(src) { newDest = make([]Histogram, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteHistogram(&dest[i], false) } } for i := range src { CopyHistogram(&newDest[i], &src[i]) } return newDest } func CopyHistogramPtrSlice(dest, src []*Histogram) []*Histogram { var newDest []*Histogram if cap(dest) < len(src) { newDest = make([]*Histogram, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewHistogram() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteHistogram(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewHistogram() } } for i := range src { CopyHistogram(newDest[i], src[i]) } return newDest } func (orig *Histogram) Reset() { *orig = Histogram{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Histogram) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.DataPoints) > 0 { dest.WriteObjectField("dataPoints") dest.WriteArrayStart() orig.DataPoints[0].MarshalJSON(dest) for i := 1; i < len(orig.DataPoints); i++ { dest.WriteMore() orig.DataPoints[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if int32(orig.AggregationTemporality) != 0 { dest.WriteObjectField("aggregationTemporality") dest.WriteInt32(int32(orig.AggregationTemporality)) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Histogram) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "dataPoints", "data_points": for iter.ReadArray() { orig.DataPoints = append(orig.DataPoints, NewHistogramDataPoint()) orig.DataPoints[len(orig.DataPoints)-1].UnmarshalJSON(iter) } case "aggregationTemporality", "aggregation_temporality": orig.AggregationTemporality = AggregationTemporality(iter.ReadEnumValue(AggregationTemporality_value)) default: iter.Skip() } } } func (orig *Histogram) SizeProto() int { var n int var l int _ = l for i := range orig.DataPoints { l = orig.DataPoints[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.AggregationTemporality != 0 { n += 1 + proto.Sov(uint64(orig.AggregationTemporality)) } return n } func (orig *Histogram) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.DataPoints) - 1; i >= 0; i-- { l = orig.DataPoints[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } if orig.AggregationTemporality != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.AggregationTemporality)) pos-- buf[pos] = 0x10 } return len(buf) - pos } func (orig *Histogram) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DataPoints", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DataPoints = append(orig.DataPoints, NewHistogramDataPoint()) err = orig.DataPoints[len(orig.DataPoints)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field AggregationTemporality", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.AggregationTemporality = AggregationTemporality(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestHistogram() *Histogram { orig := NewHistogram() orig.DataPoints = []*HistogramDataPoint{{}, GenTestHistogramDataPoint()} orig.AggregationTemporality = AggregationTemporality(13) return orig } func GenTestHistogramPtrSlice() []*Histogram { orig := make([]*Histogram, 5) orig[0] = NewHistogram() orig[1] = GenTestHistogram() orig[2] = NewHistogram() orig[3] = GenTestHistogram() orig[4] = NewHistogram() return orig } func GenTestHistogramSlice() []Histogram { orig := make([]Histogram, 5) orig[1] = *GenTestHistogram() orig[3] = *GenTestHistogram() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_histogram_test.go000066400000000000000000000143171511331344600302750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyHistogram(t *testing.T) { for name, src := range genTestEncodingValuesHistogram() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewHistogram() CopyHistogram(dest, src) assert.Equal(t, src, dest) CopyHistogram(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyHistogramSlice(t *testing.T) { src := []Histogram{} dest := []Histogram{} // Test CopyTo empty dest = CopyHistogramSlice(dest, src) assert.Equal(t, []Histogram{}, dest) // Test CopyTo larger slice src = GenTestHistogramSlice() dest = CopyHistogramSlice(dest, src) assert.Equal(t, GenTestHistogramSlice(), dest) // Test CopyTo same size slice dest = CopyHistogramSlice(dest, src) assert.Equal(t, GenTestHistogramSlice(), dest) // Test CopyTo smaller size slice dest = CopyHistogramSlice(dest, []Histogram{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyHistogramSlice(dest, src) assert.Equal(t, GenTestHistogramSlice(), dest) } func TestCopyHistogramPtrSlice(t *testing.T) { src := []*Histogram{} dest := []*Histogram{} // Test CopyTo empty dest = CopyHistogramPtrSlice(dest, src) assert.Equal(t, []*Histogram{}, dest) // Test CopyTo larger slice src = GenTestHistogramPtrSlice() dest = CopyHistogramPtrSlice(dest, src) assert.Equal(t, GenTestHistogramPtrSlice(), dest) // Test CopyTo same size slice dest = CopyHistogramPtrSlice(dest, src) assert.Equal(t, GenTestHistogramPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyHistogramPtrSlice(dest, []*Histogram{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyHistogramPtrSlice(dest, src) assert.Equal(t, GenTestHistogramPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONHistogramUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewHistogram() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewHistogram(), dest) } func TestMarshalAndUnmarshalJSONHistogram(t *testing.T) { for name, src := range genTestEncodingValuesHistogram() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewHistogram() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteHistogram(dest, true) }) } } } func TestMarshalAndUnmarshalProtoHistogramFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesHistogram() { t.Run(name, func(t *testing.T) { dest := NewHistogram() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoHistogramUnknown(t *testing.T) { dest := NewHistogram() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewHistogram(), dest) } func TestMarshalAndUnmarshalProtoHistogram(t *testing.T) { for name, src := range genTestEncodingValuesHistogram() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewHistogram() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteHistogram(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufHistogram(t *testing.T) { for name, src := range genTestEncodingValuesHistogram() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.Histogram{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewHistogram() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesHistogram() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "DataPoints/wrong_wire_type": {0xc}, "DataPoints/missing_value": {0xa}, "AggregationTemporality/wrong_wire_type": {0x14}, "AggregationTemporality/missing_value": {0x10}, } } func genTestEncodingValuesHistogram() map[string]*Histogram { return map[string]*Histogram{ "empty": NewHistogram(), "DataPoints/test": {DataPoints: []*HistogramDataPoint{{}, GenTestHistogramDataPoint()}}, "AggregationTemporality/test": {AggregationTemporality: AggregationTemporality(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_histogramdatapoint.go000066400000000000000000000477521511331344600311530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "math" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) func (m *HistogramDataPoint) GetSum_() any { if m != nil { return m.Sum_ } return nil } type HistogramDataPoint_Sum struct { Sum float64 } func (m *HistogramDataPoint) GetSum() float64 { if v, ok := m.GetSum_().(*HistogramDataPoint_Sum); ok { return v.Sum } return float64(0) } func (m *HistogramDataPoint) GetMin_() any { if m != nil { return m.Min_ } return nil } type HistogramDataPoint_Min struct { Min float64 } func (m *HistogramDataPoint) GetMin() float64 { if v, ok := m.GetMin_().(*HistogramDataPoint_Min); ok { return v.Min } return float64(0) } func (m *HistogramDataPoint) GetMax_() any { if m != nil { return m.Max_ } return nil } type HistogramDataPoint_Max struct { Max float64 } func (m *HistogramDataPoint) GetMax() float64 { if v, ok := m.GetMax_().(*HistogramDataPoint_Max); ok { return v.Max } return float64(0) } // HistogramDataPoint is a single data point in a timeseries that describes the time-varying values of a Histogram of values. type HistogramDataPoint struct { Attributes []KeyValue StartTimeUnixNano uint64 TimeUnixNano uint64 Count uint64 Sum_ any BucketCounts []uint64 ExplicitBounds []float64 Exemplars []Exemplar Flags uint32 Min_ any Max_ any } var ( protoPoolHistogramDataPoint = sync.Pool{ New: func() any { return &HistogramDataPoint{} }, } ProtoPoolHistogramDataPoint_Sum = sync.Pool{ New: func() any { return &HistogramDataPoint_Sum{} }, } ProtoPoolHistogramDataPoint_Min = sync.Pool{ New: func() any { return &HistogramDataPoint_Min{} }, } ProtoPoolHistogramDataPoint_Max = sync.Pool{ New: func() any { return &HistogramDataPoint_Max{} }, } ) func NewHistogramDataPoint() *HistogramDataPoint { if !UseProtoPooling.IsEnabled() { return &HistogramDataPoint{} } return protoPoolHistogramDataPoint.Get().(*HistogramDataPoint) } func DeleteHistogramDataPoint(orig *HistogramDataPoint, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } switch ov := orig.Sum_.(type) { case *HistogramDataPoint_Sum: if UseProtoPooling.IsEnabled() { ov.Sum = float64(0) ProtoPoolHistogramDataPoint_Sum.Put(ov) } } for i := range orig.Exemplars { DeleteExemplar(&orig.Exemplars[i], false) } switch ov := orig.Min_.(type) { case *HistogramDataPoint_Min: if UseProtoPooling.IsEnabled() { ov.Min = float64(0) ProtoPoolHistogramDataPoint_Min.Put(ov) } } switch ov := orig.Max_.(type) { case *HistogramDataPoint_Max: if UseProtoPooling.IsEnabled() { ov.Max = float64(0) ProtoPoolHistogramDataPoint_Max.Put(ov) } } orig.Reset() if nullable { protoPoolHistogramDataPoint.Put(orig) } } func CopyHistogramDataPoint(dest, src *HistogramDataPoint) *HistogramDataPoint { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewHistogramDataPoint() } dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.StartTimeUnixNano = src.StartTimeUnixNano dest.TimeUnixNano = src.TimeUnixNano dest.Count = src.Count switch t := src.Sum_.(type) { case *HistogramDataPoint_Sum: var ov *HistogramDataPoint_Sum if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Sum{} } else { ov = ProtoPoolHistogramDataPoint_Sum.Get().(*HistogramDataPoint_Sum) } ov.Sum = t.Sum dest.Sum_ = ov default: dest.Sum_ = nil } dest.BucketCounts = append(dest.BucketCounts[:0], src.BucketCounts...) dest.ExplicitBounds = append(dest.ExplicitBounds[:0], src.ExplicitBounds...) dest.Exemplars = CopyExemplarSlice(dest.Exemplars, src.Exemplars) dest.Flags = src.Flags switch t := src.Min_.(type) { case *HistogramDataPoint_Min: var ov *HistogramDataPoint_Min if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Min{} } else { ov = ProtoPoolHistogramDataPoint_Min.Get().(*HistogramDataPoint_Min) } ov.Min = t.Min dest.Min_ = ov default: dest.Min_ = nil } switch t := src.Max_.(type) { case *HistogramDataPoint_Max: var ov *HistogramDataPoint_Max if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Max{} } else { ov = ProtoPoolHistogramDataPoint_Max.Get().(*HistogramDataPoint_Max) } ov.Max = t.Max dest.Max_ = ov default: dest.Max_ = nil } return dest } func CopyHistogramDataPointSlice(dest, src []HistogramDataPoint) []HistogramDataPoint { var newDest []HistogramDataPoint if cap(dest) < len(src) { newDest = make([]HistogramDataPoint, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteHistogramDataPoint(&dest[i], false) } } for i := range src { CopyHistogramDataPoint(&newDest[i], &src[i]) } return newDest } func CopyHistogramDataPointPtrSlice(dest, src []*HistogramDataPoint) []*HistogramDataPoint { var newDest []*HistogramDataPoint if cap(dest) < len(src) { newDest = make([]*HistogramDataPoint, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewHistogramDataPoint() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteHistogramDataPoint(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewHistogramDataPoint() } } for i := range src { CopyHistogramDataPoint(newDest[i], src[i]) } return newDest } func (orig *HistogramDataPoint) Reset() { *orig = HistogramDataPoint{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *HistogramDataPoint) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.StartTimeUnixNano != uint64(0) { dest.WriteObjectField("startTimeUnixNano") dest.WriteUint64(orig.StartTimeUnixNano) } if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } if orig.Count != uint64(0) { dest.WriteObjectField("count") dest.WriteUint64(orig.Count) } if orig, ok := orig.Sum_.(*HistogramDataPoint_Sum); ok { dest.WriteObjectField("sum") dest.WriteFloat64(orig.Sum) } if len(orig.BucketCounts) > 0 { dest.WriteObjectField("bucketCounts") dest.WriteArrayStart() dest.WriteUint64(orig.BucketCounts[0]) for i := 1; i < len(orig.BucketCounts); i++ { dest.WriteMore() dest.WriteUint64(orig.BucketCounts[i]) } dest.WriteArrayEnd() } if len(orig.ExplicitBounds) > 0 { dest.WriteObjectField("explicitBounds") dest.WriteArrayStart() dest.WriteFloat64(orig.ExplicitBounds[0]) for i := 1; i < len(orig.ExplicitBounds); i++ { dest.WriteMore() dest.WriteFloat64(orig.ExplicitBounds[i]) } dest.WriteArrayEnd() } if len(orig.Exemplars) > 0 { dest.WriteObjectField("exemplars") dest.WriteArrayStart() orig.Exemplars[0].MarshalJSON(dest) for i := 1; i < len(orig.Exemplars); i++ { dest.WriteMore() orig.Exemplars[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.Flags != uint32(0) { dest.WriteObjectField("flags") dest.WriteUint32(orig.Flags) } if orig, ok := orig.Min_.(*HistogramDataPoint_Min); ok { dest.WriteObjectField("min") dest.WriteFloat64(orig.Min) } if orig, ok := orig.Max_.(*HistogramDataPoint_Max); ok { dest.WriteObjectField("max") dest.WriteFloat64(orig.Max) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *HistogramDataPoint) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "startTimeUnixNano", "start_time_unix_nano": orig.StartTimeUnixNano = iter.ReadUint64() case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "count": orig.Count = iter.ReadUint64() case "sum": { var ov *HistogramDataPoint_Sum if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Sum{} } else { ov = ProtoPoolHistogramDataPoint_Sum.Get().(*HistogramDataPoint_Sum) } ov.Sum = iter.ReadFloat64() orig.Sum_ = ov } case "bucketCounts", "bucket_counts": for iter.ReadArray() { orig.BucketCounts = append(orig.BucketCounts, iter.ReadUint64()) } case "explicitBounds", "explicit_bounds": for iter.ReadArray() { orig.ExplicitBounds = append(orig.ExplicitBounds, iter.ReadFloat64()) } case "exemplars": for iter.ReadArray() { orig.Exemplars = append(orig.Exemplars, Exemplar{}) orig.Exemplars[len(orig.Exemplars)-1].UnmarshalJSON(iter) } case "flags": orig.Flags = iter.ReadUint32() case "min": { var ov *HistogramDataPoint_Min if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Min{} } else { ov = ProtoPoolHistogramDataPoint_Min.Get().(*HistogramDataPoint_Min) } ov.Min = iter.ReadFloat64() orig.Min_ = ov } case "max": { var ov *HistogramDataPoint_Max if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Max{} } else { ov = ProtoPoolHistogramDataPoint_Max.Get().(*HistogramDataPoint_Max) } ov.Max = iter.ReadFloat64() orig.Max_ = ov } default: iter.Skip() } } } func (orig *HistogramDataPoint) SizeProto() int { var n int var l int _ = l for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.StartTimeUnixNano != 0 { n += 9 } if orig.TimeUnixNano != 0 { n += 9 } if orig.Count != 0 { n += 9 } if orig, ok := orig.Sum_.(*HistogramDataPoint_Sum); ok { _ = orig n += 9 } l = len(orig.BucketCounts) if l > 0 { l *= 8 n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.ExplicitBounds) if l > 0 { l *= 8 n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.Exemplars { l = orig.Exemplars[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.Flags != 0 { n += 1 + proto.Sov(uint64(orig.Flags)) } if orig, ok := orig.Min_.(*HistogramDataPoint_Min); ok { _ = orig n += 9 } if orig, ok := orig.Max_.(*HistogramDataPoint_Max); ok { _ = orig n += 9 } return n } func (orig *HistogramDataPoint) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x4a } if orig.StartTimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.StartTimeUnixNano)) pos-- buf[pos] = 0x11 } if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x19 } if orig.Count != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.Count)) pos-- buf[pos] = 0x21 } if orig, ok := orig.Sum_.(*HistogramDataPoint_Sum); ok { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Sum)) pos-- buf[pos] = 0x29 } l = len(orig.BucketCounts) if l > 0 { for i := l - 1; i >= 0; i-- { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.BucketCounts[i])) } pos = proto.EncodeVarint(buf, pos, uint64(l*8)) pos-- buf[pos] = 0x32 } l = len(orig.ExplicitBounds) if l > 0 { for i := l - 1; i >= 0; i-- { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.ExplicitBounds[i])) } pos = proto.EncodeVarint(buf, pos, uint64(l*8)) pos-- buf[pos] = 0x3a } for i := len(orig.Exemplars) - 1; i >= 0; i-- { l = orig.Exemplars[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x42 } if orig.Flags != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Flags)) pos-- buf[pos] = 0x50 } if orig, ok := orig.Min_.(*HistogramDataPoint_Min); ok { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Min)) pos-- buf[pos] = 0x59 } if orig, ok := orig.Max_.(*HistogramDataPoint_Max); ok { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Max)) pos-- buf[pos] = 0x61 } return len(buf) - pos } func (orig *HistogramDataPoint) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 9: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field StartTimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.StartTimeUnixNano = uint64(num) case 3: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 4: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.Count = uint64(num) case 5: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Sum", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *HistogramDataPoint_Sum if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Sum{} } else { ov = ProtoPoolHistogramDataPoint_Sum.Get().(*HistogramDataPoint_Sum) } ov.Sum = math.Float64frombits(num) orig.Sum_ = ov case 6: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length size := length / 8 orig.BucketCounts = make([]uint64, size) var num uint64 for i := 0; i < size; i++ { num, startPos, err = proto.ConsumeI64(buf[:pos], startPos) if err != nil { return err } orig.BucketCounts[i] = uint64(num) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field BucketCounts", pos-startPos) } case proto.WireTypeI64: var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.BucketCounts = append(orig.BucketCounts, uint64(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field BucketCounts", wireType) } case 7: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length size := length / 8 orig.ExplicitBounds = make([]float64, size) var num uint64 for i := 0; i < size; i++ { num, startPos, err = proto.ConsumeI64(buf[:pos], startPos) if err != nil { return err } orig.ExplicitBounds[i] = math.Float64frombits(num) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field ExplicitBounds", pos-startPos) } case proto.WireTypeI64: var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.ExplicitBounds = append(orig.ExplicitBounds, math.Float64frombits(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field ExplicitBounds", wireType) } case 8: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Exemplars", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Exemplars = append(orig.Exemplars, Exemplar{}) err = orig.Exemplars[len(orig.Exemplars)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 10: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Flags = uint32(num) case 11: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Min", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *HistogramDataPoint_Min if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Min{} } else { ov = ProtoPoolHistogramDataPoint_Min.Get().(*HistogramDataPoint_Min) } ov.Min = math.Float64frombits(num) orig.Min_ = ov case 12: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Max", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *HistogramDataPoint_Max if !UseProtoPooling.IsEnabled() { ov = &HistogramDataPoint_Max{} } else { ov = ProtoPoolHistogramDataPoint_Max.Get().(*HistogramDataPoint_Max) } ov.Max = math.Float64frombits(num) orig.Max_ = ov default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestHistogramDataPoint() *HistogramDataPoint { orig := NewHistogramDataPoint() orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.StartTimeUnixNano = uint64(13) orig.TimeUnixNano = uint64(13) orig.Count = uint64(13) orig.Sum_ = &HistogramDataPoint_Sum{Sum: float64(3.1415926)} orig.BucketCounts = []uint64{uint64(0), uint64(13)} orig.ExplicitBounds = []float64{float64(0), float64(3.1415926)} orig.Exemplars = []Exemplar{{}, *GenTestExemplar()} orig.Flags = uint32(13) orig.Min_ = &HistogramDataPoint_Min{Min: float64(3.1415926)} orig.Max_ = &HistogramDataPoint_Max{Max: float64(3.1415926)} return orig } func GenTestHistogramDataPointPtrSlice() []*HistogramDataPoint { orig := make([]*HistogramDataPoint, 5) orig[0] = NewHistogramDataPoint() orig[1] = GenTestHistogramDataPoint() orig[2] = NewHistogramDataPoint() orig[3] = GenTestHistogramDataPoint() orig[4] = NewHistogramDataPoint() return orig } func GenTestHistogramDataPointSlice() []HistogramDataPoint { orig := make([]HistogramDataPoint, 5) orig[1] = *GenTestHistogramDataPoint() orig[3] = *GenTestHistogramDataPoint() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_histogramdatapoint_test.go000066400000000000000000000204101511331344600321700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesHistogramDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewHistogramDataPoint() CopyHistogramDataPoint(dest, src) assert.Equal(t, src, dest) CopyHistogramDataPoint(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyHistogramDataPointSlice(t *testing.T) { src := []HistogramDataPoint{} dest := []HistogramDataPoint{} // Test CopyTo empty dest = CopyHistogramDataPointSlice(dest, src) assert.Equal(t, []HistogramDataPoint{}, dest) // Test CopyTo larger slice src = GenTestHistogramDataPointSlice() dest = CopyHistogramDataPointSlice(dest, src) assert.Equal(t, GenTestHistogramDataPointSlice(), dest) // Test CopyTo same size slice dest = CopyHistogramDataPointSlice(dest, src) assert.Equal(t, GenTestHistogramDataPointSlice(), dest) // Test CopyTo smaller size slice dest = CopyHistogramDataPointSlice(dest, []HistogramDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyHistogramDataPointSlice(dest, src) assert.Equal(t, GenTestHistogramDataPointSlice(), dest) } func TestCopyHistogramDataPointPtrSlice(t *testing.T) { src := []*HistogramDataPoint{} dest := []*HistogramDataPoint{} // Test CopyTo empty dest = CopyHistogramDataPointPtrSlice(dest, src) assert.Equal(t, []*HistogramDataPoint{}, dest) // Test CopyTo larger slice src = GenTestHistogramDataPointPtrSlice() dest = CopyHistogramDataPointPtrSlice(dest, src) assert.Equal(t, GenTestHistogramDataPointPtrSlice(), dest) // Test CopyTo same size slice dest = CopyHistogramDataPointPtrSlice(dest, src) assert.Equal(t, GenTestHistogramDataPointPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyHistogramDataPointPtrSlice(dest, []*HistogramDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyHistogramDataPointPtrSlice(dest, src) assert.Equal(t, GenTestHistogramDataPointPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONHistogramDataPointUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewHistogramDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewHistogramDataPoint(), dest) } func TestMarshalAndUnmarshalJSONHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesHistogramDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewHistogramDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteHistogramDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoHistogramDataPointFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesHistogramDataPoint() { t.Run(name, func(t *testing.T) { dest := NewHistogramDataPoint() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoHistogramDataPointUnknown(t *testing.T) { dest := NewHistogramDataPoint() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewHistogramDataPoint(), dest) } func TestMarshalAndUnmarshalProtoHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesHistogramDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewHistogramDataPoint() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteHistogramDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufHistogramDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesHistogramDataPoint() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.HistogramDataPoint{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewHistogramDataPoint() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesHistogramDataPoint() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Attributes/wrong_wire_type": {0x4c}, "Attributes/missing_value": {0x4a}, "StartTimeUnixNano/wrong_wire_type": {0x14}, "StartTimeUnixNano/missing_value": {0x11}, "TimeUnixNano/wrong_wire_type": {0x1c}, "TimeUnixNano/missing_value": {0x19}, "Count/wrong_wire_type": {0x24}, "Count/missing_value": {0x21}, "Sum/wrong_wire_type": {0x2c}, "Sum/missing_value": {0x29}, "BucketCounts/wrong_wire_type": {0x34}, "BucketCounts/missing_value": {0x32}, "ExplicitBounds/wrong_wire_type": {0x3c}, "ExplicitBounds/missing_value": {0x3a}, "Exemplars/wrong_wire_type": {0x44}, "Exemplars/missing_value": {0x42}, "Flags/wrong_wire_type": {0x54}, "Flags/missing_value": {0x50}, "Min/wrong_wire_type": {0x5c}, "Min/missing_value": {0x59}, "Max/wrong_wire_type": {0x64}, "Max/missing_value": {0x61}, } } func genTestEncodingValuesHistogramDataPoint() map[string]*HistogramDataPoint { return map[string]*HistogramDataPoint{ "empty": NewHistogramDataPoint(), "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "StartTimeUnixNano/test": {StartTimeUnixNano: uint64(13)}, "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "Count/test": {Count: uint64(13)}, "Sum/default": {Sum_: &HistogramDataPoint_Sum{Sum: float64(0)}}, "Sum/test": {Sum_: &HistogramDataPoint_Sum{Sum: float64(3.1415926)}}, "BucketCounts/test": {BucketCounts: []uint64{uint64(0), uint64(13)}}, "ExplicitBounds/test": {ExplicitBounds: []float64{float64(0), float64(3.1415926)}}, "Exemplars/test": {Exemplars: []Exemplar{{}, *GenTestExemplar()}}, "Flags/test": {Flags: uint32(13)}, "Min/default": {Min_: &HistogramDataPoint_Min{Min: float64(0)}}, "Min/test": {Min_: &HistogramDataPoint_Min{Min: float64(3.1415926)}}, "Max/default": {Max_: &HistogramDataPoint_Max{Max: float64(0)}}, "Max/test": {Max_: &HistogramDataPoint_Max{Max: float64(3.1415926)}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_instrumentationscope.go000066400000000000000000000206701511331344600315350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // InstrumentationScope is a message representing the instrumentation scope information. type InstrumentationScope struct { Name string Version string Attributes []KeyValue DroppedAttributesCount uint32 } var ( protoPoolInstrumentationScope = sync.Pool{ New: func() any { return &InstrumentationScope{} }, } ) func NewInstrumentationScope() *InstrumentationScope { if !UseProtoPooling.IsEnabled() { return &InstrumentationScope{} } return protoPoolInstrumentationScope.Get().(*InstrumentationScope) } func DeleteInstrumentationScope(orig *InstrumentationScope, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } orig.Reset() if nullable { protoPoolInstrumentationScope.Put(orig) } } func CopyInstrumentationScope(dest, src *InstrumentationScope) *InstrumentationScope { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewInstrumentationScope() } dest.Name = src.Name dest.Version = src.Version dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.DroppedAttributesCount = src.DroppedAttributesCount return dest } func CopyInstrumentationScopeSlice(dest, src []InstrumentationScope) []InstrumentationScope { var newDest []InstrumentationScope if cap(dest) < len(src) { newDest = make([]InstrumentationScope, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteInstrumentationScope(&dest[i], false) } } for i := range src { CopyInstrumentationScope(&newDest[i], &src[i]) } return newDest } func CopyInstrumentationScopePtrSlice(dest, src []*InstrumentationScope) []*InstrumentationScope { var newDest []*InstrumentationScope if cap(dest) < len(src) { newDest = make([]*InstrumentationScope, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewInstrumentationScope() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteInstrumentationScope(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewInstrumentationScope() } } for i := range src { CopyInstrumentationScope(newDest[i], src[i]) } return newDest } func (orig *InstrumentationScope) Reset() { *orig = InstrumentationScope{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *InstrumentationScope) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.Name != "" { dest.WriteObjectField("name") dest.WriteString(orig.Name) } if orig.Version != "" { dest.WriteObjectField("version") dest.WriteString(orig.Version) } if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedAttributesCount != uint32(0) { dest.WriteObjectField("droppedAttributesCount") dest.WriteUint32(orig.DroppedAttributesCount) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *InstrumentationScope) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "name": orig.Name = iter.ReadString() case "version": orig.Version = iter.ReadString() case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "droppedAttributesCount", "dropped_attributes_count": orig.DroppedAttributesCount = iter.ReadUint32() default: iter.Skip() } } } func (orig *InstrumentationScope) SizeProto() int { var n int var l int _ = l l = len(orig.Name) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.Version) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedAttributesCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedAttributesCount)) } return n } func (orig *InstrumentationScope) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.Name) if l > 0 { pos -= l copy(buf[pos:], orig.Name) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = len(orig.Version) if l > 0 { pos -= l copy(buf[pos:], orig.Version) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } if orig.DroppedAttributesCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedAttributesCount)) pos-- buf[pos] = 0x20 } return len(buf) - pos } func (orig *InstrumentationScope) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Name = string(buf[startPos:pos]) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Version", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Version = string(buf[startPos:pos]) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 4: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedAttributesCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedAttributesCount = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestInstrumentationScope() *InstrumentationScope { orig := NewInstrumentationScope() orig.Name = "test_name" orig.Version = "test_version" orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.DroppedAttributesCount = uint32(13) return orig } func GenTestInstrumentationScopePtrSlice() []*InstrumentationScope { orig := make([]*InstrumentationScope, 5) orig[0] = NewInstrumentationScope() orig[1] = GenTestInstrumentationScope() orig[2] = NewInstrumentationScope() orig[3] = GenTestInstrumentationScope() orig[4] = NewInstrumentationScope() return orig } func GenTestInstrumentationScopeSlice() []InstrumentationScope { orig := make([]InstrumentationScope, 5) orig[1] = *GenTestInstrumentationScope() orig[3] = *GenTestInstrumentationScope() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_instrumentationscope_test.go000066400000000000000000000161631511331344600325760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyInstrumentationScope(t *testing.T) { for name, src := range genTestEncodingValuesInstrumentationScope() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewInstrumentationScope() CopyInstrumentationScope(dest, src) assert.Equal(t, src, dest) CopyInstrumentationScope(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyInstrumentationScopeSlice(t *testing.T) { src := []InstrumentationScope{} dest := []InstrumentationScope{} // Test CopyTo empty dest = CopyInstrumentationScopeSlice(dest, src) assert.Equal(t, []InstrumentationScope{}, dest) // Test CopyTo larger slice src = GenTestInstrumentationScopeSlice() dest = CopyInstrumentationScopeSlice(dest, src) assert.Equal(t, GenTestInstrumentationScopeSlice(), dest) // Test CopyTo same size slice dest = CopyInstrumentationScopeSlice(dest, src) assert.Equal(t, GenTestInstrumentationScopeSlice(), dest) // Test CopyTo smaller size slice dest = CopyInstrumentationScopeSlice(dest, []InstrumentationScope{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyInstrumentationScopeSlice(dest, src) assert.Equal(t, GenTestInstrumentationScopeSlice(), dest) } func TestCopyInstrumentationScopePtrSlice(t *testing.T) { src := []*InstrumentationScope{} dest := []*InstrumentationScope{} // Test CopyTo empty dest = CopyInstrumentationScopePtrSlice(dest, src) assert.Equal(t, []*InstrumentationScope{}, dest) // Test CopyTo larger slice src = GenTestInstrumentationScopePtrSlice() dest = CopyInstrumentationScopePtrSlice(dest, src) assert.Equal(t, GenTestInstrumentationScopePtrSlice(), dest) // Test CopyTo same size slice dest = CopyInstrumentationScopePtrSlice(dest, src) assert.Equal(t, GenTestInstrumentationScopePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyInstrumentationScopePtrSlice(dest, []*InstrumentationScope{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyInstrumentationScopePtrSlice(dest, src) assert.Equal(t, GenTestInstrumentationScopePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONInstrumentationScopeUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewInstrumentationScope() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewInstrumentationScope(), dest) } func TestMarshalAndUnmarshalJSONInstrumentationScope(t *testing.T) { for name, src := range genTestEncodingValuesInstrumentationScope() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewInstrumentationScope() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteInstrumentationScope(dest, true) }) } } } func TestMarshalAndUnmarshalProtoInstrumentationScopeFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesInstrumentationScope() { t.Run(name, func(t *testing.T) { dest := NewInstrumentationScope() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoInstrumentationScopeUnknown(t *testing.T) { dest := NewInstrumentationScope() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewInstrumentationScope(), dest) } func TestMarshalAndUnmarshalProtoInstrumentationScope(t *testing.T) { for name, src := range genTestEncodingValuesInstrumentationScope() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewInstrumentationScope() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteInstrumentationScope(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufInstrumentationScope(t *testing.T) { for name, src := range genTestEncodingValuesInstrumentationScope() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcommon.InstrumentationScope{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewInstrumentationScope() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesInstrumentationScope() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Name/wrong_wire_type": {0xc}, "Name/missing_value": {0xa}, "Version/wrong_wire_type": {0x14}, "Version/missing_value": {0x12}, "Attributes/wrong_wire_type": {0x1c}, "Attributes/missing_value": {0x1a}, "DroppedAttributesCount/wrong_wire_type": {0x24}, "DroppedAttributesCount/missing_value": {0x20}, } } func genTestEncodingValuesInstrumentationScope() map[string]*InstrumentationScope { return map[string]*InstrumentationScope{ "empty": NewInstrumentationScope(), "Name/test": {Name: "test_name"}, "Version/test": {Version: "test_version"}, "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "DroppedAttributesCount/test": {DroppedAttributesCount: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_ipaddr.go000066400000000000000000000123771511331344600265100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type IPAddr struct { IP []byte Zone string } var ( protoPoolIPAddr = sync.Pool{ New: func() any { return &IPAddr{} }, } ) func NewIPAddr() *IPAddr { if !UseProtoPooling.IsEnabled() { return &IPAddr{} } return protoPoolIPAddr.Get().(*IPAddr) } func DeleteIPAddr(orig *IPAddr, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolIPAddr.Put(orig) } } func CopyIPAddr(dest, src *IPAddr) *IPAddr { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewIPAddr() } dest.IP = src.IP dest.Zone = src.Zone return dest } func CopyIPAddrSlice(dest, src []IPAddr) []IPAddr { var newDest []IPAddr if cap(dest) < len(src) { newDest = make([]IPAddr, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteIPAddr(&dest[i], false) } } for i := range src { CopyIPAddr(&newDest[i], &src[i]) } return newDest } func CopyIPAddrPtrSlice(dest, src []*IPAddr) []*IPAddr { var newDest []*IPAddr if cap(dest) < len(src) { newDest = make([]*IPAddr, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewIPAddr() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteIPAddr(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewIPAddr() } } for i := range src { CopyIPAddr(newDest[i], src[i]) } return newDest } func (orig *IPAddr) Reset() { *orig = IPAddr{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *IPAddr) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.IP) > 0 { dest.WriteObjectField("iP") dest.WriteBytes(orig.IP) } if orig.Zone != "" { dest.WriteObjectField("zone") dest.WriteString(orig.Zone) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *IPAddr) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "iP": orig.IP = iter.ReadBytes() case "zone": orig.Zone = iter.ReadString() default: iter.Skip() } } } func (orig *IPAddr) SizeProto() int { var n int var l int _ = l l = len(orig.IP) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.Zone) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *IPAddr) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.IP) if l > 0 { pos -= l copy(buf[pos:], orig.IP) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = len(orig.Zone) if l > 0 { pos -= l copy(buf[pos:], orig.Zone) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } return len(buf) - pos } func (orig *IPAddr) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field IP", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length if length != 0 { orig.IP = make([]byte, length) copy(orig.IP, buf[startPos:pos]) } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Zone", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Zone = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestIPAddr() *IPAddr { orig := NewIPAddr() orig.IP = []byte{1, 2, 3} orig.Zone = "test_zone" return orig } func GenTestIPAddrPtrSlice() []*IPAddr { orig := make([]*IPAddr, 5) orig[0] = NewIPAddr() orig[1] = GenTestIPAddr() orig[2] = NewIPAddr() orig[3] = GenTestIPAddr() orig[4] = NewIPAddr() return orig } func GenTestIPAddrSlice() []IPAddr { orig := make([]IPAddr, 5) orig[1] = *GenTestIPAddr() orig[3] = *GenTestIPAddr() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_ipaddr_test.go000066400000000000000000000134511511331344600275410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyIPAddr(t *testing.T) { for name, src := range genTestEncodingValuesIPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewIPAddr() CopyIPAddr(dest, src) assert.Equal(t, src, dest) CopyIPAddr(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyIPAddrSlice(t *testing.T) { src := []IPAddr{} dest := []IPAddr{} // Test CopyTo empty dest = CopyIPAddrSlice(dest, src) assert.Equal(t, []IPAddr{}, dest) // Test CopyTo larger slice src = GenTestIPAddrSlice() dest = CopyIPAddrSlice(dest, src) assert.Equal(t, GenTestIPAddrSlice(), dest) // Test CopyTo same size slice dest = CopyIPAddrSlice(dest, src) assert.Equal(t, GenTestIPAddrSlice(), dest) // Test CopyTo smaller size slice dest = CopyIPAddrSlice(dest, []IPAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyIPAddrSlice(dest, src) assert.Equal(t, GenTestIPAddrSlice(), dest) } func TestCopyIPAddrPtrSlice(t *testing.T) { src := []*IPAddr{} dest := []*IPAddr{} // Test CopyTo empty dest = CopyIPAddrPtrSlice(dest, src) assert.Equal(t, []*IPAddr{}, dest) // Test CopyTo larger slice src = GenTestIPAddrPtrSlice() dest = CopyIPAddrPtrSlice(dest, src) assert.Equal(t, GenTestIPAddrPtrSlice(), dest) // Test CopyTo same size slice dest = CopyIPAddrPtrSlice(dest, src) assert.Equal(t, GenTestIPAddrPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyIPAddrPtrSlice(dest, []*IPAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyIPAddrPtrSlice(dest, src) assert.Equal(t, GenTestIPAddrPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONIPAddrUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewIPAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewIPAddr(), dest) } func TestMarshalAndUnmarshalJSONIPAddr(t *testing.T) { for name, src := range genTestEncodingValuesIPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewIPAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteIPAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoIPAddrFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesIPAddr() { t.Run(name, func(t *testing.T) { dest := NewIPAddr() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoIPAddrUnknown(t *testing.T) { dest := NewIPAddr() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewIPAddr(), dest) } func TestMarshalAndUnmarshalProtoIPAddr(t *testing.T) { for name, src := range genTestEncodingValuesIPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewIPAddr() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteIPAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufIPAddr(t *testing.T) { for name, src := range genTestEncodingValuesIPAddr() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewIPAddr() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesIPAddr() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "IP/wrong_wire_type": {0xc}, "IP/missing_value": {0xa}, "Zone/wrong_wire_type": {0x14}, "Zone/missing_value": {0x12}, } } func genTestEncodingValuesIPAddr() map[string]*IPAddr { return map[string]*IPAddr{ "empty": NewIPAddr(), "IP/test": {IP: []byte{1, 2, 3}}, "Zone/test": {Zone: "test_zone"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_keyvalue.go000066400000000000000000000125661511331344600270720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type KeyValue struct { Key string Value AnyValue } var ( protoPoolKeyValue = sync.Pool{ New: func() any { return &KeyValue{} }, } ) func NewKeyValue() *KeyValue { if !UseProtoPooling.IsEnabled() { return &KeyValue{} } return protoPoolKeyValue.Get().(*KeyValue) } func DeleteKeyValue(orig *KeyValue, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteAnyValue(&orig.Value, false) orig.Reset() if nullable { protoPoolKeyValue.Put(orig) } } func CopyKeyValue(dest, src *KeyValue) *KeyValue { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewKeyValue() } dest.Key = src.Key CopyAnyValue(&dest.Value, &src.Value) return dest } func CopyKeyValueSlice(dest, src []KeyValue) []KeyValue { var newDest []KeyValue if cap(dest) < len(src) { newDest = make([]KeyValue, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteKeyValue(&dest[i], false) } } for i := range src { CopyKeyValue(&newDest[i], &src[i]) } return newDest } func CopyKeyValuePtrSlice(dest, src []*KeyValue) []*KeyValue { var newDest []*KeyValue if cap(dest) < len(src) { newDest = make([]*KeyValue, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewKeyValue() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteKeyValue(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewKeyValue() } } for i := range src { CopyKeyValue(newDest[i], src[i]) } return newDest } func (orig *KeyValue) Reset() { *orig = KeyValue{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *KeyValue) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.Key != "" { dest.WriteObjectField("key") dest.WriteString(orig.Key) } dest.WriteObjectField("value") orig.Value.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *KeyValue) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "key": orig.Key = iter.ReadString() case "value": orig.Value.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *KeyValue) SizeProto() int { var n int var l int _ = l l = len(orig.Key) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = orig.Value.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *KeyValue) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.Key) if l > 0 { pos -= l copy(buf[pos:], orig.Key) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = orig.Value.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 return len(buf) - pos } func (orig *KeyValue) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Key = string(buf[startPos:pos]) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Value.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestKeyValue() *KeyValue { orig := NewKeyValue() orig.Key = "test_key" orig.Value = *GenTestAnyValue() return orig } func GenTestKeyValuePtrSlice() []*KeyValue { orig := make([]*KeyValue, 5) orig[0] = NewKeyValue() orig[1] = GenTestKeyValue() orig[2] = NewKeyValue() orig[3] = GenTestKeyValue() orig[4] = NewKeyValue() return orig } func GenTestKeyValueSlice() []KeyValue { orig := make([]KeyValue, 5) orig[1] = *GenTestKeyValue() orig[3] = *GenTestKeyValue() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_keyvalue_test.go000066400000000000000000000136751511331344600301330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyKeyValue(t *testing.T) { for name, src := range genTestEncodingValuesKeyValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewKeyValue() CopyKeyValue(dest, src) assert.Equal(t, src, dest) CopyKeyValue(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyKeyValueSlice(t *testing.T) { src := []KeyValue{} dest := []KeyValue{} // Test CopyTo empty dest = CopyKeyValueSlice(dest, src) assert.Equal(t, []KeyValue{}, dest) // Test CopyTo larger slice src = GenTestKeyValueSlice() dest = CopyKeyValueSlice(dest, src) assert.Equal(t, GenTestKeyValueSlice(), dest) // Test CopyTo same size slice dest = CopyKeyValueSlice(dest, src) assert.Equal(t, GenTestKeyValueSlice(), dest) // Test CopyTo smaller size slice dest = CopyKeyValueSlice(dest, []KeyValue{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyKeyValueSlice(dest, src) assert.Equal(t, GenTestKeyValueSlice(), dest) } func TestCopyKeyValuePtrSlice(t *testing.T) { src := []*KeyValue{} dest := []*KeyValue{} // Test CopyTo empty dest = CopyKeyValuePtrSlice(dest, src) assert.Equal(t, []*KeyValue{}, dest) // Test CopyTo larger slice src = GenTestKeyValuePtrSlice() dest = CopyKeyValuePtrSlice(dest, src) assert.Equal(t, GenTestKeyValuePtrSlice(), dest) // Test CopyTo same size slice dest = CopyKeyValuePtrSlice(dest, src) assert.Equal(t, GenTestKeyValuePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyKeyValuePtrSlice(dest, []*KeyValue{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyKeyValuePtrSlice(dest, src) assert.Equal(t, GenTestKeyValuePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONKeyValueUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewKeyValue() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewKeyValue(), dest) } func TestMarshalAndUnmarshalJSONKeyValue(t *testing.T) { for name, src := range genTestEncodingValuesKeyValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewKeyValue() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteKeyValue(dest, true) }) } } } func TestMarshalAndUnmarshalProtoKeyValueFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesKeyValue() { t.Run(name, func(t *testing.T) { dest := NewKeyValue() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoKeyValueUnknown(t *testing.T) { dest := NewKeyValue() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewKeyValue(), dest) } func TestMarshalAndUnmarshalProtoKeyValue(t *testing.T) { for name, src := range genTestEncodingValuesKeyValue() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewKeyValue() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteKeyValue(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufKeyValue(t *testing.T) { for name, src := range genTestEncodingValuesKeyValue() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcommon.KeyValue{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewKeyValue() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesKeyValue() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Key/wrong_wire_type": {0xc}, "Key/missing_value": {0xa}, "Value/wrong_wire_type": {0x14}, "Value/missing_value": {0x12}, } } func genTestEncodingValuesKeyValue() map[string]*KeyValue { return map[string]*KeyValue{ "empty": NewKeyValue(), "Key/test": {Key: "test_key"}, "Value/test": {Value: *GenTestAnyValue()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_keyvalueandunit.go000066400000000000000000000153321511331344600304470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // KeyValueAndUnit represents a custom 'dictionary native' // style of encoding attributes which is more convenient // for profiles than opentelemetry.proto.common.v1.KeyValue. type KeyValueAndUnit struct { KeyStrindex int32 Value AnyValue UnitStrindex int32 } var ( protoPoolKeyValueAndUnit = sync.Pool{ New: func() any { return &KeyValueAndUnit{} }, } ) func NewKeyValueAndUnit() *KeyValueAndUnit { if !UseProtoPooling.IsEnabled() { return &KeyValueAndUnit{} } return protoPoolKeyValueAndUnit.Get().(*KeyValueAndUnit) } func DeleteKeyValueAndUnit(orig *KeyValueAndUnit, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteAnyValue(&orig.Value, false) orig.Reset() if nullable { protoPoolKeyValueAndUnit.Put(orig) } } func CopyKeyValueAndUnit(dest, src *KeyValueAndUnit) *KeyValueAndUnit { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewKeyValueAndUnit() } dest.KeyStrindex = src.KeyStrindex CopyAnyValue(&dest.Value, &src.Value) dest.UnitStrindex = src.UnitStrindex return dest } func CopyKeyValueAndUnitSlice(dest, src []KeyValueAndUnit) []KeyValueAndUnit { var newDest []KeyValueAndUnit if cap(dest) < len(src) { newDest = make([]KeyValueAndUnit, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteKeyValueAndUnit(&dest[i], false) } } for i := range src { CopyKeyValueAndUnit(&newDest[i], &src[i]) } return newDest } func CopyKeyValueAndUnitPtrSlice(dest, src []*KeyValueAndUnit) []*KeyValueAndUnit { var newDest []*KeyValueAndUnit if cap(dest) < len(src) { newDest = make([]*KeyValueAndUnit, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewKeyValueAndUnit() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteKeyValueAndUnit(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewKeyValueAndUnit() } } for i := range src { CopyKeyValueAndUnit(newDest[i], src[i]) } return newDest } func (orig *KeyValueAndUnit) Reset() { *orig = KeyValueAndUnit{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *KeyValueAndUnit) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.KeyStrindex != int32(0) { dest.WriteObjectField("keyStrindex") dest.WriteInt32(orig.KeyStrindex) } dest.WriteObjectField("value") orig.Value.MarshalJSON(dest) if orig.UnitStrindex != int32(0) { dest.WriteObjectField("unitStrindex") dest.WriteInt32(orig.UnitStrindex) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *KeyValueAndUnit) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "keyStrindex", "key_strindex": orig.KeyStrindex = iter.ReadInt32() case "value": orig.Value.UnmarshalJSON(iter) case "unitStrindex", "unit_strindex": orig.UnitStrindex = iter.ReadInt32() default: iter.Skip() } } } func (orig *KeyValueAndUnit) SizeProto() int { var n int var l int _ = l if orig.KeyStrindex != 0 { n += 1 + proto.Sov(uint64(orig.KeyStrindex)) } l = orig.Value.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.UnitStrindex != 0 { n += 1 + proto.Sov(uint64(orig.UnitStrindex)) } return n } func (orig *KeyValueAndUnit) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.KeyStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.KeyStrindex)) pos-- buf[pos] = 0x8 } l = orig.Value.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 if orig.UnitStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.UnitStrindex)) pos-- buf[pos] = 0x18 } return len(buf) - pos } func (orig *KeyValueAndUnit) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field KeyStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.KeyStrindex = int32(num) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Value.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field UnitStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.UnitStrindex = int32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestKeyValueAndUnit() *KeyValueAndUnit { orig := NewKeyValueAndUnit() orig.KeyStrindex = int32(13) orig.Value = *GenTestAnyValue() orig.UnitStrindex = int32(13) return orig } func GenTestKeyValueAndUnitPtrSlice() []*KeyValueAndUnit { orig := make([]*KeyValueAndUnit, 5) orig[0] = NewKeyValueAndUnit() orig[1] = GenTestKeyValueAndUnit() orig[2] = NewKeyValueAndUnit() orig[3] = GenTestKeyValueAndUnit() orig[4] = NewKeyValueAndUnit() return orig } func GenTestKeyValueAndUnitSlice() []KeyValueAndUnit { orig := make([]KeyValueAndUnit, 5) orig[1] = *GenTestKeyValueAndUnit() orig[3] = *GenTestKeyValueAndUnit() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_keyvalueandunit_test.go000066400000000000000000000150601511331344600315040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyKeyValueAndUnit(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueAndUnit() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewKeyValueAndUnit() CopyKeyValueAndUnit(dest, src) assert.Equal(t, src, dest) CopyKeyValueAndUnit(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyKeyValueAndUnitSlice(t *testing.T) { src := []KeyValueAndUnit{} dest := []KeyValueAndUnit{} // Test CopyTo empty dest = CopyKeyValueAndUnitSlice(dest, src) assert.Equal(t, []KeyValueAndUnit{}, dest) // Test CopyTo larger slice src = GenTestKeyValueAndUnitSlice() dest = CopyKeyValueAndUnitSlice(dest, src) assert.Equal(t, GenTestKeyValueAndUnitSlice(), dest) // Test CopyTo same size slice dest = CopyKeyValueAndUnitSlice(dest, src) assert.Equal(t, GenTestKeyValueAndUnitSlice(), dest) // Test CopyTo smaller size slice dest = CopyKeyValueAndUnitSlice(dest, []KeyValueAndUnit{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyKeyValueAndUnitSlice(dest, src) assert.Equal(t, GenTestKeyValueAndUnitSlice(), dest) } func TestCopyKeyValueAndUnitPtrSlice(t *testing.T) { src := []*KeyValueAndUnit{} dest := []*KeyValueAndUnit{} // Test CopyTo empty dest = CopyKeyValueAndUnitPtrSlice(dest, src) assert.Equal(t, []*KeyValueAndUnit{}, dest) // Test CopyTo larger slice src = GenTestKeyValueAndUnitPtrSlice() dest = CopyKeyValueAndUnitPtrSlice(dest, src) assert.Equal(t, GenTestKeyValueAndUnitPtrSlice(), dest) // Test CopyTo same size slice dest = CopyKeyValueAndUnitPtrSlice(dest, src) assert.Equal(t, GenTestKeyValueAndUnitPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyKeyValueAndUnitPtrSlice(dest, []*KeyValueAndUnit{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyKeyValueAndUnitPtrSlice(dest, src) assert.Equal(t, GenTestKeyValueAndUnitPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONKeyValueAndUnitUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewKeyValueAndUnit() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewKeyValueAndUnit(), dest) } func TestMarshalAndUnmarshalJSONKeyValueAndUnit(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueAndUnit() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewKeyValueAndUnit() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteKeyValueAndUnit(dest, true) }) } } } func TestMarshalAndUnmarshalProtoKeyValueAndUnitFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesKeyValueAndUnit() { t.Run(name, func(t *testing.T) { dest := NewKeyValueAndUnit() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoKeyValueAndUnitUnknown(t *testing.T) { dest := NewKeyValueAndUnit() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewKeyValueAndUnit(), dest) } func TestMarshalAndUnmarshalProtoKeyValueAndUnit(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueAndUnit() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewKeyValueAndUnit() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteKeyValueAndUnit(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufKeyValueAndUnit(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueAndUnit() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.KeyValueAndUnit{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewKeyValueAndUnit() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesKeyValueAndUnit() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "KeyStrindex/wrong_wire_type": {0xc}, "KeyStrindex/missing_value": {0x8}, "Value/wrong_wire_type": {0x14}, "Value/missing_value": {0x12}, "UnitStrindex/wrong_wire_type": {0x1c}, "UnitStrindex/missing_value": {0x18}, } } func genTestEncodingValuesKeyValueAndUnit() map[string]*KeyValueAndUnit { return map[string]*KeyValueAndUnit{ "empty": NewKeyValueAndUnit(), "KeyStrindex/test": {KeyStrindex: int32(13)}, "Value/test": {Value: *GenTestAnyValue()}, "UnitStrindex/test": {UnitStrindex: int32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_keyvaluelist.go000066400000000000000000000130511511331344600277540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // KeyValueList is a list of KeyValue messages. We need KeyValueList as a message since oneof in AnyValue does not allow repeated fields. type KeyValueList struct { Values []KeyValue } var ( protoPoolKeyValueList = sync.Pool{ New: func() any { return &KeyValueList{} }, } ) func NewKeyValueList() *KeyValueList { if !UseProtoPooling.IsEnabled() { return &KeyValueList{} } return protoPoolKeyValueList.Get().(*KeyValueList) } func DeleteKeyValueList(orig *KeyValueList, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Values { DeleteKeyValue(&orig.Values[i], false) } orig.Reset() if nullable { protoPoolKeyValueList.Put(orig) } } func CopyKeyValueList(dest, src *KeyValueList) *KeyValueList { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewKeyValueList() } dest.Values = CopyKeyValueSlice(dest.Values, src.Values) return dest } func CopyKeyValueListSlice(dest, src []KeyValueList) []KeyValueList { var newDest []KeyValueList if cap(dest) < len(src) { newDest = make([]KeyValueList, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteKeyValueList(&dest[i], false) } } for i := range src { CopyKeyValueList(&newDest[i], &src[i]) } return newDest } func CopyKeyValueListPtrSlice(dest, src []*KeyValueList) []*KeyValueList { var newDest []*KeyValueList if cap(dest) < len(src) { newDest = make([]*KeyValueList, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewKeyValueList() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteKeyValueList(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewKeyValueList() } } for i := range src { CopyKeyValueList(newDest[i], src[i]) } return newDest } func (orig *KeyValueList) Reset() { *orig = KeyValueList{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *KeyValueList) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.Values) > 0 { dest.WriteObjectField("values") dest.WriteArrayStart() orig.Values[0].MarshalJSON(dest) for i := 1; i < len(orig.Values); i++ { dest.WriteMore() orig.Values[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *KeyValueList) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "values": for iter.ReadArray() { orig.Values = append(orig.Values, KeyValue{}) orig.Values[len(orig.Values)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *KeyValueList) SizeProto() int { var n int var l int _ = l for i := range orig.Values { l = orig.Values[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *KeyValueList) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.Values) - 1; i >= 0; i-- { l = orig.Values[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *KeyValueList) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Values = append(orig.Values, KeyValue{}) err = orig.Values[len(orig.Values)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestKeyValueList() *KeyValueList { orig := NewKeyValueList() orig.Values = []KeyValue{{}, *GenTestKeyValue()} return orig } func GenTestKeyValueListPtrSlice() []*KeyValueList { orig := make([]*KeyValueList, 5) orig[0] = NewKeyValueList() orig[1] = GenTestKeyValueList() orig[2] = NewKeyValueList() orig[3] = GenTestKeyValueList() orig[4] = NewKeyValueList() return orig } func GenTestKeyValueListSlice() []KeyValueList { orig := make([]KeyValueList, 5) orig[1] = *GenTestKeyValueList() orig[3] = *GenTestKeyValueList() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_keyvaluelist_test.go000066400000000000000000000141261511331344600310170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyKeyValueList(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueList() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewKeyValueList() CopyKeyValueList(dest, src) assert.Equal(t, src, dest) CopyKeyValueList(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyKeyValueListSlice(t *testing.T) { src := []KeyValueList{} dest := []KeyValueList{} // Test CopyTo empty dest = CopyKeyValueListSlice(dest, src) assert.Equal(t, []KeyValueList{}, dest) // Test CopyTo larger slice src = GenTestKeyValueListSlice() dest = CopyKeyValueListSlice(dest, src) assert.Equal(t, GenTestKeyValueListSlice(), dest) // Test CopyTo same size slice dest = CopyKeyValueListSlice(dest, src) assert.Equal(t, GenTestKeyValueListSlice(), dest) // Test CopyTo smaller size slice dest = CopyKeyValueListSlice(dest, []KeyValueList{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyKeyValueListSlice(dest, src) assert.Equal(t, GenTestKeyValueListSlice(), dest) } func TestCopyKeyValueListPtrSlice(t *testing.T) { src := []*KeyValueList{} dest := []*KeyValueList{} // Test CopyTo empty dest = CopyKeyValueListPtrSlice(dest, src) assert.Equal(t, []*KeyValueList{}, dest) // Test CopyTo larger slice src = GenTestKeyValueListPtrSlice() dest = CopyKeyValueListPtrSlice(dest, src) assert.Equal(t, GenTestKeyValueListPtrSlice(), dest) // Test CopyTo same size slice dest = CopyKeyValueListPtrSlice(dest, src) assert.Equal(t, GenTestKeyValueListPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyKeyValueListPtrSlice(dest, []*KeyValueList{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyKeyValueListPtrSlice(dest, src) assert.Equal(t, GenTestKeyValueListPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONKeyValueListUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewKeyValueList() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewKeyValueList(), dest) } func TestMarshalAndUnmarshalJSONKeyValueList(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueList() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewKeyValueList() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteKeyValueList(dest, true) }) } } } func TestMarshalAndUnmarshalProtoKeyValueListFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesKeyValueList() { t.Run(name, func(t *testing.T) { dest := NewKeyValueList() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoKeyValueListUnknown(t *testing.T) { dest := NewKeyValueList() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewKeyValueList(), dest) } func TestMarshalAndUnmarshalProtoKeyValueList(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueList() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewKeyValueList() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteKeyValueList(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufKeyValueList(t *testing.T) { for name, src := range genTestEncodingValuesKeyValueList() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpcommon.KeyValueList{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewKeyValueList() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesKeyValueList() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Values/wrong_wire_type": {0xc}, "Values/missing_value": {0xa}, } } func genTestEncodingValuesKeyValueList() map[string]*KeyValueList { return map[string]*KeyValueList{ "empty": NewKeyValueList(), "Values/test": {Values: []KeyValue{{}, *GenTestKeyValue()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_line.go000066400000000000000000000135061511331344600261670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Line details a specific line in a source code, linked to a function. type Line struct { FunctionIndex int32 Line int64 Column int64 } var ( protoPoolLine = sync.Pool{ New: func() any { return &Line{} }, } ) func NewLine() *Line { if !UseProtoPooling.IsEnabled() { return &Line{} } return protoPoolLine.Get().(*Line) } func DeleteLine(orig *Line, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolLine.Put(orig) } } func CopyLine(dest, src *Line) *Line { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewLine() } dest.FunctionIndex = src.FunctionIndex dest.Line = src.Line dest.Column = src.Column return dest } func CopyLineSlice(dest, src []Line) []Line { var newDest []Line if cap(dest) < len(src) { newDest = make([]Line, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLine(&dest[i], false) } } for i := range src { CopyLine(&newDest[i], &src[i]) } return newDest } func CopyLinePtrSlice(dest, src []*Line) []*Line { var newDest []*Line if cap(dest) < len(src) { newDest = make([]*Line, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewLine() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLine(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewLine() } } for i := range src { CopyLine(newDest[i], src[i]) } return newDest } func (orig *Line) Reset() { *orig = Line{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Line) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.FunctionIndex != int32(0) { dest.WriteObjectField("functionIndex") dest.WriteInt32(orig.FunctionIndex) } if orig.Line != int64(0) { dest.WriteObjectField("line") dest.WriteInt64(orig.Line) } if orig.Column != int64(0) { dest.WriteObjectField("column") dest.WriteInt64(orig.Column) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Line) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "functionIndex", "function_index": orig.FunctionIndex = iter.ReadInt32() case "line": orig.Line = iter.ReadInt64() case "column": orig.Column = iter.ReadInt64() default: iter.Skip() } } } func (orig *Line) SizeProto() int { var n int var l int _ = l if orig.FunctionIndex != 0 { n += 1 + proto.Sov(uint64(orig.FunctionIndex)) } if orig.Line != 0 { n += 1 + proto.Sov(uint64(orig.Line)) } if orig.Column != 0 { n += 1 + proto.Sov(uint64(orig.Column)) } return n } func (orig *Line) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.FunctionIndex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.FunctionIndex)) pos-- buf[pos] = 0x8 } if orig.Line != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Line)) pos-- buf[pos] = 0x10 } if orig.Column != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Column)) pos-- buf[pos] = 0x18 } return len(buf) - pos } func (orig *Line) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field FunctionIndex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.FunctionIndex = int32(num) case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Line", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Line = int64(num) case 3: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Column", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Column = int64(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestLine() *Line { orig := NewLine() orig.FunctionIndex = int32(13) orig.Line = int64(13) orig.Column = int64(13) return orig } func GenTestLinePtrSlice() []*Line { orig := make([]*Line, 5) orig[0] = NewLine() orig[1] = GenTestLine() orig[2] = NewLine() orig[3] = GenTestLine() orig[4] = NewLine() return orig } func GenTestLineSlice() []Line { orig := make([]Line, 5) orig[1] = *GenTestLine() orig[3] = *GenTestLine() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_line_test.go000066400000000000000000000136441511331344600272310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyLine(t *testing.T) { for name, src := range genTestEncodingValuesLine() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewLine() CopyLine(dest, src) assert.Equal(t, src, dest) CopyLine(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyLineSlice(t *testing.T) { src := []Line{} dest := []Line{} // Test CopyTo empty dest = CopyLineSlice(dest, src) assert.Equal(t, []Line{}, dest) // Test CopyTo larger slice src = GenTestLineSlice() dest = CopyLineSlice(dest, src) assert.Equal(t, GenTestLineSlice(), dest) // Test CopyTo same size slice dest = CopyLineSlice(dest, src) assert.Equal(t, GenTestLineSlice(), dest) // Test CopyTo smaller size slice dest = CopyLineSlice(dest, []Line{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLineSlice(dest, src) assert.Equal(t, GenTestLineSlice(), dest) } func TestCopyLinePtrSlice(t *testing.T) { src := []*Line{} dest := []*Line{} // Test CopyTo empty dest = CopyLinePtrSlice(dest, src) assert.Equal(t, []*Line{}, dest) // Test CopyTo larger slice src = GenTestLinePtrSlice() dest = CopyLinePtrSlice(dest, src) assert.Equal(t, GenTestLinePtrSlice(), dest) // Test CopyTo same size slice dest = CopyLinePtrSlice(dest, src) assert.Equal(t, GenTestLinePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyLinePtrSlice(dest, []*Line{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLinePtrSlice(dest, src) assert.Equal(t, GenTestLinePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONLineUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewLine() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewLine(), dest) } func TestMarshalAndUnmarshalJSONLine(t *testing.T) { for name, src := range genTestEncodingValuesLine() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewLine() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteLine(dest, true) }) } } } func TestMarshalAndUnmarshalProtoLineFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesLine() { t.Run(name, func(t *testing.T) { dest := NewLine() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoLineUnknown(t *testing.T) { dest := NewLine() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewLine(), dest) } func TestMarshalAndUnmarshalProtoLine(t *testing.T) { for name, src := range genTestEncodingValuesLine() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewLine() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteLine(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufLine(t *testing.T) { for name, src := range genTestEncodingValuesLine() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Line{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewLine() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesLine() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "FunctionIndex/wrong_wire_type": {0xc}, "FunctionIndex/missing_value": {0x8}, "Line/wrong_wire_type": {0x14}, "Line/missing_value": {0x10}, "Column/wrong_wire_type": {0x1c}, "Column/missing_value": {0x18}, } } func genTestEncodingValuesLine() map[string]*Line { return map[string]*Line{ "empty": NewLine(), "FunctionIndex/test": {FunctionIndex: int32(13)}, "Line/test": {Line: int64(13)}, "Column/test": {Column: int64(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_link.go000066400000000000000000000126441511331344600261770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Link represents a pointer from a profile Sample to a trace Span. type Link struct { TraceId TraceID SpanId SpanID } var ( protoPoolLink = sync.Pool{ New: func() any { return &Link{} }, } ) func NewLink() *Link { if !UseProtoPooling.IsEnabled() { return &Link{} } return protoPoolLink.Get().(*Link) } func DeleteLink(orig *Link, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteTraceID(&orig.TraceId, false) DeleteSpanID(&orig.SpanId, false) orig.Reset() if nullable { protoPoolLink.Put(orig) } } func CopyLink(dest, src *Link) *Link { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewLink() } CopyTraceID(&dest.TraceId, &src.TraceId) CopySpanID(&dest.SpanId, &src.SpanId) return dest } func CopyLinkSlice(dest, src []Link) []Link { var newDest []Link if cap(dest) < len(src) { newDest = make([]Link, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLink(&dest[i], false) } } for i := range src { CopyLink(&newDest[i], &src[i]) } return newDest } func CopyLinkPtrSlice(dest, src []*Link) []*Link { var newDest []*Link if cap(dest) < len(src) { newDest = make([]*Link, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewLink() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLink(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewLink() } } for i := range src { CopyLink(newDest[i], src[i]) } return newDest } func (orig *Link) Reset() { *orig = Link{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Link) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if !orig.TraceId.IsEmpty() { dest.WriteObjectField("traceId") orig.TraceId.MarshalJSON(dest) } if !orig.SpanId.IsEmpty() { dest.WriteObjectField("spanId") orig.SpanId.MarshalJSON(dest) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Link) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "traceId", "trace_id": orig.TraceId.UnmarshalJSON(iter) case "spanId", "span_id": orig.SpanId.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *Link) SizeProto() int { var n int var l int _ = l l = orig.TraceId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = orig.SpanId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *Link) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.TraceId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa l = orig.SpanId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 return len(buf) - pos } func (orig *Link) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.TraceId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.SpanId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestLink() *Link { orig := NewLink() orig.TraceId = *GenTestTraceID() orig.SpanId = *GenTestSpanID() return orig } func GenTestLinkPtrSlice() []*Link { orig := make([]*Link, 5) orig[0] = NewLink() orig[1] = GenTestLink() orig[2] = NewLink() orig[3] = GenTestLink() orig[4] = NewLink() return orig } func GenTestLinkSlice() []Link { orig := make([]Link, 5) orig[1] = *GenTestLink() orig[3] = *GenTestLink() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_link_test.go000066400000000000000000000133741511331344600272370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyLink(t *testing.T) { for name, src := range genTestEncodingValuesLink() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewLink() CopyLink(dest, src) assert.Equal(t, src, dest) CopyLink(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyLinkSlice(t *testing.T) { src := []Link{} dest := []Link{} // Test CopyTo empty dest = CopyLinkSlice(dest, src) assert.Equal(t, []Link{}, dest) // Test CopyTo larger slice src = GenTestLinkSlice() dest = CopyLinkSlice(dest, src) assert.Equal(t, GenTestLinkSlice(), dest) // Test CopyTo same size slice dest = CopyLinkSlice(dest, src) assert.Equal(t, GenTestLinkSlice(), dest) // Test CopyTo smaller size slice dest = CopyLinkSlice(dest, []Link{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLinkSlice(dest, src) assert.Equal(t, GenTestLinkSlice(), dest) } func TestCopyLinkPtrSlice(t *testing.T) { src := []*Link{} dest := []*Link{} // Test CopyTo empty dest = CopyLinkPtrSlice(dest, src) assert.Equal(t, []*Link{}, dest) // Test CopyTo larger slice src = GenTestLinkPtrSlice() dest = CopyLinkPtrSlice(dest, src) assert.Equal(t, GenTestLinkPtrSlice(), dest) // Test CopyTo same size slice dest = CopyLinkPtrSlice(dest, src) assert.Equal(t, GenTestLinkPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyLinkPtrSlice(dest, []*Link{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLinkPtrSlice(dest, src) assert.Equal(t, GenTestLinkPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONLinkUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewLink() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewLink(), dest) } func TestMarshalAndUnmarshalJSONLink(t *testing.T) { for name, src := range genTestEncodingValuesLink() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewLink() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteLink(dest, true) }) } } } func TestMarshalAndUnmarshalProtoLinkFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesLink() { t.Run(name, func(t *testing.T) { dest := NewLink() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoLinkUnknown(t *testing.T) { dest := NewLink() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewLink(), dest) } func TestMarshalAndUnmarshalProtoLink(t *testing.T) { for name, src := range genTestEncodingValuesLink() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewLink() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteLink(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufLink(t *testing.T) { for name, src := range genTestEncodingValuesLink() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Link{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewLink() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesLink() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "TraceId/wrong_wire_type": {0xc}, "TraceId/missing_value": {0xa}, "SpanId/wrong_wire_type": {0x14}, "SpanId/missing_value": {0x12}, } } func genTestEncodingValuesLink() map[string]*Link { return map[string]*Link{ "empty": NewLink(), "TraceId/test": {TraceId: *GenTestTraceID()}, "SpanId/test": {SpanId: *GenTestSpanID()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_location.go000066400000000000000000000210271511331344600270450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Location describes function and line table debug information. type Location struct { MappingIndex int32 Address uint64 Lines []*Line AttributeIndices []int32 } var ( protoPoolLocation = sync.Pool{ New: func() any { return &Location{} }, } ) func NewLocation() *Location { if !UseProtoPooling.IsEnabled() { return &Location{} } return protoPoolLocation.Get().(*Location) } func DeleteLocation(orig *Location, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Lines { DeleteLine(orig.Lines[i], true) } orig.Reset() if nullable { protoPoolLocation.Put(orig) } } func CopyLocation(dest, src *Location) *Location { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewLocation() } dest.MappingIndex = src.MappingIndex dest.Address = src.Address dest.Lines = CopyLinePtrSlice(dest.Lines, src.Lines) dest.AttributeIndices = append(dest.AttributeIndices[:0], src.AttributeIndices...) return dest } func CopyLocationSlice(dest, src []Location) []Location { var newDest []Location if cap(dest) < len(src) { newDest = make([]Location, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLocation(&dest[i], false) } } for i := range src { CopyLocation(&newDest[i], &src[i]) } return newDest } func CopyLocationPtrSlice(dest, src []*Location) []*Location { var newDest []*Location if cap(dest) < len(src) { newDest = make([]*Location, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewLocation() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLocation(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewLocation() } } for i := range src { CopyLocation(newDest[i], src[i]) } return newDest } func (orig *Location) Reset() { *orig = Location{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Location) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.MappingIndex != int32(0) { dest.WriteObjectField("mappingIndex") dest.WriteInt32(orig.MappingIndex) } if orig.Address != uint64(0) { dest.WriteObjectField("address") dest.WriteUint64(orig.Address) } if len(orig.Lines) > 0 { dest.WriteObjectField("lines") dest.WriteArrayStart() orig.Lines[0].MarshalJSON(dest) for i := 1; i < len(orig.Lines); i++ { dest.WriteMore() orig.Lines[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if len(orig.AttributeIndices) > 0 { dest.WriteObjectField("attributeIndices") dest.WriteArrayStart() dest.WriteInt32(orig.AttributeIndices[0]) for i := 1; i < len(orig.AttributeIndices); i++ { dest.WriteMore() dest.WriteInt32(orig.AttributeIndices[i]) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Location) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "mappingIndex", "mapping_index": orig.MappingIndex = iter.ReadInt32() case "address": orig.Address = iter.ReadUint64() case "lines": for iter.ReadArray() { orig.Lines = append(orig.Lines, NewLine()) orig.Lines[len(orig.Lines)-1].UnmarshalJSON(iter) } case "attributeIndices", "attribute_indices": for iter.ReadArray() { orig.AttributeIndices = append(orig.AttributeIndices, iter.ReadInt32()) } default: iter.Skip() } } } func (orig *Location) SizeProto() int { var n int var l int _ = l if orig.MappingIndex != 0 { n += 1 + proto.Sov(uint64(orig.MappingIndex)) } if orig.Address != 0 { n += 1 + proto.Sov(uint64(orig.Address)) } for i := range orig.Lines { l = orig.Lines[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if len(orig.AttributeIndices) > 0 { l = 0 for _, e := range orig.AttributeIndices { l += proto.Sov(uint64(e)) } n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Location) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.MappingIndex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.MappingIndex)) pos-- buf[pos] = 0x8 } if orig.Address != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Address)) pos-- buf[pos] = 0x10 } for i := len(orig.Lines) - 1; i >= 0; i-- { l = orig.Lines[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } l = len(orig.AttributeIndices) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.AttributeIndices[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) pos-- buf[pos] = 0x22 } return len(buf) - pos } func (orig *Location) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field MappingIndex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.MappingIndex = int32(num) case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Address", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Address = uint64(num) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Lines", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Lines = append(orig.Lines, NewLine()) err = orig.Lines[len(orig.Lines)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 4: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field AttributeIndices", pos-startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field AttributeIndices", wireType) } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestLocation() *Location { orig := NewLocation() orig.MappingIndex = int32(13) orig.Address = uint64(13) orig.Lines = []*Line{{}, GenTestLine()} orig.AttributeIndices = []int32{int32(0), int32(13)} return orig } func GenTestLocationPtrSlice() []*Location { orig := make([]*Location, 5) orig[0] = NewLocation() orig[1] = GenTestLocation() orig[2] = NewLocation() orig[3] = GenTestLocation() orig[4] = NewLocation() return orig } func GenTestLocationSlice() []Location { orig := make([]Location, 5) orig[1] = *GenTestLocation() orig[3] = *GenTestLocation() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_location_test.go000066400000000000000000000145551511331344600301140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyLocation(t *testing.T) { for name, src := range genTestEncodingValuesLocation() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewLocation() CopyLocation(dest, src) assert.Equal(t, src, dest) CopyLocation(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyLocationSlice(t *testing.T) { src := []Location{} dest := []Location{} // Test CopyTo empty dest = CopyLocationSlice(dest, src) assert.Equal(t, []Location{}, dest) // Test CopyTo larger slice src = GenTestLocationSlice() dest = CopyLocationSlice(dest, src) assert.Equal(t, GenTestLocationSlice(), dest) // Test CopyTo same size slice dest = CopyLocationSlice(dest, src) assert.Equal(t, GenTestLocationSlice(), dest) // Test CopyTo smaller size slice dest = CopyLocationSlice(dest, []Location{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLocationSlice(dest, src) assert.Equal(t, GenTestLocationSlice(), dest) } func TestCopyLocationPtrSlice(t *testing.T) { src := []*Location{} dest := []*Location{} // Test CopyTo empty dest = CopyLocationPtrSlice(dest, src) assert.Equal(t, []*Location{}, dest) // Test CopyTo larger slice src = GenTestLocationPtrSlice() dest = CopyLocationPtrSlice(dest, src) assert.Equal(t, GenTestLocationPtrSlice(), dest) // Test CopyTo same size slice dest = CopyLocationPtrSlice(dest, src) assert.Equal(t, GenTestLocationPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyLocationPtrSlice(dest, []*Location{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLocationPtrSlice(dest, src) assert.Equal(t, GenTestLocationPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONLocationUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewLocation() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewLocation(), dest) } func TestMarshalAndUnmarshalJSONLocation(t *testing.T) { for name, src := range genTestEncodingValuesLocation() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewLocation() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteLocation(dest, true) }) } } } func TestMarshalAndUnmarshalProtoLocationFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesLocation() { t.Run(name, func(t *testing.T) { dest := NewLocation() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoLocationUnknown(t *testing.T) { dest := NewLocation() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewLocation(), dest) } func TestMarshalAndUnmarshalProtoLocation(t *testing.T) { for name, src := range genTestEncodingValuesLocation() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewLocation() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteLocation(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufLocation(t *testing.T) { for name, src := range genTestEncodingValuesLocation() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Location{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewLocation() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesLocation() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "MappingIndex/wrong_wire_type": {0xc}, "MappingIndex/missing_value": {0x8}, "Address/wrong_wire_type": {0x14}, "Address/missing_value": {0x10}, "Lines/wrong_wire_type": {0x1c}, "Lines/missing_value": {0x1a}, "AttributeIndices/wrong_wire_type": {0x24}, "AttributeIndices/missing_value": {0x22}, } } func genTestEncodingValuesLocation() map[string]*Location { return map[string]*Location{ "empty": NewLocation(), "MappingIndex/test": {MappingIndex: int32(13)}, "Address/test": {Address: uint64(13)}, "Lines/test": {Lines: []*Line{{}, GenTestLine()}}, "AttributeIndices/test": {AttributeIndices: []int32{int32(0), int32(13)}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_logrecord.go000066400000000000000000000331071511331344600272170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // LogRecord are experimental implementation of OpenTelemetry Log Data Model. type LogRecord struct { TimeUnixNano uint64 ObservedTimeUnixNano uint64 SeverityNumber SeverityNumber SeverityText string Body AnyValue Attributes []KeyValue DroppedAttributesCount uint32 Flags uint32 TraceId TraceID SpanId SpanID EventName string } var ( protoPoolLogRecord = sync.Pool{ New: func() any { return &LogRecord{} }, } ) func NewLogRecord() *LogRecord { if !UseProtoPooling.IsEnabled() { return &LogRecord{} } return protoPoolLogRecord.Get().(*LogRecord) } func DeleteLogRecord(orig *LogRecord, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteAnyValue(&orig.Body, false) for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } DeleteTraceID(&orig.TraceId, false) DeleteSpanID(&orig.SpanId, false) orig.Reset() if nullable { protoPoolLogRecord.Put(orig) } } func CopyLogRecord(dest, src *LogRecord) *LogRecord { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewLogRecord() } dest.TimeUnixNano = src.TimeUnixNano dest.ObservedTimeUnixNano = src.ObservedTimeUnixNano dest.SeverityNumber = src.SeverityNumber dest.SeverityText = src.SeverityText CopyAnyValue(&dest.Body, &src.Body) dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.DroppedAttributesCount = src.DroppedAttributesCount dest.Flags = src.Flags CopyTraceID(&dest.TraceId, &src.TraceId) CopySpanID(&dest.SpanId, &src.SpanId) dest.EventName = src.EventName return dest } func CopyLogRecordSlice(dest, src []LogRecord) []LogRecord { var newDest []LogRecord if cap(dest) < len(src) { newDest = make([]LogRecord, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLogRecord(&dest[i], false) } } for i := range src { CopyLogRecord(&newDest[i], &src[i]) } return newDest } func CopyLogRecordPtrSlice(dest, src []*LogRecord) []*LogRecord { var newDest []*LogRecord if cap(dest) < len(src) { newDest = make([]*LogRecord, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewLogRecord() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLogRecord(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewLogRecord() } } for i := range src { CopyLogRecord(newDest[i], src[i]) } return newDest } func (orig *LogRecord) Reset() { *orig = LogRecord{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *LogRecord) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } if orig.ObservedTimeUnixNano != uint64(0) { dest.WriteObjectField("observedTimeUnixNano") dest.WriteUint64(orig.ObservedTimeUnixNano) } if int32(orig.SeverityNumber) != 0 { dest.WriteObjectField("severityNumber") dest.WriteInt32(int32(orig.SeverityNumber)) } if orig.SeverityText != "" { dest.WriteObjectField("severityText") dest.WriteString(orig.SeverityText) } dest.WriteObjectField("body") orig.Body.MarshalJSON(dest) if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedAttributesCount != uint32(0) { dest.WriteObjectField("droppedAttributesCount") dest.WriteUint32(orig.DroppedAttributesCount) } if orig.Flags != uint32(0) { dest.WriteObjectField("flags") dest.WriteUint32(orig.Flags) } if !orig.TraceId.IsEmpty() { dest.WriteObjectField("traceId") orig.TraceId.MarshalJSON(dest) } if !orig.SpanId.IsEmpty() { dest.WriteObjectField("spanId") orig.SpanId.MarshalJSON(dest) } if orig.EventName != "" { dest.WriteObjectField("eventName") dest.WriteString(orig.EventName) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *LogRecord) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "observedTimeUnixNano", "observed_time_unix_nano": orig.ObservedTimeUnixNano = iter.ReadUint64() case "severityNumber", "severity_number": orig.SeverityNumber = SeverityNumber(iter.ReadEnumValue(SeverityNumber_value)) case "severityText", "severity_text": orig.SeverityText = iter.ReadString() case "body": orig.Body.UnmarshalJSON(iter) case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "droppedAttributesCount", "dropped_attributes_count": orig.DroppedAttributesCount = iter.ReadUint32() case "flags": orig.Flags = iter.ReadUint32() case "traceId", "trace_id": orig.TraceId.UnmarshalJSON(iter) case "spanId", "span_id": orig.SpanId.UnmarshalJSON(iter) case "eventName", "event_name": orig.EventName = iter.ReadString() default: iter.Skip() } } } func (orig *LogRecord) SizeProto() int { var n int var l int _ = l if orig.TimeUnixNano != 0 { n += 9 } if orig.ObservedTimeUnixNano != 0 { n += 9 } if orig.SeverityNumber != 0 { n += 1 + proto.Sov(uint64(orig.SeverityNumber)) } l = len(orig.SeverityText) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = orig.Body.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedAttributesCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedAttributesCount)) } if orig.Flags != 0 { n += 5 } l = orig.TraceId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = orig.SpanId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = len(orig.EventName) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *LogRecord) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x9 } if orig.ObservedTimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.ObservedTimeUnixNano)) pos-- buf[pos] = 0x59 } if orig.SeverityNumber != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.SeverityNumber)) pos-- buf[pos] = 0x10 } l = len(orig.SeverityText) if l > 0 { pos -= l copy(buf[pos:], orig.SeverityText) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } l = orig.Body.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x32 } if orig.DroppedAttributesCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedAttributesCount)) pos-- buf[pos] = 0x38 } if orig.Flags != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.Flags)) pos-- buf[pos] = 0x45 } l = orig.TraceId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x4a l = orig.SpanId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x52 l = len(orig.EventName) if l > 0 { pos -= l copy(buf[pos:], orig.EventName) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x62 } return len(buf) - pos } func (orig *LogRecord) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 11: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field ObservedTimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.ObservedTimeUnixNano = uint64(num) case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field SeverityNumber", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.SeverityNumber = SeverityNumber(num) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SeverityText", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SeverityText = string(buf[startPos:pos]) case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Body", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Body.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 6: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 7: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedAttributesCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedAttributesCount = uint32(num) case 8: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.Flags = uint32(num) case 9: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.TraceId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 10: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.SpanId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 12: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field EventName", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.EventName = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestLogRecord() *LogRecord { orig := NewLogRecord() orig.TimeUnixNano = uint64(13) orig.ObservedTimeUnixNano = uint64(13) orig.SeverityNumber = SeverityNumber(13) orig.SeverityText = "test_severitytext" orig.Body = *GenTestAnyValue() orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.DroppedAttributesCount = uint32(13) orig.Flags = uint32(13) orig.TraceId = *GenTestTraceID() orig.SpanId = *GenTestSpanID() orig.EventName = "test_eventname" return orig } func GenTestLogRecordPtrSlice() []*LogRecord { orig := make([]*LogRecord, 5) orig[0] = NewLogRecord() orig[1] = GenTestLogRecord() orig[2] = NewLogRecord() orig[3] = GenTestLogRecord() orig[4] = NewLogRecord() return orig } func GenTestLogRecordSlice() []LogRecord { orig := make([]LogRecord, 5) orig[1] = *GenTestLogRecord() orig[3] = *GenTestLogRecord() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_logrecord_test.go000066400000000000000000000172101511331344600302530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlplogs "go.opentelemetry.io/proto/slim/otlp/logs/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyLogRecord(t *testing.T) { for name, src := range genTestEncodingValuesLogRecord() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewLogRecord() CopyLogRecord(dest, src) assert.Equal(t, src, dest) CopyLogRecord(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyLogRecordSlice(t *testing.T) { src := []LogRecord{} dest := []LogRecord{} // Test CopyTo empty dest = CopyLogRecordSlice(dest, src) assert.Equal(t, []LogRecord{}, dest) // Test CopyTo larger slice src = GenTestLogRecordSlice() dest = CopyLogRecordSlice(dest, src) assert.Equal(t, GenTestLogRecordSlice(), dest) // Test CopyTo same size slice dest = CopyLogRecordSlice(dest, src) assert.Equal(t, GenTestLogRecordSlice(), dest) // Test CopyTo smaller size slice dest = CopyLogRecordSlice(dest, []LogRecord{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLogRecordSlice(dest, src) assert.Equal(t, GenTestLogRecordSlice(), dest) } func TestCopyLogRecordPtrSlice(t *testing.T) { src := []*LogRecord{} dest := []*LogRecord{} // Test CopyTo empty dest = CopyLogRecordPtrSlice(dest, src) assert.Equal(t, []*LogRecord{}, dest) // Test CopyTo larger slice src = GenTestLogRecordPtrSlice() dest = CopyLogRecordPtrSlice(dest, src) assert.Equal(t, GenTestLogRecordPtrSlice(), dest) // Test CopyTo same size slice dest = CopyLogRecordPtrSlice(dest, src) assert.Equal(t, GenTestLogRecordPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyLogRecordPtrSlice(dest, []*LogRecord{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLogRecordPtrSlice(dest, src) assert.Equal(t, GenTestLogRecordPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONLogRecordUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewLogRecord() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewLogRecord(), dest) } func TestMarshalAndUnmarshalJSONLogRecord(t *testing.T) { for name, src := range genTestEncodingValuesLogRecord() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewLogRecord() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteLogRecord(dest, true) }) } } } func TestMarshalAndUnmarshalProtoLogRecordFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesLogRecord() { t.Run(name, func(t *testing.T) { dest := NewLogRecord() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoLogRecordUnknown(t *testing.T) { dest := NewLogRecord() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewLogRecord(), dest) } func TestMarshalAndUnmarshalProtoLogRecord(t *testing.T) { for name, src := range genTestEncodingValuesLogRecord() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewLogRecord() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteLogRecord(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufLogRecord(t *testing.T) { for name, src := range genTestEncodingValuesLogRecord() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlplogs.LogRecord{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewLogRecord() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesLogRecord() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "TimeUnixNano/wrong_wire_type": {0xc}, "TimeUnixNano/missing_value": {0x9}, "ObservedTimeUnixNano/wrong_wire_type": {0x5c}, "ObservedTimeUnixNano/missing_value": {0x59}, "SeverityNumber/wrong_wire_type": {0x14}, "SeverityNumber/missing_value": {0x10}, "SeverityText/wrong_wire_type": {0x1c}, "SeverityText/missing_value": {0x1a}, "Body/wrong_wire_type": {0x2c}, "Body/missing_value": {0x2a}, "Attributes/wrong_wire_type": {0x34}, "Attributes/missing_value": {0x32}, "DroppedAttributesCount/wrong_wire_type": {0x3c}, "DroppedAttributesCount/missing_value": {0x38}, "Flags/wrong_wire_type": {0x44}, "Flags/missing_value": {0x45}, "TraceId/wrong_wire_type": {0x4c}, "TraceId/missing_value": {0x4a}, "SpanId/wrong_wire_type": {0x54}, "SpanId/missing_value": {0x52}, "EventName/wrong_wire_type": {0x64}, "EventName/missing_value": {0x62}, } } func genTestEncodingValuesLogRecord() map[string]*LogRecord { return map[string]*LogRecord{ "empty": NewLogRecord(), "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "ObservedTimeUnixNano/test": {ObservedTimeUnixNano: uint64(13)}, "SeverityNumber/test": {SeverityNumber: SeverityNumber(13)}, "SeverityText/test": {SeverityText: "test_severitytext"}, "Body/test": {Body: *GenTestAnyValue()}, "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "DroppedAttributesCount/test": {DroppedAttributesCount: uint32(13)}, "Flags/test": {Flags: uint32(13)}, "TraceId/test": {TraceId: *GenTestTraceID()}, "SpanId/test": {SpanId: *GenTestSpanID()}, "EventName/test": {EventName: "test_eventname"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_logsdata.go000066400000000000000000000131321511331344600270310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // LogsData represents the logs data that can be stored in a persistent storage, // OR can be embedded by other protocols that transfer OTLP logs data but do not // implement the OTLP protocol. type LogsData struct { ResourceLogs []*ResourceLogs } var ( protoPoolLogsData = sync.Pool{ New: func() any { return &LogsData{} }, } ) func NewLogsData() *LogsData { if !UseProtoPooling.IsEnabled() { return &LogsData{} } return protoPoolLogsData.Get().(*LogsData) } func DeleteLogsData(orig *LogsData, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceLogs { DeleteResourceLogs(orig.ResourceLogs[i], true) } orig.Reset() if nullable { protoPoolLogsData.Put(orig) } } func CopyLogsData(dest, src *LogsData) *LogsData { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewLogsData() } dest.ResourceLogs = CopyResourceLogsPtrSlice(dest.ResourceLogs, src.ResourceLogs) return dest } func CopyLogsDataSlice(dest, src []LogsData) []LogsData { var newDest []LogsData if cap(dest) < len(src) { newDest = make([]LogsData, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLogsData(&dest[i], false) } } for i := range src { CopyLogsData(&newDest[i], &src[i]) } return newDest } func CopyLogsDataPtrSlice(dest, src []*LogsData) []*LogsData { var newDest []*LogsData if cap(dest) < len(src) { newDest = make([]*LogsData, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewLogsData() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLogsData(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewLogsData() } } for i := range src { CopyLogsData(newDest[i], src[i]) } return newDest } func (orig *LogsData) Reset() { *orig = LogsData{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *LogsData) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceLogs) > 0 { dest.WriteObjectField("resourceLogs") dest.WriteArrayStart() orig.ResourceLogs[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceLogs); i++ { dest.WriteMore() orig.ResourceLogs[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *LogsData) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceLogs", "resource_logs": for iter.ReadArray() { orig.ResourceLogs = append(orig.ResourceLogs, NewResourceLogs()) orig.ResourceLogs[len(orig.ResourceLogs)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *LogsData) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceLogs { l = orig.ResourceLogs[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *LogsData) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceLogs) - 1; i >= 0; i-- { l = orig.ResourceLogs[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *LogsData) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceLogs", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceLogs = append(orig.ResourceLogs, NewResourceLogs()) err = orig.ResourceLogs[len(orig.ResourceLogs)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestLogsData() *LogsData { orig := NewLogsData() orig.ResourceLogs = []*ResourceLogs{{}, GenTestResourceLogs()} return orig } func GenTestLogsDataPtrSlice() []*LogsData { orig := make([]*LogsData, 5) orig[0] = NewLogsData() orig[1] = GenTestLogsData() orig[2] = NewLogsData() orig[3] = GenTestLogsData() orig[4] = NewLogsData() return orig } func GenTestLogsDataSlice() []LogsData { orig := make([]LogsData, 5) orig[1] = *GenTestLogsData() orig[3] = *GenTestLogsData() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_logsdata_test.go000066400000000000000000000136201511331344600300720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlplogs "go.opentelemetry.io/proto/slim/otlp/logs/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyLogsData(t *testing.T) { for name, src := range genTestEncodingValuesLogsData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewLogsData() CopyLogsData(dest, src) assert.Equal(t, src, dest) CopyLogsData(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyLogsDataSlice(t *testing.T) { src := []LogsData{} dest := []LogsData{} // Test CopyTo empty dest = CopyLogsDataSlice(dest, src) assert.Equal(t, []LogsData{}, dest) // Test CopyTo larger slice src = GenTestLogsDataSlice() dest = CopyLogsDataSlice(dest, src) assert.Equal(t, GenTestLogsDataSlice(), dest) // Test CopyTo same size slice dest = CopyLogsDataSlice(dest, src) assert.Equal(t, GenTestLogsDataSlice(), dest) // Test CopyTo smaller size slice dest = CopyLogsDataSlice(dest, []LogsData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLogsDataSlice(dest, src) assert.Equal(t, GenTestLogsDataSlice(), dest) } func TestCopyLogsDataPtrSlice(t *testing.T) { src := []*LogsData{} dest := []*LogsData{} // Test CopyTo empty dest = CopyLogsDataPtrSlice(dest, src) assert.Equal(t, []*LogsData{}, dest) // Test CopyTo larger slice src = GenTestLogsDataPtrSlice() dest = CopyLogsDataPtrSlice(dest, src) assert.Equal(t, GenTestLogsDataPtrSlice(), dest) // Test CopyTo same size slice dest = CopyLogsDataPtrSlice(dest, src) assert.Equal(t, GenTestLogsDataPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyLogsDataPtrSlice(dest, []*LogsData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLogsDataPtrSlice(dest, src) assert.Equal(t, GenTestLogsDataPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONLogsDataUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewLogsData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewLogsData(), dest) } func TestMarshalAndUnmarshalJSONLogsData(t *testing.T) { for name, src := range genTestEncodingValuesLogsData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewLogsData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteLogsData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoLogsDataFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesLogsData() { t.Run(name, func(t *testing.T) { dest := NewLogsData() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoLogsDataUnknown(t *testing.T) { dest := NewLogsData() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewLogsData(), dest) } func TestMarshalAndUnmarshalProtoLogsData(t *testing.T) { for name, src := range genTestEncodingValuesLogsData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewLogsData() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteLogsData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufLogsData(t *testing.T) { for name, src := range genTestEncodingValuesLogsData() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlplogs.LogsData{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewLogsData() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesLogsData() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceLogs/wrong_wire_type": {0xc}, "ResourceLogs/missing_value": {0xa}, } } func genTestEncodingValuesLogsData() map[string]*LogsData { return map[string]*LogsData{ "empty": NewLogsData(), "ResourceLogs/test": {ResourceLogs: []*ResourceLogs{{}, GenTestResourceLogs()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_logsrequest.go000066400000000000000000000154531511331344600276200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type LogsRequest struct { RequestContext *RequestContext LogsData LogsData FormatVersion uint32 } var ( protoPoolLogsRequest = sync.Pool{ New: func() any { return &LogsRequest{} }, } ) func NewLogsRequest() *LogsRequest { if !UseProtoPooling.IsEnabled() { return &LogsRequest{} } return protoPoolLogsRequest.Get().(*LogsRequest) } func DeleteLogsRequest(orig *LogsRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteRequestContext(orig.RequestContext, true) DeleteLogsData(&orig.LogsData, false) orig.Reset() if nullable { protoPoolLogsRequest.Put(orig) } } func CopyLogsRequest(dest, src *LogsRequest) *LogsRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewLogsRequest() } dest.RequestContext = CopyRequestContext(dest.RequestContext, src.RequestContext) CopyLogsData(&dest.LogsData, &src.LogsData) dest.FormatVersion = src.FormatVersion return dest } func CopyLogsRequestSlice(dest, src []LogsRequest) []LogsRequest { var newDest []LogsRequest if cap(dest) < len(src) { newDest = make([]LogsRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLogsRequest(&dest[i], false) } } for i := range src { CopyLogsRequest(&newDest[i], &src[i]) } return newDest } func CopyLogsRequestPtrSlice(dest, src []*LogsRequest) []*LogsRequest { var newDest []*LogsRequest if cap(dest) < len(src) { newDest = make([]*LogsRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewLogsRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteLogsRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewLogsRequest() } } for i := range src { CopyLogsRequest(newDest[i], src[i]) } return newDest } func (orig *LogsRequest) Reset() { *orig = LogsRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *LogsRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RequestContext != nil { dest.WriteObjectField("requestContext") orig.RequestContext.MarshalJSON(dest) } dest.WriteObjectField("logsData") orig.LogsData.MarshalJSON(dest) if orig.FormatVersion != uint32(0) { dest.WriteObjectField("formatVersion") dest.WriteUint32(orig.FormatVersion) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *LogsRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "requestContext", "request_context": orig.RequestContext = NewRequestContext() orig.RequestContext.UnmarshalJSON(iter) case "logsData", "logs_data": orig.LogsData.UnmarshalJSON(iter) case "formatVersion", "format_version": orig.FormatVersion = iter.ReadUint32() default: iter.Skip() } } } func (orig *LogsRequest) SizeProto() int { var n int var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = orig.LogsData.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.FormatVersion != 0 { n += 5 } return n } func (orig *LogsRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = orig.LogsData.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a if orig.FormatVersion != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.FormatVersion)) pos-- buf[pos] = 0xd } return len(buf) - pos } func (orig *LogsRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field RequestContext", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.RequestContext = NewRequestContext() err = orig.RequestContext.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field LogsData", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.LogsData.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 1: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field FormatVersion", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.FormatVersion = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestLogsRequest() *LogsRequest { orig := NewLogsRequest() orig.RequestContext = GenTestRequestContext() orig.LogsData = *GenTestLogsData() orig.FormatVersion = uint32(13) return orig } func GenTestLogsRequestPtrSlice() []*LogsRequest { orig := make([]*LogsRequest, 5) orig[0] = NewLogsRequest() orig[1] = GenTestLogsRequest() orig[2] = NewLogsRequest() orig[3] = GenTestLogsRequest() orig[4] = NewLogsRequest() return orig } func GenTestLogsRequestSlice() []LogsRequest { orig := make([]LogsRequest, 5) orig[1] = *GenTestLogsRequest() orig[3] = *GenTestLogsRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_logsrequest_test.go000066400000000000000000000145101511331344600306500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyLogsRequest(t *testing.T) { for name, src := range genTestEncodingValuesLogsRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewLogsRequest() CopyLogsRequest(dest, src) assert.Equal(t, src, dest) CopyLogsRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyLogsRequestSlice(t *testing.T) { src := []LogsRequest{} dest := []LogsRequest{} // Test CopyTo empty dest = CopyLogsRequestSlice(dest, src) assert.Equal(t, []LogsRequest{}, dest) // Test CopyTo larger slice src = GenTestLogsRequestSlice() dest = CopyLogsRequestSlice(dest, src) assert.Equal(t, GenTestLogsRequestSlice(), dest) // Test CopyTo same size slice dest = CopyLogsRequestSlice(dest, src) assert.Equal(t, GenTestLogsRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyLogsRequestSlice(dest, []LogsRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLogsRequestSlice(dest, src) assert.Equal(t, GenTestLogsRequestSlice(), dest) } func TestCopyLogsRequestPtrSlice(t *testing.T) { src := []*LogsRequest{} dest := []*LogsRequest{} // Test CopyTo empty dest = CopyLogsRequestPtrSlice(dest, src) assert.Equal(t, []*LogsRequest{}, dest) // Test CopyTo larger slice src = GenTestLogsRequestPtrSlice() dest = CopyLogsRequestPtrSlice(dest, src) assert.Equal(t, GenTestLogsRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyLogsRequestPtrSlice(dest, src) assert.Equal(t, GenTestLogsRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyLogsRequestPtrSlice(dest, []*LogsRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyLogsRequestPtrSlice(dest, src) assert.Equal(t, GenTestLogsRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONLogsRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewLogsRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewLogsRequest(), dest) } func TestMarshalAndUnmarshalJSONLogsRequest(t *testing.T) { for name, src := range genTestEncodingValuesLogsRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewLogsRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteLogsRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoLogsRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesLogsRequest() { t.Run(name, func(t *testing.T) { dest := NewLogsRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoLogsRequestUnknown(t *testing.T) { dest := NewLogsRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewLogsRequest(), dest) } func TestMarshalAndUnmarshalProtoLogsRequest(t *testing.T) { for name, src := range genTestEncodingValuesLogsRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewLogsRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteLogsRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufLogsRequest(t *testing.T) { for name, src := range genTestEncodingValuesLogsRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewLogsRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesLogsRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RequestContext/wrong_wire_type": {0x14}, "RequestContext/missing_value": {0x12}, "LogsData/wrong_wire_type": {0x1c}, "LogsData/missing_value": {0x1a}, "FormatVersion/wrong_wire_type": {0xc}, "FormatVersion/missing_value": {0xd}, } } func genTestEncodingValuesLogsRequest() map[string]*LogsRequest { return map[string]*LogsRequest{ "empty": NewLogsRequest(), "RequestContext/test": {RequestContext: GenTestRequestContext()}, "LogsData/test": {LogsData: *GenTestLogsData()}, "FormatVersion/test": {FormatVersion: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_mapping.go000066400000000000000000000216131511331344600266710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Mapping describes the mapping of a binary in memory, including its address range, file offset, and metadata like build ID type Mapping struct { MemoryStart uint64 MemoryLimit uint64 FileOffset uint64 FilenameStrindex int32 AttributeIndices []int32 } var ( protoPoolMapping = sync.Pool{ New: func() any { return &Mapping{} }, } ) func NewMapping() *Mapping { if !UseProtoPooling.IsEnabled() { return &Mapping{} } return protoPoolMapping.Get().(*Mapping) } func DeleteMapping(orig *Mapping, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolMapping.Put(orig) } } func CopyMapping(dest, src *Mapping) *Mapping { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewMapping() } dest.MemoryStart = src.MemoryStart dest.MemoryLimit = src.MemoryLimit dest.FileOffset = src.FileOffset dest.FilenameStrindex = src.FilenameStrindex dest.AttributeIndices = append(dest.AttributeIndices[:0], src.AttributeIndices...) return dest } func CopyMappingSlice(dest, src []Mapping) []Mapping { var newDest []Mapping if cap(dest) < len(src) { newDest = make([]Mapping, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMapping(&dest[i], false) } } for i := range src { CopyMapping(&newDest[i], &src[i]) } return newDest } func CopyMappingPtrSlice(dest, src []*Mapping) []*Mapping { var newDest []*Mapping if cap(dest) < len(src) { newDest = make([]*Mapping, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewMapping() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMapping(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewMapping() } } for i := range src { CopyMapping(newDest[i], src[i]) } return newDest } func (orig *Mapping) Reset() { *orig = Mapping{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Mapping) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.MemoryStart != uint64(0) { dest.WriteObjectField("memoryStart") dest.WriteUint64(orig.MemoryStart) } if orig.MemoryLimit != uint64(0) { dest.WriteObjectField("memoryLimit") dest.WriteUint64(orig.MemoryLimit) } if orig.FileOffset != uint64(0) { dest.WriteObjectField("fileOffset") dest.WriteUint64(orig.FileOffset) } if orig.FilenameStrindex != int32(0) { dest.WriteObjectField("filenameStrindex") dest.WriteInt32(orig.FilenameStrindex) } if len(orig.AttributeIndices) > 0 { dest.WriteObjectField("attributeIndices") dest.WriteArrayStart() dest.WriteInt32(orig.AttributeIndices[0]) for i := 1; i < len(orig.AttributeIndices); i++ { dest.WriteMore() dest.WriteInt32(orig.AttributeIndices[i]) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Mapping) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "memoryStart", "memory_start": orig.MemoryStart = iter.ReadUint64() case "memoryLimit", "memory_limit": orig.MemoryLimit = iter.ReadUint64() case "fileOffset", "file_offset": orig.FileOffset = iter.ReadUint64() case "filenameStrindex", "filename_strindex": orig.FilenameStrindex = iter.ReadInt32() case "attributeIndices", "attribute_indices": for iter.ReadArray() { orig.AttributeIndices = append(orig.AttributeIndices, iter.ReadInt32()) } default: iter.Skip() } } } func (orig *Mapping) SizeProto() int { var n int var l int _ = l if orig.MemoryStart != 0 { n += 1 + proto.Sov(uint64(orig.MemoryStart)) } if orig.MemoryLimit != 0 { n += 1 + proto.Sov(uint64(orig.MemoryLimit)) } if orig.FileOffset != 0 { n += 1 + proto.Sov(uint64(orig.FileOffset)) } if orig.FilenameStrindex != 0 { n += 1 + proto.Sov(uint64(orig.FilenameStrindex)) } if len(orig.AttributeIndices) > 0 { l = 0 for _, e := range orig.AttributeIndices { l += proto.Sov(uint64(e)) } n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Mapping) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.MemoryStart != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.MemoryStart)) pos-- buf[pos] = 0x8 } if orig.MemoryLimit != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.MemoryLimit)) pos-- buf[pos] = 0x10 } if orig.FileOffset != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.FileOffset)) pos-- buf[pos] = 0x18 } if orig.FilenameStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.FilenameStrindex)) pos-- buf[pos] = 0x20 } l = len(orig.AttributeIndices) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.AttributeIndices[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) pos-- buf[pos] = 0x2a } return len(buf) - pos } func (orig *Mapping) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field MemoryStart", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.MemoryStart = uint64(num) case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field MemoryLimit", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.MemoryLimit = uint64(num) case 3: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field FileOffset", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.FileOffset = uint64(num) case 4: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field FilenameStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.FilenameStrindex = int32(num) case 5: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field AttributeIndices", pos-startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field AttributeIndices", wireType) } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestMapping() *Mapping { orig := NewMapping() orig.MemoryStart = uint64(13) orig.MemoryLimit = uint64(13) orig.FileOffset = uint64(13) orig.FilenameStrindex = int32(13) orig.AttributeIndices = []int32{int32(0), int32(13)} return orig } func GenTestMappingPtrSlice() []*Mapping { orig := make([]*Mapping, 5) orig[0] = NewMapping() orig[1] = GenTestMapping() orig[2] = NewMapping() orig[3] = GenTestMapping() orig[4] = NewMapping() return orig } func GenTestMappingSlice() []Mapping { orig := make([]Mapping, 5) orig[1] = *GenTestMapping() orig[3] = *GenTestMapping() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_mapping_test.go000066400000000000000000000147011511331344600277300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyMapping(t *testing.T) { for name, src := range genTestEncodingValuesMapping() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewMapping() CopyMapping(dest, src) assert.Equal(t, src, dest) CopyMapping(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyMappingSlice(t *testing.T) { src := []Mapping{} dest := []Mapping{} // Test CopyTo empty dest = CopyMappingSlice(dest, src) assert.Equal(t, []Mapping{}, dest) // Test CopyTo larger slice src = GenTestMappingSlice() dest = CopyMappingSlice(dest, src) assert.Equal(t, GenTestMappingSlice(), dest) // Test CopyTo same size slice dest = CopyMappingSlice(dest, src) assert.Equal(t, GenTestMappingSlice(), dest) // Test CopyTo smaller size slice dest = CopyMappingSlice(dest, []Mapping{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMappingSlice(dest, src) assert.Equal(t, GenTestMappingSlice(), dest) } func TestCopyMappingPtrSlice(t *testing.T) { src := []*Mapping{} dest := []*Mapping{} // Test CopyTo empty dest = CopyMappingPtrSlice(dest, src) assert.Equal(t, []*Mapping{}, dest) // Test CopyTo larger slice src = GenTestMappingPtrSlice() dest = CopyMappingPtrSlice(dest, src) assert.Equal(t, GenTestMappingPtrSlice(), dest) // Test CopyTo same size slice dest = CopyMappingPtrSlice(dest, src) assert.Equal(t, GenTestMappingPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyMappingPtrSlice(dest, []*Mapping{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMappingPtrSlice(dest, src) assert.Equal(t, GenTestMappingPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONMappingUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewMapping() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewMapping(), dest) } func TestMarshalAndUnmarshalJSONMapping(t *testing.T) { for name, src := range genTestEncodingValuesMapping() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewMapping() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteMapping(dest, true) }) } } } func TestMarshalAndUnmarshalProtoMappingFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesMapping() { t.Run(name, func(t *testing.T) { dest := NewMapping() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoMappingUnknown(t *testing.T) { dest := NewMapping() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewMapping(), dest) } func TestMarshalAndUnmarshalProtoMapping(t *testing.T) { for name, src := range genTestEncodingValuesMapping() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewMapping() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteMapping(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufMapping(t *testing.T) { for name, src := range genTestEncodingValuesMapping() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Mapping{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewMapping() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesMapping() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "MemoryStart/wrong_wire_type": {0xc}, "MemoryStart/missing_value": {0x8}, "MemoryLimit/wrong_wire_type": {0x14}, "MemoryLimit/missing_value": {0x10}, "FileOffset/wrong_wire_type": {0x1c}, "FileOffset/missing_value": {0x18}, "FilenameStrindex/wrong_wire_type": {0x24}, "FilenameStrindex/missing_value": {0x20}, "AttributeIndices/wrong_wire_type": {0x2c}, "AttributeIndices/missing_value": {0x2a}, } } func genTestEncodingValuesMapping() map[string]*Mapping { return map[string]*Mapping{ "empty": NewMapping(), "MemoryStart/test": {MemoryStart: uint64(13)}, "MemoryLimit/test": {MemoryLimit: uint64(13)}, "FileOffset/test": {FileOffset: uint64(13)}, "FilenameStrindex/test": {FilenameStrindex: int32(13)}, "AttributeIndices/test": {AttributeIndices: []int32{int32(0), int32(13)}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_metric.go000066400000000000000000000435771511331344600265360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) func (m *Metric) GetData() any { if m != nil { return m.Data } return nil } type Metric_Gauge struct { Gauge *Gauge } func (m *Metric) GetGauge() *Gauge { if v, ok := m.GetData().(*Metric_Gauge); ok { return v.Gauge } return nil } type Metric_Sum struct { Sum *Sum } func (m *Metric) GetSum() *Sum { if v, ok := m.GetData().(*Metric_Sum); ok { return v.Sum } return nil } type Metric_Histogram struct { Histogram *Histogram } func (m *Metric) GetHistogram() *Histogram { if v, ok := m.GetData().(*Metric_Histogram); ok { return v.Histogram } return nil } type Metric_ExponentialHistogram struct { ExponentialHistogram *ExponentialHistogram } func (m *Metric) GetExponentialHistogram() *ExponentialHistogram { if v, ok := m.GetData().(*Metric_ExponentialHistogram); ok { return v.ExponentialHistogram } return nil } type Metric_Summary struct { Summary *Summary } func (m *Metric) GetSummary() *Summary { if v, ok := m.GetData().(*Metric_Summary); ok { return v.Summary } return nil } // Metric represents one metric as a collection of datapoints. // See Metric definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto type Metric struct { Name string Description string Unit string Data any Metadata []KeyValue } var ( protoPoolMetric = sync.Pool{ New: func() any { return &Metric{} }, } ProtoPoolMetric_Gauge = sync.Pool{ New: func() any { return &Metric_Gauge{} }, } ProtoPoolMetric_Sum = sync.Pool{ New: func() any { return &Metric_Sum{} }, } ProtoPoolMetric_Histogram = sync.Pool{ New: func() any { return &Metric_Histogram{} }, } ProtoPoolMetric_ExponentialHistogram = sync.Pool{ New: func() any { return &Metric_ExponentialHistogram{} }, } ProtoPoolMetric_Summary = sync.Pool{ New: func() any { return &Metric_Summary{} }, } ) func NewMetric() *Metric { if !UseProtoPooling.IsEnabled() { return &Metric{} } return protoPoolMetric.Get().(*Metric) } func DeleteMetric(orig *Metric, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } switch ov := orig.Data.(type) { case *Metric_Gauge: DeleteGauge(ov.Gauge, true) ov.Gauge = nil ProtoPoolMetric_Gauge.Put(ov) case *Metric_Sum: DeleteSum(ov.Sum, true) ov.Sum = nil ProtoPoolMetric_Sum.Put(ov) case *Metric_Histogram: DeleteHistogram(ov.Histogram, true) ov.Histogram = nil ProtoPoolMetric_Histogram.Put(ov) case *Metric_ExponentialHistogram: DeleteExponentialHistogram(ov.ExponentialHistogram, true) ov.ExponentialHistogram = nil ProtoPoolMetric_ExponentialHistogram.Put(ov) case *Metric_Summary: DeleteSummary(ov.Summary, true) ov.Summary = nil ProtoPoolMetric_Summary.Put(ov) } for i := range orig.Metadata { DeleteKeyValue(&orig.Metadata[i], false) } orig.Reset() if nullable { protoPoolMetric.Put(orig) } } func CopyMetric(dest, src *Metric) *Metric { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewMetric() } dest.Name = src.Name dest.Description = src.Description dest.Unit = src.Unit switch t := src.Data.(type) { case *Metric_Gauge: var ov *Metric_Gauge if !UseProtoPooling.IsEnabled() { ov = &Metric_Gauge{} } else { ov = ProtoPoolMetric_Gauge.Get().(*Metric_Gauge) } ov.Gauge = NewGauge() CopyGauge(ov.Gauge, t.Gauge) dest.Data = ov case *Metric_Sum: var ov *Metric_Sum if !UseProtoPooling.IsEnabled() { ov = &Metric_Sum{} } else { ov = ProtoPoolMetric_Sum.Get().(*Metric_Sum) } ov.Sum = NewSum() CopySum(ov.Sum, t.Sum) dest.Data = ov case *Metric_Histogram: var ov *Metric_Histogram if !UseProtoPooling.IsEnabled() { ov = &Metric_Histogram{} } else { ov = ProtoPoolMetric_Histogram.Get().(*Metric_Histogram) } ov.Histogram = NewHistogram() CopyHistogram(ov.Histogram, t.Histogram) dest.Data = ov case *Metric_ExponentialHistogram: var ov *Metric_ExponentialHistogram if !UseProtoPooling.IsEnabled() { ov = &Metric_ExponentialHistogram{} } else { ov = ProtoPoolMetric_ExponentialHistogram.Get().(*Metric_ExponentialHistogram) } ov.ExponentialHistogram = NewExponentialHistogram() CopyExponentialHistogram(ov.ExponentialHistogram, t.ExponentialHistogram) dest.Data = ov case *Metric_Summary: var ov *Metric_Summary if !UseProtoPooling.IsEnabled() { ov = &Metric_Summary{} } else { ov = ProtoPoolMetric_Summary.Get().(*Metric_Summary) } ov.Summary = NewSummary() CopySummary(ov.Summary, t.Summary) dest.Data = ov default: dest.Data = nil } dest.Metadata = CopyKeyValueSlice(dest.Metadata, src.Metadata) return dest } func CopyMetricSlice(dest, src []Metric) []Metric { var newDest []Metric if cap(dest) < len(src) { newDest = make([]Metric, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMetric(&dest[i], false) } } for i := range src { CopyMetric(&newDest[i], &src[i]) } return newDest } func CopyMetricPtrSlice(dest, src []*Metric) []*Metric { var newDest []*Metric if cap(dest) < len(src) { newDest = make([]*Metric, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewMetric() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMetric(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewMetric() } } for i := range src { CopyMetric(newDest[i], src[i]) } return newDest } func (orig *Metric) Reset() { *orig = Metric{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Metric) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.Name != "" { dest.WriteObjectField("name") dest.WriteString(orig.Name) } if orig.Description != "" { dest.WriteObjectField("description") dest.WriteString(orig.Description) } if orig.Unit != "" { dest.WriteObjectField("unit") dest.WriteString(orig.Unit) } switch orig := orig.Data.(type) { case *Metric_Gauge: if orig.Gauge != nil { dest.WriteObjectField("gauge") orig.Gauge.MarshalJSON(dest) } case *Metric_Sum: if orig.Sum != nil { dest.WriteObjectField("sum") orig.Sum.MarshalJSON(dest) } case *Metric_Histogram: if orig.Histogram != nil { dest.WriteObjectField("histogram") orig.Histogram.MarshalJSON(dest) } case *Metric_ExponentialHistogram: if orig.ExponentialHistogram != nil { dest.WriteObjectField("exponentialHistogram") orig.ExponentialHistogram.MarshalJSON(dest) } case *Metric_Summary: if orig.Summary != nil { dest.WriteObjectField("summary") orig.Summary.MarshalJSON(dest) } } if len(orig.Metadata) > 0 { dest.WriteObjectField("metadata") dest.WriteArrayStart() orig.Metadata[0].MarshalJSON(dest) for i := 1; i < len(orig.Metadata); i++ { dest.WriteMore() orig.Metadata[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Metric) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "name": orig.Name = iter.ReadString() case "description": orig.Description = iter.ReadString() case "unit": orig.Unit = iter.ReadString() case "gauge": { var ov *Metric_Gauge if !UseProtoPooling.IsEnabled() { ov = &Metric_Gauge{} } else { ov = ProtoPoolMetric_Gauge.Get().(*Metric_Gauge) } ov.Gauge = NewGauge() ov.Gauge.UnmarshalJSON(iter) orig.Data = ov } case "sum": { var ov *Metric_Sum if !UseProtoPooling.IsEnabled() { ov = &Metric_Sum{} } else { ov = ProtoPoolMetric_Sum.Get().(*Metric_Sum) } ov.Sum = NewSum() ov.Sum.UnmarshalJSON(iter) orig.Data = ov } case "histogram": { var ov *Metric_Histogram if !UseProtoPooling.IsEnabled() { ov = &Metric_Histogram{} } else { ov = ProtoPoolMetric_Histogram.Get().(*Metric_Histogram) } ov.Histogram = NewHistogram() ov.Histogram.UnmarshalJSON(iter) orig.Data = ov } case "exponentialHistogram", "exponential_histogram": { var ov *Metric_ExponentialHistogram if !UseProtoPooling.IsEnabled() { ov = &Metric_ExponentialHistogram{} } else { ov = ProtoPoolMetric_ExponentialHistogram.Get().(*Metric_ExponentialHistogram) } ov.ExponentialHistogram = NewExponentialHistogram() ov.ExponentialHistogram.UnmarshalJSON(iter) orig.Data = ov } case "summary": { var ov *Metric_Summary if !UseProtoPooling.IsEnabled() { ov = &Metric_Summary{} } else { ov = ProtoPoolMetric_Summary.Get().(*Metric_Summary) } ov.Summary = NewSummary() ov.Summary.UnmarshalJSON(iter) orig.Data = ov } case "metadata": for iter.ReadArray() { orig.Metadata = append(orig.Metadata, KeyValue{}) orig.Metadata[len(orig.Metadata)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *Metric) SizeProto() int { var n int var l int _ = l l = len(orig.Name) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.Description) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.Unit) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } switch orig := orig.Data.(type) { case nil: _ = orig break case *Metric_Gauge: if orig.Gauge != nil { l = orig.Gauge.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *Metric_Sum: if orig.Sum != nil { l = orig.Sum.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *Metric_Histogram: if orig.Histogram != nil { l = orig.Histogram.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *Metric_ExponentialHistogram: if orig.ExponentialHistogram != nil { l = orig.ExponentialHistogram.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *Metric_Summary: if orig.Summary != nil { l = orig.Summary.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } } for i := range orig.Metadata { l = orig.Metadata[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Metric) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.Name) if l > 0 { pos -= l copy(buf[pos:], orig.Name) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = len(orig.Description) if l > 0 { pos -= l copy(buf[pos:], orig.Description) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.Unit) if l > 0 { pos -= l copy(buf[pos:], orig.Unit) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } switch orig := orig.Data.(type) { case *Metric_Gauge: if orig.Gauge != nil { l = orig.Gauge.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a } case *Metric_Sum: if orig.Sum != nil { l = orig.Sum.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3a } case *Metric_Histogram: if orig.Histogram != nil { l = orig.Histogram.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x4a } case *Metric_ExponentialHistogram: if orig.ExponentialHistogram != nil { l = orig.ExponentialHistogram.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x52 } case *Metric_Summary: if orig.Summary != nil { l = orig.Summary.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x5a } } for i := len(orig.Metadata) - 1; i >= 0; i-- { l = orig.Metadata[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x62 } return len(buf) - pos } func (orig *Metric) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Name = string(buf[startPos:pos]) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Description", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Description = string(buf[startPos:pos]) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Unit", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Unit = string(buf[startPos:pos]) case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Gauge", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *Metric_Gauge if !UseProtoPooling.IsEnabled() { ov = &Metric_Gauge{} } else { ov = ProtoPoolMetric_Gauge.Get().(*Metric_Gauge) } ov.Gauge = NewGauge() err = ov.Gauge.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.Data = ov case 7: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Sum", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *Metric_Sum if !UseProtoPooling.IsEnabled() { ov = &Metric_Sum{} } else { ov = ProtoPoolMetric_Sum.Get().(*Metric_Sum) } ov.Sum = NewSum() err = ov.Sum.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.Data = ov case 9: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Histogram", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *Metric_Histogram if !UseProtoPooling.IsEnabled() { ov = &Metric_Histogram{} } else { ov = ProtoPoolMetric_Histogram.Get().(*Metric_Histogram) } ov.Histogram = NewHistogram() err = ov.Histogram.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.Data = ov case 10: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ExponentialHistogram", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *Metric_ExponentialHistogram if !UseProtoPooling.IsEnabled() { ov = &Metric_ExponentialHistogram{} } else { ov = ProtoPoolMetric_ExponentialHistogram.Get().(*Metric_ExponentialHistogram) } ov.ExponentialHistogram = NewExponentialHistogram() err = ov.ExponentialHistogram.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.Data = ov case 11: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Summary", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *Metric_Summary if !UseProtoPooling.IsEnabled() { ov = &Metric_Summary{} } else { ov = ProtoPoolMetric_Summary.Get().(*Metric_Summary) } ov.Summary = NewSummary() err = ov.Summary.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.Data = ov case 12: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Metadata", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Metadata = append(orig.Metadata, KeyValue{}) err = orig.Metadata[len(orig.Metadata)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestMetric() *Metric { orig := NewMetric() orig.Name = "test_name" orig.Description = "test_description" orig.Unit = "test_unit" orig.Data = &Metric_Gauge{Gauge: GenTestGauge()} orig.Metadata = []KeyValue{{}, *GenTestKeyValue()} return orig } func GenTestMetricPtrSlice() []*Metric { orig := make([]*Metric, 5) orig[0] = NewMetric() orig[1] = GenTestMetric() orig[2] = NewMetric() orig[3] = GenTestMetric() orig[4] = NewMetric() return orig } func GenTestMetricSlice() []Metric { orig := make([]Metric, 5) orig[1] = *GenTestMetric() orig[3] = *GenTestMetric() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_metric_test.go000066400000000000000000000167141511331344600275660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyMetric(t *testing.T) { for name, src := range genTestEncodingValuesMetric() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewMetric() CopyMetric(dest, src) assert.Equal(t, src, dest) CopyMetric(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyMetricSlice(t *testing.T) { src := []Metric{} dest := []Metric{} // Test CopyTo empty dest = CopyMetricSlice(dest, src) assert.Equal(t, []Metric{}, dest) // Test CopyTo larger slice src = GenTestMetricSlice() dest = CopyMetricSlice(dest, src) assert.Equal(t, GenTestMetricSlice(), dest) // Test CopyTo same size slice dest = CopyMetricSlice(dest, src) assert.Equal(t, GenTestMetricSlice(), dest) // Test CopyTo smaller size slice dest = CopyMetricSlice(dest, []Metric{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMetricSlice(dest, src) assert.Equal(t, GenTestMetricSlice(), dest) } func TestCopyMetricPtrSlice(t *testing.T) { src := []*Metric{} dest := []*Metric{} // Test CopyTo empty dest = CopyMetricPtrSlice(dest, src) assert.Equal(t, []*Metric{}, dest) // Test CopyTo larger slice src = GenTestMetricPtrSlice() dest = CopyMetricPtrSlice(dest, src) assert.Equal(t, GenTestMetricPtrSlice(), dest) // Test CopyTo same size slice dest = CopyMetricPtrSlice(dest, src) assert.Equal(t, GenTestMetricPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyMetricPtrSlice(dest, []*Metric{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMetricPtrSlice(dest, src) assert.Equal(t, GenTestMetricPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONMetricUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewMetric() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewMetric(), dest) } func TestMarshalAndUnmarshalJSONMetric(t *testing.T) { for name, src := range genTestEncodingValuesMetric() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewMetric() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteMetric(dest, true) }) } } } func TestMarshalAndUnmarshalProtoMetricFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesMetric() { t.Run(name, func(t *testing.T) { dest := NewMetric() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoMetricUnknown(t *testing.T) { dest := NewMetric() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewMetric(), dest) } func TestMarshalAndUnmarshalProtoMetric(t *testing.T) { for name, src := range genTestEncodingValuesMetric() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewMetric() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteMetric(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufMetric(t *testing.T) { for name, src := range genTestEncodingValuesMetric() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.Metric{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewMetric() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesMetric() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Name/wrong_wire_type": {0xc}, "Name/missing_value": {0xa}, "Description/wrong_wire_type": {0x14}, "Description/missing_value": {0x12}, "Unit/wrong_wire_type": {0x1c}, "Unit/missing_value": {0x1a}, "Gauge/wrong_wire_type": {0x2c}, "Gauge/missing_value": {0x2a}, "Sum/wrong_wire_type": {0x3c}, "Sum/missing_value": {0x3a}, "Histogram/wrong_wire_type": {0x4c}, "Histogram/missing_value": {0x4a}, "ExponentialHistogram/wrong_wire_type": {0x54}, "ExponentialHistogram/missing_value": {0x52}, "Summary/wrong_wire_type": {0x5c}, "Summary/missing_value": {0x5a}, "Metadata/wrong_wire_type": {0x64}, "Metadata/missing_value": {0x62}, } } func genTestEncodingValuesMetric() map[string]*Metric { return map[string]*Metric{ "empty": NewMetric(), "Name/test": {Name: "test_name"}, "Description/test": {Description: "test_description"}, "Unit/test": {Unit: "test_unit"}, "Gauge/default": {Data: &Metric_Gauge{Gauge: &Gauge{}}}, "Gauge/test": {Data: &Metric_Gauge{Gauge: GenTestGauge()}}, "Sum/default": {Data: &Metric_Sum{Sum: &Sum{}}}, "Sum/test": {Data: &Metric_Sum{Sum: GenTestSum()}}, "Histogram/default": {Data: &Metric_Histogram{Histogram: &Histogram{}}}, "Histogram/test": {Data: &Metric_Histogram{Histogram: GenTestHistogram()}}, "ExponentialHistogram/default": {Data: &Metric_ExponentialHistogram{ExponentialHistogram: &ExponentialHistogram{}}}, "ExponentialHistogram/test": {Data: &Metric_ExponentialHistogram{ExponentialHistogram: GenTestExponentialHistogram()}}, "Summary/default": {Data: &Metric_Summary{Summary: &Summary{}}}, "Summary/test": {Data: &Metric_Summary{Summary: GenTestSummary()}}, "Metadata/test": {Metadata: []KeyValue{{}, *GenTestKeyValue()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_metricsdata.go000066400000000000000000000135541511331344600275430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // MetricsData represents the metrics data that can be stored in a persistent storage, // OR can be embedded by other protocols that transfer OTLP metrics data but do not // implement the OTLP protocol.. type MetricsData struct { ResourceMetrics []*ResourceMetrics } var ( protoPoolMetricsData = sync.Pool{ New: func() any { return &MetricsData{} }, } ) func NewMetricsData() *MetricsData { if !UseProtoPooling.IsEnabled() { return &MetricsData{} } return protoPoolMetricsData.Get().(*MetricsData) } func DeleteMetricsData(orig *MetricsData, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceMetrics { DeleteResourceMetrics(orig.ResourceMetrics[i], true) } orig.Reset() if nullable { protoPoolMetricsData.Put(orig) } } func CopyMetricsData(dest, src *MetricsData) *MetricsData { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewMetricsData() } dest.ResourceMetrics = CopyResourceMetricsPtrSlice(dest.ResourceMetrics, src.ResourceMetrics) return dest } func CopyMetricsDataSlice(dest, src []MetricsData) []MetricsData { var newDest []MetricsData if cap(dest) < len(src) { newDest = make([]MetricsData, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMetricsData(&dest[i], false) } } for i := range src { CopyMetricsData(&newDest[i], &src[i]) } return newDest } func CopyMetricsDataPtrSlice(dest, src []*MetricsData) []*MetricsData { var newDest []*MetricsData if cap(dest) < len(src) { newDest = make([]*MetricsData, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewMetricsData() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMetricsData(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewMetricsData() } } for i := range src { CopyMetricsData(newDest[i], src[i]) } return newDest } func (orig *MetricsData) Reset() { *orig = MetricsData{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *MetricsData) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceMetrics) > 0 { dest.WriteObjectField("resourceMetrics") dest.WriteArrayStart() orig.ResourceMetrics[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceMetrics); i++ { dest.WriteMore() orig.ResourceMetrics[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *MetricsData) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceMetrics", "resource_metrics": for iter.ReadArray() { orig.ResourceMetrics = append(orig.ResourceMetrics, NewResourceMetrics()) orig.ResourceMetrics[len(orig.ResourceMetrics)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *MetricsData) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceMetrics { l = orig.ResourceMetrics[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *MetricsData) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceMetrics) - 1; i >= 0; i-- { l = orig.ResourceMetrics[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *MetricsData) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceMetrics", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceMetrics = append(orig.ResourceMetrics, NewResourceMetrics()) err = orig.ResourceMetrics[len(orig.ResourceMetrics)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestMetricsData() *MetricsData { orig := NewMetricsData() orig.ResourceMetrics = []*ResourceMetrics{{}, GenTestResourceMetrics()} return orig } func GenTestMetricsDataPtrSlice() []*MetricsData { orig := make([]*MetricsData, 5) orig[0] = NewMetricsData() orig[1] = GenTestMetricsData() orig[2] = NewMetricsData() orig[3] = GenTestMetricsData() orig[4] = NewMetricsData() return orig } func GenTestMetricsDataSlice() []MetricsData { orig := make([]MetricsData, 5) orig[1] = *GenTestMetricsData() orig[3] = *GenTestMetricsData() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_metricsdata_test.go000066400000000000000000000141421511331344600305740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyMetricsData(t *testing.T) { for name, src := range genTestEncodingValuesMetricsData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewMetricsData() CopyMetricsData(dest, src) assert.Equal(t, src, dest) CopyMetricsData(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyMetricsDataSlice(t *testing.T) { src := []MetricsData{} dest := []MetricsData{} // Test CopyTo empty dest = CopyMetricsDataSlice(dest, src) assert.Equal(t, []MetricsData{}, dest) // Test CopyTo larger slice src = GenTestMetricsDataSlice() dest = CopyMetricsDataSlice(dest, src) assert.Equal(t, GenTestMetricsDataSlice(), dest) // Test CopyTo same size slice dest = CopyMetricsDataSlice(dest, src) assert.Equal(t, GenTestMetricsDataSlice(), dest) // Test CopyTo smaller size slice dest = CopyMetricsDataSlice(dest, []MetricsData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMetricsDataSlice(dest, src) assert.Equal(t, GenTestMetricsDataSlice(), dest) } func TestCopyMetricsDataPtrSlice(t *testing.T) { src := []*MetricsData{} dest := []*MetricsData{} // Test CopyTo empty dest = CopyMetricsDataPtrSlice(dest, src) assert.Equal(t, []*MetricsData{}, dest) // Test CopyTo larger slice src = GenTestMetricsDataPtrSlice() dest = CopyMetricsDataPtrSlice(dest, src) assert.Equal(t, GenTestMetricsDataPtrSlice(), dest) // Test CopyTo same size slice dest = CopyMetricsDataPtrSlice(dest, src) assert.Equal(t, GenTestMetricsDataPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyMetricsDataPtrSlice(dest, []*MetricsData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMetricsDataPtrSlice(dest, src) assert.Equal(t, GenTestMetricsDataPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONMetricsDataUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewMetricsData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewMetricsData(), dest) } func TestMarshalAndUnmarshalJSONMetricsData(t *testing.T) { for name, src := range genTestEncodingValuesMetricsData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewMetricsData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteMetricsData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoMetricsDataFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesMetricsData() { t.Run(name, func(t *testing.T) { dest := NewMetricsData() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoMetricsDataUnknown(t *testing.T) { dest := NewMetricsData() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewMetricsData(), dest) } func TestMarshalAndUnmarshalProtoMetricsData(t *testing.T) { for name, src := range genTestEncodingValuesMetricsData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewMetricsData() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteMetricsData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufMetricsData(t *testing.T) { for name, src := range genTestEncodingValuesMetricsData() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.MetricsData{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewMetricsData() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesMetricsData() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceMetrics/wrong_wire_type": {0xc}, "ResourceMetrics/missing_value": {0xa}, } } func genTestEncodingValuesMetricsData() map[string]*MetricsData { return map[string]*MetricsData{ "empty": NewMetricsData(), "ResourceMetrics/test": {ResourceMetrics: []*ResourceMetrics{{}, GenTestResourceMetrics()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_metricsrequest.go000066400000000000000000000160001511331344600303070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type MetricsRequest struct { RequestContext *RequestContext MetricsData MetricsData FormatVersion uint32 } var ( protoPoolMetricsRequest = sync.Pool{ New: func() any { return &MetricsRequest{} }, } ) func NewMetricsRequest() *MetricsRequest { if !UseProtoPooling.IsEnabled() { return &MetricsRequest{} } return protoPoolMetricsRequest.Get().(*MetricsRequest) } func DeleteMetricsRequest(orig *MetricsRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteRequestContext(orig.RequestContext, true) DeleteMetricsData(&orig.MetricsData, false) orig.Reset() if nullable { protoPoolMetricsRequest.Put(orig) } } func CopyMetricsRequest(dest, src *MetricsRequest) *MetricsRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewMetricsRequest() } dest.RequestContext = CopyRequestContext(dest.RequestContext, src.RequestContext) CopyMetricsData(&dest.MetricsData, &src.MetricsData) dest.FormatVersion = src.FormatVersion return dest } func CopyMetricsRequestSlice(dest, src []MetricsRequest) []MetricsRequest { var newDest []MetricsRequest if cap(dest) < len(src) { newDest = make([]MetricsRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMetricsRequest(&dest[i], false) } } for i := range src { CopyMetricsRequest(&newDest[i], &src[i]) } return newDest } func CopyMetricsRequestPtrSlice(dest, src []*MetricsRequest) []*MetricsRequest { var newDest []*MetricsRequest if cap(dest) < len(src) { newDest = make([]*MetricsRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewMetricsRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteMetricsRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewMetricsRequest() } } for i := range src { CopyMetricsRequest(newDest[i], src[i]) } return newDest } func (orig *MetricsRequest) Reset() { *orig = MetricsRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *MetricsRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RequestContext != nil { dest.WriteObjectField("requestContext") orig.RequestContext.MarshalJSON(dest) } dest.WriteObjectField("metricsData") orig.MetricsData.MarshalJSON(dest) if orig.FormatVersion != uint32(0) { dest.WriteObjectField("formatVersion") dest.WriteUint32(orig.FormatVersion) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *MetricsRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "requestContext", "request_context": orig.RequestContext = NewRequestContext() orig.RequestContext.UnmarshalJSON(iter) case "metricsData", "metrics_data": orig.MetricsData.UnmarshalJSON(iter) case "formatVersion", "format_version": orig.FormatVersion = iter.ReadUint32() default: iter.Skip() } } } func (orig *MetricsRequest) SizeProto() int { var n int var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = orig.MetricsData.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.FormatVersion != 0 { n += 5 } return n } func (orig *MetricsRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = orig.MetricsData.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a if orig.FormatVersion != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.FormatVersion)) pos-- buf[pos] = 0xd } return len(buf) - pos } func (orig *MetricsRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field RequestContext", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.RequestContext = NewRequestContext() err = orig.RequestContext.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field MetricsData", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.MetricsData.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 1: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field FormatVersion", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.FormatVersion = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestMetricsRequest() *MetricsRequest { orig := NewMetricsRequest() orig.RequestContext = GenTestRequestContext() orig.MetricsData = *GenTestMetricsData() orig.FormatVersion = uint32(13) return orig } func GenTestMetricsRequestPtrSlice() []*MetricsRequest { orig := make([]*MetricsRequest, 5) orig[0] = NewMetricsRequest() orig[1] = GenTestMetricsRequest() orig[2] = NewMetricsRequest() orig[3] = GenTestMetricsRequest() orig[4] = NewMetricsRequest() return orig } func GenTestMetricsRequestSlice() []MetricsRequest { orig := make([]MetricsRequest, 5) orig[1] = *GenTestMetricsRequest() orig[3] = *GenTestMetricsRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_metricsrequest_test.go000066400000000000000000000147741511331344600313660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyMetricsRequest(t *testing.T) { for name, src := range genTestEncodingValuesMetricsRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewMetricsRequest() CopyMetricsRequest(dest, src) assert.Equal(t, src, dest) CopyMetricsRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyMetricsRequestSlice(t *testing.T) { src := []MetricsRequest{} dest := []MetricsRequest{} // Test CopyTo empty dest = CopyMetricsRequestSlice(dest, src) assert.Equal(t, []MetricsRequest{}, dest) // Test CopyTo larger slice src = GenTestMetricsRequestSlice() dest = CopyMetricsRequestSlice(dest, src) assert.Equal(t, GenTestMetricsRequestSlice(), dest) // Test CopyTo same size slice dest = CopyMetricsRequestSlice(dest, src) assert.Equal(t, GenTestMetricsRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyMetricsRequestSlice(dest, []MetricsRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMetricsRequestSlice(dest, src) assert.Equal(t, GenTestMetricsRequestSlice(), dest) } func TestCopyMetricsRequestPtrSlice(t *testing.T) { src := []*MetricsRequest{} dest := []*MetricsRequest{} // Test CopyTo empty dest = CopyMetricsRequestPtrSlice(dest, src) assert.Equal(t, []*MetricsRequest{}, dest) // Test CopyTo larger slice src = GenTestMetricsRequestPtrSlice() dest = CopyMetricsRequestPtrSlice(dest, src) assert.Equal(t, GenTestMetricsRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyMetricsRequestPtrSlice(dest, src) assert.Equal(t, GenTestMetricsRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyMetricsRequestPtrSlice(dest, []*MetricsRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyMetricsRequestPtrSlice(dest, src) assert.Equal(t, GenTestMetricsRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONMetricsRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewMetricsRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewMetricsRequest(), dest) } func TestMarshalAndUnmarshalJSONMetricsRequest(t *testing.T) { for name, src := range genTestEncodingValuesMetricsRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewMetricsRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteMetricsRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoMetricsRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesMetricsRequest() { t.Run(name, func(t *testing.T) { dest := NewMetricsRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoMetricsRequestUnknown(t *testing.T) { dest := NewMetricsRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewMetricsRequest(), dest) } func TestMarshalAndUnmarshalProtoMetricsRequest(t *testing.T) { for name, src := range genTestEncodingValuesMetricsRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewMetricsRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteMetricsRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufMetricsRequest(t *testing.T) { for name, src := range genTestEncodingValuesMetricsRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewMetricsRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesMetricsRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RequestContext/wrong_wire_type": {0x14}, "RequestContext/missing_value": {0x12}, "MetricsData/wrong_wire_type": {0x1c}, "MetricsData/missing_value": {0x1a}, "FormatVersion/wrong_wire_type": {0xc}, "FormatVersion/missing_value": {0xd}, } } func genTestEncodingValuesMetricsRequest() map[string]*MetricsRequest { return map[string]*MetricsRequest{ "empty": NewMetricsRequest(), "RequestContext/test": {RequestContext: GenTestRequestContext()}, "MetricsData/test": {MetricsData: *GenTestMetricsData()}, "FormatVersion/test": {FormatVersion: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_numberdatapoint.go000066400000000000000000000324521511331344600304350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "math" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) func (m *NumberDataPoint) GetValue() any { if m != nil { return m.Value } return nil } type NumberDataPoint_AsDouble struct { AsDouble float64 } func (m *NumberDataPoint) GetAsDouble() float64 { if v, ok := m.GetValue().(*NumberDataPoint_AsDouble); ok { return v.AsDouble } return float64(0) } type NumberDataPoint_AsInt struct { AsInt int64 } func (m *NumberDataPoint) GetAsInt() int64 { if v, ok := m.GetValue().(*NumberDataPoint_AsInt); ok { return v.AsInt } return int64(0) } // NumberDataPoint is a single data point in a timeseries that describes the time-varying value of a number metric. type NumberDataPoint struct { Attributes []KeyValue StartTimeUnixNano uint64 TimeUnixNano uint64 Value any Exemplars []Exemplar Flags uint32 } var ( protoPoolNumberDataPoint = sync.Pool{ New: func() any { return &NumberDataPoint{} }, } ProtoPoolNumberDataPoint_AsDouble = sync.Pool{ New: func() any { return &NumberDataPoint_AsDouble{} }, } ProtoPoolNumberDataPoint_AsInt = sync.Pool{ New: func() any { return &NumberDataPoint_AsInt{} }, } ) func NewNumberDataPoint() *NumberDataPoint { if !UseProtoPooling.IsEnabled() { return &NumberDataPoint{} } return protoPoolNumberDataPoint.Get().(*NumberDataPoint) } func DeleteNumberDataPoint(orig *NumberDataPoint, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } switch ov := orig.Value.(type) { case *NumberDataPoint_AsDouble: if UseProtoPooling.IsEnabled() { ov.AsDouble = float64(0) ProtoPoolNumberDataPoint_AsDouble.Put(ov) } case *NumberDataPoint_AsInt: if UseProtoPooling.IsEnabled() { ov.AsInt = int64(0) ProtoPoolNumberDataPoint_AsInt.Put(ov) } } for i := range orig.Exemplars { DeleteExemplar(&orig.Exemplars[i], false) } orig.Reset() if nullable { protoPoolNumberDataPoint.Put(orig) } } func CopyNumberDataPoint(dest, src *NumberDataPoint) *NumberDataPoint { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewNumberDataPoint() } dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.StartTimeUnixNano = src.StartTimeUnixNano dest.TimeUnixNano = src.TimeUnixNano switch t := src.Value.(type) { case *NumberDataPoint_AsDouble: var ov *NumberDataPoint_AsDouble if !UseProtoPooling.IsEnabled() { ov = &NumberDataPoint_AsDouble{} } else { ov = ProtoPoolNumberDataPoint_AsDouble.Get().(*NumberDataPoint_AsDouble) } ov.AsDouble = t.AsDouble dest.Value = ov case *NumberDataPoint_AsInt: var ov *NumberDataPoint_AsInt if !UseProtoPooling.IsEnabled() { ov = &NumberDataPoint_AsInt{} } else { ov = ProtoPoolNumberDataPoint_AsInt.Get().(*NumberDataPoint_AsInt) } ov.AsInt = t.AsInt dest.Value = ov default: dest.Value = nil } dest.Exemplars = CopyExemplarSlice(dest.Exemplars, src.Exemplars) dest.Flags = src.Flags return dest } func CopyNumberDataPointSlice(dest, src []NumberDataPoint) []NumberDataPoint { var newDest []NumberDataPoint if cap(dest) < len(src) { newDest = make([]NumberDataPoint, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteNumberDataPoint(&dest[i], false) } } for i := range src { CopyNumberDataPoint(&newDest[i], &src[i]) } return newDest } func CopyNumberDataPointPtrSlice(dest, src []*NumberDataPoint) []*NumberDataPoint { var newDest []*NumberDataPoint if cap(dest) < len(src) { newDest = make([]*NumberDataPoint, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewNumberDataPoint() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteNumberDataPoint(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewNumberDataPoint() } } for i := range src { CopyNumberDataPoint(newDest[i], src[i]) } return newDest } func (orig *NumberDataPoint) Reset() { *orig = NumberDataPoint{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *NumberDataPoint) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.StartTimeUnixNano != uint64(0) { dest.WriteObjectField("startTimeUnixNano") dest.WriteUint64(orig.StartTimeUnixNano) } if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } switch orig := orig.Value.(type) { case *NumberDataPoint_AsDouble: dest.WriteObjectField("asDouble") dest.WriteFloat64(orig.AsDouble) case *NumberDataPoint_AsInt: dest.WriteObjectField("asInt") dest.WriteInt64(orig.AsInt) } if len(orig.Exemplars) > 0 { dest.WriteObjectField("exemplars") dest.WriteArrayStart() orig.Exemplars[0].MarshalJSON(dest) for i := 1; i < len(orig.Exemplars); i++ { dest.WriteMore() orig.Exemplars[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.Flags != uint32(0) { dest.WriteObjectField("flags") dest.WriteUint32(orig.Flags) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *NumberDataPoint) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "startTimeUnixNano", "start_time_unix_nano": orig.StartTimeUnixNano = iter.ReadUint64() case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "asDouble", "as_double": { var ov *NumberDataPoint_AsDouble if !UseProtoPooling.IsEnabled() { ov = &NumberDataPoint_AsDouble{} } else { ov = ProtoPoolNumberDataPoint_AsDouble.Get().(*NumberDataPoint_AsDouble) } ov.AsDouble = iter.ReadFloat64() orig.Value = ov } case "asInt", "as_int": { var ov *NumberDataPoint_AsInt if !UseProtoPooling.IsEnabled() { ov = &NumberDataPoint_AsInt{} } else { ov = ProtoPoolNumberDataPoint_AsInt.Get().(*NumberDataPoint_AsInt) } ov.AsInt = iter.ReadInt64() orig.Value = ov } case "exemplars": for iter.ReadArray() { orig.Exemplars = append(orig.Exemplars, Exemplar{}) orig.Exemplars[len(orig.Exemplars)-1].UnmarshalJSON(iter) } case "flags": orig.Flags = iter.ReadUint32() default: iter.Skip() } } } func (orig *NumberDataPoint) SizeProto() int { var n int var l int _ = l for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.StartTimeUnixNano != 0 { n += 9 } if orig.TimeUnixNano != 0 { n += 9 } switch orig := orig.Value.(type) { case nil: _ = orig break case *NumberDataPoint_AsDouble: n += 9 case *NumberDataPoint_AsInt: n += 9 } for i := range orig.Exemplars { l = orig.Exemplars[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.Flags != 0 { n += 1 + proto.Sov(uint64(orig.Flags)) } return n } func (orig *NumberDataPoint) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3a } if orig.StartTimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.StartTimeUnixNano)) pos-- buf[pos] = 0x11 } if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x19 } switch orig := orig.Value.(type) { case *NumberDataPoint_AsDouble: pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.AsDouble)) pos-- buf[pos] = 0x21 case *NumberDataPoint_AsInt: pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.AsInt)) pos-- buf[pos] = 0x31 } for i := len(orig.Exemplars) - 1; i >= 0; i-- { l = orig.Exemplars[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a } if orig.Flags != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Flags)) pos-- buf[pos] = 0x40 } return len(buf) - pos } func (orig *NumberDataPoint) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 7: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field StartTimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.StartTimeUnixNano = uint64(num) case 3: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 4: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field AsDouble", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *NumberDataPoint_AsDouble if !UseProtoPooling.IsEnabled() { ov = &NumberDataPoint_AsDouble{} } else { ov = ProtoPoolNumberDataPoint_AsDouble.Get().(*NumberDataPoint_AsDouble) } ov.AsDouble = math.Float64frombits(num) orig.Value = ov case 6: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field AsInt", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } var ov *NumberDataPoint_AsInt if !UseProtoPooling.IsEnabled() { ov = &NumberDataPoint_AsInt{} } else { ov = ProtoPoolNumberDataPoint_AsInt.Get().(*NumberDataPoint_AsInt) } ov.AsInt = int64(num) orig.Value = ov case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Exemplars", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Exemplars = append(orig.Exemplars, Exemplar{}) err = orig.Exemplars[len(orig.Exemplars)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 8: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Flags = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestNumberDataPoint() *NumberDataPoint { orig := NewNumberDataPoint() orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.StartTimeUnixNano = uint64(13) orig.TimeUnixNano = uint64(13) orig.Value = &NumberDataPoint_AsDouble{AsDouble: float64(3.1415926)} orig.Exemplars = []Exemplar{{}, *GenTestExemplar()} orig.Flags = uint32(13) return orig } func GenTestNumberDataPointPtrSlice() []*NumberDataPoint { orig := make([]*NumberDataPoint, 5) orig[0] = NewNumberDataPoint() orig[1] = GenTestNumberDataPoint() orig[2] = NewNumberDataPoint() orig[3] = GenTestNumberDataPoint() orig[4] = NewNumberDataPoint() return orig } func GenTestNumberDataPointSlice() []NumberDataPoint { orig := make([]NumberDataPoint, 5) orig[1] = *GenTestNumberDataPoint() orig[3] = *GenTestNumberDataPoint() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_numberdatapoint_test.go000066400000000000000000000165771511331344600315060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyNumberDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesNumberDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewNumberDataPoint() CopyNumberDataPoint(dest, src) assert.Equal(t, src, dest) CopyNumberDataPoint(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyNumberDataPointSlice(t *testing.T) { src := []NumberDataPoint{} dest := []NumberDataPoint{} // Test CopyTo empty dest = CopyNumberDataPointSlice(dest, src) assert.Equal(t, []NumberDataPoint{}, dest) // Test CopyTo larger slice src = GenTestNumberDataPointSlice() dest = CopyNumberDataPointSlice(dest, src) assert.Equal(t, GenTestNumberDataPointSlice(), dest) // Test CopyTo same size slice dest = CopyNumberDataPointSlice(dest, src) assert.Equal(t, GenTestNumberDataPointSlice(), dest) // Test CopyTo smaller size slice dest = CopyNumberDataPointSlice(dest, []NumberDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyNumberDataPointSlice(dest, src) assert.Equal(t, GenTestNumberDataPointSlice(), dest) } func TestCopyNumberDataPointPtrSlice(t *testing.T) { src := []*NumberDataPoint{} dest := []*NumberDataPoint{} // Test CopyTo empty dest = CopyNumberDataPointPtrSlice(dest, src) assert.Equal(t, []*NumberDataPoint{}, dest) // Test CopyTo larger slice src = GenTestNumberDataPointPtrSlice() dest = CopyNumberDataPointPtrSlice(dest, src) assert.Equal(t, GenTestNumberDataPointPtrSlice(), dest) // Test CopyTo same size slice dest = CopyNumberDataPointPtrSlice(dest, src) assert.Equal(t, GenTestNumberDataPointPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyNumberDataPointPtrSlice(dest, []*NumberDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyNumberDataPointPtrSlice(dest, src) assert.Equal(t, GenTestNumberDataPointPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONNumberDataPointUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewNumberDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewNumberDataPoint(), dest) } func TestMarshalAndUnmarshalJSONNumberDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesNumberDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewNumberDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteNumberDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoNumberDataPointFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesNumberDataPoint() { t.Run(name, func(t *testing.T) { dest := NewNumberDataPoint() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoNumberDataPointUnknown(t *testing.T) { dest := NewNumberDataPoint() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewNumberDataPoint(), dest) } func TestMarshalAndUnmarshalProtoNumberDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesNumberDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewNumberDataPoint() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteNumberDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufNumberDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesNumberDataPoint() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.NumberDataPoint{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewNumberDataPoint() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesNumberDataPoint() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Attributes/wrong_wire_type": {0x3c}, "Attributes/missing_value": {0x3a}, "StartTimeUnixNano/wrong_wire_type": {0x14}, "StartTimeUnixNano/missing_value": {0x11}, "TimeUnixNano/wrong_wire_type": {0x1c}, "TimeUnixNano/missing_value": {0x19}, "AsDouble/wrong_wire_type": {0x24}, "AsDouble/missing_value": {0x21}, "AsInt/wrong_wire_type": {0x34}, "AsInt/missing_value": {0x31}, "Exemplars/wrong_wire_type": {0x2c}, "Exemplars/missing_value": {0x2a}, "Flags/wrong_wire_type": {0x44}, "Flags/missing_value": {0x40}, } } func genTestEncodingValuesNumberDataPoint() map[string]*NumberDataPoint { return map[string]*NumberDataPoint{ "empty": NewNumberDataPoint(), "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "StartTimeUnixNano/test": {StartTimeUnixNano: uint64(13)}, "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "AsDouble/default": {Value: &NumberDataPoint_AsDouble{AsDouble: float64(0)}}, "AsDouble/test": {Value: &NumberDataPoint_AsDouble{AsDouble: float64(3.1415926)}}, "AsInt/default": {Value: &NumberDataPoint_AsInt{AsInt: int64(0)}}, "AsInt/test": {Value: &NumberDataPoint_AsInt{AsInt: int64(13)}}, "Exemplars/test": {Exemplars: []Exemplar{{}, *GenTestExemplar()}}, "Flags/test": {Flags: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profile.go000066400000000000000000000354121511331344600267000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Profile are an implementation of the pprofextended data model. type Profile struct { SampleType ValueType Samples []*Sample TimeUnixNano uint64 DurationNano uint64 PeriodType ValueType Period int64 ProfileId ProfileID DroppedAttributesCount uint32 OriginalPayloadFormat string OriginalPayload []byte AttributeIndices []int32 } var ( protoPoolProfile = sync.Pool{ New: func() any { return &Profile{} }, } ) func NewProfile() *Profile { if !UseProtoPooling.IsEnabled() { return &Profile{} } return protoPoolProfile.Get().(*Profile) } func DeleteProfile(orig *Profile, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteValueType(&orig.SampleType, false) for i := range orig.Samples { DeleteSample(orig.Samples[i], true) } DeleteValueType(&orig.PeriodType, false) DeleteProfileID(&orig.ProfileId, false) orig.Reset() if nullable { protoPoolProfile.Put(orig) } } func CopyProfile(dest, src *Profile) *Profile { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewProfile() } CopyValueType(&dest.SampleType, &src.SampleType) dest.Samples = CopySamplePtrSlice(dest.Samples, src.Samples) dest.TimeUnixNano = src.TimeUnixNano dest.DurationNano = src.DurationNano CopyValueType(&dest.PeriodType, &src.PeriodType) dest.Period = src.Period CopyProfileID(&dest.ProfileId, &src.ProfileId) dest.DroppedAttributesCount = src.DroppedAttributesCount dest.OriginalPayloadFormat = src.OriginalPayloadFormat dest.OriginalPayload = src.OriginalPayload dest.AttributeIndices = append(dest.AttributeIndices[:0], src.AttributeIndices...) return dest } func CopyProfileSlice(dest, src []Profile) []Profile { var newDest []Profile if cap(dest) < len(src) { newDest = make([]Profile, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfile(&dest[i], false) } } for i := range src { CopyProfile(&newDest[i], &src[i]) } return newDest } func CopyProfilePtrSlice(dest, src []*Profile) []*Profile { var newDest []*Profile if cap(dest) < len(src) { newDest = make([]*Profile, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfile() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfile(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfile() } } for i := range src { CopyProfile(newDest[i], src[i]) } return newDest } func (orig *Profile) Reset() { *orig = Profile{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Profile) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("sampleType") orig.SampleType.MarshalJSON(dest) if len(orig.Samples) > 0 { dest.WriteObjectField("samples") dest.WriteArrayStart() orig.Samples[0].MarshalJSON(dest) for i := 1; i < len(orig.Samples); i++ { dest.WriteMore() orig.Samples[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } if orig.DurationNano != uint64(0) { dest.WriteObjectField("durationNano") dest.WriteUint64(orig.DurationNano) } dest.WriteObjectField("periodType") orig.PeriodType.MarshalJSON(dest) if orig.Period != int64(0) { dest.WriteObjectField("period") dest.WriteInt64(orig.Period) } if !orig.ProfileId.IsEmpty() { dest.WriteObjectField("profileId") orig.ProfileId.MarshalJSON(dest) } if orig.DroppedAttributesCount != uint32(0) { dest.WriteObjectField("droppedAttributesCount") dest.WriteUint32(orig.DroppedAttributesCount) } if orig.OriginalPayloadFormat != "" { dest.WriteObjectField("originalPayloadFormat") dest.WriteString(orig.OriginalPayloadFormat) } if len(orig.OriginalPayload) > 0 { dest.WriteObjectField("originalPayload") dest.WriteBytes(orig.OriginalPayload) } if len(orig.AttributeIndices) > 0 { dest.WriteObjectField("attributeIndices") dest.WriteArrayStart() dest.WriteInt32(orig.AttributeIndices[0]) for i := 1; i < len(orig.AttributeIndices); i++ { dest.WriteMore() dest.WriteInt32(orig.AttributeIndices[i]) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Profile) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "sampleType", "sample_type": orig.SampleType.UnmarshalJSON(iter) case "samples": for iter.ReadArray() { orig.Samples = append(orig.Samples, NewSample()) orig.Samples[len(orig.Samples)-1].UnmarshalJSON(iter) } case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "durationNano", "duration_nano": orig.DurationNano = iter.ReadUint64() case "periodType", "period_type": orig.PeriodType.UnmarshalJSON(iter) case "period": orig.Period = iter.ReadInt64() case "profileId", "profile_id": orig.ProfileId.UnmarshalJSON(iter) case "droppedAttributesCount", "dropped_attributes_count": orig.DroppedAttributesCount = iter.ReadUint32() case "originalPayloadFormat", "original_payload_format": orig.OriginalPayloadFormat = iter.ReadString() case "originalPayload", "original_payload": orig.OriginalPayload = iter.ReadBytes() case "attributeIndices", "attribute_indices": for iter.ReadArray() { orig.AttributeIndices = append(orig.AttributeIndices, iter.ReadInt32()) } default: iter.Skip() } } } func (orig *Profile) SizeProto() int { var n int var l int _ = l l = orig.SampleType.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.Samples { l = orig.Samples[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.TimeUnixNano != 0 { n += 9 } if orig.DurationNano != 0 { n += 1 + proto.Sov(uint64(orig.DurationNano)) } l = orig.PeriodType.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.Period != 0 { n += 1 + proto.Sov(uint64(orig.Period)) } l = orig.ProfileId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.DroppedAttributesCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedAttributesCount)) } l = len(orig.OriginalPayloadFormat) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.OriginalPayload) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } if len(orig.AttributeIndices) > 0 { l = 0 for _, e := range orig.AttributeIndices { l += proto.Sov(uint64(e)) } n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Profile) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.SampleType.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.Samples) - 1; i >= 0; i-- { l = orig.Samples[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x19 } if orig.DurationNano != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DurationNano)) pos-- buf[pos] = 0x20 } l = orig.PeriodType.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a if orig.Period != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Period)) pos-- buf[pos] = 0x30 } l = orig.ProfileId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3a if orig.DroppedAttributesCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedAttributesCount)) pos-- buf[pos] = 0x40 } l = len(orig.OriginalPayloadFormat) if l > 0 { pos -= l copy(buf[pos:], orig.OriginalPayloadFormat) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x4a } l = len(orig.OriginalPayload) if l > 0 { pos -= l copy(buf[pos:], orig.OriginalPayload) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x52 } l = len(orig.AttributeIndices) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.AttributeIndices[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) pos-- buf[pos] = 0x5a } return len(buf) - pos } func (orig *Profile) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SampleType", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.SampleType.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Samples", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Samples = append(orig.Samples, NewSample()) err = orig.Samples[len(orig.Samples)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 4: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DurationNano", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DurationNano = uint64(num) case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field PeriodType", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.PeriodType.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 6: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Period", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Period = int64(num) case 7: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ProfileId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.ProfileId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 8: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedAttributesCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedAttributesCount = uint32(num) case 9: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field OriginalPayloadFormat", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.OriginalPayloadFormat = string(buf[startPos:pos]) case 10: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field OriginalPayload", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length if length != 0 { orig.OriginalPayload = make([]byte, length) copy(orig.OriginalPayload, buf[startPos:pos]) } case 11: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field AttributeIndices", pos-startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field AttributeIndices", wireType) } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestProfile() *Profile { orig := NewProfile() orig.SampleType = *GenTestValueType() orig.Samples = []*Sample{{}, GenTestSample()} orig.TimeUnixNano = uint64(13) orig.DurationNano = uint64(13) orig.PeriodType = *GenTestValueType() orig.Period = int64(13) orig.ProfileId = *GenTestProfileID() orig.DroppedAttributesCount = uint32(13) orig.OriginalPayloadFormat = "test_originalpayloadformat" orig.OriginalPayload = []byte{1, 2, 3} orig.AttributeIndices = []int32{int32(0), int32(13)} return orig } func GenTestProfilePtrSlice() []*Profile { orig := make([]*Profile, 5) orig[0] = NewProfile() orig[1] = GenTestProfile() orig[2] = NewProfile() orig[3] = GenTestProfile() orig[4] = NewProfile() return orig } func GenTestProfileSlice() []Profile { orig := make([]Profile, 5) orig[1] = *GenTestProfile() orig[3] = *GenTestProfile() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profile_test.go000066400000000000000000000171171511331344600277410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyProfile(t *testing.T) { for name, src := range genTestEncodingValuesProfile() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewProfile() CopyProfile(dest, src) assert.Equal(t, src, dest) CopyProfile(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyProfileSlice(t *testing.T) { src := []Profile{} dest := []Profile{} // Test CopyTo empty dest = CopyProfileSlice(dest, src) assert.Equal(t, []Profile{}, dest) // Test CopyTo larger slice src = GenTestProfileSlice() dest = CopyProfileSlice(dest, src) assert.Equal(t, GenTestProfileSlice(), dest) // Test CopyTo same size slice dest = CopyProfileSlice(dest, src) assert.Equal(t, GenTestProfileSlice(), dest) // Test CopyTo smaller size slice dest = CopyProfileSlice(dest, []Profile{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfileSlice(dest, src) assert.Equal(t, GenTestProfileSlice(), dest) } func TestCopyProfilePtrSlice(t *testing.T) { src := []*Profile{} dest := []*Profile{} // Test CopyTo empty dest = CopyProfilePtrSlice(dest, src) assert.Equal(t, []*Profile{}, dest) // Test CopyTo larger slice src = GenTestProfilePtrSlice() dest = CopyProfilePtrSlice(dest, src) assert.Equal(t, GenTestProfilePtrSlice(), dest) // Test CopyTo same size slice dest = CopyProfilePtrSlice(dest, src) assert.Equal(t, GenTestProfilePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyProfilePtrSlice(dest, []*Profile{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfilePtrSlice(dest, src) assert.Equal(t, GenTestProfilePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONProfileUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewProfile() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewProfile(), dest) } func TestMarshalAndUnmarshalJSONProfile(t *testing.T) { for name, src := range genTestEncodingValuesProfile() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewProfile() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteProfile(dest, true) }) } } } func TestMarshalAndUnmarshalProtoProfileFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesProfile() { t.Run(name, func(t *testing.T) { dest := NewProfile() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoProfileUnknown(t *testing.T) { dest := NewProfile() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewProfile(), dest) } func TestMarshalAndUnmarshalProtoProfile(t *testing.T) { for name, src := range genTestEncodingValuesProfile() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewProfile() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteProfile(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufProfile(t *testing.T) { for name, src := range genTestEncodingValuesProfile() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Profile{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewProfile() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesProfile() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "SampleType/wrong_wire_type": {0xc}, "SampleType/missing_value": {0xa}, "Samples/wrong_wire_type": {0x14}, "Samples/missing_value": {0x12}, "TimeUnixNano/wrong_wire_type": {0x1c}, "TimeUnixNano/missing_value": {0x19}, "DurationNano/wrong_wire_type": {0x24}, "DurationNano/missing_value": {0x20}, "PeriodType/wrong_wire_type": {0x2c}, "PeriodType/missing_value": {0x2a}, "Period/wrong_wire_type": {0x34}, "Period/missing_value": {0x30}, "ProfileId/wrong_wire_type": {0x3c}, "ProfileId/missing_value": {0x3a}, "DroppedAttributesCount/wrong_wire_type": {0x44}, "DroppedAttributesCount/missing_value": {0x40}, "OriginalPayloadFormat/wrong_wire_type": {0x4c}, "OriginalPayloadFormat/missing_value": {0x4a}, "OriginalPayload/wrong_wire_type": {0x54}, "OriginalPayload/missing_value": {0x52}, "AttributeIndices/wrong_wire_type": {0x5c}, "AttributeIndices/missing_value": {0x5a}, } } func genTestEncodingValuesProfile() map[string]*Profile { return map[string]*Profile{ "empty": NewProfile(), "SampleType/test": {SampleType: *GenTestValueType()}, "Samples/test": {Samples: []*Sample{{}, GenTestSample()}}, "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "DurationNano/test": {DurationNano: uint64(13)}, "PeriodType/test": {PeriodType: *GenTestValueType()}, "Period/test": {Period: int64(13)}, "ProfileId/test": {ProfileId: *GenTestProfileID()}, "DroppedAttributesCount/test": {DroppedAttributesCount: uint32(13)}, "OriginalPayloadFormat/test": {OriginalPayloadFormat: "test_originalpayloadformat"}, "OriginalPayload/test": {OriginalPayload: []byte{1, 2, 3}}, "AttributeIndices/test": {AttributeIndices: []int32{int32(0), int32(13)}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profilesdata.go000066400000000000000000000155021511331344600277130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ProfilesData represents the profiles data that can be stored in persistent storage, // OR can be embedded by other protocols that transfer OTLP profiles data but do not // implement the OTLP protocol. type ProfilesData struct { ResourceProfiles []*ResourceProfiles Dictionary ProfilesDictionary } var ( protoPoolProfilesData = sync.Pool{ New: func() any { return &ProfilesData{} }, } ) func NewProfilesData() *ProfilesData { if !UseProtoPooling.IsEnabled() { return &ProfilesData{} } return protoPoolProfilesData.Get().(*ProfilesData) } func DeleteProfilesData(orig *ProfilesData, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceProfiles { DeleteResourceProfiles(orig.ResourceProfiles[i], true) } DeleteProfilesDictionary(&orig.Dictionary, false) orig.Reset() if nullable { protoPoolProfilesData.Put(orig) } } func CopyProfilesData(dest, src *ProfilesData) *ProfilesData { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewProfilesData() } dest.ResourceProfiles = CopyResourceProfilesPtrSlice(dest.ResourceProfiles, src.ResourceProfiles) CopyProfilesDictionary(&dest.Dictionary, &src.Dictionary) return dest } func CopyProfilesDataSlice(dest, src []ProfilesData) []ProfilesData { var newDest []ProfilesData if cap(dest) < len(src) { newDest = make([]ProfilesData, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfilesData(&dest[i], false) } } for i := range src { CopyProfilesData(&newDest[i], &src[i]) } return newDest } func CopyProfilesDataPtrSlice(dest, src []*ProfilesData) []*ProfilesData { var newDest []*ProfilesData if cap(dest) < len(src) { newDest = make([]*ProfilesData, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfilesData() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfilesData(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfilesData() } } for i := range src { CopyProfilesData(newDest[i], src[i]) } return newDest } func (orig *ProfilesData) Reset() { *orig = ProfilesData{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ProfilesData) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceProfiles) > 0 { dest.WriteObjectField("resourceProfiles") dest.WriteArrayStart() orig.ResourceProfiles[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceProfiles); i++ { dest.WriteMore() orig.ResourceProfiles[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectField("dictionary") orig.Dictionary.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ProfilesData) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceProfiles", "resource_profiles": for iter.ReadArray() { orig.ResourceProfiles = append(orig.ResourceProfiles, NewResourceProfiles()) orig.ResourceProfiles[len(orig.ResourceProfiles)-1].UnmarshalJSON(iter) } case "dictionary": orig.Dictionary.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *ProfilesData) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceProfiles { l = orig.ResourceProfiles[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = orig.Dictionary.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *ProfilesData) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceProfiles) - 1; i >= 0; i-- { l = orig.ResourceProfiles[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = orig.Dictionary.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 return len(buf) - pos } func (orig *ProfilesData) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceProfiles", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceProfiles = append(orig.ResourceProfiles, NewResourceProfiles()) err = orig.ResourceProfiles[len(orig.ResourceProfiles)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Dictionary", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Dictionary.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestProfilesData() *ProfilesData { orig := NewProfilesData() orig.ResourceProfiles = []*ResourceProfiles{{}, GenTestResourceProfiles()} orig.Dictionary = *GenTestProfilesDictionary() return orig } func GenTestProfilesDataPtrSlice() []*ProfilesData { orig := make([]*ProfilesData, 5) orig[0] = NewProfilesData() orig[1] = GenTestProfilesData() orig[2] = NewProfilesData() orig[3] = GenTestProfilesData() orig[4] = NewProfilesData() return orig } func GenTestProfilesDataSlice() []ProfilesData { orig := make([]ProfilesData, 5) orig[1] = *GenTestProfilesData() orig[3] = *GenTestProfilesData() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profilesdata_test.go000066400000000000000000000145261511331344600307570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyProfilesData(t *testing.T) { for name, src := range genTestEncodingValuesProfilesData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewProfilesData() CopyProfilesData(dest, src) assert.Equal(t, src, dest) CopyProfilesData(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyProfilesDataSlice(t *testing.T) { src := []ProfilesData{} dest := []ProfilesData{} // Test CopyTo empty dest = CopyProfilesDataSlice(dest, src) assert.Equal(t, []ProfilesData{}, dest) // Test CopyTo larger slice src = GenTestProfilesDataSlice() dest = CopyProfilesDataSlice(dest, src) assert.Equal(t, GenTestProfilesDataSlice(), dest) // Test CopyTo same size slice dest = CopyProfilesDataSlice(dest, src) assert.Equal(t, GenTestProfilesDataSlice(), dest) // Test CopyTo smaller size slice dest = CopyProfilesDataSlice(dest, []ProfilesData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfilesDataSlice(dest, src) assert.Equal(t, GenTestProfilesDataSlice(), dest) } func TestCopyProfilesDataPtrSlice(t *testing.T) { src := []*ProfilesData{} dest := []*ProfilesData{} // Test CopyTo empty dest = CopyProfilesDataPtrSlice(dest, src) assert.Equal(t, []*ProfilesData{}, dest) // Test CopyTo larger slice src = GenTestProfilesDataPtrSlice() dest = CopyProfilesDataPtrSlice(dest, src) assert.Equal(t, GenTestProfilesDataPtrSlice(), dest) // Test CopyTo same size slice dest = CopyProfilesDataPtrSlice(dest, src) assert.Equal(t, GenTestProfilesDataPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyProfilesDataPtrSlice(dest, []*ProfilesData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfilesDataPtrSlice(dest, src) assert.Equal(t, GenTestProfilesDataPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONProfilesDataUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewProfilesData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewProfilesData(), dest) } func TestMarshalAndUnmarshalJSONProfilesData(t *testing.T) { for name, src := range genTestEncodingValuesProfilesData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewProfilesData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteProfilesData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoProfilesDataFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesProfilesData() { t.Run(name, func(t *testing.T) { dest := NewProfilesData() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoProfilesDataUnknown(t *testing.T) { dest := NewProfilesData() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewProfilesData(), dest) } func TestMarshalAndUnmarshalProtoProfilesData(t *testing.T) { for name, src := range genTestEncodingValuesProfilesData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewProfilesData() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteProfilesData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufProfilesData(t *testing.T) { for name, src := range genTestEncodingValuesProfilesData() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.ProfilesData{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewProfilesData() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesProfilesData() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceProfiles/wrong_wire_type": {0xc}, "ResourceProfiles/missing_value": {0xa}, "Dictionary/wrong_wire_type": {0x14}, "Dictionary/missing_value": {0x12}, } } func genTestEncodingValuesProfilesData() map[string]*ProfilesData { return map[string]*ProfilesData{ "empty": NewProfilesData(), "ResourceProfiles/test": {ResourceProfiles: []*ResourceProfiles{{}, GenTestResourceProfiles()}}, "Dictionary/test": {Dictionary: *GenTestProfilesDictionary()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profilesdictionary.go000066400000000000000000000347531511331344600311600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ProfilesDictionary is the reference table containing all data shared by profiles across the message being sent. type ProfilesDictionary struct { MappingTable []*Mapping LocationTable []*Location FunctionTable []*Function LinkTable []*Link StringTable []string AttributeTable []*KeyValueAndUnit StackTable []*Stack } var ( protoPoolProfilesDictionary = sync.Pool{ New: func() any { return &ProfilesDictionary{} }, } ) func NewProfilesDictionary() *ProfilesDictionary { if !UseProtoPooling.IsEnabled() { return &ProfilesDictionary{} } return protoPoolProfilesDictionary.Get().(*ProfilesDictionary) } func DeleteProfilesDictionary(orig *ProfilesDictionary, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.MappingTable { DeleteMapping(orig.MappingTable[i], true) } for i := range orig.LocationTable { DeleteLocation(orig.LocationTable[i], true) } for i := range orig.FunctionTable { DeleteFunction(orig.FunctionTable[i], true) } for i := range orig.LinkTable { DeleteLink(orig.LinkTable[i], true) } for i := range orig.AttributeTable { DeleteKeyValueAndUnit(orig.AttributeTable[i], true) } for i := range orig.StackTable { DeleteStack(orig.StackTable[i], true) } orig.Reset() if nullable { protoPoolProfilesDictionary.Put(orig) } } func CopyProfilesDictionary(dest, src *ProfilesDictionary) *ProfilesDictionary { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewProfilesDictionary() } dest.MappingTable = CopyMappingPtrSlice(dest.MappingTable, src.MappingTable) dest.LocationTable = CopyLocationPtrSlice(dest.LocationTable, src.LocationTable) dest.FunctionTable = CopyFunctionPtrSlice(dest.FunctionTable, src.FunctionTable) dest.LinkTable = CopyLinkPtrSlice(dest.LinkTable, src.LinkTable) dest.StringTable = append(dest.StringTable[:0], src.StringTable...) dest.AttributeTable = CopyKeyValueAndUnitPtrSlice(dest.AttributeTable, src.AttributeTable) dest.StackTable = CopyStackPtrSlice(dest.StackTable, src.StackTable) return dest } func CopyProfilesDictionarySlice(dest, src []ProfilesDictionary) []ProfilesDictionary { var newDest []ProfilesDictionary if cap(dest) < len(src) { newDest = make([]ProfilesDictionary, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfilesDictionary(&dest[i], false) } } for i := range src { CopyProfilesDictionary(&newDest[i], &src[i]) } return newDest } func CopyProfilesDictionaryPtrSlice(dest, src []*ProfilesDictionary) []*ProfilesDictionary { var newDest []*ProfilesDictionary if cap(dest) < len(src) { newDest = make([]*ProfilesDictionary, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfilesDictionary() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfilesDictionary(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfilesDictionary() } } for i := range src { CopyProfilesDictionary(newDest[i], src[i]) } return newDest } func (orig *ProfilesDictionary) Reset() { *orig = ProfilesDictionary{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ProfilesDictionary) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.MappingTable) > 0 { dest.WriteObjectField("mappingTable") dest.WriteArrayStart() orig.MappingTable[0].MarshalJSON(dest) for i := 1; i < len(orig.MappingTable); i++ { dest.WriteMore() orig.MappingTable[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if len(orig.LocationTable) > 0 { dest.WriteObjectField("locationTable") dest.WriteArrayStart() orig.LocationTable[0].MarshalJSON(dest) for i := 1; i < len(orig.LocationTable); i++ { dest.WriteMore() orig.LocationTable[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if len(orig.FunctionTable) > 0 { dest.WriteObjectField("functionTable") dest.WriteArrayStart() orig.FunctionTable[0].MarshalJSON(dest) for i := 1; i < len(orig.FunctionTable); i++ { dest.WriteMore() orig.FunctionTable[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if len(orig.LinkTable) > 0 { dest.WriteObjectField("linkTable") dest.WriteArrayStart() orig.LinkTable[0].MarshalJSON(dest) for i := 1; i < len(orig.LinkTable); i++ { dest.WriteMore() orig.LinkTable[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if len(orig.StringTable) > 0 { dest.WriteObjectField("stringTable") dest.WriteArrayStart() dest.WriteString(orig.StringTable[0]) for i := 1; i < len(orig.StringTable); i++ { dest.WriteMore() dest.WriteString(orig.StringTable[i]) } dest.WriteArrayEnd() } if len(orig.AttributeTable) > 0 { dest.WriteObjectField("attributeTable") dest.WriteArrayStart() orig.AttributeTable[0].MarshalJSON(dest) for i := 1; i < len(orig.AttributeTable); i++ { dest.WriteMore() orig.AttributeTable[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if len(orig.StackTable) > 0 { dest.WriteObjectField("stackTable") dest.WriteArrayStart() orig.StackTable[0].MarshalJSON(dest) for i := 1; i < len(orig.StackTable); i++ { dest.WriteMore() orig.StackTable[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ProfilesDictionary) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "mappingTable", "mapping_table": for iter.ReadArray() { orig.MappingTable = append(orig.MappingTable, NewMapping()) orig.MappingTable[len(orig.MappingTable)-1].UnmarshalJSON(iter) } case "locationTable", "location_table": for iter.ReadArray() { orig.LocationTable = append(orig.LocationTable, NewLocation()) orig.LocationTable[len(orig.LocationTable)-1].UnmarshalJSON(iter) } case "functionTable", "function_table": for iter.ReadArray() { orig.FunctionTable = append(orig.FunctionTable, NewFunction()) orig.FunctionTable[len(orig.FunctionTable)-1].UnmarshalJSON(iter) } case "linkTable", "link_table": for iter.ReadArray() { orig.LinkTable = append(orig.LinkTable, NewLink()) orig.LinkTable[len(orig.LinkTable)-1].UnmarshalJSON(iter) } case "stringTable", "string_table": for iter.ReadArray() { orig.StringTable = append(orig.StringTable, iter.ReadString()) } case "attributeTable", "attribute_table": for iter.ReadArray() { orig.AttributeTable = append(orig.AttributeTable, NewKeyValueAndUnit()) orig.AttributeTable[len(orig.AttributeTable)-1].UnmarshalJSON(iter) } case "stackTable", "stack_table": for iter.ReadArray() { orig.StackTable = append(orig.StackTable, NewStack()) orig.StackTable[len(orig.StackTable)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ProfilesDictionary) SizeProto() int { var n int var l int _ = l for i := range orig.MappingTable { l = orig.MappingTable[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.LocationTable { l = orig.LocationTable[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.FunctionTable { l = orig.FunctionTable[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.LinkTable { l = orig.LinkTable[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } for _, s := range orig.StringTable { l = len(s) n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.AttributeTable { l = orig.AttributeTable[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.StackTable { l = orig.StackTable[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ProfilesDictionary) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.MappingTable) - 1; i >= 0; i-- { l = orig.MappingTable[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } for i := len(orig.LocationTable) - 1; i >= 0; i-- { l = orig.LocationTable[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } for i := len(orig.FunctionTable) - 1; i >= 0; i-- { l = orig.FunctionTable[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } for i := len(orig.LinkTable) - 1; i >= 0; i-- { l = orig.LinkTable[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x22 } for i := len(orig.StringTable) - 1; i >= 0; i-- { l = len(orig.StringTable[i]) pos -= l copy(buf[pos:], orig.StringTable[i]) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a } for i := len(orig.AttributeTable) - 1; i >= 0; i-- { l = orig.AttributeTable[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x32 } for i := len(orig.StackTable) - 1; i >= 0; i-- { l = orig.StackTable[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3a } return len(buf) - pos } func (orig *ProfilesDictionary) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field MappingTable", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.MappingTable = append(orig.MappingTable, NewMapping()) err = orig.MappingTable[len(orig.MappingTable)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field LocationTable", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.LocationTable = append(orig.LocationTable, NewLocation()) err = orig.LocationTable[len(orig.LocationTable)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field FunctionTable", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.FunctionTable = append(orig.FunctionTable, NewFunction()) err = orig.FunctionTable[len(orig.FunctionTable)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 4: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field LinkTable", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.LinkTable = append(orig.LinkTable, NewLink()) err = orig.LinkTable[len(orig.LinkTable)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field StringTable", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.StringTable = append(orig.StringTable, string(buf[startPos:pos])) case 6: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field AttributeTable", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.AttributeTable = append(orig.AttributeTable, NewKeyValueAndUnit()) err = orig.AttributeTable[len(orig.AttributeTable)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 7: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field StackTable", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.StackTable = append(orig.StackTable, NewStack()) err = orig.StackTable[len(orig.StackTable)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestProfilesDictionary() *ProfilesDictionary { orig := NewProfilesDictionary() orig.MappingTable = []*Mapping{{}, GenTestMapping()} orig.LocationTable = []*Location{{}, GenTestLocation()} orig.FunctionTable = []*Function{{}, GenTestFunction()} orig.LinkTable = []*Link{{}, GenTestLink()} orig.StringTable = []string{"", "test_stringtable"} orig.AttributeTable = []*KeyValueAndUnit{{}, GenTestKeyValueAndUnit()} orig.StackTable = []*Stack{{}, GenTestStack()} return orig } func GenTestProfilesDictionaryPtrSlice() []*ProfilesDictionary { orig := make([]*ProfilesDictionary, 5) orig[0] = NewProfilesDictionary() orig[1] = GenTestProfilesDictionary() orig[2] = NewProfilesDictionary() orig[3] = GenTestProfilesDictionary() orig[4] = NewProfilesDictionary() return orig } func GenTestProfilesDictionarySlice() []ProfilesDictionary { orig := make([]ProfilesDictionary, 5) orig[1] = *GenTestProfilesDictionary() orig[3] = *GenTestProfilesDictionary() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profilesdictionary_test.go000066400000000000000000000167171511331344600322170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyProfilesDictionary(t *testing.T) { for name, src := range genTestEncodingValuesProfilesDictionary() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewProfilesDictionary() CopyProfilesDictionary(dest, src) assert.Equal(t, src, dest) CopyProfilesDictionary(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyProfilesDictionarySlice(t *testing.T) { src := []ProfilesDictionary{} dest := []ProfilesDictionary{} // Test CopyTo empty dest = CopyProfilesDictionarySlice(dest, src) assert.Equal(t, []ProfilesDictionary{}, dest) // Test CopyTo larger slice src = GenTestProfilesDictionarySlice() dest = CopyProfilesDictionarySlice(dest, src) assert.Equal(t, GenTestProfilesDictionarySlice(), dest) // Test CopyTo same size slice dest = CopyProfilesDictionarySlice(dest, src) assert.Equal(t, GenTestProfilesDictionarySlice(), dest) // Test CopyTo smaller size slice dest = CopyProfilesDictionarySlice(dest, []ProfilesDictionary{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfilesDictionarySlice(dest, src) assert.Equal(t, GenTestProfilesDictionarySlice(), dest) } func TestCopyProfilesDictionaryPtrSlice(t *testing.T) { src := []*ProfilesDictionary{} dest := []*ProfilesDictionary{} // Test CopyTo empty dest = CopyProfilesDictionaryPtrSlice(dest, src) assert.Equal(t, []*ProfilesDictionary{}, dest) // Test CopyTo larger slice src = GenTestProfilesDictionaryPtrSlice() dest = CopyProfilesDictionaryPtrSlice(dest, src) assert.Equal(t, GenTestProfilesDictionaryPtrSlice(), dest) // Test CopyTo same size slice dest = CopyProfilesDictionaryPtrSlice(dest, src) assert.Equal(t, GenTestProfilesDictionaryPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyProfilesDictionaryPtrSlice(dest, []*ProfilesDictionary{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfilesDictionaryPtrSlice(dest, src) assert.Equal(t, GenTestProfilesDictionaryPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONProfilesDictionaryUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewProfilesDictionary() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewProfilesDictionary(), dest) } func TestMarshalAndUnmarshalJSONProfilesDictionary(t *testing.T) { for name, src := range genTestEncodingValuesProfilesDictionary() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewProfilesDictionary() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteProfilesDictionary(dest, true) }) } } } func TestMarshalAndUnmarshalProtoProfilesDictionaryFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesProfilesDictionary() { t.Run(name, func(t *testing.T) { dest := NewProfilesDictionary() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoProfilesDictionaryUnknown(t *testing.T) { dest := NewProfilesDictionary() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewProfilesDictionary(), dest) } func TestMarshalAndUnmarshalProtoProfilesDictionary(t *testing.T) { for name, src := range genTestEncodingValuesProfilesDictionary() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewProfilesDictionary() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteProfilesDictionary(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufProfilesDictionary(t *testing.T) { for name, src := range genTestEncodingValuesProfilesDictionary() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.ProfilesDictionary{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewProfilesDictionary() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesProfilesDictionary() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "MappingTable/wrong_wire_type": {0xc}, "MappingTable/missing_value": {0xa}, "LocationTable/wrong_wire_type": {0x14}, "LocationTable/missing_value": {0x12}, "FunctionTable/wrong_wire_type": {0x1c}, "FunctionTable/missing_value": {0x1a}, "LinkTable/wrong_wire_type": {0x24}, "LinkTable/missing_value": {0x22}, "StringTable/wrong_wire_type": {0x2c}, "StringTable/missing_value": {0x2a}, "AttributeTable/wrong_wire_type": {0x34}, "AttributeTable/missing_value": {0x32}, "StackTable/wrong_wire_type": {0x3c}, "StackTable/missing_value": {0x3a}, } } func genTestEncodingValuesProfilesDictionary() map[string]*ProfilesDictionary { return map[string]*ProfilesDictionary{ "empty": NewProfilesDictionary(), "MappingTable/test": {MappingTable: []*Mapping{{}, GenTestMapping()}}, "LocationTable/test": {LocationTable: []*Location{{}, GenTestLocation()}}, "FunctionTable/test": {FunctionTable: []*Function{{}, GenTestFunction()}}, "LinkTable/test": {LinkTable: []*Link{{}, GenTestLink()}}, "StringTable/test": {StringTable: []string{"", "test_stringtable"}}, "AttributeTable/test": {AttributeTable: []*KeyValueAndUnit{{}, GenTestKeyValueAndUnit()}}, "StackTable/test": {StackTable: []*Stack{{}, GenTestStack()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profilesrequest.go000066400000000000000000000161071511331344600304740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type ProfilesRequest struct { RequestContext *RequestContext ProfilesData ProfilesData FormatVersion uint32 } var ( protoPoolProfilesRequest = sync.Pool{ New: func() any { return &ProfilesRequest{} }, } ) func NewProfilesRequest() *ProfilesRequest { if !UseProtoPooling.IsEnabled() { return &ProfilesRequest{} } return protoPoolProfilesRequest.Get().(*ProfilesRequest) } func DeleteProfilesRequest(orig *ProfilesRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteRequestContext(orig.RequestContext, true) DeleteProfilesData(&orig.ProfilesData, false) orig.Reset() if nullable { protoPoolProfilesRequest.Put(orig) } } func CopyProfilesRequest(dest, src *ProfilesRequest) *ProfilesRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewProfilesRequest() } dest.RequestContext = CopyRequestContext(dest.RequestContext, src.RequestContext) CopyProfilesData(&dest.ProfilesData, &src.ProfilesData) dest.FormatVersion = src.FormatVersion return dest } func CopyProfilesRequestSlice(dest, src []ProfilesRequest) []ProfilesRequest { var newDest []ProfilesRequest if cap(dest) < len(src) { newDest = make([]ProfilesRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfilesRequest(&dest[i], false) } } for i := range src { CopyProfilesRequest(&newDest[i], &src[i]) } return newDest } func CopyProfilesRequestPtrSlice(dest, src []*ProfilesRequest) []*ProfilesRequest { var newDest []*ProfilesRequest if cap(dest) < len(src) { newDest = make([]*ProfilesRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfilesRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteProfilesRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewProfilesRequest() } } for i := range src { CopyProfilesRequest(newDest[i], src[i]) } return newDest } func (orig *ProfilesRequest) Reset() { *orig = ProfilesRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ProfilesRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RequestContext != nil { dest.WriteObjectField("requestContext") orig.RequestContext.MarshalJSON(dest) } dest.WriteObjectField("profilesData") orig.ProfilesData.MarshalJSON(dest) if orig.FormatVersion != uint32(0) { dest.WriteObjectField("formatVersion") dest.WriteUint32(orig.FormatVersion) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ProfilesRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "requestContext", "request_context": orig.RequestContext = NewRequestContext() orig.RequestContext.UnmarshalJSON(iter) case "profilesData", "profiles_data": orig.ProfilesData.UnmarshalJSON(iter) case "formatVersion", "format_version": orig.FormatVersion = iter.ReadUint32() default: iter.Skip() } } } func (orig *ProfilesRequest) SizeProto() int { var n int var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = orig.ProfilesData.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.FormatVersion != 0 { n += 5 } return n } func (orig *ProfilesRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = orig.ProfilesData.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a if orig.FormatVersion != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.FormatVersion)) pos-- buf[pos] = 0xd } return len(buf) - pos } func (orig *ProfilesRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field RequestContext", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.RequestContext = NewRequestContext() err = orig.RequestContext.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ProfilesData", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.ProfilesData.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 1: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field FormatVersion", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.FormatVersion = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestProfilesRequest() *ProfilesRequest { orig := NewProfilesRequest() orig.RequestContext = GenTestRequestContext() orig.ProfilesData = *GenTestProfilesData() orig.FormatVersion = uint32(13) return orig } func GenTestProfilesRequestPtrSlice() []*ProfilesRequest { orig := make([]*ProfilesRequest, 5) orig[0] = NewProfilesRequest() orig[1] = GenTestProfilesRequest() orig[2] = NewProfilesRequest() orig[3] = GenTestProfilesRequest() orig[4] = NewProfilesRequest() return orig } func GenTestProfilesRequestSlice() []ProfilesRequest { orig := make([]ProfilesRequest, 5) orig[1] = *GenTestProfilesRequest() orig[3] = *GenTestProfilesRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_profilesrequest_test.go000066400000000000000000000150701511331344600315310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyProfilesRequest(t *testing.T) { for name, src := range genTestEncodingValuesProfilesRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewProfilesRequest() CopyProfilesRequest(dest, src) assert.Equal(t, src, dest) CopyProfilesRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyProfilesRequestSlice(t *testing.T) { src := []ProfilesRequest{} dest := []ProfilesRequest{} // Test CopyTo empty dest = CopyProfilesRequestSlice(dest, src) assert.Equal(t, []ProfilesRequest{}, dest) // Test CopyTo larger slice src = GenTestProfilesRequestSlice() dest = CopyProfilesRequestSlice(dest, src) assert.Equal(t, GenTestProfilesRequestSlice(), dest) // Test CopyTo same size slice dest = CopyProfilesRequestSlice(dest, src) assert.Equal(t, GenTestProfilesRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyProfilesRequestSlice(dest, []ProfilesRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfilesRequestSlice(dest, src) assert.Equal(t, GenTestProfilesRequestSlice(), dest) } func TestCopyProfilesRequestPtrSlice(t *testing.T) { src := []*ProfilesRequest{} dest := []*ProfilesRequest{} // Test CopyTo empty dest = CopyProfilesRequestPtrSlice(dest, src) assert.Equal(t, []*ProfilesRequest{}, dest) // Test CopyTo larger slice src = GenTestProfilesRequestPtrSlice() dest = CopyProfilesRequestPtrSlice(dest, src) assert.Equal(t, GenTestProfilesRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyProfilesRequestPtrSlice(dest, src) assert.Equal(t, GenTestProfilesRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyProfilesRequestPtrSlice(dest, []*ProfilesRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyProfilesRequestPtrSlice(dest, src) assert.Equal(t, GenTestProfilesRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONProfilesRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewProfilesRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewProfilesRequest(), dest) } func TestMarshalAndUnmarshalJSONProfilesRequest(t *testing.T) { for name, src := range genTestEncodingValuesProfilesRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewProfilesRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteProfilesRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoProfilesRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesProfilesRequest() { t.Run(name, func(t *testing.T) { dest := NewProfilesRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoProfilesRequestUnknown(t *testing.T) { dest := NewProfilesRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewProfilesRequest(), dest) } func TestMarshalAndUnmarshalProtoProfilesRequest(t *testing.T) { for name, src := range genTestEncodingValuesProfilesRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewProfilesRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteProfilesRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufProfilesRequest(t *testing.T) { for name, src := range genTestEncodingValuesProfilesRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewProfilesRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesProfilesRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RequestContext/wrong_wire_type": {0x14}, "RequestContext/missing_value": {0x12}, "ProfilesData/wrong_wire_type": {0x1c}, "ProfilesData/missing_value": {0x1a}, "FormatVersion/wrong_wire_type": {0xc}, "FormatVersion/missing_value": {0xd}, } } func genTestEncodingValuesProfilesRequest() map[string]*ProfilesRequest { return map[string]*ProfilesRequest{ "empty": NewProfilesRequest(), "RequestContext/test": {RequestContext: GenTestRequestContext()}, "ProfilesData/test": {ProfilesData: *GenTestProfilesData()}, "FormatVersion/test": {FormatVersion: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_requestcontext.go000066400000000000000000000360251511331344600303360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) func (m *RequestContext) GetClientAddress() any { if m != nil { return m.ClientAddress } return nil } type RequestContext_IP struct { IP *IPAddr } func (m *RequestContext) GetIP() *IPAddr { if v, ok := m.GetClientAddress().(*RequestContext_IP); ok { return v.IP } return nil } type RequestContext_TCP struct { TCP *TCPAddr } func (m *RequestContext) GetTCP() *TCPAddr { if v, ok := m.GetClientAddress().(*RequestContext_TCP); ok { return v.TCP } return nil } type RequestContext_UDP struct { UDP *UDPAddr } func (m *RequestContext) GetUDP() *UDPAddr { if v, ok := m.GetClientAddress().(*RequestContext_UDP); ok { return v.UDP } return nil } type RequestContext_Unix struct { Unix *UnixAddr } func (m *RequestContext) GetUnix() *UnixAddr { if v, ok := m.GetClientAddress().(*RequestContext_Unix); ok { return v.Unix } return nil } type RequestContext struct { SpanContext *SpanContext ClientMetadata []KeyValue ClientAddress any } var ( protoPoolRequestContext = sync.Pool{ New: func() any { return &RequestContext{} }, } ProtoPoolRequestContext_IP = sync.Pool{ New: func() any { return &RequestContext_IP{} }, } ProtoPoolRequestContext_TCP = sync.Pool{ New: func() any { return &RequestContext_TCP{} }, } ProtoPoolRequestContext_UDP = sync.Pool{ New: func() any { return &RequestContext_UDP{} }, } ProtoPoolRequestContext_Unix = sync.Pool{ New: func() any { return &RequestContext_Unix{} }, } ) func NewRequestContext() *RequestContext { if !UseProtoPooling.IsEnabled() { return &RequestContext{} } return protoPoolRequestContext.Get().(*RequestContext) } func DeleteRequestContext(orig *RequestContext, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteSpanContext(orig.SpanContext, true) for i := range orig.ClientMetadata { DeleteKeyValue(&orig.ClientMetadata[i], false) } switch ov := orig.ClientAddress.(type) { case *RequestContext_IP: DeleteIPAddr(ov.IP, true) ov.IP = nil ProtoPoolRequestContext_IP.Put(ov) case *RequestContext_TCP: DeleteTCPAddr(ov.TCP, true) ov.TCP = nil ProtoPoolRequestContext_TCP.Put(ov) case *RequestContext_UDP: DeleteUDPAddr(ov.UDP, true) ov.UDP = nil ProtoPoolRequestContext_UDP.Put(ov) case *RequestContext_Unix: DeleteUnixAddr(ov.Unix, true) ov.Unix = nil ProtoPoolRequestContext_Unix.Put(ov) } orig.Reset() if nullable { protoPoolRequestContext.Put(orig) } } func CopyRequestContext(dest, src *RequestContext) *RequestContext { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewRequestContext() } dest.SpanContext = CopySpanContext(dest.SpanContext, src.SpanContext) dest.ClientMetadata = CopyKeyValueSlice(dest.ClientMetadata, src.ClientMetadata) switch t := src.ClientAddress.(type) { case *RequestContext_IP: var ov *RequestContext_IP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_IP{} } else { ov = ProtoPoolRequestContext_IP.Get().(*RequestContext_IP) } ov.IP = NewIPAddr() CopyIPAddr(ov.IP, t.IP) dest.ClientAddress = ov case *RequestContext_TCP: var ov *RequestContext_TCP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_TCP{} } else { ov = ProtoPoolRequestContext_TCP.Get().(*RequestContext_TCP) } ov.TCP = NewTCPAddr() CopyTCPAddr(ov.TCP, t.TCP) dest.ClientAddress = ov case *RequestContext_UDP: var ov *RequestContext_UDP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_UDP{} } else { ov = ProtoPoolRequestContext_UDP.Get().(*RequestContext_UDP) } ov.UDP = NewUDPAddr() CopyUDPAddr(ov.UDP, t.UDP) dest.ClientAddress = ov case *RequestContext_Unix: var ov *RequestContext_Unix if !UseProtoPooling.IsEnabled() { ov = &RequestContext_Unix{} } else { ov = ProtoPoolRequestContext_Unix.Get().(*RequestContext_Unix) } ov.Unix = NewUnixAddr() CopyUnixAddr(ov.Unix, t.Unix) dest.ClientAddress = ov default: dest.ClientAddress = nil } return dest } func CopyRequestContextSlice(dest, src []RequestContext) []RequestContext { var newDest []RequestContext if cap(dest) < len(src) { newDest = make([]RequestContext, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteRequestContext(&dest[i], false) } } for i := range src { CopyRequestContext(&newDest[i], &src[i]) } return newDest } func CopyRequestContextPtrSlice(dest, src []*RequestContext) []*RequestContext { var newDest []*RequestContext if cap(dest) < len(src) { newDest = make([]*RequestContext, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewRequestContext() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteRequestContext(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewRequestContext() } } for i := range src { CopyRequestContext(newDest[i], src[i]) } return newDest } func (orig *RequestContext) Reset() { *orig = RequestContext{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *RequestContext) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.SpanContext != nil { dest.WriteObjectField("spanContext") orig.SpanContext.MarshalJSON(dest) } if len(orig.ClientMetadata) > 0 { dest.WriteObjectField("clientMetadata") dest.WriteArrayStart() orig.ClientMetadata[0].MarshalJSON(dest) for i := 1; i < len(orig.ClientMetadata); i++ { dest.WriteMore() orig.ClientMetadata[i].MarshalJSON(dest) } dest.WriteArrayEnd() } switch orig := orig.ClientAddress.(type) { case *RequestContext_IP: if orig.IP != nil { dest.WriteObjectField("iP") orig.IP.MarshalJSON(dest) } case *RequestContext_TCP: if orig.TCP != nil { dest.WriteObjectField("tCP") orig.TCP.MarshalJSON(dest) } case *RequestContext_UDP: if orig.UDP != nil { dest.WriteObjectField("uDP") orig.UDP.MarshalJSON(dest) } case *RequestContext_Unix: if orig.Unix != nil { dest.WriteObjectField("unix") orig.Unix.MarshalJSON(dest) } } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *RequestContext) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "spanContext", "span_context": orig.SpanContext = NewSpanContext() orig.SpanContext.UnmarshalJSON(iter) case "clientMetadata", "client_metadata": for iter.ReadArray() { orig.ClientMetadata = append(orig.ClientMetadata, KeyValue{}) orig.ClientMetadata[len(orig.ClientMetadata)-1].UnmarshalJSON(iter) } case "iP": { var ov *RequestContext_IP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_IP{} } else { ov = ProtoPoolRequestContext_IP.Get().(*RequestContext_IP) } ov.IP = NewIPAddr() ov.IP.UnmarshalJSON(iter) orig.ClientAddress = ov } case "tCP": { var ov *RequestContext_TCP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_TCP{} } else { ov = ProtoPoolRequestContext_TCP.Get().(*RequestContext_TCP) } ov.TCP = NewTCPAddr() ov.TCP.UnmarshalJSON(iter) orig.ClientAddress = ov } case "uDP": { var ov *RequestContext_UDP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_UDP{} } else { ov = ProtoPoolRequestContext_UDP.Get().(*RequestContext_UDP) } ov.UDP = NewUDPAddr() ov.UDP.UnmarshalJSON(iter) orig.ClientAddress = ov } case "unix": { var ov *RequestContext_Unix if !UseProtoPooling.IsEnabled() { ov = &RequestContext_Unix{} } else { ov = ProtoPoolRequestContext_Unix.Get().(*RequestContext_Unix) } ov.Unix = NewUnixAddr() ov.Unix.UnmarshalJSON(iter) orig.ClientAddress = ov } default: iter.Skip() } } } func (orig *RequestContext) SizeProto() int { var n int var l int _ = l if orig.SpanContext != nil { l = orig.SpanContext.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.ClientMetadata { l = orig.ClientMetadata[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } switch orig := orig.ClientAddress.(type) { case nil: _ = orig break case *RequestContext_IP: if orig.IP != nil { l = orig.IP.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *RequestContext_TCP: if orig.TCP != nil { l = orig.TCP.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *RequestContext_UDP: if orig.UDP != nil { l = orig.UDP.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } case *RequestContext_Unix: if orig.Unix != nil { l = orig.Unix.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } } return n } func (orig *RequestContext) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.SpanContext != nil { l = orig.SpanContext.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } for i := len(orig.ClientMetadata) - 1; i >= 0; i-- { l = orig.ClientMetadata[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } switch orig := orig.ClientAddress.(type) { case *RequestContext_IP: if orig.IP != nil { l = orig.IP.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } case *RequestContext_TCP: if orig.TCP != nil { l = orig.TCP.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x22 } case *RequestContext_UDP: if orig.UDP != nil { l = orig.UDP.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a } case *RequestContext_Unix: if orig.Unix != nil { l = orig.Unix.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x32 } } return len(buf) - pos } func (orig *RequestContext) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SpanContext", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SpanContext = NewSpanContext() err = orig.SpanContext.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ClientMetadata", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ClientMetadata = append(orig.ClientMetadata, KeyValue{}) err = orig.ClientMetadata[len(orig.ClientMetadata)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field IP", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *RequestContext_IP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_IP{} } else { ov = ProtoPoolRequestContext_IP.Get().(*RequestContext_IP) } ov.IP = NewIPAddr() err = ov.IP.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.ClientAddress = ov case 4: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TCP", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *RequestContext_TCP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_TCP{} } else { ov = ProtoPoolRequestContext_TCP.Get().(*RequestContext_TCP) } ov.TCP = NewTCPAddr() err = ov.TCP.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.ClientAddress = ov case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field UDP", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *RequestContext_UDP if !UseProtoPooling.IsEnabled() { ov = &RequestContext_UDP{} } else { ov = ProtoPoolRequestContext_UDP.Get().(*RequestContext_UDP) } ov.UDP = NewUDPAddr() err = ov.UDP.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.ClientAddress = ov case 6: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Unix", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var ov *RequestContext_Unix if !UseProtoPooling.IsEnabled() { ov = &RequestContext_Unix{} } else { ov = ProtoPoolRequestContext_Unix.Get().(*RequestContext_Unix) } ov.Unix = NewUnixAddr() err = ov.Unix.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } orig.ClientAddress = ov default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestRequestContext() *RequestContext { orig := NewRequestContext() orig.SpanContext = GenTestSpanContext() orig.ClientMetadata = []KeyValue{{}, *GenTestKeyValue()} orig.ClientAddress = &RequestContext_IP{IP: GenTestIPAddr()} return orig } func GenTestRequestContextPtrSlice() []*RequestContext { orig := make([]*RequestContext, 5) orig[0] = NewRequestContext() orig[1] = GenTestRequestContext() orig[2] = NewRequestContext() orig[3] = GenTestRequestContext() orig[4] = NewRequestContext() return orig } func GenTestRequestContextSlice() []RequestContext { orig := make([]RequestContext, 5) orig[1] = *GenTestRequestContext() orig[3] = *GenTestRequestContext() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_requestcontext_test.go000066400000000000000000000164341511331344600313770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyRequestContext(t *testing.T) { for name, src := range genTestEncodingValuesRequestContext() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewRequestContext() CopyRequestContext(dest, src) assert.Equal(t, src, dest) CopyRequestContext(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyRequestContextSlice(t *testing.T) { src := []RequestContext{} dest := []RequestContext{} // Test CopyTo empty dest = CopyRequestContextSlice(dest, src) assert.Equal(t, []RequestContext{}, dest) // Test CopyTo larger slice src = GenTestRequestContextSlice() dest = CopyRequestContextSlice(dest, src) assert.Equal(t, GenTestRequestContextSlice(), dest) // Test CopyTo same size slice dest = CopyRequestContextSlice(dest, src) assert.Equal(t, GenTestRequestContextSlice(), dest) // Test CopyTo smaller size slice dest = CopyRequestContextSlice(dest, []RequestContext{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyRequestContextSlice(dest, src) assert.Equal(t, GenTestRequestContextSlice(), dest) } func TestCopyRequestContextPtrSlice(t *testing.T) { src := []*RequestContext{} dest := []*RequestContext{} // Test CopyTo empty dest = CopyRequestContextPtrSlice(dest, src) assert.Equal(t, []*RequestContext{}, dest) // Test CopyTo larger slice src = GenTestRequestContextPtrSlice() dest = CopyRequestContextPtrSlice(dest, src) assert.Equal(t, GenTestRequestContextPtrSlice(), dest) // Test CopyTo same size slice dest = CopyRequestContextPtrSlice(dest, src) assert.Equal(t, GenTestRequestContextPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyRequestContextPtrSlice(dest, []*RequestContext{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyRequestContextPtrSlice(dest, src) assert.Equal(t, GenTestRequestContextPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONRequestContextUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewRequestContext() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewRequestContext(), dest) } func TestMarshalAndUnmarshalJSONRequestContext(t *testing.T) { for name, src := range genTestEncodingValuesRequestContext() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewRequestContext() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteRequestContext(dest, true) }) } } } func TestMarshalAndUnmarshalProtoRequestContextFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesRequestContext() { t.Run(name, func(t *testing.T) { dest := NewRequestContext() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoRequestContextUnknown(t *testing.T) { dest := NewRequestContext() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewRequestContext(), dest) } func TestMarshalAndUnmarshalProtoRequestContext(t *testing.T) { for name, src := range genTestEncodingValuesRequestContext() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewRequestContext() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteRequestContext(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufRequestContext(t *testing.T) { for name, src := range genTestEncodingValuesRequestContext() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewRequestContext() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesRequestContext() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "SpanContext/wrong_wire_type": {0xc}, "SpanContext/missing_value": {0xa}, "ClientMetadata/wrong_wire_type": {0x14}, "ClientMetadata/missing_value": {0x12}, "IP/wrong_wire_type": {0x1c}, "IP/missing_value": {0x1a}, "TCP/wrong_wire_type": {0x24}, "TCP/missing_value": {0x22}, "UDP/wrong_wire_type": {0x2c}, "UDP/missing_value": {0x2a}, "Unix/wrong_wire_type": {0x34}, "Unix/missing_value": {0x32}, } } func genTestEncodingValuesRequestContext() map[string]*RequestContext { return map[string]*RequestContext{ "empty": NewRequestContext(), "SpanContext/test": {SpanContext: GenTestSpanContext()}, "ClientMetadata/test": {ClientMetadata: []KeyValue{{}, *GenTestKeyValue()}}, "IP/default": {ClientAddress: &RequestContext_IP{IP: &IPAddr{}}}, "IP/test": {ClientAddress: &RequestContext_IP{IP: GenTestIPAddr()}}, "TCP/default": {ClientAddress: &RequestContext_TCP{TCP: &TCPAddr{}}}, "TCP/test": {ClientAddress: &RequestContext_TCP{TCP: GenTestTCPAddr()}}, "UDP/default": {ClientAddress: &RequestContext_UDP{UDP: &UDPAddr{}}}, "UDP/test": {ClientAddress: &RequestContext_UDP{UDP: GenTestUDPAddr()}}, "Unix/default": {ClientAddress: &RequestContext_Unix{Unix: &UnixAddr{}}}, "Unix/test": {ClientAddress: &RequestContext_Unix{Unix: GenTestUnixAddr()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resource.go000066400000000000000000000173341511331344600270720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Resource is a message representing the resource information. type Resource struct { Attributes []KeyValue DroppedAttributesCount uint32 EntityRefs []*EntityRef } var ( protoPoolResource = sync.Pool{ New: func() any { return &Resource{} }, } ) func NewResource() *Resource { if !UseProtoPooling.IsEnabled() { return &Resource{} } return protoPoolResource.Get().(*Resource) } func DeleteResource(orig *Resource, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } for i := range orig.EntityRefs { DeleteEntityRef(orig.EntityRefs[i], true) } orig.Reset() if nullable { protoPoolResource.Put(orig) } } func CopyResource(dest, src *Resource) *Resource { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewResource() } dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.DroppedAttributesCount = src.DroppedAttributesCount dest.EntityRefs = CopyEntityRefPtrSlice(dest.EntityRefs, src.EntityRefs) return dest } func CopyResourceSlice(dest, src []Resource) []Resource { var newDest []Resource if cap(dest) < len(src) { newDest = make([]Resource, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResource(&dest[i], false) } } for i := range src { CopyResource(&newDest[i], &src[i]) } return newDest } func CopyResourcePtrSlice(dest, src []*Resource) []*Resource { var newDest []*Resource if cap(dest) < len(src) { newDest = make([]*Resource, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewResource() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResource(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewResource() } } for i := range src { CopyResource(newDest[i], src[i]) } return newDest } func (orig *Resource) Reset() { *orig = Resource{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Resource) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedAttributesCount != uint32(0) { dest.WriteObjectField("droppedAttributesCount") dest.WriteUint32(orig.DroppedAttributesCount) } if len(orig.EntityRefs) > 0 { dest.WriteObjectField("entityRefs") dest.WriteArrayStart() orig.EntityRefs[0].MarshalJSON(dest) for i := 1; i < len(orig.EntityRefs); i++ { dest.WriteMore() orig.EntityRefs[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Resource) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "droppedAttributesCount", "dropped_attributes_count": orig.DroppedAttributesCount = iter.ReadUint32() case "entityRefs", "entity_refs": for iter.ReadArray() { orig.EntityRefs = append(orig.EntityRefs, NewEntityRef()) orig.EntityRefs[len(orig.EntityRefs)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *Resource) SizeProto() int { var n int var l int _ = l for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedAttributesCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedAttributesCount)) } for i := range orig.EntityRefs { l = orig.EntityRefs[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Resource) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } if orig.DroppedAttributesCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedAttributesCount)) pos-- buf[pos] = 0x10 } for i := len(orig.EntityRefs) - 1; i >= 0; i-- { l = orig.EntityRefs[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *Resource) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedAttributesCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedAttributesCount = uint32(num) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field EntityRefs", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.EntityRefs = append(orig.EntityRefs, NewEntityRef()) err = orig.EntityRefs[len(orig.EntityRefs)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestResource() *Resource { orig := NewResource() orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.DroppedAttributesCount = uint32(13) orig.EntityRefs = []*EntityRef{{}, GenTestEntityRef()} return orig } func GenTestResourcePtrSlice() []*Resource { orig := make([]*Resource, 5) orig[0] = NewResource() orig[1] = GenTestResource() orig[2] = NewResource() orig[3] = GenTestResource() orig[4] = NewResource() return orig } func GenTestResourceSlice() []Resource { orig := make([]Resource, 5) orig[1] = *GenTestResource() orig[3] = *GenTestResource() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resource_test.go000066400000000000000000000144601511331344600301260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpresource "go.opentelemetry.io/proto/slim/otlp/resource/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyResource(t *testing.T) { for name, src := range genTestEncodingValuesResource() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewResource() CopyResource(dest, src) assert.Equal(t, src, dest) CopyResource(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyResourceSlice(t *testing.T) { src := []Resource{} dest := []Resource{} // Test CopyTo empty dest = CopyResourceSlice(dest, src) assert.Equal(t, []Resource{}, dest) // Test CopyTo larger slice src = GenTestResourceSlice() dest = CopyResourceSlice(dest, src) assert.Equal(t, GenTestResourceSlice(), dest) // Test CopyTo same size slice dest = CopyResourceSlice(dest, src) assert.Equal(t, GenTestResourceSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceSlice(dest, []Resource{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceSlice(dest, src) assert.Equal(t, GenTestResourceSlice(), dest) } func TestCopyResourcePtrSlice(t *testing.T) { src := []*Resource{} dest := []*Resource{} // Test CopyTo empty dest = CopyResourcePtrSlice(dest, src) assert.Equal(t, []*Resource{}, dest) // Test CopyTo larger slice src = GenTestResourcePtrSlice() dest = CopyResourcePtrSlice(dest, src) assert.Equal(t, GenTestResourcePtrSlice(), dest) // Test CopyTo same size slice dest = CopyResourcePtrSlice(dest, src) assert.Equal(t, GenTestResourcePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourcePtrSlice(dest, []*Resource{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourcePtrSlice(dest, src) assert.Equal(t, GenTestResourcePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONResourceUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewResource() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewResource(), dest) } func TestMarshalAndUnmarshalJSONResource(t *testing.T) { for name, src := range genTestEncodingValuesResource() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewResource() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteResource(dest, true) }) } } } func TestMarshalAndUnmarshalProtoResourceFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesResource() { t.Run(name, func(t *testing.T) { dest := NewResource() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoResourceUnknown(t *testing.T) { dest := NewResource() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewResource(), dest) } func TestMarshalAndUnmarshalProtoResource(t *testing.T) { for name, src := range genTestEncodingValuesResource() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewResource() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteResource(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufResource(t *testing.T) { for name, src := range genTestEncodingValuesResource() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpresource.Resource{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewResource() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesResource() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Attributes/wrong_wire_type": {0xc}, "Attributes/missing_value": {0xa}, "DroppedAttributesCount/wrong_wire_type": {0x14}, "DroppedAttributesCount/missing_value": {0x10}, "EntityRefs/wrong_wire_type": {0x1c}, "EntityRefs/missing_value": {0x1a}, } } func genTestEncodingValuesResource() map[string]*Resource { return map[string]*Resource{ "empty": NewResource(), "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "DroppedAttributesCount/test": {DroppedAttributesCount: uint32(13)}, "EntityRefs/test": {EntityRefs: []*EntityRef{{}, GenTestEntityRef()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourcelogs.go000066400000000000000000000215771511331344600277630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ResourceLogs is a collection of logs from a Resource. type ResourceLogs struct { Resource Resource ScopeLogs []*ScopeLogs SchemaUrl string DeprecatedScopeLogs []*ScopeLogs } var ( protoPoolResourceLogs = sync.Pool{ New: func() any { return &ResourceLogs{} }, } ) func NewResourceLogs() *ResourceLogs { if !UseProtoPooling.IsEnabled() { return &ResourceLogs{} } return protoPoolResourceLogs.Get().(*ResourceLogs) } func DeleteResourceLogs(orig *ResourceLogs, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteResource(&orig.Resource, false) for i := range orig.ScopeLogs { DeleteScopeLogs(orig.ScopeLogs[i], true) } for i := range orig.DeprecatedScopeLogs { DeleteScopeLogs(orig.DeprecatedScopeLogs[i], true) } orig.Reset() if nullable { protoPoolResourceLogs.Put(orig) } } func CopyResourceLogs(dest, src *ResourceLogs) *ResourceLogs { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewResourceLogs() } CopyResource(&dest.Resource, &src.Resource) dest.ScopeLogs = CopyScopeLogsPtrSlice(dest.ScopeLogs, src.ScopeLogs) dest.SchemaUrl = src.SchemaUrl dest.DeprecatedScopeLogs = CopyScopeLogsPtrSlice(dest.DeprecatedScopeLogs, src.DeprecatedScopeLogs) return dest } func CopyResourceLogsSlice(dest, src []ResourceLogs) []ResourceLogs { var newDest []ResourceLogs if cap(dest) < len(src) { newDest = make([]ResourceLogs, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceLogs(&dest[i], false) } } for i := range src { CopyResourceLogs(&newDest[i], &src[i]) } return newDest } func CopyResourceLogsPtrSlice(dest, src []*ResourceLogs) []*ResourceLogs { var newDest []*ResourceLogs if cap(dest) < len(src) { newDest = make([]*ResourceLogs, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceLogs() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceLogs(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceLogs() } } for i := range src { CopyResourceLogs(newDest[i], src[i]) } return newDest } func (orig *ResourceLogs) Reset() { *orig = ResourceLogs{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ResourceLogs) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("resource") orig.Resource.MarshalJSON(dest) if len(orig.ScopeLogs) > 0 { dest.WriteObjectField("scopeLogs") dest.WriteArrayStart() orig.ScopeLogs[0].MarshalJSON(dest) for i := 1; i < len(orig.ScopeLogs); i++ { dest.WriteMore() orig.ScopeLogs[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } if len(orig.DeprecatedScopeLogs) > 0 { dest.WriteObjectField("deprecatedScopeLogs") dest.WriteArrayStart() orig.DeprecatedScopeLogs[0].MarshalJSON(dest) for i := 1; i < len(orig.DeprecatedScopeLogs); i++ { dest.WriteMore() orig.DeprecatedScopeLogs[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ResourceLogs) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resource": orig.Resource.UnmarshalJSON(iter) case "scopeLogs", "scope_logs": for iter.ReadArray() { orig.ScopeLogs = append(orig.ScopeLogs, NewScopeLogs()) orig.ScopeLogs[len(orig.ScopeLogs)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() case "deprecatedScopeLogs", "deprecated_scope_logs": for iter.ReadArray() { orig.DeprecatedScopeLogs = append(orig.DeprecatedScopeLogs, NewScopeLogs()) orig.DeprecatedScopeLogs[len(orig.DeprecatedScopeLogs)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ResourceLogs) SizeProto() int { var n int var l int _ = l l = orig.Resource.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.ScopeLogs { l = orig.ScopeLogs[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.DeprecatedScopeLogs { l = orig.DeprecatedScopeLogs[i].SizeProto() n += 2 + proto.Sov(uint64(l)) + l } return n } func (orig *ResourceLogs) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Resource.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.ScopeLogs) - 1; i >= 0; i-- { l = orig.ScopeLogs[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } for i := len(orig.DeprecatedScopeLogs) - 1; i >= 0; i-- { l = orig.DeprecatedScopeLogs[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3e pos-- buf[pos] = 0xc2 } return len(buf) - pos } func (orig *ResourceLogs) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Resource.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ScopeLogs", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ScopeLogs = append(orig.ScopeLogs, NewScopeLogs()) err = orig.ScopeLogs[len(orig.ScopeLogs)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) case 1000: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedScopeLogs", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DeprecatedScopeLogs = append(orig.DeprecatedScopeLogs, NewScopeLogs()) err = orig.DeprecatedScopeLogs[len(orig.DeprecatedScopeLogs)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestResourceLogs() *ResourceLogs { orig := NewResourceLogs() orig.Resource = *GenTestResource() orig.ScopeLogs = []*ScopeLogs{{}, GenTestScopeLogs()} orig.SchemaUrl = "test_schemaurl" orig.DeprecatedScopeLogs = []*ScopeLogs{{}, GenTestScopeLogs()} return orig } func GenTestResourceLogsPtrSlice() []*ResourceLogs { orig := make([]*ResourceLogs, 5) orig[0] = NewResourceLogs() orig[1] = GenTestResourceLogs() orig[2] = NewResourceLogs() orig[3] = GenTestResourceLogs() orig[4] = NewResourceLogs() return orig } func GenTestResourceLogsSlice() []ResourceLogs { orig := make([]ResourceLogs, 5) orig[1] = *GenTestResourceLogs() orig[3] = *GenTestResourceLogs() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourcelogs_test.go000066400000000000000000000152361511331344600310150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlplogs "go.opentelemetry.io/proto/slim/otlp/logs/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyResourceLogs(t *testing.T) { for name, src := range genTestEncodingValuesResourceLogs() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewResourceLogs() CopyResourceLogs(dest, src) assert.Equal(t, src, dest) CopyResourceLogs(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyResourceLogsSlice(t *testing.T) { src := []ResourceLogs{} dest := []ResourceLogs{} // Test CopyTo empty dest = CopyResourceLogsSlice(dest, src) assert.Equal(t, []ResourceLogs{}, dest) // Test CopyTo larger slice src = GenTestResourceLogsSlice() dest = CopyResourceLogsSlice(dest, src) assert.Equal(t, GenTestResourceLogsSlice(), dest) // Test CopyTo same size slice dest = CopyResourceLogsSlice(dest, src) assert.Equal(t, GenTestResourceLogsSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceLogsSlice(dest, []ResourceLogs{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceLogsSlice(dest, src) assert.Equal(t, GenTestResourceLogsSlice(), dest) } func TestCopyResourceLogsPtrSlice(t *testing.T) { src := []*ResourceLogs{} dest := []*ResourceLogs{} // Test CopyTo empty dest = CopyResourceLogsPtrSlice(dest, src) assert.Equal(t, []*ResourceLogs{}, dest) // Test CopyTo larger slice src = GenTestResourceLogsPtrSlice() dest = CopyResourceLogsPtrSlice(dest, src) assert.Equal(t, GenTestResourceLogsPtrSlice(), dest) // Test CopyTo same size slice dest = CopyResourceLogsPtrSlice(dest, src) assert.Equal(t, GenTestResourceLogsPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceLogsPtrSlice(dest, []*ResourceLogs{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceLogsPtrSlice(dest, src) assert.Equal(t, GenTestResourceLogsPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONResourceLogsUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewResourceLogs() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewResourceLogs(), dest) } func TestMarshalAndUnmarshalJSONResourceLogs(t *testing.T) { for name, src := range genTestEncodingValuesResourceLogs() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewResourceLogs() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteResourceLogs(dest, true) }) } } } func TestMarshalAndUnmarshalProtoResourceLogsFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesResourceLogs() { t.Run(name, func(t *testing.T) { dest := NewResourceLogs() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoResourceLogsUnknown(t *testing.T) { dest := NewResourceLogs() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewResourceLogs(), dest) } func TestMarshalAndUnmarshalProtoResourceLogs(t *testing.T) { for name, src := range genTestEncodingValuesResourceLogs() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewResourceLogs() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteResourceLogs(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufResourceLogs(t *testing.T) { for name, src := range genTestEncodingValuesResourceLogs() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlplogs.ResourceLogs{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewResourceLogs() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesResourceLogs() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Resource/wrong_wire_type": {0xc}, "Resource/missing_value": {0xa}, "ScopeLogs/wrong_wire_type": {0x14}, "ScopeLogs/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, "DeprecatedScopeLogs/wrong_wire_type": {0xc4, 0x3e}, "DeprecatedScopeLogs/missing_value": {0xc2, 0x3e}, } } func genTestEncodingValuesResourceLogs() map[string]*ResourceLogs { return map[string]*ResourceLogs{ "empty": NewResourceLogs(), "Resource/test": {Resource: *GenTestResource()}, "ScopeLogs/test": {ScopeLogs: []*ScopeLogs{{}, GenTestScopeLogs()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, "DeprecatedScopeLogs/test": {DeprecatedScopeLogs: []*ScopeLogs{{}, GenTestScopeLogs()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourcemetrics.go000066400000000000000000000223711511331344600304560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ResourceMetrics is a collection of metrics from a Resource. type ResourceMetrics struct { Resource Resource ScopeMetrics []*ScopeMetrics SchemaUrl string DeprecatedScopeMetrics []*ScopeMetrics } var ( protoPoolResourceMetrics = sync.Pool{ New: func() any { return &ResourceMetrics{} }, } ) func NewResourceMetrics() *ResourceMetrics { if !UseProtoPooling.IsEnabled() { return &ResourceMetrics{} } return protoPoolResourceMetrics.Get().(*ResourceMetrics) } func DeleteResourceMetrics(orig *ResourceMetrics, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteResource(&orig.Resource, false) for i := range orig.ScopeMetrics { DeleteScopeMetrics(orig.ScopeMetrics[i], true) } for i := range orig.DeprecatedScopeMetrics { DeleteScopeMetrics(orig.DeprecatedScopeMetrics[i], true) } orig.Reset() if nullable { protoPoolResourceMetrics.Put(orig) } } func CopyResourceMetrics(dest, src *ResourceMetrics) *ResourceMetrics { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewResourceMetrics() } CopyResource(&dest.Resource, &src.Resource) dest.ScopeMetrics = CopyScopeMetricsPtrSlice(dest.ScopeMetrics, src.ScopeMetrics) dest.SchemaUrl = src.SchemaUrl dest.DeprecatedScopeMetrics = CopyScopeMetricsPtrSlice(dest.DeprecatedScopeMetrics, src.DeprecatedScopeMetrics) return dest } func CopyResourceMetricsSlice(dest, src []ResourceMetrics) []ResourceMetrics { var newDest []ResourceMetrics if cap(dest) < len(src) { newDest = make([]ResourceMetrics, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceMetrics(&dest[i], false) } } for i := range src { CopyResourceMetrics(&newDest[i], &src[i]) } return newDest } func CopyResourceMetricsPtrSlice(dest, src []*ResourceMetrics) []*ResourceMetrics { var newDest []*ResourceMetrics if cap(dest) < len(src) { newDest = make([]*ResourceMetrics, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceMetrics() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceMetrics(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceMetrics() } } for i := range src { CopyResourceMetrics(newDest[i], src[i]) } return newDest } func (orig *ResourceMetrics) Reset() { *orig = ResourceMetrics{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ResourceMetrics) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("resource") orig.Resource.MarshalJSON(dest) if len(orig.ScopeMetrics) > 0 { dest.WriteObjectField("scopeMetrics") dest.WriteArrayStart() orig.ScopeMetrics[0].MarshalJSON(dest) for i := 1; i < len(orig.ScopeMetrics); i++ { dest.WriteMore() orig.ScopeMetrics[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } if len(orig.DeprecatedScopeMetrics) > 0 { dest.WriteObjectField("deprecatedScopeMetrics") dest.WriteArrayStart() orig.DeprecatedScopeMetrics[0].MarshalJSON(dest) for i := 1; i < len(orig.DeprecatedScopeMetrics); i++ { dest.WriteMore() orig.DeprecatedScopeMetrics[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ResourceMetrics) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resource": orig.Resource.UnmarshalJSON(iter) case "scopeMetrics", "scope_metrics": for iter.ReadArray() { orig.ScopeMetrics = append(orig.ScopeMetrics, NewScopeMetrics()) orig.ScopeMetrics[len(orig.ScopeMetrics)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() case "deprecatedScopeMetrics", "deprecated_scope_metrics": for iter.ReadArray() { orig.DeprecatedScopeMetrics = append(orig.DeprecatedScopeMetrics, NewScopeMetrics()) orig.DeprecatedScopeMetrics[len(orig.DeprecatedScopeMetrics)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ResourceMetrics) SizeProto() int { var n int var l int _ = l l = orig.Resource.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.ScopeMetrics { l = orig.ScopeMetrics[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.DeprecatedScopeMetrics { l = orig.DeprecatedScopeMetrics[i].SizeProto() n += 2 + proto.Sov(uint64(l)) + l } return n } func (orig *ResourceMetrics) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Resource.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.ScopeMetrics) - 1; i >= 0; i-- { l = orig.ScopeMetrics[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } for i := len(orig.DeprecatedScopeMetrics) - 1; i >= 0; i-- { l = orig.DeprecatedScopeMetrics[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3e pos-- buf[pos] = 0xc2 } return len(buf) - pos } func (orig *ResourceMetrics) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Resource.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ScopeMetrics", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ScopeMetrics = append(orig.ScopeMetrics, NewScopeMetrics()) err = orig.ScopeMetrics[len(orig.ScopeMetrics)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) case 1000: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedScopeMetrics", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DeprecatedScopeMetrics = append(orig.DeprecatedScopeMetrics, NewScopeMetrics()) err = orig.DeprecatedScopeMetrics[len(orig.DeprecatedScopeMetrics)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestResourceMetrics() *ResourceMetrics { orig := NewResourceMetrics() orig.Resource = *GenTestResource() orig.ScopeMetrics = []*ScopeMetrics{{}, GenTestScopeMetrics()} orig.SchemaUrl = "test_schemaurl" orig.DeprecatedScopeMetrics = []*ScopeMetrics{{}, GenTestScopeMetrics()} return orig } func GenTestResourceMetricsPtrSlice() []*ResourceMetrics { orig := make([]*ResourceMetrics, 5) orig[0] = NewResourceMetrics() orig[1] = GenTestResourceMetrics() orig[2] = NewResourceMetrics() orig[3] = GenTestResourceMetrics() orig[4] = NewResourceMetrics() return orig } func GenTestResourceMetricsSlice() []ResourceMetrics { orig := make([]ResourceMetrics, 5) orig[1] = *GenTestResourceMetrics() orig[3] = *GenTestResourceMetrics() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourcemetrics_test.go000066400000000000000000000156241511331344600315200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyResourceMetrics(t *testing.T) { for name, src := range genTestEncodingValuesResourceMetrics() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewResourceMetrics() CopyResourceMetrics(dest, src) assert.Equal(t, src, dest) CopyResourceMetrics(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyResourceMetricsSlice(t *testing.T) { src := []ResourceMetrics{} dest := []ResourceMetrics{} // Test CopyTo empty dest = CopyResourceMetricsSlice(dest, src) assert.Equal(t, []ResourceMetrics{}, dest) // Test CopyTo larger slice src = GenTestResourceMetricsSlice() dest = CopyResourceMetricsSlice(dest, src) assert.Equal(t, GenTestResourceMetricsSlice(), dest) // Test CopyTo same size slice dest = CopyResourceMetricsSlice(dest, src) assert.Equal(t, GenTestResourceMetricsSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceMetricsSlice(dest, []ResourceMetrics{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceMetricsSlice(dest, src) assert.Equal(t, GenTestResourceMetricsSlice(), dest) } func TestCopyResourceMetricsPtrSlice(t *testing.T) { src := []*ResourceMetrics{} dest := []*ResourceMetrics{} // Test CopyTo empty dest = CopyResourceMetricsPtrSlice(dest, src) assert.Equal(t, []*ResourceMetrics{}, dest) // Test CopyTo larger slice src = GenTestResourceMetricsPtrSlice() dest = CopyResourceMetricsPtrSlice(dest, src) assert.Equal(t, GenTestResourceMetricsPtrSlice(), dest) // Test CopyTo same size slice dest = CopyResourceMetricsPtrSlice(dest, src) assert.Equal(t, GenTestResourceMetricsPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceMetricsPtrSlice(dest, []*ResourceMetrics{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceMetricsPtrSlice(dest, src) assert.Equal(t, GenTestResourceMetricsPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONResourceMetricsUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewResourceMetrics() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewResourceMetrics(), dest) } func TestMarshalAndUnmarshalJSONResourceMetrics(t *testing.T) { for name, src := range genTestEncodingValuesResourceMetrics() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewResourceMetrics() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteResourceMetrics(dest, true) }) } } } func TestMarshalAndUnmarshalProtoResourceMetricsFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesResourceMetrics() { t.Run(name, func(t *testing.T) { dest := NewResourceMetrics() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoResourceMetricsUnknown(t *testing.T) { dest := NewResourceMetrics() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewResourceMetrics(), dest) } func TestMarshalAndUnmarshalProtoResourceMetrics(t *testing.T) { for name, src := range genTestEncodingValuesResourceMetrics() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewResourceMetrics() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteResourceMetrics(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufResourceMetrics(t *testing.T) { for name, src := range genTestEncodingValuesResourceMetrics() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.ResourceMetrics{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewResourceMetrics() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesResourceMetrics() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Resource/wrong_wire_type": {0xc}, "Resource/missing_value": {0xa}, "ScopeMetrics/wrong_wire_type": {0x14}, "ScopeMetrics/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, "DeprecatedScopeMetrics/wrong_wire_type": {0xc4, 0x3e}, "DeprecatedScopeMetrics/missing_value": {0xc2, 0x3e}, } } func genTestEncodingValuesResourceMetrics() map[string]*ResourceMetrics { return map[string]*ResourceMetrics{ "empty": NewResourceMetrics(), "Resource/test": {Resource: *GenTestResource()}, "ScopeMetrics/test": {ScopeMetrics: []*ScopeMetrics{{}, GenTestScopeMetrics()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, "DeprecatedScopeMetrics/test": {DeprecatedScopeMetrics: []*ScopeMetrics{{}, GenTestScopeMetrics()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourceprofiles.go000066400000000000000000000170251511331344600306330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ResourceProfiles is a collection of profiles from a Resource. type ResourceProfiles struct { Resource Resource ScopeProfiles []*ScopeProfiles SchemaUrl string } var ( protoPoolResourceProfiles = sync.Pool{ New: func() any { return &ResourceProfiles{} }, } ) func NewResourceProfiles() *ResourceProfiles { if !UseProtoPooling.IsEnabled() { return &ResourceProfiles{} } return protoPoolResourceProfiles.Get().(*ResourceProfiles) } func DeleteResourceProfiles(orig *ResourceProfiles, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteResource(&orig.Resource, false) for i := range orig.ScopeProfiles { DeleteScopeProfiles(orig.ScopeProfiles[i], true) } orig.Reset() if nullable { protoPoolResourceProfiles.Put(orig) } } func CopyResourceProfiles(dest, src *ResourceProfiles) *ResourceProfiles { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewResourceProfiles() } CopyResource(&dest.Resource, &src.Resource) dest.ScopeProfiles = CopyScopeProfilesPtrSlice(dest.ScopeProfiles, src.ScopeProfiles) dest.SchemaUrl = src.SchemaUrl return dest } func CopyResourceProfilesSlice(dest, src []ResourceProfiles) []ResourceProfiles { var newDest []ResourceProfiles if cap(dest) < len(src) { newDest = make([]ResourceProfiles, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceProfiles(&dest[i], false) } } for i := range src { CopyResourceProfiles(&newDest[i], &src[i]) } return newDest } func CopyResourceProfilesPtrSlice(dest, src []*ResourceProfiles) []*ResourceProfiles { var newDest []*ResourceProfiles if cap(dest) < len(src) { newDest = make([]*ResourceProfiles, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceProfiles() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceProfiles(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceProfiles() } } for i := range src { CopyResourceProfiles(newDest[i], src[i]) } return newDest } func (orig *ResourceProfiles) Reset() { *orig = ResourceProfiles{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ResourceProfiles) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("resource") orig.Resource.MarshalJSON(dest) if len(orig.ScopeProfiles) > 0 { dest.WriteObjectField("scopeProfiles") dest.WriteArrayStart() orig.ScopeProfiles[0].MarshalJSON(dest) for i := 1; i < len(orig.ScopeProfiles); i++ { dest.WriteMore() orig.ScopeProfiles[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ResourceProfiles) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resource": orig.Resource.UnmarshalJSON(iter) case "scopeProfiles", "scope_profiles": for iter.ReadArray() { orig.ScopeProfiles = append(orig.ScopeProfiles, NewScopeProfiles()) orig.ScopeProfiles[len(orig.ScopeProfiles)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() default: iter.Skip() } } } func (orig *ResourceProfiles) SizeProto() int { var n int var l int _ = l l = orig.Resource.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.ScopeProfiles { l = orig.ScopeProfiles[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ResourceProfiles) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Resource.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.ScopeProfiles) - 1; i >= 0; i-- { l = orig.ScopeProfiles[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *ResourceProfiles) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Resource.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ScopeProfiles", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ScopeProfiles = append(orig.ScopeProfiles, NewScopeProfiles()) err = orig.ScopeProfiles[len(orig.ScopeProfiles)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestResourceProfiles() *ResourceProfiles { orig := NewResourceProfiles() orig.Resource = *GenTestResource() orig.ScopeProfiles = []*ScopeProfiles{{}, GenTestScopeProfiles()} orig.SchemaUrl = "test_schemaurl" return orig } func GenTestResourceProfilesPtrSlice() []*ResourceProfiles { orig := make([]*ResourceProfiles, 5) orig[0] = NewResourceProfiles() orig[1] = GenTestResourceProfiles() orig[2] = NewResourceProfiles() orig[3] = GenTestResourceProfiles() orig[4] = NewResourceProfiles() return orig } func GenTestResourceProfilesSlice() []ResourceProfiles { orig := make([]ResourceProfiles, 5) orig[1] = *GenTestResourceProfiles() orig[3] = *GenTestResourceProfiles() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourceprofiles_test.go000066400000000000000000000152421511331344600316710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyResourceProfiles(t *testing.T) { for name, src := range genTestEncodingValuesResourceProfiles() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewResourceProfiles() CopyResourceProfiles(dest, src) assert.Equal(t, src, dest) CopyResourceProfiles(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyResourceProfilesSlice(t *testing.T) { src := []ResourceProfiles{} dest := []ResourceProfiles{} // Test CopyTo empty dest = CopyResourceProfilesSlice(dest, src) assert.Equal(t, []ResourceProfiles{}, dest) // Test CopyTo larger slice src = GenTestResourceProfilesSlice() dest = CopyResourceProfilesSlice(dest, src) assert.Equal(t, GenTestResourceProfilesSlice(), dest) // Test CopyTo same size slice dest = CopyResourceProfilesSlice(dest, src) assert.Equal(t, GenTestResourceProfilesSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceProfilesSlice(dest, []ResourceProfiles{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceProfilesSlice(dest, src) assert.Equal(t, GenTestResourceProfilesSlice(), dest) } func TestCopyResourceProfilesPtrSlice(t *testing.T) { src := []*ResourceProfiles{} dest := []*ResourceProfiles{} // Test CopyTo empty dest = CopyResourceProfilesPtrSlice(dest, src) assert.Equal(t, []*ResourceProfiles{}, dest) // Test CopyTo larger slice src = GenTestResourceProfilesPtrSlice() dest = CopyResourceProfilesPtrSlice(dest, src) assert.Equal(t, GenTestResourceProfilesPtrSlice(), dest) // Test CopyTo same size slice dest = CopyResourceProfilesPtrSlice(dest, src) assert.Equal(t, GenTestResourceProfilesPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceProfilesPtrSlice(dest, []*ResourceProfiles{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceProfilesPtrSlice(dest, src) assert.Equal(t, GenTestResourceProfilesPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONResourceProfilesUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewResourceProfiles() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewResourceProfiles(), dest) } func TestMarshalAndUnmarshalJSONResourceProfiles(t *testing.T) { for name, src := range genTestEncodingValuesResourceProfiles() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewResourceProfiles() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteResourceProfiles(dest, true) }) } } } func TestMarshalAndUnmarshalProtoResourceProfilesFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesResourceProfiles() { t.Run(name, func(t *testing.T) { dest := NewResourceProfiles() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoResourceProfilesUnknown(t *testing.T) { dest := NewResourceProfiles() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewResourceProfiles(), dest) } func TestMarshalAndUnmarshalProtoResourceProfiles(t *testing.T) { for name, src := range genTestEncodingValuesResourceProfiles() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewResourceProfiles() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteResourceProfiles(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufResourceProfiles(t *testing.T) { for name, src := range genTestEncodingValuesResourceProfiles() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.ResourceProfiles{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewResourceProfiles() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesResourceProfiles() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Resource/wrong_wire_type": {0xc}, "Resource/missing_value": {0xa}, "ScopeProfiles/wrong_wire_type": {0x14}, "ScopeProfiles/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, } } func genTestEncodingValuesResourceProfiles() map[string]*ResourceProfiles { return map[string]*ResourceProfiles{ "empty": NewResourceProfiles(), "Resource/test": {Resource: *GenTestResource()}, "ScopeProfiles/test": {ScopeProfiles: []*ScopeProfiles{{}, GenTestScopeProfiles()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourcespans.go000066400000000000000000000217751511331344600301430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ResourceSpans is a collection of spans from a Resource. type ResourceSpans struct { Resource Resource ScopeSpans []*ScopeSpans SchemaUrl string DeprecatedScopeSpans []*ScopeSpans } var ( protoPoolResourceSpans = sync.Pool{ New: func() any { return &ResourceSpans{} }, } ) func NewResourceSpans() *ResourceSpans { if !UseProtoPooling.IsEnabled() { return &ResourceSpans{} } return protoPoolResourceSpans.Get().(*ResourceSpans) } func DeleteResourceSpans(orig *ResourceSpans, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteResource(&orig.Resource, false) for i := range orig.ScopeSpans { DeleteScopeSpans(orig.ScopeSpans[i], true) } for i := range orig.DeprecatedScopeSpans { DeleteScopeSpans(orig.DeprecatedScopeSpans[i], true) } orig.Reset() if nullable { protoPoolResourceSpans.Put(orig) } } func CopyResourceSpans(dest, src *ResourceSpans) *ResourceSpans { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewResourceSpans() } CopyResource(&dest.Resource, &src.Resource) dest.ScopeSpans = CopyScopeSpansPtrSlice(dest.ScopeSpans, src.ScopeSpans) dest.SchemaUrl = src.SchemaUrl dest.DeprecatedScopeSpans = CopyScopeSpansPtrSlice(dest.DeprecatedScopeSpans, src.DeprecatedScopeSpans) return dest } func CopyResourceSpansSlice(dest, src []ResourceSpans) []ResourceSpans { var newDest []ResourceSpans if cap(dest) < len(src) { newDest = make([]ResourceSpans, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceSpans(&dest[i], false) } } for i := range src { CopyResourceSpans(&newDest[i], &src[i]) } return newDest } func CopyResourceSpansPtrSlice(dest, src []*ResourceSpans) []*ResourceSpans { var newDest []*ResourceSpans if cap(dest) < len(src) { newDest = make([]*ResourceSpans, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceSpans() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteResourceSpans(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewResourceSpans() } } for i := range src { CopyResourceSpans(newDest[i], src[i]) } return newDest } func (orig *ResourceSpans) Reset() { *orig = ResourceSpans{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ResourceSpans) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("resource") orig.Resource.MarshalJSON(dest) if len(orig.ScopeSpans) > 0 { dest.WriteObjectField("scopeSpans") dest.WriteArrayStart() orig.ScopeSpans[0].MarshalJSON(dest) for i := 1; i < len(orig.ScopeSpans); i++ { dest.WriteMore() orig.ScopeSpans[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } if len(orig.DeprecatedScopeSpans) > 0 { dest.WriteObjectField("deprecatedScopeSpans") dest.WriteArrayStart() orig.DeprecatedScopeSpans[0].MarshalJSON(dest) for i := 1; i < len(orig.DeprecatedScopeSpans); i++ { dest.WriteMore() orig.DeprecatedScopeSpans[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ResourceSpans) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resource": orig.Resource.UnmarshalJSON(iter) case "scopeSpans", "scope_spans": for iter.ReadArray() { orig.ScopeSpans = append(orig.ScopeSpans, NewScopeSpans()) orig.ScopeSpans[len(orig.ScopeSpans)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() case "deprecatedScopeSpans", "deprecated_scope_spans": for iter.ReadArray() { orig.DeprecatedScopeSpans = append(orig.DeprecatedScopeSpans, NewScopeSpans()) orig.DeprecatedScopeSpans[len(orig.DeprecatedScopeSpans)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *ResourceSpans) SizeProto() int { var n int var l int _ = l l = orig.Resource.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.ScopeSpans { l = orig.ScopeSpans[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.DeprecatedScopeSpans { l = orig.DeprecatedScopeSpans[i].SizeProto() n += 2 + proto.Sov(uint64(l)) + l } return n } func (orig *ResourceSpans) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Resource.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.ScopeSpans) - 1; i >= 0; i-- { l = orig.ScopeSpans[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } for i := len(orig.DeprecatedScopeSpans) - 1; i >= 0; i-- { l = orig.DeprecatedScopeSpans[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3e pos-- buf[pos] = 0xc2 } return len(buf) - pos } func (orig *ResourceSpans) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Resource", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Resource.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ScopeSpans", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ScopeSpans = append(orig.ScopeSpans, NewScopeSpans()) err = orig.ScopeSpans[len(orig.ScopeSpans)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) case 1000: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DeprecatedScopeSpans", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DeprecatedScopeSpans = append(orig.DeprecatedScopeSpans, NewScopeSpans()) err = orig.DeprecatedScopeSpans[len(orig.DeprecatedScopeSpans)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestResourceSpans() *ResourceSpans { orig := NewResourceSpans() orig.Resource = *GenTestResource() orig.ScopeSpans = []*ScopeSpans{{}, GenTestScopeSpans()} orig.SchemaUrl = "test_schemaurl" orig.DeprecatedScopeSpans = []*ScopeSpans{{}, GenTestScopeSpans()} return orig } func GenTestResourceSpansPtrSlice() []*ResourceSpans { orig := make([]*ResourceSpans, 5) orig[0] = NewResourceSpans() orig[1] = GenTestResourceSpans() orig[2] = NewResourceSpans() orig[3] = GenTestResourceSpans() orig[4] = NewResourceSpans() return orig } func GenTestResourceSpansSlice() []ResourceSpans { orig := make([]ResourceSpans, 5) orig[1] = *GenTestResourceSpans() orig[3] = *GenTestResourceSpans() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_resourcespans_test.go000066400000000000000000000153601511331344600311730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyResourceSpans(t *testing.T) { for name, src := range genTestEncodingValuesResourceSpans() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewResourceSpans() CopyResourceSpans(dest, src) assert.Equal(t, src, dest) CopyResourceSpans(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyResourceSpansSlice(t *testing.T) { src := []ResourceSpans{} dest := []ResourceSpans{} // Test CopyTo empty dest = CopyResourceSpansSlice(dest, src) assert.Equal(t, []ResourceSpans{}, dest) // Test CopyTo larger slice src = GenTestResourceSpansSlice() dest = CopyResourceSpansSlice(dest, src) assert.Equal(t, GenTestResourceSpansSlice(), dest) // Test CopyTo same size slice dest = CopyResourceSpansSlice(dest, src) assert.Equal(t, GenTestResourceSpansSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceSpansSlice(dest, []ResourceSpans{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceSpansSlice(dest, src) assert.Equal(t, GenTestResourceSpansSlice(), dest) } func TestCopyResourceSpansPtrSlice(t *testing.T) { src := []*ResourceSpans{} dest := []*ResourceSpans{} // Test CopyTo empty dest = CopyResourceSpansPtrSlice(dest, src) assert.Equal(t, []*ResourceSpans{}, dest) // Test CopyTo larger slice src = GenTestResourceSpansPtrSlice() dest = CopyResourceSpansPtrSlice(dest, src) assert.Equal(t, GenTestResourceSpansPtrSlice(), dest) // Test CopyTo same size slice dest = CopyResourceSpansPtrSlice(dest, src) assert.Equal(t, GenTestResourceSpansPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyResourceSpansPtrSlice(dest, []*ResourceSpans{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyResourceSpansPtrSlice(dest, src) assert.Equal(t, GenTestResourceSpansPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONResourceSpansUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewResourceSpans() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewResourceSpans(), dest) } func TestMarshalAndUnmarshalJSONResourceSpans(t *testing.T) { for name, src := range genTestEncodingValuesResourceSpans() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewResourceSpans() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteResourceSpans(dest, true) }) } } } func TestMarshalAndUnmarshalProtoResourceSpansFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesResourceSpans() { t.Run(name, func(t *testing.T) { dest := NewResourceSpans() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoResourceSpansUnknown(t *testing.T) { dest := NewResourceSpans() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewResourceSpans(), dest) } func TestMarshalAndUnmarshalProtoResourceSpans(t *testing.T) { for name, src := range genTestEncodingValuesResourceSpans() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewResourceSpans() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteResourceSpans(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufResourceSpans(t *testing.T) { for name, src := range genTestEncodingValuesResourceSpans() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlptrace.ResourceSpans{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewResourceSpans() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesResourceSpans() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Resource/wrong_wire_type": {0xc}, "Resource/missing_value": {0xa}, "ScopeSpans/wrong_wire_type": {0x14}, "ScopeSpans/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, "DeprecatedScopeSpans/wrong_wire_type": {0xc4, 0x3e}, "DeprecatedScopeSpans/missing_value": {0xc2, 0x3e}, } } func genTestEncodingValuesResourceSpans() map[string]*ResourceSpans { return map[string]*ResourceSpans{ "empty": NewResourceSpans(), "Resource/test": {Resource: *GenTestResource()}, "ScopeSpans/test": {ScopeSpans: []*ScopeSpans{{}, GenTestScopeSpans()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, "DeprecatedScopeSpans/test": {DeprecatedScopeSpans: []*ScopeSpans{{}, GenTestScopeSpans()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_sample.go000066400000000000000000000253451511331344600265250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Sample represents each record value encountered within a profiled program. type Sample struct { StackIndex int32 Values []int64 AttributeIndices []int32 LinkIndex int32 TimestampsUnixNano []uint64 } var ( protoPoolSample = sync.Pool{ New: func() any { return &Sample{} }, } ) func NewSample() *Sample { if !UseProtoPooling.IsEnabled() { return &Sample{} } return protoPoolSample.Get().(*Sample) } func DeleteSample(orig *Sample, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolSample.Put(orig) } } func CopySample(dest, src *Sample) *Sample { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSample() } dest.StackIndex = src.StackIndex dest.Values = append(dest.Values[:0], src.Values...) dest.AttributeIndices = append(dest.AttributeIndices[:0], src.AttributeIndices...) dest.LinkIndex = src.LinkIndex dest.TimestampsUnixNano = append(dest.TimestampsUnixNano[:0], src.TimestampsUnixNano...) return dest } func CopySampleSlice(dest, src []Sample) []Sample { var newDest []Sample if cap(dest) < len(src) { newDest = make([]Sample, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSample(&dest[i], false) } } for i := range src { CopySample(&newDest[i], &src[i]) } return newDest } func CopySamplePtrSlice(dest, src []*Sample) []*Sample { var newDest []*Sample if cap(dest) < len(src) { newDest = make([]*Sample, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSample() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSample(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSample() } } for i := range src { CopySample(newDest[i], src[i]) } return newDest } func (orig *Sample) Reset() { *orig = Sample{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Sample) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.StackIndex != int32(0) { dest.WriteObjectField("stackIndex") dest.WriteInt32(orig.StackIndex) } if len(orig.Values) > 0 { dest.WriteObjectField("values") dest.WriteArrayStart() dest.WriteInt64(orig.Values[0]) for i := 1; i < len(orig.Values); i++ { dest.WriteMore() dest.WriteInt64(orig.Values[i]) } dest.WriteArrayEnd() } if len(orig.AttributeIndices) > 0 { dest.WriteObjectField("attributeIndices") dest.WriteArrayStart() dest.WriteInt32(orig.AttributeIndices[0]) for i := 1; i < len(orig.AttributeIndices); i++ { dest.WriteMore() dest.WriteInt32(orig.AttributeIndices[i]) } dest.WriteArrayEnd() } if orig.LinkIndex != int32(0) { dest.WriteObjectField("linkIndex") dest.WriteInt32(orig.LinkIndex) } if len(orig.TimestampsUnixNano) > 0 { dest.WriteObjectField("timestampsUnixNano") dest.WriteArrayStart() dest.WriteUint64(orig.TimestampsUnixNano[0]) for i := 1; i < len(orig.TimestampsUnixNano); i++ { dest.WriteMore() dest.WriteUint64(orig.TimestampsUnixNano[i]) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Sample) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "stackIndex", "stack_index": orig.StackIndex = iter.ReadInt32() case "values": for iter.ReadArray() { orig.Values = append(orig.Values, iter.ReadInt64()) } case "attributeIndices", "attribute_indices": for iter.ReadArray() { orig.AttributeIndices = append(orig.AttributeIndices, iter.ReadInt32()) } case "linkIndex", "link_index": orig.LinkIndex = iter.ReadInt32() case "timestampsUnixNano", "timestamps_unix_nano": for iter.ReadArray() { orig.TimestampsUnixNano = append(orig.TimestampsUnixNano, iter.ReadUint64()) } default: iter.Skip() } } } func (orig *Sample) SizeProto() int { var n int var l int _ = l if orig.StackIndex != 0 { n += 1 + proto.Sov(uint64(orig.StackIndex)) } if len(orig.Values) > 0 { l = 0 for _, e := range orig.Values { l += proto.Sov(uint64(e)) } n += 1 + proto.Sov(uint64(l)) + l } if len(orig.AttributeIndices) > 0 { l = 0 for _, e := range orig.AttributeIndices { l += proto.Sov(uint64(e)) } n += 1 + proto.Sov(uint64(l)) + l } if orig.LinkIndex != 0 { n += 1 + proto.Sov(uint64(orig.LinkIndex)) } l = len(orig.TimestampsUnixNano) if l > 0 { l *= 8 n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Sample) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.StackIndex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.StackIndex)) pos-- buf[pos] = 0x8 } l = len(orig.Values) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.Values[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) pos-- buf[pos] = 0x12 } l = len(orig.AttributeIndices) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.AttributeIndices[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) pos-- buf[pos] = 0x1a } if orig.LinkIndex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.LinkIndex)) pos-- buf[pos] = 0x20 } l = len(orig.TimestampsUnixNano) if l > 0 { for i := l - 1; i >= 0; i-- { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimestampsUnixNano[i])) } pos = proto.EncodeVarint(buf, pos, uint64(l*8)) pos-- buf[pos] = 0x2a } return len(buf) - pos } func (orig *Sample) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field StackIndex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.StackIndex = int32(num) case 2: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.Values = append(orig.Values, int64(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field Values", pos-startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Values = append(orig.Values, int64(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field Values", wireType) } case 3: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field AttributeIndices", pos-startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.AttributeIndices = append(orig.AttributeIndices, int32(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field AttributeIndices", wireType) } case 4: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field LinkIndex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.LinkIndex = int32(num) case 5: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length size := length / 8 orig.TimestampsUnixNano = make([]uint64, size) var num uint64 for i := 0; i < size; i++ { num, startPos, err = proto.ConsumeI64(buf[:pos], startPos) if err != nil { return err } orig.TimestampsUnixNano[i] = uint64(num) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field TimestampsUnixNano", pos-startPos) } case proto.WireTypeI64: var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimestampsUnixNano = append(orig.TimestampsUnixNano, uint64(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field TimestampsUnixNano", wireType) } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSample() *Sample { orig := NewSample() orig.StackIndex = int32(13) orig.Values = []int64{int64(0), int64(13)} orig.AttributeIndices = []int32{int32(0), int32(13)} orig.LinkIndex = int32(13) orig.TimestampsUnixNano = []uint64{uint64(0), uint64(13)} return orig } func GenTestSamplePtrSlice() []*Sample { orig := make([]*Sample, 5) orig[0] = NewSample() orig[1] = GenTestSample() orig[2] = NewSample() orig[3] = GenTestSample() orig[4] = NewSample() return orig } func GenTestSampleSlice() []Sample { orig := make([]Sample, 5) orig[1] = *GenTestSample() orig[3] = *GenTestSample() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_sample_test.go000066400000000000000000000147111511331344600275570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySample(t *testing.T) { for name, src := range genTestEncodingValuesSample() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSample() CopySample(dest, src) assert.Equal(t, src, dest) CopySample(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySampleSlice(t *testing.T) { src := []Sample{} dest := []Sample{} // Test CopyTo empty dest = CopySampleSlice(dest, src) assert.Equal(t, []Sample{}, dest) // Test CopyTo larger slice src = GenTestSampleSlice() dest = CopySampleSlice(dest, src) assert.Equal(t, GenTestSampleSlice(), dest) // Test CopyTo same size slice dest = CopySampleSlice(dest, src) assert.Equal(t, GenTestSampleSlice(), dest) // Test CopyTo smaller size slice dest = CopySampleSlice(dest, []Sample{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySampleSlice(dest, src) assert.Equal(t, GenTestSampleSlice(), dest) } func TestCopySamplePtrSlice(t *testing.T) { src := []*Sample{} dest := []*Sample{} // Test CopyTo empty dest = CopySamplePtrSlice(dest, src) assert.Equal(t, []*Sample{}, dest) // Test CopyTo larger slice src = GenTestSamplePtrSlice() dest = CopySamplePtrSlice(dest, src) assert.Equal(t, GenTestSamplePtrSlice(), dest) // Test CopyTo same size slice dest = CopySamplePtrSlice(dest, src) assert.Equal(t, GenTestSamplePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySamplePtrSlice(dest, []*Sample{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySamplePtrSlice(dest, src) assert.Equal(t, GenTestSamplePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSampleUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSample() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSample(), dest) } func TestMarshalAndUnmarshalJSONSample(t *testing.T) { for name, src := range genTestEncodingValuesSample() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSample() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSample(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSampleFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSample() { t.Run(name, func(t *testing.T) { dest := NewSample() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSampleUnknown(t *testing.T) { dest := NewSample() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSample(), dest) } func TestMarshalAndUnmarshalProtoSample(t *testing.T) { for name, src := range genTestEncodingValuesSample() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSample() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSample(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSample(t *testing.T) { for name, src := range genTestEncodingValuesSample() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Sample{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSample() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSample() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "StackIndex/wrong_wire_type": {0xc}, "StackIndex/missing_value": {0x8}, "Values/wrong_wire_type": {0x14}, "Values/missing_value": {0x12}, "AttributeIndices/wrong_wire_type": {0x1c}, "AttributeIndices/missing_value": {0x1a}, "LinkIndex/wrong_wire_type": {0x24}, "LinkIndex/missing_value": {0x20}, "TimestampsUnixNano/wrong_wire_type": {0x2c}, "TimestampsUnixNano/missing_value": {0x2a}, } } func genTestEncodingValuesSample() map[string]*Sample { return map[string]*Sample{ "empty": NewSample(), "StackIndex/test": {StackIndex: int32(13)}, "Values/test": {Values: []int64{int64(0), int64(13)}}, "AttributeIndices/test": {AttributeIndices: []int32{int32(0), int32(13)}}, "LinkIndex/test": {LinkIndex: int32(13)}, "TimestampsUnixNano/test": {TimestampsUnixNano: []uint64{uint64(0), uint64(13)}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopelogs.go000066400000000000000000000160671511331344600272430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ScopeLogs is a collection of logs from a LibraryInstrumentation. type ScopeLogs struct { Scope InstrumentationScope LogRecords []*LogRecord SchemaUrl string } var ( protoPoolScopeLogs = sync.Pool{ New: func() any { return &ScopeLogs{} }, } ) func NewScopeLogs() *ScopeLogs { if !UseProtoPooling.IsEnabled() { return &ScopeLogs{} } return protoPoolScopeLogs.Get().(*ScopeLogs) } func DeleteScopeLogs(orig *ScopeLogs, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteInstrumentationScope(&orig.Scope, false) for i := range orig.LogRecords { DeleteLogRecord(orig.LogRecords[i], true) } orig.Reset() if nullable { protoPoolScopeLogs.Put(orig) } } func CopyScopeLogs(dest, src *ScopeLogs) *ScopeLogs { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewScopeLogs() } CopyInstrumentationScope(&dest.Scope, &src.Scope) dest.LogRecords = CopyLogRecordPtrSlice(dest.LogRecords, src.LogRecords) dest.SchemaUrl = src.SchemaUrl return dest } func CopyScopeLogsSlice(dest, src []ScopeLogs) []ScopeLogs { var newDest []ScopeLogs if cap(dest) < len(src) { newDest = make([]ScopeLogs, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeLogs(&dest[i], false) } } for i := range src { CopyScopeLogs(&newDest[i], &src[i]) } return newDest } func CopyScopeLogsPtrSlice(dest, src []*ScopeLogs) []*ScopeLogs { var newDest []*ScopeLogs if cap(dest) < len(src) { newDest = make([]*ScopeLogs, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeLogs() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeLogs(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeLogs() } } for i := range src { CopyScopeLogs(newDest[i], src[i]) } return newDest } func (orig *ScopeLogs) Reset() { *orig = ScopeLogs{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ScopeLogs) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("scope") orig.Scope.MarshalJSON(dest) if len(orig.LogRecords) > 0 { dest.WriteObjectField("logRecords") dest.WriteArrayStart() orig.LogRecords[0].MarshalJSON(dest) for i := 1; i < len(orig.LogRecords); i++ { dest.WriteMore() orig.LogRecords[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ScopeLogs) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "scope": orig.Scope.UnmarshalJSON(iter) case "logRecords", "log_records": for iter.ReadArray() { orig.LogRecords = append(orig.LogRecords, NewLogRecord()) orig.LogRecords[len(orig.LogRecords)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() default: iter.Skip() } } } func (orig *ScopeLogs) SizeProto() int { var n int var l int _ = l l = orig.Scope.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.LogRecords { l = orig.LogRecords[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ScopeLogs) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Scope.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.LogRecords) - 1; i >= 0; i-- { l = orig.LogRecords[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *ScopeLogs) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Scope", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Scope.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field LogRecords", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.LogRecords = append(orig.LogRecords, NewLogRecord()) err = orig.LogRecords[len(orig.LogRecords)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestScopeLogs() *ScopeLogs { orig := NewScopeLogs() orig.Scope = *GenTestInstrumentationScope() orig.LogRecords = []*LogRecord{{}, GenTestLogRecord()} orig.SchemaUrl = "test_schemaurl" return orig } func GenTestScopeLogsPtrSlice() []*ScopeLogs { orig := make([]*ScopeLogs, 5) orig[0] = NewScopeLogs() orig[1] = GenTestScopeLogs() orig[2] = NewScopeLogs() orig[3] = GenTestScopeLogs() orig[4] = NewScopeLogs() return orig } func GenTestScopeLogsSlice() []ScopeLogs { orig := make([]ScopeLogs, 5) orig[1] = *GenTestScopeLogs() orig[3] = *GenTestScopeLogs() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopelogs_test.go000066400000000000000000000143131511331344600302720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlplogs "go.opentelemetry.io/proto/slim/otlp/logs/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyScopeLogs(t *testing.T) { for name, src := range genTestEncodingValuesScopeLogs() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewScopeLogs() CopyScopeLogs(dest, src) assert.Equal(t, src, dest) CopyScopeLogs(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyScopeLogsSlice(t *testing.T) { src := []ScopeLogs{} dest := []ScopeLogs{} // Test CopyTo empty dest = CopyScopeLogsSlice(dest, src) assert.Equal(t, []ScopeLogs{}, dest) // Test CopyTo larger slice src = GenTestScopeLogsSlice() dest = CopyScopeLogsSlice(dest, src) assert.Equal(t, GenTestScopeLogsSlice(), dest) // Test CopyTo same size slice dest = CopyScopeLogsSlice(dest, src) assert.Equal(t, GenTestScopeLogsSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeLogsSlice(dest, []ScopeLogs{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeLogsSlice(dest, src) assert.Equal(t, GenTestScopeLogsSlice(), dest) } func TestCopyScopeLogsPtrSlice(t *testing.T) { src := []*ScopeLogs{} dest := []*ScopeLogs{} // Test CopyTo empty dest = CopyScopeLogsPtrSlice(dest, src) assert.Equal(t, []*ScopeLogs{}, dest) // Test CopyTo larger slice src = GenTestScopeLogsPtrSlice() dest = CopyScopeLogsPtrSlice(dest, src) assert.Equal(t, GenTestScopeLogsPtrSlice(), dest) // Test CopyTo same size slice dest = CopyScopeLogsPtrSlice(dest, src) assert.Equal(t, GenTestScopeLogsPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeLogsPtrSlice(dest, []*ScopeLogs{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeLogsPtrSlice(dest, src) assert.Equal(t, GenTestScopeLogsPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONScopeLogsUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewScopeLogs() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewScopeLogs(), dest) } func TestMarshalAndUnmarshalJSONScopeLogs(t *testing.T) { for name, src := range genTestEncodingValuesScopeLogs() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewScopeLogs() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteScopeLogs(dest, true) }) } } } func TestMarshalAndUnmarshalProtoScopeLogsFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesScopeLogs() { t.Run(name, func(t *testing.T) { dest := NewScopeLogs() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoScopeLogsUnknown(t *testing.T) { dest := NewScopeLogs() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewScopeLogs(), dest) } func TestMarshalAndUnmarshalProtoScopeLogs(t *testing.T) { for name, src := range genTestEncodingValuesScopeLogs() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewScopeLogs() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteScopeLogs(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufScopeLogs(t *testing.T) { for name, src := range genTestEncodingValuesScopeLogs() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlplogs.ScopeLogs{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewScopeLogs() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesScopeLogs() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Scope/wrong_wire_type": {0xc}, "Scope/missing_value": {0xa}, "LogRecords/wrong_wire_type": {0x14}, "LogRecords/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, } } func genTestEncodingValuesScopeLogs() map[string]*ScopeLogs { return map[string]*ScopeLogs{ "empty": NewScopeLogs(), "Scope/test": {Scope: *GenTestInstrumentationScope()}, "LogRecords/test": {LogRecords: []*LogRecord{{}, GenTestLogRecord()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopemetrics.go000066400000000000000000000161551511331344600277430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ScopeMetrics is a collection of metrics from a LibraryInstrumentation. type ScopeMetrics struct { Scope InstrumentationScope Metrics []*Metric SchemaUrl string } var ( protoPoolScopeMetrics = sync.Pool{ New: func() any { return &ScopeMetrics{} }, } ) func NewScopeMetrics() *ScopeMetrics { if !UseProtoPooling.IsEnabled() { return &ScopeMetrics{} } return protoPoolScopeMetrics.Get().(*ScopeMetrics) } func DeleteScopeMetrics(orig *ScopeMetrics, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteInstrumentationScope(&orig.Scope, false) for i := range orig.Metrics { DeleteMetric(orig.Metrics[i], true) } orig.Reset() if nullable { protoPoolScopeMetrics.Put(orig) } } func CopyScopeMetrics(dest, src *ScopeMetrics) *ScopeMetrics { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewScopeMetrics() } CopyInstrumentationScope(&dest.Scope, &src.Scope) dest.Metrics = CopyMetricPtrSlice(dest.Metrics, src.Metrics) dest.SchemaUrl = src.SchemaUrl return dest } func CopyScopeMetricsSlice(dest, src []ScopeMetrics) []ScopeMetrics { var newDest []ScopeMetrics if cap(dest) < len(src) { newDest = make([]ScopeMetrics, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeMetrics(&dest[i], false) } } for i := range src { CopyScopeMetrics(&newDest[i], &src[i]) } return newDest } func CopyScopeMetricsPtrSlice(dest, src []*ScopeMetrics) []*ScopeMetrics { var newDest []*ScopeMetrics if cap(dest) < len(src) { newDest = make([]*ScopeMetrics, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeMetrics() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeMetrics(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeMetrics() } } for i := range src { CopyScopeMetrics(newDest[i], src[i]) } return newDest } func (orig *ScopeMetrics) Reset() { *orig = ScopeMetrics{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ScopeMetrics) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("scope") orig.Scope.MarshalJSON(dest) if len(orig.Metrics) > 0 { dest.WriteObjectField("metrics") dest.WriteArrayStart() orig.Metrics[0].MarshalJSON(dest) for i := 1; i < len(orig.Metrics); i++ { dest.WriteMore() orig.Metrics[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ScopeMetrics) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "scope": orig.Scope.UnmarshalJSON(iter) case "metrics": for iter.ReadArray() { orig.Metrics = append(orig.Metrics, NewMetric()) orig.Metrics[len(orig.Metrics)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() default: iter.Skip() } } } func (orig *ScopeMetrics) SizeProto() int { var n int var l int _ = l l = orig.Scope.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.Metrics { l = orig.Metrics[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ScopeMetrics) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Scope.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.Metrics) - 1; i >= 0; i-- { l = orig.Metrics[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *ScopeMetrics) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Scope", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Scope.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Metrics", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Metrics = append(orig.Metrics, NewMetric()) err = orig.Metrics[len(orig.Metrics)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestScopeMetrics() *ScopeMetrics { orig := NewScopeMetrics() orig.Scope = *GenTestInstrumentationScope() orig.Metrics = []*Metric{{}, GenTestMetric()} orig.SchemaUrl = "test_schemaurl" return orig } func GenTestScopeMetricsPtrSlice() []*ScopeMetrics { orig := make([]*ScopeMetrics, 5) orig[0] = NewScopeMetrics() orig[1] = GenTestScopeMetrics() orig[2] = NewScopeMetrics() orig[3] = GenTestScopeMetrics() orig[4] = NewScopeMetrics() return orig } func GenTestScopeMetricsSlice() []ScopeMetrics { orig := make([]ScopeMetrics, 5) orig[1] = *GenTestScopeMetrics() orig[3] = *GenTestScopeMetrics() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopemetrics_test.go000066400000000000000000000145611511331344600310010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyScopeMetrics(t *testing.T) { for name, src := range genTestEncodingValuesScopeMetrics() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewScopeMetrics() CopyScopeMetrics(dest, src) assert.Equal(t, src, dest) CopyScopeMetrics(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyScopeMetricsSlice(t *testing.T) { src := []ScopeMetrics{} dest := []ScopeMetrics{} // Test CopyTo empty dest = CopyScopeMetricsSlice(dest, src) assert.Equal(t, []ScopeMetrics{}, dest) // Test CopyTo larger slice src = GenTestScopeMetricsSlice() dest = CopyScopeMetricsSlice(dest, src) assert.Equal(t, GenTestScopeMetricsSlice(), dest) // Test CopyTo same size slice dest = CopyScopeMetricsSlice(dest, src) assert.Equal(t, GenTestScopeMetricsSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeMetricsSlice(dest, []ScopeMetrics{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeMetricsSlice(dest, src) assert.Equal(t, GenTestScopeMetricsSlice(), dest) } func TestCopyScopeMetricsPtrSlice(t *testing.T) { src := []*ScopeMetrics{} dest := []*ScopeMetrics{} // Test CopyTo empty dest = CopyScopeMetricsPtrSlice(dest, src) assert.Equal(t, []*ScopeMetrics{}, dest) // Test CopyTo larger slice src = GenTestScopeMetricsPtrSlice() dest = CopyScopeMetricsPtrSlice(dest, src) assert.Equal(t, GenTestScopeMetricsPtrSlice(), dest) // Test CopyTo same size slice dest = CopyScopeMetricsPtrSlice(dest, src) assert.Equal(t, GenTestScopeMetricsPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeMetricsPtrSlice(dest, []*ScopeMetrics{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeMetricsPtrSlice(dest, src) assert.Equal(t, GenTestScopeMetricsPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONScopeMetricsUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewScopeMetrics() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewScopeMetrics(), dest) } func TestMarshalAndUnmarshalJSONScopeMetrics(t *testing.T) { for name, src := range genTestEncodingValuesScopeMetrics() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewScopeMetrics() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteScopeMetrics(dest, true) }) } } } func TestMarshalAndUnmarshalProtoScopeMetricsFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesScopeMetrics() { t.Run(name, func(t *testing.T) { dest := NewScopeMetrics() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoScopeMetricsUnknown(t *testing.T) { dest := NewScopeMetrics() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewScopeMetrics(), dest) } func TestMarshalAndUnmarshalProtoScopeMetrics(t *testing.T) { for name, src := range genTestEncodingValuesScopeMetrics() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewScopeMetrics() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteScopeMetrics(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufScopeMetrics(t *testing.T) { for name, src := range genTestEncodingValuesScopeMetrics() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.ScopeMetrics{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewScopeMetrics() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesScopeMetrics() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Scope/wrong_wire_type": {0xc}, "Scope/missing_value": {0xa}, "Metrics/wrong_wire_type": {0x14}, "Metrics/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, } } func genTestEncodingValuesScopeMetrics() map[string]*ScopeMetrics { return map[string]*ScopeMetrics{ "empty": NewScopeMetrics(), "Scope/test": {Scope: *GenTestInstrumentationScope()}, "Metrics/test": {Metrics: []*Metric{{}, GenTestMetric()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopeprofiles.go000066400000000000000000000163051511331344600301150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ScopeProfiles is a collection of profiles from a LibraryInstrumentation. type ScopeProfiles struct { Scope InstrumentationScope Profiles []*Profile SchemaUrl string } var ( protoPoolScopeProfiles = sync.Pool{ New: func() any { return &ScopeProfiles{} }, } ) func NewScopeProfiles() *ScopeProfiles { if !UseProtoPooling.IsEnabled() { return &ScopeProfiles{} } return protoPoolScopeProfiles.Get().(*ScopeProfiles) } func DeleteScopeProfiles(orig *ScopeProfiles, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteInstrumentationScope(&orig.Scope, false) for i := range orig.Profiles { DeleteProfile(orig.Profiles[i], true) } orig.Reset() if nullable { protoPoolScopeProfiles.Put(orig) } } func CopyScopeProfiles(dest, src *ScopeProfiles) *ScopeProfiles { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewScopeProfiles() } CopyInstrumentationScope(&dest.Scope, &src.Scope) dest.Profiles = CopyProfilePtrSlice(dest.Profiles, src.Profiles) dest.SchemaUrl = src.SchemaUrl return dest } func CopyScopeProfilesSlice(dest, src []ScopeProfiles) []ScopeProfiles { var newDest []ScopeProfiles if cap(dest) < len(src) { newDest = make([]ScopeProfiles, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeProfiles(&dest[i], false) } } for i := range src { CopyScopeProfiles(&newDest[i], &src[i]) } return newDest } func CopyScopeProfilesPtrSlice(dest, src []*ScopeProfiles) []*ScopeProfiles { var newDest []*ScopeProfiles if cap(dest) < len(src) { newDest = make([]*ScopeProfiles, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeProfiles() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeProfiles(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeProfiles() } } for i := range src { CopyScopeProfiles(newDest[i], src[i]) } return newDest } func (orig *ScopeProfiles) Reset() { *orig = ScopeProfiles{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ScopeProfiles) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("scope") orig.Scope.MarshalJSON(dest) if len(orig.Profiles) > 0 { dest.WriteObjectField("profiles") dest.WriteArrayStart() orig.Profiles[0].MarshalJSON(dest) for i := 1; i < len(orig.Profiles); i++ { dest.WriteMore() orig.Profiles[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ScopeProfiles) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "scope": orig.Scope.UnmarshalJSON(iter) case "profiles": for iter.ReadArray() { orig.Profiles = append(orig.Profiles, NewProfile()) orig.Profiles[len(orig.Profiles)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() default: iter.Skip() } } } func (orig *ScopeProfiles) SizeProto() int { var n int var l int _ = l l = orig.Scope.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.Profiles { l = orig.Profiles[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ScopeProfiles) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Scope.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.Profiles) - 1; i >= 0; i-- { l = orig.Profiles[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *ScopeProfiles) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Scope", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Scope.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Profiles", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Profiles = append(orig.Profiles, NewProfile()) err = orig.Profiles[len(orig.Profiles)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestScopeProfiles() *ScopeProfiles { orig := NewScopeProfiles() orig.Scope = *GenTestInstrumentationScope() orig.Profiles = []*Profile{{}, GenTestProfile()} orig.SchemaUrl = "test_schemaurl" return orig } func GenTestScopeProfilesPtrSlice() []*ScopeProfiles { orig := make([]*ScopeProfiles, 5) orig[0] = NewScopeProfiles() orig[1] = GenTestScopeProfiles() orig[2] = NewScopeProfiles() orig[3] = GenTestScopeProfiles() orig[4] = NewScopeProfiles() return orig } func GenTestScopeProfilesSlice() []ScopeProfiles { orig := make([]ScopeProfiles, 5) orig[1] = *GenTestScopeProfiles() orig[3] = *GenTestScopeProfiles() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopeprofiles_test.go000066400000000000000000000146751511331344600311640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyScopeProfiles(t *testing.T) { for name, src := range genTestEncodingValuesScopeProfiles() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewScopeProfiles() CopyScopeProfiles(dest, src) assert.Equal(t, src, dest) CopyScopeProfiles(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyScopeProfilesSlice(t *testing.T) { src := []ScopeProfiles{} dest := []ScopeProfiles{} // Test CopyTo empty dest = CopyScopeProfilesSlice(dest, src) assert.Equal(t, []ScopeProfiles{}, dest) // Test CopyTo larger slice src = GenTestScopeProfilesSlice() dest = CopyScopeProfilesSlice(dest, src) assert.Equal(t, GenTestScopeProfilesSlice(), dest) // Test CopyTo same size slice dest = CopyScopeProfilesSlice(dest, src) assert.Equal(t, GenTestScopeProfilesSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeProfilesSlice(dest, []ScopeProfiles{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeProfilesSlice(dest, src) assert.Equal(t, GenTestScopeProfilesSlice(), dest) } func TestCopyScopeProfilesPtrSlice(t *testing.T) { src := []*ScopeProfiles{} dest := []*ScopeProfiles{} // Test CopyTo empty dest = CopyScopeProfilesPtrSlice(dest, src) assert.Equal(t, []*ScopeProfiles{}, dest) // Test CopyTo larger slice src = GenTestScopeProfilesPtrSlice() dest = CopyScopeProfilesPtrSlice(dest, src) assert.Equal(t, GenTestScopeProfilesPtrSlice(), dest) // Test CopyTo same size slice dest = CopyScopeProfilesPtrSlice(dest, src) assert.Equal(t, GenTestScopeProfilesPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeProfilesPtrSlice(dest, []*ScopeProfiles{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeProfilesPtrSlice(dest, src) assert.Equal(t, GenTestScopeProfilesPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONScopeProfilesUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewScopeProfiles() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewScopeProfiles(), dest) } func TestMarshalAndUnmarshalJSONScopeProfiles(t *testing.T) { for name, src := range genTestEncodingValuesScopeProfiles() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewScopeProfiles() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteScopeProfiles(dest, true) }) } } } func TestMarshalAndUnmarshalProtoScopeProfilesFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesScopeProfiles() { t.Run(name, func(t *testing.T) { dest := NewScopeProfiles() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoScopeProfilesUnknown(t *testing.T) { dest := NewScopeProfiles() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewScopeProfiles(), dest) } func TestMarshalAndUnmarshalProtoScopeProfiles(t *testing.T) { for name, src := range genTestEncodingValuesScopeProfiles() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewScopeProfiles() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteScopeProfiles(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufScopeProfiles(t *testing.T) { for name, src := range genTestEncodingValuesScopeProfiles() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.ScopeProfiles{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewScopeProfiles() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesScopeProfiles() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Scope/wrong_wire_type": {0xc}, "Scope/missing_value": {0xa}, "Profiles/wrong_wire_type": {0x14}, "Profiles/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, } } func genTestEncodingValuesScopeProfiles() map[string]*ScopeProfiles { return map[string]*ScopeProfiles{ "empty": NewScopeProfiles(), "Scope/test": {Scope: *GenTestInstrumentationScope()}, "Profiles/test": {Profiles: []*Profile{{}, GenTestProfile()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopespans.go000066400000000000000000000156751511331344600274270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ScopeSpans is a collection of spans from a LibraryInstrumentation. type ScopeSpans struct { Scope InstrumentationScope Spans []*Span SchemaUrl string } var ( protoPoolScopeSpans = sync.Pool{ New: func() any { return &ScopeSpans{} }, } ) func NewScopeSpans() *ScopeSpans { if !UseProtoPooling.IsEnabled() { return &ScopeSpans{} } return protoPoolScopeSpans.Get().(*ScopeSpans) } func DeleteScopeSpans(orig *ScopeSpans, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteInstrumentationScope(&orig.Scope, false) for i := range orig.Spans { DeleteSpan(orig.Spans[i], true) } orig.Reset() if nullable { protoPoolScopeSpans.Put(orig) } } func CopyScopeSpans(dest, src *ScopeSpans) *ScopeSpans { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewScopeSpans() } CopyInstrumentationScope(&dest.Scope, &src.Scope) dest.Spans = CopySpanPtrSlice(dest.Spans, src.Spans) dest.SchemaUrl = src.SchemaUrl return dest } func CopyScopeSpansSlice(dest, src []ScopeSpans) []ScopeSpans { var newDest []ScopeSpans if cap(dest) < len(src) { newDest = make([]ScopeSpans, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeSpans(&dest[i], false) } } for i := range src { CopyScopeSpans(&newDest[i], &src[i]) } return newDest } func CopyScopeSpansPtrSlice(dest, src []*ScopeSpans) []*ScopeSpans { var newDest []*ScopeSpans if cap(dest) < len(src) { newDest = make([]*ScopeSpans, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeSpans() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteScopeSpans(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewScopeSpans() } } for i := range src { CopyScopeSpans(newDest[i], src[i]) } return newDest } func (orig *ScopeSpans) Reset() { *orig = ScopeSpans{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ScopeSpans) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() dest.WriteObjectField("scope") orig.Scope.MarshalJSON(dest) if len(orig.Spans) > 0 { dest.WriteObjectField("spans") dest.WriteArrayStart() orig.Spans[0].MarshalJSON(dest) for i := 1; i < len(orig.Spans); i++ { dest.WriteMore() orig.Spans[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.SchemaUrl != "" { dest.WriteObjectField("schemaUrl") dest.WriteString(orig.SchemaUrl) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ScopeSpans) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "scope": orig.Scope.UnmarshalJSON(iter) case "spans": for iter.ReadArray() { orig.Spans = append(orig.Spans, NewSpan()) orig.Spans[len(orig.Spans)-1].UnmarshalJSON(iter) } case "schemaUrl", "schema_url": orig.SchemaUrl = iter.ReadString() default: iter.Skip() } } } func (orig *ScopeSpans) SizeProto() int { var n int var l int _ = l l = orig.Scope.SizeProto() n += 1 + proto.Sov(uint64(l)) + l for i := range orig.Spans { l = orig.Spans[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.SchemaUrl) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *ScopeSpans) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.Scope.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa for i := len(orig.Spans) - 1; i >= 0; i-- { l = orig.Spans[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = len(orig.SchemaUrl) if l > 0 { pos -= l copy(buf[pos:], orig.SchemaUrl) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *ScopeSpans) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Scope", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Scope.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Spans", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Spans = append(orig.Spans, NewSpan()) err = orig.Spans[len(orig.Spans)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SchemaUrl", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.SchemaUrl = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestScopeSpans() *ScopeSpans { orig := NewScopeSpans() orig.Scope = *GenTestInstrumentationScope() orig.Spans = []*Span{{}, GenTestSpan()} orig.SchemaUrl = "test_schemaurl" return orig } func GenTestScopeSpansPtrSlice() []*ScopeSpans { orig := make([]*ScopeSpans, 5) orig[0] = NewScopeSpans() orig[1] = GenTestScopeSpans() orig[2] = NewScopeSpans() orig[3] = GenTestScopeSpans() orig[4] = NewScopeSpans() return orig } func GenTestScopeSpansSlice() []ScopeSpans { orig := make([]ScopeSpans, 5) orig[1] = *GenTestScopeSpans() orig[3] = *GenTestScopeSpans() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_scopespans_test.go000066400000000000000000000143571511331344600304620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyScopeSpans(t *testing.T) { for name, src := range genTestEncodingValuesScopeSpans() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewScopeSpans() CopyScopeSpans(dest, src) assert.Equal(t, src, dest) CopyScopeSpans(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyScopeSpansSlice(t *testing.T) { src := []ScopeSpans{} dest := []ScopeSpans{} // Test CopyTo empty dest = CopyScopeSpansSlice(dest, src) assert.Equal(t, []ScopeSpans{}, dest) // Test CopyTo larger slice src = GenTestScopeSpansSlice() dest = CopyScopeSpansSlice(dest, src) assert.Equal(t, GenTestScopeSpansSlice(), dest) // Test CopyTo same size slice dest = CopyScopeSpansSlice(dest, src) assert.Equal(t, GenTestScopeSpansSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeSpansSlice(dest, []ScopeSpans{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeSpansSlice(dest, src) assert.Equal(t, GenTestScopeSpansSlice(), dest) } func TestCopyScopeSpansPtrSlice(t *testing.T) { src := []*ScopeSpans{} dest := []*ScopeSpans{} // Test CopyTo empty dest = CopyScopeSpansPtrSlice(dest, src) assert.Equal(t, []*ScopeSpans{}, dest) // Test CopyTo larger slice src = GenTestScopeSpansPtrSlice() dest = CopyScopeSpansPtrSlice(dest, src) assert.Equal(t, GenTestScopeSpansPtrSlice(), dest) // Test CopyTo same size slice dest = CopyScopeSpansPtrSlice(dest, src) assert.Equal(t, GenTestScopeSpansPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyScopeSpansPtrSlice(dest, []*ScopeSpans{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyScopeSpansPtrSlice(dest, src) assert.Equal(t, GenTestScopeSpansPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONScopeSpansUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewScopeSpans() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewScopeSpans(), dest) } func TestMarshalAndUnmarshalJSONScopeSpans(t *testing.T) { for name, src := range genTestEncodingValuesScopeSpans() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewScopeSpans() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteScopeSpans(dest, true) }) } } } func TestMarshalAndUnmarshalProtoScopeSpansFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesScopeSpans() { t.Run(name, func(t *testing.T) { dest := NewScopeSpans() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoScopeSpansUnknown(t *testing.T) { dest := NewScopeSpans() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewScopeSpans(), dest) } func TestMarshalAndUnmarshalProtoScopeSpans(t *testing.T) { for name, src := range genTestEncodingValuesScopeSpans() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewScopeSpans() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteScopeSpans(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufScopeSpans(t *testing.T) { for name, src := range genTestEncodingValuesScopeSpans() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlptrace.ScopeSpans{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewScopeSpans() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesScopeSpans() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Scope/wrong_wire_type": {0xc}, "Scope/missing_value": {0xa}, "Spans/wrong_wire_type": {0x14}, "Spans/missing_value": {0x12}, "SchemaUrl/wrong_wire_type": {0x1c}, "SchemaUrl/missing_value": {0x1a}, } } func genTestEncodingValuesScopeSpans() map[string]*ScopeSpans { return map[string]*ScopeSpans{ "empty": NewScopeSpans(), "Scope/test": {Scope: *GenTestInstrumentationScope()}, "Spans/test": {Spans: []*Span{{}, GenTestSpan()}}, "SchemaUrl/test": {SchemaUrl: "test_schemaurl"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_span.go000066400000000000000000000446031511331344600262030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Span represents a single operation within a trace. // See Span definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto type Span struct { TraceId TraceID SpanId SpanID TraceState string ParentSpanId SpanID Flags uint32 Name string Kind SpanKind StartTimeUnixNano uint64 EndTimeUnixNano uint64 Attributes []KeyValue DroppedAttributesCount uint32 Events []*SpanEvent DroppedEventsCount uint32 Links []*SpanLink DroppedLinksCount uint32 Status Status } var ( protoPoolSpan = sync.Pool{ New: func() any { return &Span{} }, } ) func NewSpan() *Span { if !UseProtoPooling.IsEnabled() { return &Span{} } return protoPoolSpan.Get().(*Span) } func DeleteSpan(orig *Span, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteTraceID(&orig.TraceId, false) DeleteSpanID(&orig.SpanId, false) DeleteSpanID(&orig.ParentSpanId, false) for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } for i := range orig.Events { DeleteSpanEvent(orig.Events[i], true) } for i := range orig.Links { DeleteSpanLink(orig.Links[i], true) } DeleteStatus(&orig.Status, false) orig.Reset() if nullable { protoPoolSpan.Put(orig) } } func CopySpan(dest, src *Span) *Span { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSpan() } CopyTraceID(&dest.TraceId, &src.TraceId) CopySpanID(&dest.SpanId, &src.SpanId) dest.TraceState = src.TraceState CopySpanID(&dest.ParentSpanId, &src.ParentSpanId) dest.Flags = src.Flags dest.Name = src.Name dest.Kind = src.Kind dest.StartTimeUnixNano = src.StartTimeUnixNano dest.EndTimeUnixNano = src.EndTimeUnixNano dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.DroppedAttributesCount = src.DroppedAttributesCount dest.Events = CopySpanEventPtrSlice(dest.Events, src.Events) dest.DroppedEventsCount = src.DroppedEventsCount dest.Links = CopySpanLinkPtrSlice(dest.Links, src.Links) dest.DroppedLinksCount = src.DroppedLinksCount CopyStatus(&dest.Status, &src.Status) return dest } func CopySpanSlice(dest, src []Span) []Span { var newDest []Span if cap(dest) < len(src) { newDest = make([]Span, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpan(&dest[i], false) } } for i := range src { CopySpan(&newDest[i], &src[i]) } return newDest } func CopySpanPtrSlice(dest, src []*Span) []*Span { var newDest []*Span if cap(dest) < len(src) { newDest = make([]*Span, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpan() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpan(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpan() } } for i := range src { CopySpan(newDest[i], src[i]) } return newDest } func (orig *Span) Reset() { *orig = Span{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Span) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if !orig.TraceId.IsEmpty() { dest.WriteObjectField("traceId") orig.TraceId.MarshalJSON(dest) } if !orig.SpanId.IsEmpty() { dest.WriteObjectField("spanId") orig.SpanId.MarshalJSON(dest) } if orig.TraceState != "" { dest.WriteObjectField("traceState") dest.WriteString(orig.TraceState) } if !orig.ParentSpanId.IsEmpty() { dest.WriteObjectField("parentSpanId") orig.ParentSpanId.MarshalJSON(dest) } if orig.Flags != uint32(0) { dest.WriteObjectField("flags") dest.WriteUint32(orig.Flags) } if orig.Name != "" { dest.WriteObjectField("name") dest.WriteString(orig.Name) } if int32(orig.Kind) != 0 { dest.WriteObjectField("kind") dest.WriteInt32(int32(orig.Kind)) } if orig.StartTimeUnixNano != uint64(0) { dest.WriteObjectField("startTimeUnixNano") dest.WriteUint64(orig.StartTimeUnixNano) } if orig.EndTimeUnixNano != uint64(0) { dest.WriteObjectField("endTimeUnixNano") dest.WriteUint64(orig.EndTimeUnixNano) } if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedAttributesCount != uint32(0) { dest.WriteObjectField("droppedAttributesCount") dest.WriteUint32(orig.DroppedAttributesCount) } if len(orig.Events) > 0 { dest.WriteObjectField("events") dest.WriteArrayStart() orig.Events[0].MarshalJSON(dest) for i := 1; i < len(orig.Events); i++ { dest.WriteMore() orig.Events[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedEventsCount != uint32(0) { dest.WriteObjectField("droppedEventsCount") dest.WriteUint32(orig.DroppedEventsCount) } if len(orig.Links) > 0 { dest.WriteObjectField("links") dest.WriteArrayStart() orig.Links[0].MarshalJSON(dest) for i := 1; i < len(orig.Links); i++ { dest.WriteMore() orig.Links[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedLinksCount != uint32(0) { dest.WriteObjectField("droppedLinksCount") dest.WriteUint32(orig.DroppedLinksCount) } dest.WriteObjectField("status") orig.Status.MarshalJSON(dest) dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Span) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "traceId", "trace_id": orig.TraceId.UnmarshalJSON(iter) case "spanId", "span_id": orig.SpanId.UnmarshalJSON(iter) case "traceState", "trace_state": orig.TraceState = iter.ReadString() case "parentSpanId", "parent_span_id": orig.ParentSpanId.UnmarshalJSON(iter) case "flags": orig.Flags = iter.ReadUint32() case "name": orig.Name = iter.ReadString() case "kind": orig.Kind = SpanKind(iter.ReadEnumValue(SpanKind_value)) case "startTimeUnixNano", "start_time_unix_nano": orig.StartTimeUnixNano = iter.ReadUint64() case "endTimeUnixNano", "end_time_unix_nano": orig.EndTimeUnixNano = iter.ReadUint64() case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "droppedAttributesCount", "dropped_attributes_count": orig.DroppedAttributesCount = iter.ReadUint32() case "events": for iter.ReadArray() { orig.Events = append(orig.Events, NewSpanEvent()) orig.Events[len(orig.Events)-1].UnmarshalJSON(iter) } case "droppedEventsCount", "dropped_events_count": orig.DroppedEventsCount = iter.ReadUint32() case "links": for iter.ReadArray() { orig.Links = append(orig.Links, NewSpanLink()) orig.Links[len(orig.Links)-1].UnmarshalJSON(iter) } case "droppedLinksCount", "dropped_links_count": orig.DroppedLinksCount = iter.ReadUint32() case "status": orig.Status.UnmarshalJSON(iter) default: iter.Skip() } } } func (orig *Span) SizeProto() int { var n int var l int _ = l l = orig.TraceId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = orig.SpanId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = len(orig.TraceState) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = orig.ParentSpanId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.Flags != 0 { n += 6 } l = len(orig.Name) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } if orig.Kind != 0 { n += 1 + proto.Sov(uint64(orig.Kind)) } if orig.StartTimeUnixNano != 0 { n += 9 } if orig.EndTimeUnixNano != 0 { n += 9 } for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedAttributesCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedAttributesCount)) } for i := range orig.Events { l = orig.Events[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedEventsCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedEventsCount)) } for i := range orig.Links { l = orig.Links[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedLinksCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedLinksCount)) } l = orig.Status.SizeProto() n += 1 + proto.Sov(uint64(l)) + l return n } func (orig *Span) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.TraceId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa l = orig.SpanId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 l = len(orig.TraceState) if l > 0 { pos -= l copy(buf[pos:], orig.TraceState) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } l = orig.ParentSpanId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x22 if orig.Flags != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.Flags)) pos-- buf[pos] = 0x1 pos-- buf[pos] = 0x85 } l = len(orig.Name) if l > 0 { pos -= l copy(buf[pos:], orig.Name) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x2a } if orig.Kind != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Kind)) pos-- buf[pos] = 0x30 } if orig.StartTimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.StartTimeUnixNano)) pos-- buf[pos] = 0x39 } if orig.EndTimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.EndTimeUnixNano)) pos-- buf[pos] = 0x41 } for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x4a } if orig.DroppedAttributesCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedAttributesCount)) pos-- buf[pos] = 0x50 } for i := len(orig.Events) - 1; i >= 0; i-- { l = orig.Events[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x5a } if orig.DroppedEventsCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedEventsCount)) pos-- buf[pos] = 0x60 } for i := len(orig.Links) - 1; i >= 0; i-- { l = orig.Links[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x6a } if orig.DroppedLinksCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedLinksCount)) pos-- buf[pos] = 0x70 } l = orig.Status.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x7a return len(buf) - pos } func (orig *Span) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.TraceId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.SpanId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceState", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.TraceState = string(buf[startPos:pos]) case 4: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ParentSpanId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.ParentSpanId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 16: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.Flags = uint32(num) case 5: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Name = string(buf[startPos:pos]) case 6: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Kind", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Kind = SpanKind(num) case 7: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field StartTimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.StartTimeUnixNano = uint64(num) case 8: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field EndTimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.EndTimeUnixNano = uint64(num) case 9: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 10: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedAttributesCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedAttributesCount = uint32(num) case 11: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Events", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Events = append(orig.Events, NewSpanEvent()) err = orig.Events[len(orig.Events)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 12: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedEventsCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedEventsCount = uint32(num) case 13: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Links", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Links = append(orig.Links, NewSpanLink()) err = orig.Links[len(orig.Links)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 14: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedLinksCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedLinksCount = uint32(num) case 15: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Status", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.Status.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSpan() *Span { orig := NewSpan() orig.TraceId = *GenTestTraceID() orig.SpanId = *GenTestSpanID() orig.TraceState = "test_tracestate" orig.ParentSpanId = *GenTestSpanID() orig.Flags = uint32(13) orig.Name = "test_name" orig.Kind = SpanKind(13) orig.StartTimeUnixNano = uint64(13) orig.EndTimeUnixNano = uint64(13) orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.DroppedAttributesCount = uint32(13) orig.Events = []*SpanEvent{{}, GenTestSpanEvent()} orig.DroppedEventsCount = uint32(13) orig.Links = []*SpanLink{{}, GenTestSpanLink()} orig.DroppedLinksCount = uint32(13) orig.Status = *GenTestStatus() return orig } func GenTestSpanPtrSlice() []*Span { orig := make([]*Span, 5) orig[0] = NewSpan() orig[1] = GenTestSpan() orig[2] = NewSpan() orig[3] = GenTestSpan() orig[4] = NewSpan() return orig } func GenTestSpanSlice() []Span { orig := make([]Span, 5) orig[1] = *GenTestSpan() orig[3] = *GenTestSpan() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_span_test.go000066400000000000000000000202771511331344600272430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySpan(t *testing.T) { for name, src := range genTestEncodingValuesSpan() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSpan() CopySpan(dest, src) assert.Equal(t, src, dest) CopySpan(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySpanSlice(t *testing.T) { src := []Span{} dest := []Span{} // Test CopyTo empty dest = CopySpanSlice(dest, src) assert.Equal(t, []Span{}, dest) // Test CopyTo larger slice src = GenTestSpanSlice() dest = CopySpanSlice(dest, src) assert.Equal(t, GenTestSpanSlice(), dest) // Test CopyTo same size slice dest = CopySpanSlice(dest, src) assert.Equal(t, GenTestSpanSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanSlice(dest, []Span{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanSlice(dest, src) assert.Equal(t, GenTestSpanSlice(), dest) } func TestCopySpanPtrSlice(t *testing.T) { src := []*Span{} dest := []*Span{} // Test CopyTo empty dest = CopySpanPtrSlice(dest, src) assert.Equal(t, []*Span{}, dest) // Test CopyTo larger slice src = GenTestSpanPtrSlice() dest = CopySpanPtrSlice(dest, src) assert.Equal(t, GenTestSpanPtrSlice(), dest) // Test CopyTo same size slice dest = CopySpanPtrSlice(dest, src) assert.Equal(t, GenTestSpanPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanPtrSlice(dest, []*Span{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanPtrSlice(dest, src) assert.Equal(t, GenTestSpanPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSpanUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSpan() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSpan(), dest) } func TestMarshalAndUnmarshalJSONSpan(t *testing.T) { for name, src := range genTestEncodingValuesSpan() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSpan() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSpan(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSpanFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSpan() { t.Run(name, func(t *testing.T) { dest := NewSpan() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSpanUnknown(t *testing.T) { dest := NewSpan() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSpan(), dest) } func TestMarshalAndUnmarshalProtoSpan(t *testing.T) { for name, src := range genTestEncodingValuesSpan() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSpan() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSpan(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSpan(t *testing.T) { for name, src := range genTestEncodingValuesSpan() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlptrace.Span{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSpan() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSpan() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "TraceId/wrong_wire_type": {0xc}, "TraceId/missing_value": {0xa}, "SpanId/wrong_wire_type": {0x14}, "SpanId/missing_value": {0x12}, "TraceState/wrong_wire_type": {0x1c}, "TraceState/missing_value": {0x1a}, "ParentSpanId/wrong_wire_type": {0x24}, "ParentSpanId/missing_value": {0x22}, "Flags/wrong_wire_type": {0x84, 0x1}, "Flags/missing_value": {0x85, 0x1}, "Name/wrong_wire_type": {0x2c}, "Name/missing_value": {0x2a}, "Kind/wrong_wire_type": {0x34}, "Kind/missing_value": {0x30}, "StartTimeUnixNano/wrong_wire_type": {0x3c}, "StartTimeUnixNano/missing_value": {0x39}, "EndTimeUnixNano/wrong_wire_type": {0x44}, "EndTimeUnixNano/missing_value": {0x41}, "Attributes/wrong_wire_type": {0x4c}, "Attributes/missing_value": {0x4a}, "DroppedAttributesCount/wrong_wire_type": {0x54}, "DroppedAttributesCount/missing_value": {0x50}, "Events/wrong_wire_type": {0x5c}, "Events/missing_value": {0x5a}, "DroppedEventsCount/wrong_wire_type": {0x64}, "DroppedEventsCount/missing_value": {0x60}, "Links/wrong_wire_type": {0x6c}, "Links/missing_value": {0x6a}, "DroppedLinksCount/wrong_wire_type": {0x74}, "DroppedLinksCount/missing_value": {0x70}, "Status/wrong_wire_type": {0x7c}, "Status/missing_value": {0x7a}, } } func genTestEncodingValuesSpan() map[string]*Span { return map[string]*Span{ "empty": NewSpan(), "TraceId/test": {TraceId: *GenTestTraceID()}, "SpanId/test": {SpanId: *GenTestSpanID()}, "TraceState/test": {TraceState: "test_tracestate"}, "ParentSpanId/test": {ParentSpanId: *GenTestSpanID()}, "Flags/test": {Flags: uint32(13)}, "Name/test": {Name: "test_name"}, "Kind/test": {Kind: SpanKind(13)}, "StartTimeUnixNano/test": {StartTimeUnixNano: uint64(13)}, "EndTimeUnixNano/test": {EndTimeUnixNano: uint64(13)}, "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "DroppedAttributesCount/test": {DroppedAttributesCount: uint32(13)}, "Events/test": {Events: []*SpanEvent{{}, GenTestSpanEvent()}}, "DroppedEventsCount/test": {DroppedEventsCount: uint32(13)}, "Links/test": {Links: []*SpanLink{{}, GenTestSpanLink()}}, "DroppedLinksCount/test": {DroppedLinksCount: uint32(13)}, "Status/test": {Status: *GenTestStatus()}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_spancontext.go000066400000000000000000000175611511331344600276130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type SpanContext struct { TraceID TraceID SpanID SpanID TraceFlags uint32 TraceState string Remote bool } var ( protoPoolSpanContext = sync.Pool{ New: func() any { return &SpanContext{} }, } ) func NewSpanContext() *SpanContext { if !UseProtoPooling.IsEnabled() { return &SpanContext{} } return protoPoolSpanContext.Get().(*SpanContext) } func DeleteSpanContext(orig *SpanContext, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteTraceID(&orig.TraceID, false) DeleteSpanID(&orig.SpanID, false) orig.Reset() if nullable { protoPoolSpanContext.Put(orig) } } func CopySpanContext(dest, src *SpanContext) *SpanContext { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSpanContext() } CopyTraceID(&dest.TraceID, &src.TraceID) CopySpanID(&dest.SpanID, &src.SpanID) dest.TraceFlags = src.TraceFlags dest.TraceState = src.TraceState dest.Remote = src.Remote return dest } func CopySpanContextSlice(dest, src []SpanContext) []SpanContext { var newDest []SpanContext if cap(dest) < len(src) { newDest = make([]SpanContext, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpanContext(&dest[i], false) } } for i := range src { CopySpanContext(&newDest[i], &src[i]) } return newDest } func CopySpanContextPtrSlice(dest, src []*SpanContext) []*SpanContext { var newDest []*SpanContext if cap(dest) < len(src) { newDest = make([]*SpanContext, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpanContext() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpanContext(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpanContext() } } for i := range src { CopySpanContext(newDest[i], src[i]) } return newDest } func (orig *SpanContext) Reset() { *orig = SpanContext{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *SpanContext) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if !orig.TraceID.IsEmpty() { dest.WriteObjectField("traceID") orig.TraceID.MarshalJSON(dest) } if !orig.SpanID.IsEmpty() { dest.WriteObjectField("spanID") orig.SpanID.MarshalJSON(dest) } if orig.TraceFlags != uint32(0) { dest.WriteObjectField("traceFlags") dest.WriteUint32(orig.TraceFlags) } if orig.TraceState != "" { dest.WriteObjectField("traceState") dest.WriteString(orig.TraceState) } if orig.Remote != false { dest.WriteObjectField("remote") dest.WriteBool(orig.Remote) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *SpanContext) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "traceID", "trace_id": orig.TraceID.UnmarshalJSON(iter) case "spanID", "span_id": orig.SpanID.UnmarshalJSON(iter) case "traceFlags", "trace_flags": orig.TraceFlags = iter.ReadUint32() case "traceState", "trace_state": orig.TraceState = iter.ReadString() case "remote": orig.Remote = iter.ReadBool() default: iter.Skip() } } } func (orig *SpanContext) SizeProto() int { var n int var l int _ = l l = orig.TraceID.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = orig.SpanID.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.TraceFlags != 0 { n += 5 } l = len(orig.TraceState) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } if orig.Remote { n += 2 } return n } func (orig *SpanContext) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.TraceID.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa l = orig.SpanID.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 if orig.TraceFlags != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.TraceFlags)) pos-- buf[pos] = 0x1d } l = len(orig.TraceState) if l > 0 { pos -= l copy(buf[pos:], orig.TraceState) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x22 } if orig.Remote { pos-- if orig.Remote { buf[pos] = 1 } else { buf[pos] = 0 } pos-- buf[pos] = 0x28 } return len(buf) - pos } func (orig *SpanContext) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceID", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.TraceID.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SpanID", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.SpanID.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field TraceFlags", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.TraceFlags = uint32(num) case 4: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceState", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.TraceState = string(buf[startPos:pos]) case 5: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Remote", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Remote = num != 0 default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSpanContext() *SpanContext { orig := NewSpanContext() orig.TraceID = *GenTestTraceID() orig.SpanID = *GenTestSpanID() orig.TraceFlags = uint32(13) orig.TraceState = "test_tracestate" orig.Remote = true return orig } func GenTestSpanContextPtrSlice() []*SpanContext { orig := make([]*SpanContext, 5) orig[0] = NewSpanContext() orig[1] = GenTestSpanContext() orig[2] = NewSpanContext() orig[3] = GenTestSpanContext() orig[4] = NewSpanContext() return orig } func GenTestSpanContextSlice() []SpanContext { orig := make([]SpanContext, 5) orig[1] = *GenTestSpanContext() orig[3] = *GenTestSpanContext() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_spancontext_test.go000066400000000000000000000150031511331344600306370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySpanContext(t *testing.T) { for name, src := range genTestEncodingValuesSpanContext() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSpanContext() CopySpanContext(dest, src) assert.Equal(t, src, dest) CopySpanContext(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySpanContextSlice(t *testing.T) { src := []SpanContext{} dest := []SpanContext{} // Test CopyTo empty dest = CopySpanContextSlice(dest, src) assert.Equal(t, []SpanContext{}, dest) // Test CopyTo larger slice src = GenTestSpanContextSlice() dest = CopySpanContextSlice(dest, src) assert.Equal(t, GenTestSpanContextSlice(), dest) // Test CopyTo same size slice dest = CopySpanContextSlice(dest, src) assert.Equal(t, GenTestSpanContextSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanContextSlice(dest, []SpanContext{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanContextSlice(dest, src) assert.Equal(t, GenTestSpanContextSlice(), dest) } func TestCopySpanContextPtrSlice(t *testing.T) { src := []*SpanContext{} dest := []*SpanContext{} // Test CopyTo empty dest = CopySpanContextPtrSlice(dest, src) assert.Equal(t, []*SpanContext{}, dest) // Test CopyTo larger slice src = GenTestSpanContextPtrSlice() dest = CopySpanContextPtrSlice(dest, src) assert.Equal(t, GenTestSpanContextPtrSlice(), dest) // Test CopyTo same size slice dest = CopySpanContextPtrSlice(dest, src) assert.Equal(t, GenTestSpanContextPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanContextPtrSlice(dest, []*SpanContext{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanContextPtrSlice(dest, src) assert.Equal(t, GenTestSpanContextPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSpanContextUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSpanContext() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSpanContext(), dest) } func TestMarshalAndUnmarshalJSONSpanContext(t *testing.T) { for name, src := range genTestEncodingValuesSpanContext() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSpanContext() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSpanContext(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSpanContextFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSpanContext() { t.Run(name, func(t *testing.T) { dest := NewSpanContext() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSpanContextUnknown(t *testing.T) { dest := NewSpanContext() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSpanContext(), dest) } func TestMarshalAndUnmarshalProtoSpanContext(t *testing.T) { for name, src := range genTestEncodingValuesSpanContext() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSpanContext() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSpanContext(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSpanContext(t *testing.T) { for name, src := range genTestEncodingValuesSpanContext() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSpanContext() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSpanContext() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "TraceID/wrong_wire_type": {0xc}, "TraceID/missing_value": {0xa}, "SpanID/wrong_wire_type": {0x14}, "SpanID/missing_value": {0x12}, "TraceFlags/wrong_wire_type": {0x1c}, "TraceFlags/missing_value": {0x1d}, "TraceState/wrong_wire_type": {0x24}, "TraceState/missing_value": {0x22}, "Remote/wrong_wire_type": {0x2c}, "Remote/missing_value": {0x28}, } } func genTestEncodingValuesSpanContext() map[string]*SpanContext { return map[string]*SpanContext{ "empty": NewSpanContext(), "TraceID/test": {TraceID: *GenTestTraceID()}, "SpanID/test": {SpanID: *GenTestSpanID()}, "TraceFlags/test": {TraceFlags: uint32(13)}, "TraceState/test": {TraceState: "test_tracestate"}, "Remote/test": {Remote: true}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_spanevent.go000066400000000000000000000176451511331344600272530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // SpanEvent is a time-stamped annotation of the span, consisting of user-supplied // text description and key-value pairs. See OTLP for event definition. type SpanEvent struct { TimeUnixNano uint64 Name string Attributes []KeyValue DroppedAttributesCount uint32 } var ( protoPoolSpanEvent = sync.Pool{ New: func() any { return &SpanEvent{} }, } ) func NewSpanEvent() *SpanEvent { if !UseProtoPooling.IsEnabled() { return &SpanEvent{} } return protoPoolSpanEvent.Get().(*SpanEvent) } func DeleteSpanEvent(orig *SpanEvent, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } orig.Reset() if nullable { protoPoolSpanEvent.Put(orig) } } func CopySpanEvent(dest, src *SpanEvent) *SpanEvent { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSpanEvent() } dest.TimeUnixNano = src.TimeUnixNano dest.Name = src.Name dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.DroppedAttributesCount = src.DroppedAttributesCount return dest } func CopySpanEventSlice(dest, src []SpanEvent) []SpanEvent { var newDest []SpanEvent if cap(dest) < len(src) { newDest = make([]SpanEvent, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpanEvent(&dest[i], false) } } for i := range src { CopySpanEvent(&newDest[i], &src[i]) } return newDest } func CopySpanEventPtrSlice(dest, src []*SpanEvent) []*SpanEvent { var newDest []*SpanEvent if cap(dest) < len(src) { newDest = make([]*SpanEvent, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpanEvent() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpanEvent(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpanEvent() } } for i := range src { CopySpanEvent(newDest[i], src[i]) } return newDest } func (orig *SpanEvent) Reset() { *orig = SpanEvent{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *SpanEvent) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } if orig.Name != "" { dest.WriteObjectField("name") dest.WriteString(orig.Name) } if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedAttributesCount != uint32(0) { dest.WriteObjectField("droppedAttributesCount") dest.WriteUint32(orig.DroppedAttributesCount) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *SpanEvent) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "name": orig.Name = iter.ReadString() case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "droppedAttributesCount", "dropped_attributes_count": orig.DroppedAttributesCount = iter.ReadUint32() default: iter.Skip() } } } func (orig *SpanEvent) SizeProto() int { var n int var l int _ = l if orig.TimeUnixNano != 0 { n += 9 } l = len(orig.Name) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedAttributesCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedAttributesCount)) } return n } func (orig *SpanEvent) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x9 } l = len(orig.Name) if l > 0 { pos -= l copy(buf[pos:], orig.Name) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } if orig.DroppedAttributesCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedAttributesCount)) pos-- buf[pos] = 0x20 } return len(buf) - pos } func (orig *SpanEvent) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Name = string(buf[startPos:pos]) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 4: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedAttributesCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedAttributesCount = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSpanEvent() *SpanEvent { orig := NewSpanEvent() orig.TimeUnixNano = uint64(13) orig.Name = "test_name" orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.DroppedAttributesCount = uint32(13) return orig } func GenTestSpanEventPtrSlice() []*SpanEvent { orig := make([]*SpanEvent, 5) orig[0] = NewSpanEvent() orig[1] = GenTestSpanEvent() orig[2] = NewSpanEvent() orig[3] = GenTestSpanEvent() orig[4] = NewSpanEvent() return orig } func GenTestSpanEventSlice() []SpanEvent { orig := make([]SpanEvent, 5) orig[1] = *GenTestSpanEvent() orig[3] = *GenTestSpanEvent() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_spanevent_test.go000066400000000000000000000147511511331344600303050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySpanEvent(t *testing.T) { for name, src := range genTestEncodingValuesSpanEvent() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSpanEvent() CopySpanEvent(dest, src) assert.Equal(t, src, dest) CopySpanEvent(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySpanEventSlice(t *testing.T) { src := []SpanEvent{} dest := []SpanEvent{} // Test CopyTo empty dest = CopySpanEventSlice(dest, src) assert.Equal(t, []SpanEvent{}, dest) // Test CopyTo larger slice src = GenTestSpanEventSlice() dest = CopySpanEventSlice(dest, src) assert.Equal(t, GenTestSpanEventSlice(), dest) // Test CopyTo same size slice dest = CopySpanEventSlice(dest, src) assert.Equal(t, GenTestSpanEventSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanEventSlice(dest, []SpanEvent{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanEventSlice(dest, src) assert.Equal(t, GenTestSpanEventSlice(), dest) } func TestCopySpanEventPtrSlice(t *testing.T) { src := []*SpanEvent{} dest := []*SpanEvent{} // Test CopyTo empty dest = CopySpanEventPtrSlice(dest, src) assert.Equal(t, []*SpanEvent{}, dest) // Test CopyTo larger slice src = GenTestSpanEventPtrSlice() dest = CopySpanEventPtrSlice(dest, src) assert.Equal(t, GenTestSpanEventPtrSlice(), dest) // Test CopyTo same size slice dest = CopySpanEventPtrSlice(dest, src) assert.Equal(t, GenTestSpanEventPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanEventPtrSlice(dest, []*SpanEvent{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanEventPtrSlice(dest, src) assert.Equal(t, GenTestSpanEventPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSpanEventUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSpanEvent() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSpanEvent(), dest) } func TestMarshalAndUnmarshalJSONSpanEvent(t *testing.T) { for name, src := range genTestEncodingValuesSpanEvent() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSpanEvent() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSpanEvent(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSpanEventFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSpanEvent() { t.Run(name, func(t *testing.T) { dest := NewSpanEvent() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSpanEventUnknown(t *testing.T) { dest := NewSpanEvent() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSpanEvent(), dest) } func TestMarshalAndUnmarshalProtoSpanEvent(t *testing.T) { for name, src := range genTestEncodingValuesSpanEvent() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSpanEvent() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSpanEvent(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSpanEvent(t *testing.T) { for name, src := range genTestEncodingValuesSpanEvent() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlptrace.Span_Event{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSpanEvent() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSpanEvent() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "TimeUnixNano/wrong_wire_type": {0xc}, "TimeUnixNano/missing_value": {0x9}, "Name/wrong_wire_type": {0x14}, "Name/missing_value": {0x12}, "Attributes/wrong_wire_type": {0x1c}, "Attributes/missing_value": {0x1a}, "DroppedAttributesCount/wrong_wire_type": {0x24}, "DroppedAttributesCount/missing_value": {0x20}, } } func genTestEncodingValuesSpanEvent() map[string]*SpanEvent { return map[string]*SpanEvent{ "empty": NewSpanEvent(), "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "Name/test": {Name: "test_name"}, "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "DroppedAttributesCount/test": {DroppedAttributesCount: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_spanlink.go000066400000000000000000000231641511331344600270600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // SpanLink is a pointer from the current span to another span in the same trace or in a // different trace. // See Link definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto type SpanLink struct { TraceId TraceID SpanId SpanID TraceState string Attributes []KeyValue DroppedAttributesCount uint32 Flags uint32 } var ( protoPoolSpanLink = sync.Pool{ New: func() any { return &SpanLink{} }, } ) func NewSpanLink() *SpanLink { if !UseProtoPooling.IsEnabled() { return &SpanLink{} } return protoPoolSpanLink.Get().(*SpanLink) } func DeleteSpanLink(orig *SpanLink, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteTraceID(&orig.TraceId, false) DeleteSpanID(&orig.SpanId, false) for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } orig.Reset() if nullable { protoPoolSpanLink.Put(orig) } } func CopySpanLink(dest, src *SpanLink) *SpanLink { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSpanLink() } CopyTraceID(&dest.TraceId, &src.TraceId) CopySpanID(&dest.SpanId, &src.SpanId) dest.TraceState = src.TraceState dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.DroppedAttributesCount = src.DroppedAttributesCount dest.Flags = src.Flags return dest } func CopySpanLinkSlice(dest, src []SpanLink) []SpanLink { var newDest []SpanLink if cap(dest) < len(src) { newDest = make([]SpanLink, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpanLink(&dest[i], false) } } for i := range src { CopySpanLink(&newDest[i], &src[i]) } return newDest } func CopySpanLinkPtrSlice(dest, src []*SpanLink) []*SpanLink { var newDest []*SpanLink if cap(dest) < len(src) { newDest = make([]*SpanLink, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpanLink() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSpanLink(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSpanLink() } } for i := range src { CopySpanLink(newDest[i], src[i]) } return newDest } func (orig *SpanLink) Reset() { *orig = SpanLink{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *SpanLink) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if !orig.TraceId.IsEmpty() { dest.WriteObjectField("traceId") orig.TraceId.MarshalJSON(dest) } if !orig.SpanId.IsEmpty() { dest.WriteObjectField("spanId") orig.SpanId.MarshalJSON(dest) } if orig.TraceState != "" { dest.WriteObjectField("traceState") dest.WriteString(orig.TraceState) } if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.DroppedAttributesCount != uint32(0) { dest.WriteObjectField("droppedAttributesCount") dest.WriteUint32(orig.DroppedAttributesCount) } if orig.Flags != uint32(0) { dest.WriteObjectField("flags") dest.WriteUint32(orig.Flags) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *SpanLink) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "traceId", "trace_id": orig.TraceId.UnmarshalJSON(iter) case "spanId", "span_id": orig.SpanId.UnmarshalJSON(iter) case "traceState", "trace_state": orig.TraceState = iter.ReadString() case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "droppedAttributesCount", "dropped_attributes_count": orig.DroppedAttributesCount = iter.ReadUint32() case "flags": orig.Flags = iter.ReadUint32() default: iter.Skip() } } } func (orig *SpanLink) SizeProto() int { var n int var l int _ = l l = orig.TraceId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = orig.SpanId.SizeProto() n += 1 + proto.Sov(uint64(l)) + l l = len(orig.TraceState) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.DroppedAttributesCount != 0 { n += 1 + proto.Sov(uint64(orig.DroppedAttributesCount)) } if orig.Flags != 0 { n += 5 } return n } func (orig *SpanLink) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = orig.TraceId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa l = orig.SpanId.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 l = len(orig.TraceState) if l > 0 { pos -= l copy(buf[pos:], orig.TraceState) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x22 } if orig.DroppedAttributesCount != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.DroppedAttributesCount)) pos-- buf[pos] = 0x28 } if orig.Flags != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.Flags)) pos-- buf[pos] = 0x35 } return len(buf) - pos } func (orig *SpanLink) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.TraceId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field SpanId", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.SpanId.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TraceState", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.TraceState = string(buf[startPos:pos]) case 4: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 5: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field DroppedAttributesCount", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.DroppedAttributesCount = uint32(num) case 6: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.Flags = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSpanLink() *SpanLink { orig := NewSpanLink() orig.TraceId = *GenTestTraceID() orig.SpanId = *GenTestSpanID() orig.TraceState = "test_tracestate" orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.DroppedAttributesCount = uint32(13) orig.Flags = uint32(13) return orig } func GenTestSpanLinkPtrSlice() []*SpanLink { orig := make([]*SpanLink, 5) orig[0] = NewSpanLink() orig[1] = GenTestSpanLink() orig[2] = NewSpanLink() orig[3] = GenTestSpanLink() orig[4] = NewSpanLink() return orig } func GenTestSpanLinkSlice() []SpanLink { orig := make([]SpanLink, 5) orig[1] = *GenTestSpanLink() orig[3] = *GenTestSpanLink() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_spanlink_test.go000066400000000000000000000153771511331344600301260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySpanLink(t *testing.T) { for name, src := range genTestEncodingValuesSpanLink() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSpanLink() CopySpanLink(dest, src) assert.Equal(t, src, dest) CopySpanLink(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySpanLinkSlice(t *testing.T) { src := []SpanLink{} dest := []SpanLink{} // Test CopyTo empty dest = CopySpanLinkSlice(dest, src) assert.Equal(t, []SpanLink{}, dest) // Test CopyTo larger slice src = GenTestSpanLinkSlice() dest = CopySpanLinkSlice(dest, src) assert.Equal(t, GenTestSpanLinkSlice(), dest) // Test CopyTo same size slice dest = CopySpanLinkSlice(dest, src) assert.Equal(t, GenTestSpanLinkSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanLinkSlice(dest, []SpanLink{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanLinkSlice(dest, src) assert.Equal(t, GenTestSpanLinkSlice(), dest) } func TestCopySpanLinkPtrSlice(t *testing.T) { src := []*SpanLink{} dest := []*SpanLink{} // Test CopyTo empty dest = CopySpanLinkPtrSlice(dest, src) assert.Equal(t, []*SpanLink{}, dest) // Test CopyTo larger slice src = GenTestSpanLinkPtrSlice() dest = CopySpanLinkPtrSlice(dest, src) assert.Equal(t, GenTestSpanLinkPtrSlice(), dest) // Test CopyTo same size slice dest = CopySpanLinkPtrSlice(dest, src) assert.Equal(t, GenTestSpanLinkPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySpanLinkPtrSlice(dest, []*SpanLink{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySpanLinkPtrSlice(dest, src) assert.Equal(t, GenTestSpanLinkPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSpanLinkUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSpanLink() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSpanLink(), dest) } func TestMarshalAndUnmarshalJSONSpanLink(t *testing.T) { for name, src := range genTestEncodingValuesSpanLink() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSpanLink() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSpanLink(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSpanLinkFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSpanLink() { t.Run(name, func(t *testing.T) { dest := NewSpanLink() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSpanLinkUnknown(t *testing.T) { dest := NewSpanLink() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSpanLink(), dest) } func TestMarshalAndUnmarshalProtoSpanLink(t *testing.T) { for name, src := range genTestEncodingValuesSpanLink() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSpanLink() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSpanLink(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSpanLink(t *testing.T) { for name, src := range genTestEncodingValuesSpanLink() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlptrace.Span_Link{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSpanLink() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSpanLink() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "TraceId/wrong_wire_type": {0xc}, "TraceId/missing_value": {0xa}, "SpanId/wrong_wire_type": {0x14}, "SpanId/missing_value": {0x12}, "TraceState/wrong_wire_type": {0x1c}, "TraceState/missing_value": {0x1a}, "Attributes/wrong_wire_type": {0x24}, "Attributes/missing_value": {0x22}, "DroppedAttributesCount/wrong_wire_type": {0x2c}, "DroppedAttributesCount/missing_value": {0x28}, "Flags/wrong_wire_type": {0x34}, "Flags/missing_value": {0x35}, } } func genTestEncodingValuesSpanLink() map[string]*SpanLink { return map[string]*SpanLink{ "empty": NewSpanLink(), "TraceId/test": {TraceId: *GenTestTraceID()}, "SpanId/test": {SpanId: *GenTestSpanID()}, "TraceState/test": {TraceState: "test_tracestate"}, "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "DroppedAttributesCount/test": {DroppedAttributesCount: uint32(13)}, "Flags/test": {Flags: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_stack.go000066400000000000000000000132271511331344600263450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Stack represents a stack trace as a list of locations. type Stack struct { LocationIndices []int32 } var ( protoPoolStack = sync.Pool{ New: func() any { return &Stack{} }, } ) func NewStack() *Stack { if !UseProtoPooling.IsEnabled() { return &Stack{} } return protoPoolStack.Get().(*Stack) } func DeleteStack(orig *Stack, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolStack.Put(orig) } } func CopyStack(dest, src *Stack) *Stack { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewStack() } dest.LocationIndices = append(dest.LocationIndices[:0], src.LocationIndices...) return dest } func CopyStackSlice(dest, src []Stack) []Stack { var newDest []Stack if cap(dest) < len(src) { newDest = make([]Stack, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteStack(&dest[i], false) } } for i := range src { CopyStack(&newDest[i], &src[i]) } return newDest } func CopyStackPtrSlice(dest, src []*Stack) []*Stack { var newDest []*Stack if cap(dest) < len(src) { newDest = make([]*Stack, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewStack() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteStack(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewStack() } } for i := range src { CopyStack(newDest[i], src[i]) } return newDest } func (orig *Stack) Reset() { *orig = Stack{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Stack) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.LocationIndices) > 0 { dest.WriteObjectField("locationIndices") dest.WriteArrayStart() dest.WriteInt32(orig.LocationIndices[0]) for i := 1; i < len(orig.LocationIndices); i++ { dest.WriteMore() dest.WriteInt32(orig.LocationIndices[i]) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Stack) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "locationIndices", "location_indices": for iter.ReadArray() { orig.LocationIndices = append(orig.LocationIndices, iter.ReadInt32()) } default: iter.Skip() } } } func (orig *Stack) SizeProto() int { var n int var l int _ = l if len(orig.LocationIndices) > 0 { l = 0 for _, e := range orig.LocationIndices { l += proto.Sov(uint64(e)) } n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Stack) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.LocationIndices) if l > 0 { endPos := pos for i := l - 1; i >= 0; i-- { pos = proto.EncodeVarint(buf, pos, uint64(orig.LocationIndices[i])) } pos = proto.EncodeVarint(buf, pos, uint64(endPos-pos)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *Stack) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: switch wireType { case proto.WireTypeLen: var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length var num uint64 for startPos < pos { num, startPos, err = proto.ConsumeVarint(buf[:pos], startPos) if err != nil { return err } orig.LocationIndices = append(orig.LocationIndices, int32(num)) } if startPos != pos { return fmt.Errorf("proto: invalid field len = %d for field LocationIndices", pos-startPos) } case proto.WireTypeVarint: var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.LocationIndices = append(orig.LocationIndices, int32(num)) default: return fmt.Errorf("proto: wrong wireType = %d for field LocationIndices", wireType) } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestStack() *Stack { orig := NewStack() orig.LocationIndices = []int32{int32(0), int32(13)} return orig } func GenTestStackPtrSlice() []*Stack { orig := make([]*Stack, 5) orig[0] = NewStack() orig[1] = GenTestStack() orig[2] = NewStack() orig[3] = GenTestStack() orig[4] = NewStack() return orig } func GenTestStackSlice() []Stack { orig := make([]Stack, 5) orig[1] = *GenTestStack() orig[3] = *GenTestStack() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_stack_test.go000066400000000000000000000133721511331344600274050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyStack(t *testing.T) { for name, src := range genTestEncodingValuesStack() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewStack() CopyStack(dest, src) assert.Equal(t, src, dest) CopyStack(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyStackSlice(t *testing.T) { src := []Stack{} dest := []Stack{} // Test CopyTo empty dest = CopyStackSlice(dest, src) assert.Equal(t, []Stack{}, dest) // Test CopyTo larger slice src = GenTestStackSlice() dest = CopyStackSlice(dest, src) assert.Equal(t, GenTestStackSlice(), dest) // Test CopyTo same size slice dest = CopyStackSlice(dest, src) assert.Equal(t, GenTestStackSlice(), dest) // Test CopyTo smaller size slice dest = CopyStackSlice(dest, []Stack{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyStackSlice(dest, src) assert.Equal(t, GenTestStackSlice(), dest) } func TestCopyStackPtrSlice(t *testing.T) { src := []*Stack{} dest := []*Stack{} // Test CopyTo empty dest = CopyStackPtrSlice(dest, src) assert.Equal(t, []*Stack{}, dest) // Test CopyTo larger slice src = GenTestStackPtrSlice() dest = CopyStackPtrSlice(dest, src) assert.Equal(t, GenTestStackPtrSlice(), dest) // Test CopyTo same size slice dest = CopyStackPtrSlice(dest, src) assert.Equal(t, GenTestStackPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyStackPtrSlice(dest, []*Stack{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyStackPtrSlice(dest, src) assert.Equal(t, GenTestStackPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONStackUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewStack() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewStack(), dest) } func TestMarshalAndUnmarshalJSONStack(t *testing.T) { for name, src := range genTestEncodingValuesStack() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewStack() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteStack(dest, true) }) } } } func TestMarshalAndUnmarshalProtoStackFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesStack() { t.Run(name, func(t *testing.T) { dest := NewStack() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoStackUnknown(t *testing.T) { dest := NewStack() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewStack(), dest) } func TestMarshalAndUnmarshalProtoStack(t *testing.T) { for name, src := range genTestEncodingValuesStack() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewStack() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteStack(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufStack(t *testing.T) { for name, src := range genTestEncodingValuesStack() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.Stack{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewStack() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesStack() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "LocationIndices/wrong_wire_type": {0xc}, "LocationIndices/missing_value": {0xa}, } } func genTestEncodingValuesStack() map[string]*Stack { return map[string]*Stack{ "empty": NewStack(), "LocationIndices/test": {LocationIndices: []int32{int32(0), int32(13)}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_status.go000066400000000000000000000126251511331344600265640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Status is an optional final status for this span. Semantically, when Status was not // set, that means the span ended without errors and to assume Status.Ok (code = 0). type Status struct { Message string Code StatusCode } var ( protoPoolStatus = sync.Pool{ New: func() any { return &Status{} }, } ) func NewStatus() *Status { if !UseProtoPooling.IsEnabled() { return &Status{} } return protoPoolStatus.Get().(*Status) } func DeleteStatus(orig *Status, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolStatus.Put(orig) } } func CopyStatus(dest, src *Status) *Status { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewStatus() } dest.Message = src.Message dest.Code = src.Code return dest } func CopyStatusSlice(dest, src []Status) []Status { var newDest []Status if cap(dest) < len(src) { newDest = make([]Status, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteStatus(&dest[i], false) } } for i := range src { CopyStatus(&newDest[i], &src[i]) } return newDest } func CopyStatusPtrSlice(dest, src []*Status) []*Status { var newDest []*Status if cap(dest) < len(src) { newDest = make([]*Status, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewStatus() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteStatus(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewStatus() } } for i := range src { CopyStatus(newDest[i], src[i]) } return newDest } func (orig *Status) Reset() { *orig = Status{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Status) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.Message != "" { dest.WriteObjectField("message") dest.WriteString(orig.Message) } if int32(orig.Code) != 0 { dest.WriteObjectField("code") dest.WriteInt32(int32(orig.Code)) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Status) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "message": orig.Message = iter.ReadString() case "code": orig.Code = StatusCode(iter.ReadEnumValue(StatusCode_value)) default: iter.Skip() } } } func (orig *Status) SizeProto() int { var n int var l int _ = l l = len(orig.Message) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } if orig.Code != 0 { n += 1 + proto.Sov(uint64(orig.Code)) } return n } func (orig *Status) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.Message) if l > 0 { pos -= l copy(buf[pos:], orig.Message) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } if orig.Code != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Code)) pos-- buf[pos] = 0x18 } return len(buf) - pos } func (orig *Status) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Message", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Message = string(buf[startPos:pos]) case 3: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Code", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Code = StatusCode(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestStatus() *Status { orig := NewStatus() orig.Message = "test_message" orig.Code = StatusCode(13) return orig } func GenTestStatusPtrSlice() []*Status { orig := make([]*Status, 5) orig[0] = NewStatus() orig[1] = GenTestStatus() orig[2] = NewStatus() orig[3] = GenTestStatus() orig[4] = NewStatus() return orig } func GenTestStatusSlice() []Status { orig := make([]Status, 5) orig[1] = *GenTestStatus() orig[3] = *GenTestStatus() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_status_test.go000066400000000000000000000135311511331344600276200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyStatus(t *testing.T) { for name, src := range genTestEncodingValuesStatus() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewStatus() CopyStatus(dest, src) assert.Equal(t, src, dest) CopyStatus(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyStatusSlice(t *testing.T) { src := []Status{} dest := []Status{} // Test CopyTo empty dest = CopyStatusSlice(dest, src) assert.Equal(t, []Status{}, dest) // Test CopyTo larger slice src = GenTestStatusSlice() dest = CopyStatusSlice(dest, src) assert.Equal(t, GenTestStatusSlice(), dest) // Test CopyTo same size slice dest = CopyStatusSlice(dest, src) assert.Equal(t, GenTestStatusSlice(), dest) // Test CopyTo smaller size slice dest = CopyStatusSlice(dest, []Status{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyStatusSlice(dest, src) assert.Equal(t, GenTestStatusSlice(), dest) } func TestCopyStatusPtrSlice(t *testing.T) { src := []*Status{} dest := []*Status{} // Test CopyTo empty dest = CopyStatusPtrSlice(dest, src) assert.Equal(t, []*Status{}, dest) // Test CopyTo larger slice src = GenTestStatusPtrSlice() dest = CopyStatusPtrSlice(dest, src) assert.Equal(t, GenTestStatusPtrSlice(), dest) // Test CopyTo same size slice dest = CopyStatusPtrSlice(dest, src) assert.Equal(t, GenTestStatusPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyStatusPtrSlice(dest, []*Status{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyStatusPtrSlice(dest, src) assert.Equal(t, GenTestStatusPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONStatusUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewStatus() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewStatus(), dest) } func TestMarshalAndUnmarshalJSONStatus(t *testing.T) { for name, src := range genTestEncodingValuesStatus() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewStatus() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteStatus(dest, true) }) } } } func TestMarshalAndUnmarshalProtoStatusFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesStatus() { t.Run(name, func(t *testing.T) { dest := NewStatus() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoStatusUnknown(t *testing.T) { dest := NewStatus() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewStatus(), dest) } func TestMarshalAndUnmarshalProtoStatus(t *testing.T) { for name, src := range genTestEncodingValuesStatus() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewStatus() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteStatus(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufStatus(t *testing.T) { for name, src := range genTestEncodingValuesStatus() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlptrace.Status{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewStatus() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesStatus() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Message/wrong_wire_type": {0x14}, "Message/missing_value": {0x12}, "Code/wrong_wire_type": {0x1c}, "Code/missing_value": {0x18}, } } func genTestEncodingValuesStatus() map[string]*Status { return map[string]*Status{ "empty": NewStatus(), "Message/test": {Message: "test_message"}, "Code/test": {Code: StatusCode(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_sum.go000066400000000000000000000157321511331344600260470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Sum represents the type of a numeric metric that is calculated as a sum of all reported measurements over a time interval. type Sum struct { DataPoints []*NumberDataPoint AggregationTemporality AggregationTemporality IsMonotonic bool } var ( protoPoolSum = sync.Pool{ New: func() any { return &Sum{} }, } ) func NewSum() *Sum { if !UseProtoPooling.IsEnabled() { return &Sum{} } return protoPoolSum.Get().(*Sum) } func DeleteSum(orig *Sum, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.DataPoints { DeleteNumberDataPoint(orig.DataPoints[i], true) } orig.Reset() if nullable { protoPoolSum.Put(orig) } } func CopySum(dest, src *Sum) *Sum { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSum() } dest.DataPoints = CopyNumberDataPointPtrSlice(dest.DataPoints, src.DataPoints) dest.AggregationTemporality = src.AggregationTemporality dest.IsMonotonic = src.IsMonotonic return dest } func CopySumSlice(dest, src []Sum) []Sum { var newDest []Sum if cap(dest) < len(src) { newDest = make([]Sum, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSum(&dest[i], false) } } for i := range src { CopySum(&newDest[i], &src[i]) } return newDest } func CopySumPtrSlice(dest, src []*Sum) []*Sum { var newDest []*Sum if cap(dest) < len(src) { newDest = make([]*Sum, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSum() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSum(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSum() } } for i := range src { CopySum(newDest[i], src[i]) } return newDest } func (orig *Sum) Reset() { *orig = Sum{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Sum) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.DataPoints) > 0 { dest.WriteObjectField("dataPoints") dest.WriteArrayStart() orig.DataPoints[0].MarshalJSON(dest) for i := 1; i < len(orig.DataPoints); i++ { dest.WriteMore() orig.DataPoints[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if int32(orig.AggregationTemporality) != 0 { dest.WriteObjectField("aggregationTemporality") dest.WriteInt32(int32(orig.AggregationTemporality)) } if orig.IsMonotonic != false { dest.WriteObjectField("isMonotonic") dest.WriteBool(orig.IsMonotonic) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Sum) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "dataPoints", "data_points": for iter.ReadArray() { orig.DataPoints = append(orig.DataPoints, NewNumberDataPoint()) orig.DataPoints[len(orig.DataPoints)-1].UnmarshalJSON(iter) } case "aggregationTemporality", "aggregation_temporality": orig.AggregationTemporality = AggregationTemporality(iter.ReadEnumValue(AggregationTemporality_value)) case "isMonotonic", "is_monotonic": orig.IsMonotonic = iter.ReadBool() default: iter.Skip() } } } func (orig *Sum) SizeProto() int { var n int var l int _ = l for i := range orig.DataPoints { l = orig.DataPoints[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.AggregationTemporality != 0 { n += 1 + proto.Sov(uint64(orig.AggregationTemporality)) } if orig.IsMonotonic { n += 2 } return n } func (orig *Sum) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.DataPoints) - 1; i >= 0; i-- { l = orig.DataPoints[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } if orig.AggregationTemporality != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.AggregationTemporality)) pos-- buf[pos] = 0x10 } if orig.IsMonotonic { pos-- if orig.IsMonotonic { buf[pos] = 1 } else { buf[pos] = 0 } pos-- buf[pos] = 0x18 } return len(buf) - pos } func (orig *Sum) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DataPoints", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DataPoints = append(orig.DataPoints, NewNumberDataPoint()) err = orig.DataPoints[len(orig.DataPoints)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field AggregationTemporality", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.AggregationTemporality = AggregationTemporality(num) case 3: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field IsMonotonic", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.IsMonotonic = num != 0 default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSum() *Sum { orig := NewSum() orig.DataPoints = []*NumberDataPoint{{}, GenTestNumberDataPoint()} orig.AggregationTemporality = AggregationTemporality(13) orig.IsMonotonic = true return orig } func GenTestSumPtrSlice() []*Sum { orig := make([]*Sum, 5) orig[0] = NewSum() orig[1] = GenTestSum() orig[2] = NewSum() orig[3] = GenTestSum() orig[4] = NewSum() return orig } func GenTestSumSlice() []Sum { orig := make([]Sum, 5) orig[1] = *GenTestSum() orig[3] = *GenTestSum() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_sum_test.go000066400000000000000000000140051511331344600270760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySum(t *testing.T) { for name, src := range genTestEncodingValuesSum() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSum() CopySum(dest, src) assert.Equal(t, src, dest) CopySum(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySumSlice(t *testing.T) { src := []Sum{} dest := []Sum{} // Test CopyTo empty dest = CopySumSlice(dest, src) assert.Equal(t, []Sum{}, dest) // Test CopyTo larger slice src = GenTestSumSlice() dest = CopySumSlice(dest, src) assert.Equal(t, GenTestSumSlice(), dest) // Test CopyTo same size slice dest = CopySumSlice(dest, src) assert.Equal(t, GenTestSumSlice(), dest) // Test CopyTo smaller size slice dest = CopySumSlice(dest, []Sum{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySumSlice(dest, src) assert.Equal(t, GenTestSumSlice(), dest) } func TestCopySumPtrSlice(t *testing.T) { src := []*Sum{} dest := []*Sum{} // Test CopyTo empty dest = CopySumPtrSlice(dest, src) assert.Equal(t, []*Sum{}, dest) // Test CopyTo larger slice src = GenTestSumPtrSlice() dest = CopySumPtrSlice(dest, src) assert.Equal(t, GenTestSumPtrSlice(), dest) // Test CopyTo same size slice dest = CopySumPtrSlice(dest, src) assert.Equal(t, GenTestSumPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySumPtrSlice(dest, []*Sum{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySumPtrSlice(dest, src) assert.Equal(t, GenTestSumPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSumUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSum() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSum(), dest) } func TestMarshalAndUnmarshalJSONSum(t *testing.T) { for name, src := range genTestEncodingValuesSum() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSum() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSum(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSumFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSum() { t.Run(name, func(t *testing.T) { dest := NewSum() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSumUnknown(t *testing.T) { dest := NewSum() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSum(), dest) } func TestMarshalAndUnmarshalProtoSum(t *testing.T) { for name, src := range genTestEncodingValuesSum() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSum() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSum(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSum(t *testing.T) { for name, src := range genTestEncodingValuesSum() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.Sum{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSum() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSum() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "DataPoints/wrong_wire_type": {0xc}, "DataPoints/missing_value": {0xa}, "AggregationTemporality/wrong_wire_type": {0x14}, "AggregationTemporality/missing_value": {0x10}, "IsMonotonic/wrong_wire_type": {0x1c}, "IsMonotonic/missing_value": {0x18}, } } func genTestEncodingValuesSum() map[string]*Sum { return map[string]*Sum{ "empty": NewSum(), "DataPoints/test": {DataPoints: []*NumberDataPoint{{}, GenTestNumberDataPoint()}}, "AggregationTemporality/test": {AggregationTemporality: AggregationTemporality(13)}, "IsMonotonic/test": {IsMonotonic: true}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_summary.go000066400000000000000000000127341511331344600267370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // Summary represents the type of a metric that is calculated by aggregating as a Summary of all reported double measurements over a time interval. type Summary struct { DataPoints []*SummaryDataPoint } var ( protoPoolSummary = sync.Pool{ New: func() any { return &Summary{} }, } ) func NewSummary() *Summary { if !UseProtoPooling.IsEnabled() { return &Summary{} } return protoPoolSummary.Get().(*Summary) } func DeleteSummary(orig *Summary, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.DataPoints { DeleteSummaryDataPoint(orig.DataPoints[i], true) } orig.Reset() if nullable { protoPoolSummary.Put(orig) } } func CopySummary(dest, src *Summary) *Summary { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSummary() } dest.DataPoints = CopySummaryDataPointPtrSlice(dest.DataPoints, src.DataPoints) return dest } func CopySummarySlice(dest, src []Summary) []Summary { var newDest []Summary if cap(dest) < len(src) { newDest = make([]Summary, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSummary(&dest[i], false) } } for i := range src { CopySummary(&newDest[i], &src[i]) } return newDest } func CopySummaryPtrSlice(dest, src []*Summary) []*Summary { var newDest []*Summary if cap(dest) < len(src) { newDest = make([]*Summary, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSummary() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSummary(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSummary() } } for i := range src { CopySummary(newDest[i], src[i]) } return newDest } func (orig *Summary) Reset() { *orig = Summary{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *Summary) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.DataPoints) > 0 { dest.WriteObjectField("dataPoints") dest.WriteArrayStart() orig.DataPoints[0].MarshalJSON(dest) for i := 1; i < len(orig.DataPoints); i++ { dest.WriteMore() orig.DataPoints[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *Summary) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "dataPoints", "data_points": for iter.ReadArray() { orig.DataPoints = append(orig.DataPoints, NewSummaryDataPoint()) orig.DataPoints[len(orig.DataPoints)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *Summary) SizeProto() int { var n int var l int _ = l for i := range orig.DataPoints { l = orig.DataPoints[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *Summary) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.DataPoints) - 1; i >= 0; i-- { l = orig.DataPoints[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *Summary) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field DataPoints", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.DataPoints = append(orig.DataPoints, NewSummaryDataPoint()) err = orig.DataPoints[len(orig.DataPoints)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSummary() *Summary { orig := NewSummary() orig.DataPoints = []*SummaryDataPoint{{}, GenTestSummaryDataPoint()} return orig } func GenTestSummaryPtrSlice() []*Summary { orig := make([]*Summary, 5) orig[0] = NewSummary() orig[1] = GenTestSummary() orig[2] = NewSummary() orig[3] = GenTestSummary() orig[4] = NewSummary() return orig } func GenTestSummarySlice() []Summary { orig := make([]Summary, 5) orig[1] = *GenTestSummary() orig[3] = *GenTestSummary() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_summary_test.go000066400000000000000000000135321511331344600277730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySummary(t *testing.T) { for name, src := range genTestEncodingValuesSummary() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSummary() CopySummary(dest, src) assert.Equal(t, src, dest) CopySummary(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySummarySlice(t *testing.T) { src := []Summary{} dest := []Summary{} // Test CopyTo empty dest = CopySummarySlice(dest, src) assert.Equal(t, []Summary{}, dest) // Test CopyTo larger slice src = GenTestSummarySlice() dest = CopySummarySlice(dest, src) assert.Equal(t, GenTestSummarySlice(), dest) // Test CopyTo same size slice dest = CopySummarySlice(dest, src) assert.Equal(t, GenTestSummarySlice(), dest) // Test CopyTo smaller size slice dest = CopySummarySlice(dest, []Summary{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySummarySlice(dest, src) assert.Equal(t, GenTestSummarySlice(), dest) } func TestCopySummaryPtrSlice(t *testing.T) { src := []*Summary{} dest := []*Summary{} // Test CopyTo empty dest = CopySummaryPtrSlice(dest, src) assert.Equal(t, []*Summary{}, dest) // Test CopyTo larger slice src = GenTestSummaryPtrSlice() dest = CopySummaryPtrSlice(dest, src) assert.Equal(t, GenTestSummaryPtrSlice(), dest) // Test CopyTo same size slice dest = CopySummaryPtrSlice(dest, src) assert.Equal(t, GenTestSummaryPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySummaryPtrSlice(dest, []*Summary{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySummaryPtrSlice(dest, src) assert.Equal(t, GenTestSummaryPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSummaryUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSummary() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSummary(), dest) } func TestMarshalAndUnmarshalJSONSummary(t *testing.T) { for name, src := range genTestEncodingValuesSummary() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSummary() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSummary(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSummaryFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSummary() { t.Run(name, func(t *testing.T) { dest := NewSummary() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSummaryUnknown(t *testing.T) { dest := NewSummary() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSummary(), dest) } func TestMarshalAndUnmarshalProtoSummary(t *testing.T) { for name, src := range genTestEncodingValuesSummary() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSummary() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSummary(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSummary(t *testing.T) { for name, src := range genTestEncodingValuesSummary() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.Summary{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSummary() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSummary() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "DataPoints/wrong_wire_type": {0xc}, "DataPoints/missing_value": {0xa}, } } func genTestEncodingValuesSummary() map[string]*Summary { return map[string]*Summary{ "empty": NewSummary(), "DataPoints/test": {DataPoints: []*SummaryDataPoint{{}, GenTestSummaryDataPoint()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_summarydatapoint.go000066400000000000000000000260251511331344600306410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "math" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // SummaryDataPoint is a single data point in a timeseries that describes the time-varying values of a Summary of double values. type SummaryDataPoint struct { Attributes []KeyValue StartTimeUnixNano uint64 TimeUnixNano uint64 Count uint64 Sum float64 QuantileValues []*SummaryDataPointValueAtQuantile Flags uint32 } var ( protoPoolSummaryDataPoint = sync.Pool{ New: func() any { return &SummaryDataPoint{} }, } ) func NewSummaryDataPoint() *SummaryDataPoint { if !UseProtoPooling.IsEnabled() { return &SummaryDataPoint{} } return protoPoolSummaryDataPoint.Get().(*SummaryDataPoint) } func DeleteSummaryDataPoint(orig *SummaryDataPoint, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.Attributes { DeleteKeyValue(&orig.Attributes[i], false) } for i := range orig.QuantileValues { DeleteSummaryDataPointValueAtQuantile(orig.QuantileValues[i], true) } orig.Reset() if nullable { protoPoolSummaryDataPoint.Put(orig) } } func CopySummaryDataPoint(dest, src *SummaryDataPoint) *SummaryDataPoint { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSummaryDataPoint() } dest.Attributes = CopyKeyValueSlice(dest.Attributes, src.Attributes) dest.StartTimeUnixNano = src.StartTimeUnixNano dest.TimeUnixNano = src.TimeUnixNano dest.Count = src.Count dest.Sum = src.Sum dest.QuantileValues = CopySummaryDataPointValueAtQuantilePtrSlice(dest.QuantileValues, src.QuantileValues) dest.Flags = src.Flags return dest } func CopySummaryDataPointSlice(dest, src []SummaryDataPoint) []SummaryDataPoint { var newDest []SummaryDataPoint if cap(dest) < len(src) { newDest = make([]SummaryDataPoint, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSummaryDataPoint(&dest[i], false) } } for i := range src { CopySummaryDataPoint(&newDest[i], &src[i]) } return newDest } func CopySummaryDataPointPtrSlice(dest, src []*SummaryDataPoint) []*SummaryDataPoint { var newDest []*SummaryDataPoint if cap(dest) < len(src) { newDest = make([]*SummaryDataPoint, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSummaryDataPoint() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSummaryDataPoint(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSummaryDataPoint() } } for i := range src { CopySummaryDataPoint(newDest[i], src[i]) } return newDest } func (orig *SummaryDataPoint) Reset() { *orig = SummaryDataPoint{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *SummaryDataPoint) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.Attributes) > 0 { dest.WriteObjectField("attributes") dest.WriteArrayStart() orig.Attributes[0].MarshalJSON(dest) for i := 1; i < len(orig.Attributes); i++ { dest.WriteMore() orig.Attributes[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.StartTimeUnixNano != uint64(0) { dest.WriteObjectField("startTimeUnixNano") dest.WriteUint64(orig.StartTimeUnixNano) } if orig.TimeUnixNano != uint64(0) { dest.WriteObjectField("timeUnixNano") dest.WriteUint64(orig.TimeUnixNano) } if orig.Count != uint64(0) { dest.WriteObjectField("count") dest.WriteUint64(orig.Count) } if orig.Sum != float64(0) { dest.WriteObjectField("sum") dest.WriteFloat64(orig.Sum) } if len(orig.QuantileValues) > 0 { dest.WriteObjectField("quantileValues") dest.WriteArrayStart() orig.QuantileValues[0].MarshalJSON(dest) for i := 1; i < len(orig.QuantileValues); i++ { dest.WriteMore() orig.QuantileValues[i].MarshalJSON(dest) } dest.WriteArrayEnd() } if orig.Flags != uint32(0) { dest.WriteObjectField("flags") dest.WriteUint32(orig.Flags) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *SummaryDataPoint) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "attributes": for iter.ReadArray() { orig.Attributes = append(orig.Attributes, KeyValue{}) orig.Attributes[len(orig.Attributes)-1].UnmarshalJSON(iter) } case "startTimeUnixNano", "start_time_unix_nano": orig.StartTimeUnixNano = iter.ReadUint64() case "timeUnixNano", "time_unix_nano": orig.TimeUnixNano = iter.ReadUint64() case "count": orig.Count = iter.ReadUint64() case "sum": orig.Sum = iter.ReadFloat64() case "quantileValues", "quantile_values": for iter.ReadArray() { orig.QuantileValues = append(orig.QuantileValues, NewSummaryDataPointValueAtQuantile()) orig.QuantileValues[len(orig.QuantileValues)-1].UnmarshalJSON(iter) } case "flags": orig.Flags = iter.ReadUint32() default: iter.Skip() } } } func (orig *SummaryDataPoint) SizeProto() int { var n int var l int _ = l for i := range orig.Attributes { l = orig.Attributes[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.StartTimeUnixNano != 0 { n += 9 } if orig.TimeUnixNano != 0 { n += 9 } if orig.Count != 0 { n += 9 } if orig.Sum != 0 { n += 9 } for i := range orig.QuantileValues { l = orig.QuantileValues[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } if orig.Flags != 0 { n += 1 + proto.Sov(uint64(orig.Flags)) } return n } func (orig *SummaryDataPoint) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.Attributes) - 1; i >= 0; i-- { l = orig.Attributes[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x3a } if orig.StartTimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.StartTimeUnixNano)) pos-- buf[pos] = 0x11 } if orig.TimeUnixNano != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.TimeUnixNano)) pos-- buf[pos] = 0x19 } if orig.Count != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], uint64(orig.Count)) pos-- buf[pos] = 0x21 } if orig.Sum != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Sum)) pos-- buf[pos] = 0x29 } for i := len(orig.QuantileValues) - 1; i >= 0; i-- { l = orig.QuantileValues[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x32 } if orig.Flags != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Flags)) pos-- buf[pos] = 0x40 } return len(buf) - pos } func (orig *SummaryDataPoint) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 7: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Attributes", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Attributes = append(orig.Attributes, KeyValue{}) err = orig.Attributes[len(orig.Attributes)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 2: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field StartTimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.StartTimeUnixNano = uint64(num) case 3: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field TimeUnixNano", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.TimeUnixNano = uint64(num) case 4: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Count", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.Count = uint64(num) case 5: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Sum", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.Sum = math.Float64frombits(num) case 6: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field QuantileValues", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.QuantileValues = append(orig.QuantileValues, NewSummaryDataPointValueAtQuantile()) err = orig.QuantileValues[len(orig.QuantileValues)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 8: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Flags", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Flags = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSummaryDataPoint() *SummaryDataPoint { orig := NewSummaryDataPoint() orig.Attributes = []KeyValue{{}, *GenTestKeyValue()} orig.StartTimeUnixNano = uint64(13) orig.TimeUnixNano = uint64(13) orig.Count = uint64(13) orig.Sum = float64(3.1415926) orig.QuantileValues = []*SummaryDataPointValueAtQuantile{{}, GenTestSummaryDataPointValueAtQuantile()} orig.Flags = uint32(13) return orig } func GenTestSummaryDataPointPtrSlice() []*SummaryDataPoint { orig := make([]*SummaryDataPoint, 5) orig[0] = NewSummaryDataPoint() orig[1] = GenTestSummaryDataPoint() orig[2] = NewSummaryDataPoint() orig[3] = GenTestSummaryDataPoint() orig[4] = NewSummaryDataPoint() return orig } func GenTestSummaryDataPointSlice() []SummaryDataPoint { orig := make([]SummaryDataPoint, 5) orig[1] = *GenTestSummaryDataPoint() orig[3] = *GenTestSummaryDataPoint() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_summarydatapoint_test.go000066400000000000000000000165041511331344600317010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySummaryDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSummaryDataPoint() CopySummaryDataPoint(dest, src) assert.Equal(t, src, dest) CopySummaryDataPoint(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySummaryDataPointSlice(t *testing.T) { src := []SummaryDataPoint{} dest := []SummaryDataPoint{} // Test CopyTo empty dest = CopySummaryDataPointSlice(dest, src) assert.Equal(t, []SummaryDataPoint{}, dest) // Test CopyTo larger slice src = GenTestSummaryDataPointSlice() dest = CopySummaryDataPointSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointSlice(), dest) // Test CopyTo same size slice dest = CopySummaryDataPointSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointSlice(), dest) // Test CopyTo smaller size slice dest = CopySummaryDataPointSlice(dest, []SummaryDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySummaryDataPointSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointSlice(), dest) } func TestCopySummaryDataPointPtrSlice(t *testing.T) { src := []*SummaryDataPoint{} dest := []*SummaryDataPoint{} // Test CopyTo empty dest = CopySummaryDataPointPtrSlice(dest, src) assert.Equal(t, []*SummaryDataPoint{}, dest) // Test CopyTo larger slice src = GenTestSummaryDataPointPtrSlice() dest = CopySummaryDataPointPtrSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointPtrSlice(), dest) // Test CopyTo same size slice dest = CopySummaryDataPointPtrSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySummaryDataPointPtrSlice(dest, []*SummaryDataPoint{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySummaryDataPointPtrSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSummaryDataPointUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSummaryDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSummaryDataPoint(), dest) } func TestMarshalAndUnmarshalJSONSummaryDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSummaryDataPoint() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSummaryDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSummaryDataPointFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSummaryDataPoint() { t.Run(name, func(t *testing.T) { dest := NewSummaryDataPoint() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSummaryDataPointUnknown(t *testing.T) { dest := NewSummaryDataPoint() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSummaryDataPoint(), dest) } func TestMarshalAndUnmarshalProtoSummaryDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPoint() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSummaryDataPoint() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSummaryDataPoint(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSummaryDataPoint(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPoint() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.SummaryDataPoint{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSummaryDataPoint() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSummaryDataPoint() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Attributes/wrong_wire_type": {0x3c}, "Attributes/missing_value": {0x3a}, "StartTimeUnixNano/wrong_wire_type": {0x14}, "StartTimeUnixNano/missing_value": {0x11}, "TimeUnixNano/wrong_wire_type": {0x1c}, "TimeUnixNano/missing_value": {0x19}, "Count/wrong_wire_type": {0x24}, "Count/missing_value": {0x21}, "Sum/wrong_wire_type": {0x2c}, "Sum/missing_value": {0x29}, "QuantileValues/wrong_wire_type": {0x34}, "QuantileValues/missing_value": {0x32}, "Flags/wrong_wire_type": {0x44}, "Flags/missing_value": {0x40}, } } func genTestEncodingValuesSummaryDataPoint() map[string]*SummaryDataPoint { return map[string]*SummaryDataPoint{ "empty": NewSummaryDataPoint(), "Attributes/test": {Attributes: []KeyValue{{}, *GenTestKeyValue()}}, "StartTimeUnixNano/test": {StartTimeUnixNano: uint64(13)}, "TimeUnixNano/test": {TimeUnixNano: uint64(13)}, "Count/test": {Count: uint64(13)}, "Sum/test": {Sum: float64(3.1415926)}, "QuantileValues/test": {QuantileValues: []*SummaryDataPointValueAtQuantile{{}, GenTestSummaryDataPointValueAtQuantile()}}, "Flags/test": {Flags: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_summarydatapointvalueatquantile.go000066400000000000000000000151231511331344600337630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "math" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // SummaryDataPointValueAtQuantile is a quantile value within a Summary data point. type SummaryDataPointValueAtQuantile struct { Quantile float64 Value float64 } var ( protoPoolSummaryDataPointValueAtQuantile = sync.Pool{ New: func() any { return &SummaryDataPointValueAtQuantile{} }, } ) func NewSummaryDataPointValueAtQuantile() *SummaryDataPointValueAtQuantile { if !UseProtoPooling.IsEnabled() { return &SummaryDataPointValueAtQuantile{} } return protoPoolSummaryDataPointValueAtQuantile.Get().(*SummaryDataPointValueAtQuantile) } func DeleteSummaryDataPointValueAtQuantile(orig *SummaryDataPointValueAtQuantile, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolSummaryDataPointValueAtQuantile.Put(orig) } } func CopySummaryDataPointValueAtQuantile(dest, src *SummaryDataPointValueAtQuantile) *SummaryDataPointValueAtQuantile { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewSummaryDataPointValueAtQuantile() } dest.Quantile = src.Quantile dest.Value = src.Value return dest } func CopySummaryDataPointValueAtQuantileSlice(dest, src []SummaryDataPointValueAtQuantile) []SummaryDataPointValueAtQuantile { var newDest []SummaryDataPointValueAtQuantile if cap(dest) < len(src) { newDest = make([]SummaryDataPointValueAtQuantile, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSummaryDataPointValueAtQuantile(&dest[i], false) } } for i := range src { CopySummaryDataPointValueAtQuantile(&newDest[i], &src[i]) } return newDest } func CopySummaryDataPointValueAtQuantilePtrSlice(dest, src []*SummaryDataPointValueAtQuantile) []*SummaryDataPointValueAtQuantile { var newDest []*SummaryDataPointValueAtQuantile if cap(dest) < len(src) { newDest = make([]*SummaryDataPointValueAtQuantile, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewSummaryDataPointValueAtQuantile() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteSummaryDataPointValueAtQuantile(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewSummaryDataPointValueAtQuantile() } } for i := range src { CopySummaryDataPointValueAtQuantile(newDest[i], src[i]) } return newDest } func (orig *SummaryDataPointValueAtQuantile) Reset() { *orig = SummaryDataPointValueAtQuantile{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *SummaryDataPointValueAtQuantile) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.Quantile != float64(0) { dest.WriteObjectField("quantile") dest.WriteFloat64(orig.Quantile) } if orig.Value != float64(0) { dest.WriteObjectField("value") dest.WriteFloat64(orig.Value) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *SummaryDataPointValueAtQuantile) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "quantile": orig.Quantile = iter.ReadFloat64() case "value": orig.Value = iter.ReadFloat64() default: iter.Skip() } } } func (orig *SummaryDataPointValueAtQuantile) SizeProto() int { var n int var l int _ = l if orig.Quantile != 0 { n += 9 } if orig.Value != 0 { n += 9 } return n } func (orig *SummaryDataPointValueAtQuantile) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.Quantile != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Quantile)) pos-- buf[pos] = 0x9 } if orig.Value != 0 { pos -= 8 binary.LittleEndian.PutUint64(buf[pos:], math.Float64bits(orig.Value)) pos-- buf[pos] = 0x11 } return len(buf) - pos } func (orig *SummaryDataPointValueAtQuantile) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Quantile", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.Quantile = math.Float64frombits(num) case 2: if wireType != proto.WireTypeI64 { return fmt.Errorf("proto: wrong wireType = %d for field Value", wireType) } var num uint64 num, pos, err = proto.ConsumeI64(buf, pos) if err != nil { return err } orig.Value = math.Float64frombits(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestSummaryDataPointValueAtQuantile() *SummaryDataPointValueAtQuantile { orig := NewSummaryDataPointValueAtQuantile() orig.Quantile = float64(3.1415926) orig.Value = float64(3.1415926) return orig } func GenTestSummaryDataPointValueAtQuantilePtrSlice() []*SummaryDataPointValueAtQuantile { orig := make([]*SummaryDataPointValueAtQuantile, 5) orig[0] = NewSummaryDataPointValueAtQuantile() orig[1] = GenTestSummaryDataPointValueAtQuantile() orig[2] = NewSummaryDataPointValueAtQuantile() orig[3] = GenTestSummaryDataPointValueAtQuantile() orig[4] = NewSummaryDataPointValueAtQuantile() return orig } func GenTestSummaryDataPointValueAtQuantileSlice() []SummaryDataPointValueAtQuantile { orig := make([]SummaryDataPointValueAtQuantile, 5) orig[1] = *GenTestSummaryDataPointValueAtQuantile() orig[3] = *GenTestSummaryDataPointValueAtQuantile() return orig } generated_proto_summarydatapointvalueatquantile_test.go000066400000000000000000000164631511331344600347530ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopySummaryDataPointValueAtQuantile(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPointValueAtQuantile() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewSummaryDataPointValueAtQuantile() CopySummaryDataPointValueAtQuantile(dest, src) assert.Equal(t, src, dest) CopySummaryDataPointValueAtQuantile(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopySummaryDataPointValueAtQuantileSlice(t *testing.T) { src := []SummaryDataPointValueAtQuantile{} dest := []SummaryDataPointValueAtQuantile{} // Test CopyTo empty dest = CopySummaryDataPointValueAtQuantileSlice(dest, src) assert.Equal(t, []SummaryDataPointValueAtQuantile{}, dest) // Test CopyTo larger slice src = GenTestSummaryDataPointValueAtQuantileSlice() dest = CopySummaryDataPointValueAtQuantileSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointValueAtQuantileSlice(), dest) // Test CopyTo same size slice dest = CopySummaryDataPointValueAtQuantileSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointValueAtQuantileSlice(), dest) // Test CopyTo smaller size slice dest = CopySummaryDataPointValueAtQuantileSlice(dest, []SummaryDataPointValueAtQuantile{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySummaryDataPointValueAtQuantileSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointValueAtQuantileSlice(), dest) } func TestCopySummaryDataPointValueAtQuantilePtrSlice(t *testing.T) { src := []*SummaryDataPointValueAtQuantile{} dest := []*SummaryDataPointValueAtQuantile{} // Test CopyTo empty dest = CopySummaryDataPointValueAtQuantilePtrSlice(dest, src) assert.Equal(t, []*SummaryDataPointValueAtQuantile{}, dest) // Test CopyTo larger slice src = GenTestSummaryDataPointValueAtQuantilePtrSlice() dest = CopySummaryDataPointValueAtQuantilePtrSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointValueAtQuantilePtrSlice(), dest) // Test CopyTo same size slice dest = CopySummaryDataPointValueAtQuantilePtrSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointValueAtQuantilePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopySummaryDataPointValueAtQuantilePtrSlice(dest, []*SummaryDataPointValueAtQuantile{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopySummaryDataPointValueAtQuantilePtrSlice(dest, src) assert.Equal(t, GenTestSummaryDataPointValueAtQuantilePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONSummaryDataPointValueAtQuantileUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewSummaryDataPointValueAtQuantile() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewSummaryDataPointValueAtQuantile(), dest) } func TestMarshalAndUnmarshalJSONSummaryDataPointValueAtQuantile(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPointValueAtQuantile() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewSummaryDataPointValueAtQuantile() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteSummaryDataPointValueAtQuantile(dest, true) }) } } } func TestMarshalAndUnmarshalProtoSummaryDataPointValueAtQuantileFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesSummaryDataPointValueAtQuantile() { t.Run(name, func(t *testing.T) { dest := NewSummaryDataPointValueAtQuantile() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoSummaryDataPointValueAtQuantileUnknown(t *testing.T) { dest := NewSummaryDataPointValueAtQuantile() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewSummaryDataPointValueAtQuantile(), dest) } func TestMarshalAndUnmarshalProtoSummaryDataPointValueAtQuantile(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPointValueAtQuantile() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewSummaryDataPointValueAtQuantile() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteSummaryDataPointValueAtQuantile(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufSummaryDataPointValueAtQuantile(t *testing.T) { for name, src := range genTestEncodingValuesSummaryDataPointValueAtQuantile() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpmetrics.SummaryDataPoint_ValueAtQuantile{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewSummaryDataPointValueAtQuantile() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesSummaryDataPointValueAtQuantile() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Quantile/wrong_wire_type": {0xc}, "Quantile/missing_value": {0x9}, "Value/wrong_wire_type": {0x14}, "Value/missing_value": {0x11}, } } func genTestEncodingValuesSummaryDataPointValueAtQuantile() map[string]*SummaryDataPointValueAtQuantile { return map[string]*SummaryDataPointValueAtQuantile{ "empty": NewSummaryDataPointValueAtQuantile(), "Quantile/test": {Quantile: float64(3.1415926)}, "Value/test": {Value: float64(3.1415926)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_tcpaddr.go000066400000000000000000000136571511331344600266700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type TCPAddr struct { IP []byte Port int64 Zone string } var ( protoPoolTCPAddr = sync.Pool{ New: func() any { return &TCPAddr{} }, } ) func NewTCPAddr() *TCPAddr { if !UseProtoPooling.IsEnabled() { return &TCPAddr{} } return protoPoolTCPAddr.Get().(*TCPAddr) } func DeleteTCPAddr(orig *TCPAddr, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolTCPAddr.Put(orig) } } func CopyTCPAddr(dest, src *TCPAddr) *TCPAddr { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewTCPAddr() } dest.IP = src.IP dest.Port = src.Port dest.Zone = src.Zone return dest } func CopyTCPAddrSlice(dest, src []TCPAddr) []TCPAddr { var newDest []TCPAddr if cap(dest) < len(src) { newDest = make([]TCPAddr, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteTCPAddr(&dest[i], false) } } for i := range src { CopyTCPAddr(&newDest[i], &src[i]) } return newDest } func CopyTCPAddrPtrSlice(dest, src []*TCPAddr) []*TCPAddr { var newDest []*TCPAddr if cap(dest) < len(src) { newDest = make([]*TCPAddr, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewTCPAddr() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteTCPAddr(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewTCPAddr() } } for i := range src { CopyTCPAddr(newDest[i], src[i]) } return newDest } func (orig *TCPAddr) Reset() { *orig = TCPAddr{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *TCPAddr) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.IP) > 0 { dest.WriteObjectField("iP") dest.WriteBytes(orig.IP) } if orig.Port != int64(0) { dest.WriteObjectField("port") dest.WriteInt64(orig.Port) } if orig.Zone != "" { dest.WriteObjectField("zone") dest.WriteString(orig.Zone) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *TCPAddr) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "iP": orig.IP = iter.ReadBytes() case "port": orig.Port = iter.ReadInt64() case "zone": orig.Zone = iter.ReadString() default: iter.Skip() } } } func (orig *TCPAddr) SizeProto() int { var n int var l int _ = l l = len(orig.IP) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } if orig.Port != 0 { n += 1 + proto.Sov(uint64(orig.Port)) } l = len(orig.Zone) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *TCPAddr) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.IP) if l > 0 { pos -= l copy(buf[pos:], orig.IP) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } if orig.Port != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Port)) pos-- buf[pos] = 0x10 } l = len(orig.Zone) if l > 0 { pos -= l copy(buf[pos:], orig.Zone) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *TCPAddr) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field IP", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length if length != 0 { orig.IP = make([]byte, length) copy(orig.IP, buf[startPos:pos]) } case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Port", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Port = int64(num) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Zone", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Zone = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestTCPAddr() *TCPAddr { orig := NewTCPAddr() orig.IP = []byte{1, 2, 3} orig.Port = int64(13) orig.Zone = "test_zone" return orig } func GenTestTCPAddrPtrSlice() []*TCPAddr { orig := make([]*TCPAddr, 5) orig[0] = NewTCPAddr() orig[1] = GenTestTCPAddr() orig[2] = NewTCPAddr() orig[3] = GenTestTCPAddr() orig[4] = NewTCPAddr() return orig } func GenTestTCPAddrSlice() []TCPAddr { orig := make([]TCPAddr, 5) orig[1] = *GenTestTCPAddr() orig[3] = *GenTestTCPAddr() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_tcpaddr_test.go000066400000000000000000000137111511331344600277160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyTCPAddr(t *testing.T) { for name, src := range genTestEncodingValuesTCPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewTCPAddr() CopyTCPAddr(dest, src) assert.Equal(t, src, dest) CopyTCPAddr(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyTCPAddrSlice(t *testing.T) { src := []TCPAddr{} dest := []TCPAddr{} // Test CopyTo empty dest = CopyTCPAddrSlice(dest, src) assert.Equal(t, []TCPAddr{}, dest) // Test CopyTo larger slice src = GenTestTCPAddrSlice() dest = CopyTCPAddrSlice(dest, src) assert.Equal(t, GenTestTCPAddrSlice(), dest) // Test CopyTo same size slice dest = CopyTCPAddrSlice(dest, src) assert.Equal(t, GenTestTCPAddrSlice(), dest) // Test CopyTo smaller size slice dest = CopyTCPAddrSlice(dest, []TCPAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyTCPAddrSlice(dest, src) assert.Equal(t, GenTestTCPAddrSlice(), dest) } func TestCopyTCPAddrPtrSlice(t *testing.T) { src := []*TCPAddr{} dest := []*TCPAddr{} // Test CopyTo empty dest = CopyTCPAddrPtrSlice(dest, src) assert.Equal(t, []*TCPAddr{}, dest) // Test CopyTo larger slice src = GenTestTCPAddrPtrSlice() dest = CopyTCPAddrPtrSlice(dest, src) assert.Equal(t, GenTestTCPAddrPtrSlice(), dest) // Test CopyTo same size slice dest = CopyTCPAddrPtrSlice(dest, src) assert.Equal(t, GenTestTCPAddrPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyTCPAddrPtrSlice(dest, []*TCPAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyTCPAddrPtrSlice(dest, src) assert.Equal(t, GenTestTCPAddrPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONTCPAddrUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewTCPAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewTCPAddr(), dest) } func TestMarshalAndUnmarshalJSONTCPAddr(t *testing.T) { for name, src := range genTestEncodingValuesTCPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewTCPAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteTCPAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoTCPAddrFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesTCPAddr() { t.Run(name, func(t *testing.T) { dest := NewTCPAddr() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoTCPAddrUnknown(t *testing.T) { dest := NewTCPAddr() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewTCPAddr(), dest) } func TestMarshalAndUnmarshalProtoTCPAddr(t *testing.T) { for name, src := range genTestEncodingValuesTCPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewTCPAddr() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteTCPAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufTCPAddr(t *testing.T) { for name, src := range genTestEncodingValuesTCPAddr() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewTCPAddr() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesTCPAddr() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "IP/wrong_wire_type": {0xc}, "IP/missing_value": {0xa}, "Port/wrong_wire_type": {0x14}, "Port/missing_value": {0x10}, "Zone/wrong_wire_type": {0x1c}, "Zone/missing_value": {0x1a}, } } func genTestEncodingValuesTCPAddr() map[string]*TCPAddr { return map[string]*TCPAddr{ "empty": NewTCPAddr(), "IP/test": {IP: []byte{1, 2, 3}}, "Port/test": {Port: int64(13)}, "Zone/test": {Zone: "test_zone"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_tracesdata.go000066400000000000000000000133561511331344600273560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // TracesData represents the traces data that can be stored in a persistent storage, // OR can be embedded by other protocols that transfer OTLP traces data but do not // implement the OTLP protocol. type TracesData struct { ResourceSpans []*ResourceSpans } var ( protoPoolTracesData = sync.Pool{ New: func() any { return &TracesData{} }, } ) func NewTracesData() *TracesData { if !UseProtoPooling.IsEnabled() { return &TracesData{} } return protoPoolTracesData.Get().(*TracesData) } func DeleteTracesData(orig *TracesData, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } for i := range orig.ResourceSpans { DeleteResourceSpans(orig.ResourceSpans[i], true) } orig.Reset() if nullable { protoPoolTracesData.Put(orig) } } func CopyTracesData(dest, src *TracesData) *TracesData { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewTracesData() } dest.ResourceSpans = CopyResourceSpansPtrSlice(dest.ResourceSpans, src.ResourceSpans) return dest } func CopyTracesDataSlice(dest, src []TracesData) []TracesData { var newDest []TracesData if cap(dest) < len(src) { newDest = make([]TracesData, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteTracesData(&dest[i], false) } } for i := range src { CopyTracesData(&newDest[i], &src[i]) } return newDest } func CopyTracesDataPtrSlice(dest, src []*TracesData) []*TracesData { var newDest []*TracesData if cap(dest) < len(src) { newDest = make([]*TracesData, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewTracesData() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteTracesData(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewTracesData() } } for i := range src { CopyTracesData(newDest[i], src[i]) } return newDest } func (orig *TracesData) Reset() { *orig = TracesData{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *TracesData) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.ResourceSpans) > 0 { dest.WriteObjectField("resourceSpans") dest.WriteArrayStart() orig.ResourceSpans[0].MarshalJSON(dest) for i := 1; i < len(orig.ResourceSpans); i++ { dest.WriteMore() orig.ResourceSpans[i].MarshalJSON(dest) } dest.WriteArrayEnd() } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *TracesData) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "resourceSpans", "resource_spans": for iter.ReadArray() { orig.ResourceSpans = append(orig.ResourceSpans, NewResourceSpans()) orig.ResourceSpans[len(orig.ResourceSpans)-1].UnmarshalJSON(iter) } default: iter.Skip() } } } func (orig *TracesData) SizeProto() int { var n int var l int _ = l for i := range orig.ResourceSpans { l = orig.ResourceSpans[i].SizeProto() n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *TracesData) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l for i := len(orig.ResourceSpans) - 1; i >= 0; i-- { l = orig.ResourceSpans[i].MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } return len(buf) - pos } func (orig *TracesData) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field ResourceSpans", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.ResourceSpans = append(orig.ResourceSpans, NewResourceSpans()) err = orig.ResourceSpans[len(orig.ResourceSpans)-1].UnmarshalProto(buf[startPos:pos]) if err != nil { return err } default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestTracesData() *TracesData { orig := NewTracesData() orig.ResourceSpans = []*ResourceSpans{{}, GenTestResourceSpans()} return orig } func GenTestTracesDataPtrSlice() []*TracesData { orig := make([]*TracesData, 5) orig[0] = NewTracesData() orig[1] = GenTestTracesData() orig[2] = NewTracesData() orig[3] = GenTestTracesData() orig[4] = NewTracesData() return orig } func GenTestTracesDataSlice() []TracesData { orig := make([]TracesData, 5) orig[1] = *GenTestTracesData() orig[3] = *GenTestTracesData() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_tracesdata_test.go000066400000000000000000000140211511331344600304030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyTracesData(t *testing.T) { for name, src := range genTestEncodingValuesTracesData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewTracesData() CopyTracesData(dest, src) assert.Equal(t, src, dest) CopyTracesData(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyTracesDataSlice(t *testing.T) { src := []TracesData{} dest := []TracesData{} // Test CopyTo empty dest = CopyTracesDataSlice(dest, src) assert.Equal(t, []TracesData{}, dest) // Test CopyTo larger slice src = GenTestTracesDataSlice() dest = CopyTracesDataSlice(dest, src) assert.Equal(t, GenTestTracesDataSlice(), dest) // Test CopyTo same size slice dest = CopyTracesDataSlice(dest, src) assert.Equal(t, GenTestTracesDataSlice(), dest) // Test CopyTo smaller size slice dest = CopyTracesDataSlice(dest, []TracesData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyTracesDataSlice(dest, src) assert.Equal(t, GenTestTracesDataSlice(), dest) } func TestCopyTracesDataPtrSlice(t *testing.T) { src := []*TracesData{} dest := []*TracesData{} // Test CopyTo empty dest = CopyTracesDataPtrSlice(dest, src) assert.Equal(t, []*TracesData{}, dest) // Test CopyTo larger slice src = GenTestTracesDataPtrSlice() dest = CopyTracesDataPtrSlice(dest, src) assert.Equal(t, GenTestTracesDataPtrSlice(), dest) // Test CopyTo same size slice dest = CopyTracesDataPtrSlice(dest, src) assert.Equal(t, GenTestTracesDataPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyTracesDataPtrSlice(dest, []*TracesData{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyTracesDataPtrSlice(dest, src) assert.Equal(t, GenTestTracesDataPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONTracesDataUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewTracesData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewTracesData(), dest) } func TestMarshalAndUnmarshalJSONTracesData(t *testing.T) { for name, src := range genTestEncodingValuesTracesData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewTracesData() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteTracesData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoTracesDataFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesTracesData() { t.Run(name, func(t *testing.T) { dest := NewTracesData() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoTracesDataUnknown(t *testing.T) { dest := NewTracesData() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewTracesData(), dest) } func TestMarshalAndUnmarshalProtoTracesData(t *testing.T) { for name, src := range genTestEncodingValuesTracesData() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewTracesData() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteTracesData(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufTracesData(t *testing.T) { for name, src := range genTestEncodingValuesTracesData() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlptrace.TracesData{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewTracesData() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesTracesData() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "ResourceSpans/wrong_wire_type": {0xc}, "ResourceSpans/missing_value": {0xa}, } } func genTestEncodingValuesTracesData() map[string]*TracesData { return map[string]*TracesData{ "empty": NewTracesData(), "ResourceSpans/test": {ResourceSpans: []*ResourceSpans{{}, GenTestResourceSpans()}}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_tracesrequest.go000066400000000000000000000156711511331344600301370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "encoding/binary" "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type TracesRequest struct { RequestContext *RequestContext TracesData TracesData FormatVersion uint32 } var ( protoPoolTracesRequest = sync.Pool{ New: func() any { return &TracesRequest{} }, } ) func NewTracesRequest() *TracesRequest { if !UseProtoPooling.IsEnabled() { return &TracesRequest{} } return protoPoolTracesRequest.Get().(*TracesRequest) } func DeleteTracesRequest(orig *TracesRequest, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } DeleteRequestContext(orig.RequestContext, true) DeleteTracesData(&orig.TracesData, false) orig.Reset() if nullable { protoPoolTracesRequest.Put(orig) } } func CopyTracesRequest(dest, src *TracesRequest) *TracesRequest { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewTracesRequest() } dest.RequestContext = CopyRequestContext(dest.RequestContext, src.RequestContext) CopyTracesData(&dest.TracesData, &src.TracesData) dest.FormatVersion = src.FormatVersion return dest } func CopyTracesRequestSlice(dest, src []TracesRequest) []TracesRequest { var newDest []TracesRequest if cap(dest) < len(src) { newDest = make([]TracesRequest, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteTracesRequest(&dest[i], false) } } for i := range src { CopyTracesRequest(&newDest[i], &src[i]) } return newDest } func CopyTracesRequestPtrSlice(dest, src []*TracesRequest) []*TracesRequest { var newDest []*TracesRequest if cap(dest) < len(src) { newDest = make([]*TracesRequest, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewTracesRequest() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteTracesRequest(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewTracesRequest() } } for i := range src { CopyTracesRequest(newDest[i], src[i]) } return newDest } func (orig *TracesRequest) Reset() { *orig = TracesRequest{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *TracesRequest) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.RequestContext != nil { dest.WriteObjectField("requestContext") orig.RequestContext.MarshalJSON(dest) } dest.WriteObjectField("tracesData") orig.TracesData.MarshalJSON(dest) if orig.FormatVersion != uint32(0) { dest.WriteObjectField("formatVersion") dest.WriteUint32(orig.FormatVersion) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *TracesRequest) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "requestContext", "request_context": orig.RequestContext = NewRequestContext() orig.RequestContext.UnmarshalJSON(iter) case "tracesData", "traces_data": orig.TracesData.UnmarshalJSON(iter) case "formatVersion", "format_version": orig.FormatVersion = iter.ReadUint32() default: iter.Skip() } } } func (orig *TracesRequest) SizeProto() int { var n int var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.SizeProto() n += 1 + proto.Sov(uint64(l)) + l } l = orig.TracesData.SizeProto() n += 1 + proto.Sov(uint64(l)) + l if orig.FormatVersion != 0 { n += 5 } return n } func (orig *TracesRequest) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.RequestContext != nil { l = orig.RequestContext.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } l = orig.TracesData.MarshalProto(buf[:pos]) pos -= l pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a if orig.FormatVersion != 0 { pos -= 4 binary.LittleEndian.PutUint32(buf[pos:], uint32(orig.FormatVersion)) pos-- buf[pos] = 0xd } return len(buf) - pos } func (orig *TracesRequest) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field RequestContext", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.RequestContext = NewRequestContext() err = orig.RequestContext.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field TracesData", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length err = orig.TracesData.UnmarshalProto(buf[startPos:pos]) if err != nil { return err } case 1: if wireType != proto.WireTypeI32 { return fmt.Errorf("proto: wrong wireType = %d for field FormatVersion", wireType) } var num uint32 num, pos, err = proto.ConsumeI32(buf, pos) if err != nil { return err } orig.FormatVersion = uint32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestTracesRequest() *TracesRequest { orig := NewTracesRequest() orig.RequestContext = GenTestRequestContext() orig.TracesData = *GenTestTracesData() orig.FormatVersion = uint32(13) return orig } func GenTestTracesRequestPtrSlice() []*TracesRequest { orig := make([]*TracesRequest, 5) orig[0] = NewTracesRequest() orig[1] = GenTestTracesRequest() orig[2] = NewTracesRequest() orig[3] = GenTestTracesRequest() orig[4] = NewTracesRequest() return orig } func GenTestTracesRequestSlice() []TracesRequest { orig := make([]TracesRequest, 5) orig[1] = *GenTestTracesRequest() orig[3] = *GenTestTracesRequest() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_tracesrequest_test.go000066400000000000000000000147001511331344600311660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyTracesRequest(t *testing.T) { for name, src := range genTestEncodingValuesTracesRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewTracesRequest() CopyTracesRequest(dest, src) assert.Equal(t, src, dest) CopyTracesRequest(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyTracesRequestSlice(t *testing.T) { src := []TracesRequest{} dest := []TracesRequest{} // Test CopyTo empty dest = CopyTracesRequestSlice(dest, src) assert.Equal(t, []TracesRequest{}, dest) // Test CopyTo larger slice src = GenTestTracesRequestSlice() dest = CopyTracesRequestSlice(dest, src) assert.Equal(t, GenTestTracesRequestSlice(), dest) // Test CopyTo same size slice dest = CopyTracesRequestSlice(dest, src) assert.Equal(t, GenTestTracesRequestSlice(), dest) // Test CopyTo smaller size slice dest = CopyTracesRequestSlice(dest, []TracesRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyTracesRequestSlice(dest, src) assert.Equal(t, GenTestTracesRequestSlice(), dest) } func TestCopyTracesRequestPtrSlice(t *testing.T) { src := []*TracesRequest{} dest := []*TracesRequest{} // Test CopyTo empty dest = CopyTracesRequestPtrSlice(dest, src) assert.Equal(t, []*TracesRequest{}, dest) // Test CopyTo larger slice src = GenTestTracesRequestPtrSlice() dest = CopyTracesRequestPtrSlice(dest, src) assert.Equal(t, GenTestTracesRequestPtrSlice(), dest) // Test CopyTo same size slice dest = CopyTracesRequestPtrSlice(dest, src) assert.Equal(t, GenTestTracesRequestPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyTracesRequestPtrSlice(dest, []*TracesRequest{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyTracesRequestPtrSlice(dest, src) assert.Equal(t, GenTestTracesRequestPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONTracesRequestUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewTracesRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewTracesRequest(), dest) } func TestMarshalAndUnmarshalJSONTracesRequest(t *testing.T) { for name, src := range genTestEncodingValuesTracesRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewTracesRequest() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteTracesRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoTracesRequestFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesTracesRequest() { t.Run(name, func(t *testing.T) { dest := NewTracesRequest() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoTracesRequestUnknown(t *testing.T) { dest := NewTracesRequest() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewTracesRequest(), dest) } func TestMarshalAndUnmarshalProtoTracesRequest(t *testing.T) { for name, src := range genTestEncodingValuesTracesRequest() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewTracesRequest() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteTracesRequest(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufTracesRequest(t *testing.T) { for name, src := range genTestEncodingValuesTracesRequest() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewTracesRequest() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesTracesRequest() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "RequestContext/wrong_wire_type": {0x14}, "RequestContext/missing_value": {0x12}, "TracesData/wrong_wire_type": {0x1c}, "TracesData/missing_value": {0x1a}, "FormatVersion/wrong_wire_type": {0xc}, "FormatVersion/missing_value": {0xd}, } } func genTestEncodingValuesTracesRequest() map[string]*TracesRequest { return map[string]*TracesRequest{ "empty": NewTracesRequest(), "RequestContext/test": {RequestContext: GenTestRequestContext()}, "TracesData/test": {TracesData: *GenTestTracesData()}, "FormatVersion/test": {FormatVersion: uint32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_udpaddr.go000066400000000000000000000136571511331344600266720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type UDPAddr struct { IP []byte Port int64 Zone string } var ( protoPoolUDPAddr = sync.Pool{ New: func() any { return &UDPAddr{} }, } ) func NewUDPAddr() *UDPAddr { if !UseProtoPooling.IsEnabled() { return &UDPAddr{} } return protoPoolUDPAddr.Get().(*UDPAddr) } func DeleteUDPAddr(orig *UDPAddr, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolUDPAddr.Put(orig) } } func CopyUDPAddr(dest, src *UDPAddr) *UDPAddr { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewUDPAddr() } dest.IP = src.IP dest.Port = src.Port dest.Zone = src.Zone return dest } func CopyUDPAddrSlice(dest, src []UDPAddr) []UDPAddr { var newDest []UDPAddr if cap(dest) < len(src) { newDest = make([]UDPAddr, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteUDPAddr(&dest[i], false) } } for i := range src { CopyUDPAddr(&newDest[i], &src[i]) } return newDest } func CopyUDPAddrPtrSlice(dest, src []*UDPAddr) []*UDPAddr { var newDest []*UDPAddr if cap(dest) < len(src) { newDest = make([]*UDPAddr, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewUDPAddr() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteUDPAddr(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewUDPAddr() } } for i := range src { CopyUDPAddr(newDest[i], src[i]) } return newDest } func (orig *UDPAddr) Reset() { *orig = UDPAddr{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *UDPAddr) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if len(orig.IP) > 0 { dest.WriteObjectField("iP") dest.WriteBytes(orig.IP) } if orig.Port != int64(0) { dest.WriteObjectField("port") dest.WriteInt64(orig.Port) } if orig.Zone != "" { dest.WriteObjectField("zone") dest.WriteString(orig.Zone) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *UDPAddr) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "iP": orig.IP = iter.ReadBytes() case "port": orig.Port = iter.ReadInt64() case "zone": orig.Zone = iter.ReadString() default: iter.Skip() } } } func (orig *UDPAddr) SizeProto() int { var n int var l int _ = l l = len(orig.IP) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } if orig.Port != 0 { n += 1 + proto.Sov(uint64(orig.Port)) } l = len(orig.Zone) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *UDPAddr) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.IP) if l > 0 { pos -= l copy(buf[pos:], orig.IP) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } if orig.Port != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.Port)) pos-- buf[pos] = 0x10 } l = len(orig.Zone) if l > 0 { pos -= l copy(buf[pos:], orig.Zone) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x1a } return len(buf) - pos } func (orig *UDPAddr) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field IP", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length if length != 0 { orig.IP = make([]byte, length) copy(orig.IP, buf[startPos:pos]) } case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field Port", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.Port = int64(num) case 3: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Zone", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Zone = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestUDPAddr() *UDPAddr { orig := NewUDPAddr() orig.IP = []byte{1, 2, 3} orig.Port = int64(13) orig.Zone = "test_zone" return orig } func GenTestUDPAddrPtrSlice() []*UDPAddr { orig := make([]*UDPAddr, 5) orig[0] = NewUDPAddr() orig[1] = GenTestUDPAddr() orig[2] = NewUDPAddr() orig[3] = GenTestUDPAddr() orig[4] = NewUDPAddr() return orig } func GenTestUDPAddrSlice() []UDPAddr { orig := make([]UDPAddr, 5) orig[1] = *GenTestUDPAddr() orig[3] = *GenTestUDPAddr() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_udpaddr_test.go000066400000000000000000000137111511331344600277200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyUDPAddr(t *testing.T) { for name, src := range genTestEncodingValuesUDPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewUDPAddr() CopyUDPAddr(dest, src) assert.Equal(t, src, dest) CopyUDPAddr(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyUDPAddrSlice(t *testing.T) { src := []UDPAddr{} dest := []UDPAddr{} // Test CopyTo empty dest = CopyUDPAddrSlice(dest, src) assert.Equal(t, []UDPAddr{}, dest) // Test CopyTo larger slice src = GenTestUDPAddrSlice() dest = CopyUDPAddrSlice(dest, src) assert.Equal(t, GenTestUDPAddrSlice(), dest) // Test CopyTo same size slice dest = CopyUDPAddrSlice(dest, src) assert.Equal(t, GenTestUDPAddrSlice(), dest) // Test CopyTo smaller size slice dest = CopyUDPAddrSlice(dest, []UDPAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyUDPAddrSlice(dest, src) assert.Equal(t, GenTestUDPAddrSlice(), dest) } func TestCopyUDPAddrPtrSlice(t *testing.T) { src := []*UDPAddr{} dest := []*UDPAddr{} // Test CopyTo empty dest = CopyUDPAddrPtrSlice(dest, src) assert.Equal(t, []*UDPAddr{}, dest) // Test CopyTo larger slice src = GenTestUDPAddrPtrSlice() dest = CopyUDPAddrPtrSlice(dest, src) assert.Equal(t, GenTestUDPAddrPtrSlice(), dest) // Test CopyTo same size slice dest = CopyUDPAddrPtrSlice(dest, src) assert.Equal(t, GenTestUDPAddrPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyUDPAddrPtrSlice(dest, []*UDPAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyUDPAddrPtrSlice(dest, src) assert.Equal(t, GenTestUDPAddrPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONUDPAddrUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewUDPAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewUDPAddr(), dest) } func TestMarshalAndUnmarshalJSONUDPAddr(t *testing.T) { for name, src := range genTestEncodingValuesUDPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewUDPAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteUDPAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoUDPAddrFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesUDPAddr() { t.Run(name, func(t *testing.T) { dest := NewUDPAddr() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoUDPAddrUnknown(t *testing.T) { dest := NewUDPAddr() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewUDPAddr(), dest) } func TestMarshalAndUnmarshalProtoUDPAddr(t *testing.T) { for name, src := range genTestEncodingValuesUDPAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewUDPAddr() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteUDPAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufUDPAddr(t *testing.T) { for name, src := range genTestEncodingValuesUDPAddr() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewUDPAddr() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesUDPAddr() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "IP/wrong_wire_type": {0xc}, "IP/missing_value": {0xa}, "Port/wrong_wire_type": {0x14}, "Port/missing_value": {0x10}, "Zone/wrong_wire_type": {0x1c}, "Zone/missing_value": {0x1a}, } } func genTestEncodingValuesUDPAddr() map[string]*UDPAddr { return map[string]*UDPAddr{ "empty": NewUDPAddr(), "IP/test": {IP: []byte{1, 2, 3}}, "Port/test": {Port: int64(13)}, "Zone/test": {Zone: "test_zone"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_unixaddr.go000066400000000000000000000124671511331344600270630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) type UnixAddr struct { Name string Net string } var ( protoPoolUnixAddr = sync.Pool{ New: func() any { return &UnixAddr{} }, } ) func NewUnixAddr() *UnixAddr { if !UseProtoPooling.IsEnabled() { return &UnixAddr{} } return protoPoolUnixAddr.Get().(*UnixAddr) } func DeleteUnixAddr(orig *UnixAddr, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolUnixAddr.Put(orig) } } func CopyUnixAddr(dest, src *UnixAddr) *UnixAddr { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewUnixAddr() } dest.Name = src.Name dest.Net = src.Net return dest } func CopyUnixAddrSlice(dest, src []UnixAddr) []UnixAddr { var newDest []UnixAddr if cap(dest) < len(src) { newDest = make([]UnixAddr, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteUnixAddr(&dest[i], false) } } for i := range src { CopyUnixAddr(&newDest[i], &src[i]) } return newDest } func CopyUnixAddrPtrSlice(dest, src []*UnixAddr) []*UnixAddr { var newDest []*UnixAddr if cap(dest) < len(src) { newDest = make([]*UnixAddr, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewUnixAddr() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteUnixAddr(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewUnixAddr() } } for i := range src { CopyUnixAddr(newDest[i], src[i]) } return newDest } func (orig *UnixAddr) Reset() { *orig = UnixAddr{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *UnixAddr) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.Name != "" { dest.WriteObjectField("name") dest.WriteString(orig.Name) } if orig.Net != "" { dest.WriteObjectField("net") dest.WriteString(orig.Net) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *UnixAddr) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "name": orig.Name = iter.ReadString() case "net": orig.Net = iter.ReadString() default: iter.Skip() } } } func (orig *UnixAddr) SizeProto() int { var n int var l int _ = l l = len(orig.Name) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } l = len(orig.Net) if l > 0 { n += 1 + proto.Sov(uint64(l)) + l } return n } func (orig *UnixAddr) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l l = len(orig.Name) if l > 0 { pos -= l copy(buf[pos:], orig.Name) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0xa } l = len(orig.Net) if l > 0 { pos -= l copy(buf[pos:], orig.Net) pos = proto.EncodeVarint(buf, pos, uint64(l)) pos-- buf[pos] = 0x12 } return len(buf) - pos } func (orig *UnixAddr) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Name = string(buf[startPos:pos]) case 2: if wireType != proto.WireTypeLen { return fmt.Errorf("proto: wrong wireType = %d for field Net", wireType) } var length int length, pos, err = proto.ConsumeLen(buf, pos) if err != nil { return err } startPos := pos - length orig.Net = string(buf[startPos:pos]) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestUnixAddr() *UnixAddr { orig := NewUnixAddr() orig.Name = "test_name" orig.Net = "test_net" return orig } func GenTestUnixAddrPtrSlice() []*UnixAddr { orig := make([]*UnixAddr, 5) orig[0] = NewUnixAddr() orig[1] = GenTestUnixAddr() orig[2] = NewUnixAddr() orig[3] = GenTestUnixAddr() orig[4] = NewUnixAddr() return orig } func GenTestUnixAddrSlice() []UnixAddr { orig := make([]UnixAddr, 5) orig[1] = *GenTestUnixAddr() orig[3] = *GenTestUnixAddr() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_unixaddr_test.go000066400000000000000000000136311511331344600301140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/emptypb" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyUnixAddr(t *testing.T) { for name, src := range genTestEncodingValuesUnixAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewUnixAddr() CopyUnixAddr(dest, src) assert.Equal(t, src, dest) CopyUnixAddr(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyUnixAddrSlice(t *testing.T) { src := []UnixAddr{} dest := []UnixAddr{} // Test CopyTo empty dest = CopyUnixAddrSlice(dest, src) assert.Equal(t, []UnixAddr{}, dest) // Test CopyTo larger slice src = GenTestUnixAddrSlice() dest = CopyUnixAddrSlice(dest, src) assert.Equal(t, GenTestUnixAddrSlice(), dest) // Test CopyTo same size slice dest = CopyUnixAddrSlice(dest, src) assert.Equal(t, GenTestUnixAddrSlice(), dest) // Test CopyTo smaller size slice dest = CopyUnixAddrSlice(dest, []UnixAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyUnixAddrSlice(dest, src) assert.Equal(t, GenTestUnixAddrSlice(), dest) } func TestCopyUnixAddrPtrSlice(t *testing.T) { src := []*UnixAddr{} dest := []*UnixAddr{} // Test CopyTo empty dest = CopyUnixAddrPtrSlice(dest, src) assert.Equal(t, []*UnixAddr{}, dest) // Test CopyTo larger slice src = GenTestUnixAddrPtrSlice() dest = CopyUnixAddrPtrSlice(dest, src) assert.Equal(t, GenTestUnixAddrPtrSlice(), dest) // Test CopyTo same size slice dest = CopyUnixAddrPtrSlice(dest, src) assert.Equal(t, GenTestUnixAddrPtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyUnixAddrPtrSlice(dest, []*UnixAddr{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyUnixAddrPtrSlice(dest, src) assert.Equal(t, GenTestUnixAddrPtrSlice(), dest) } func TestMarshalAndUnmarshalJSONUnixAddrUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewUnixAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewUnixAddr(), dest) } func TestMarshalAndUnmarshalJSONUnixAddr(t *testing.T) { for name, src := range genTestEncodingValuesUnixAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewUnixAddr() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteUnixAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoUnixAddrFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesUnixAddr() { t.Run(name, func(t *testing.T) { dest := NewUnixAddr() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoUnixAddrUnknown(t *testing.T) { dest := NewUnixAddr() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewUnixAddr(), dest) } func TestMarshalAndUnmarshalProtoUnixAddr(t *testing.T) { for name, src := range genTestEncodingValuesUnixAddr() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewUnixAddr() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteUnixAddr(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufUnixAddr(t *testing.T) { for name, src := range genTestEncodingValuesUnixAddr() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &emptypb.Empty{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewUnixAddr() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesUnixAddr() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "Name/wrong_wire_type": {0xc}, "Name/missing_value": {0xa}, "Net/wrong_wire_type": {0x14}, "Net/missing_value": {0x12}, } } func genTestEncodingValuesUnixAddr() map[string]*UnixAddr { return map[string]*UnixAddr{ "empty": NewUnixAddr(), "Name/test": {Name: "test_name"}, "Net/test": {Net: "test_net"}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_valuetype.go000066400000000000000000000130231511331344600272500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "fmt" "sync" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/proto" ) // ValueType describes the type and units of a value. type ValueType struct { TypeStrindex int32 UnitStrindex int32 } var ( protoPoolValueType = sync.Pool{ New: func() any { return &ValueType{} }, } ) func NewValueType() *ValueType { if !UseProtoPooling.IsEnabled() { return &ValueType{} } return protoPoolValueType.Get().(*ValueType) } func DeleteValueType(orig *ValueType, nullable bool) { if orig == nil { return } if !UseProtoPooling.IsEnabled() { orig.Reset() return } orig.Reset() if nullable { protoPoolValueType.Put(orig) } } func CopyValueType(dest, src *ValueType) *ValueType { // If copying to same object, just return. if src == dest { return dest } if src == nil { return nil } if dest == nil { dest = NewValueType() } dest.TypeStrindex = src.TypeStrindex dest.UnitStrindex = src.UnitStrindex return dest } func CopyValueTypeSlice(dest, src []ValueType) []ValueType { var newDest []ValueType if cap(dest) < len(src) { newDest = make([]ValueType, len(src)) } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteValueType(&dest[i], false) } } for i := range src { CopyValueType(&newDest[i], &src[i]) } return newDest } func CopyValueTypePtrSlice(dest, src []*ValueType) []*ValueType { var newDest []*ValueType if cap(dest) < len(src) { newDest = make([]*ValueType, len(src)) // Copy old pointers to re-use. copy(newDest, dest) // Add new pointers for missing elements from len(dest) to len(srt). for i := len(dest); i < len(src); i++ { newDest[i] = NewValueType() } } else { newDest = dest[:len(src)] // Cleanup the rest of the elements so GC can free the memory. // This can happen when len(src) < len(dest) < cap(dest). for i := len(src); i < len(dest); i++ { DeleteValueType(dest[i], true) dest[i] = nil } // Add new pointers for missing elements. // This can happen when len(dest) < len(src) < cap(dest). for i := len(dest); i < len(src); i++ { newDest[i] = NewValueType() } } for i := range src { CopyValueType(newDest[i], src[i]) } return newDest } func (orig *ValueType) Reset() { *orig = ValueType{} } // MarshalJSON marshals all properties from the current struct to the destination stream. func (orig *ValueType) MarshalJSON(dest *json.Stream) { dest.WriteObjectStart() if orig.TypeStrindex != int32(0) { dest.WriteObjectField("typeStrindex") dest.WriteInt32(orig.TypeStrindex) } if orig.UnitStrindex != int32(0) { dest.WriteObjectField("unitStrindex") dest.WriteInt32(orig.UnitStrindex) } dest.WriteObjectEnd() } // UnmarshalJSON unmarshals all properties from the current struct from the source iterator. func (orig *ValueType) UnmarshalJSON(iter *json.Iterator) { for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { switch f { case "typeStrindex", "type_strindex": orig.TypeStrindex = iter.ReadInt32() case "unitStrindex", "unit_strindex": orig.UnitStrindex = iter.ReadInt32() default: iter.Skip() } } } func (orig *ValueType) SizeProto() int { var n int var l int _ = l if orig.TypeStrindex != 0 { n += 1 + proto.Sov(uint64(orig.TypeStrindex)) } if orig.UnitStrindex != 0 { n += 1 + proto.Sov(uint64(orig.UnitStrindex)) } return n } func (orig *ValueType) MarshalProto(buf []byte) int { pos := len(buf) var l int _ = l if orig.TypeStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.TypeStrindex)) pos-- buf[pos] = 0x8 } if orig.UnitStrindex != 0 { pos = proto.EncodeVarint(buf, pos, uint64(orig.UnitStrindex)) pos-- buf[pos] = 0x10 } return len(buf) - pos } func (orig *ValueType) UnmarshalProto(buf []byte) error { var err error var fieldNum int32 var wireType proto.WireType l := len(buf) pos := 0 for pos < l { // If in a group parsing, move to the next tag. fieldNum, wireType, pos, err = proto.ConsumeTag(buf, pos) if err != nil { return err } switch fieldNum { case 1: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field TypeStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.TypeStrindex = int32(num) case 2: if wireType != proto.WireTypeVarint { return fmt.Errorf("proto: wrong wireType = %d for field UnitStrindex", wireType) } var num uint64 num, pos, err = proto.ConsumeVarint(buf, pos) if err != nil { return err } orig.UnitStrindex = int32(num) default: pos, err = proto.ConsumeUnknown(buf, pos, wireType) if err != nil { return err } } } return nil } func GenTestValueType() *ValueType { orig := NewValueType() orig.TypeStrindex = int32(13) orig.UnitStrindex = int32(13) return orig } func GenTestValueTypePtrSlice() []*ValueType { orig := make([]*ValueType, 5) orig[0] = NewValueType() orig[1] = GenTestValueType() orig[2] = NewValueType() orig[3] = GenTestValueType() orig[4] = NewValueType() return orig } func GenTestValueTypeSlice() []ValueType { orig := make([]ValueType, 5) orig[1] = *GenTestValueType() orig[3] = *GenTestValueType() return orig } opentelemetry-collector-0.141.0/pdata/internal/generated_proto_valuetype_test.go000066400000000000000000000141071511331344600303130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestCopyValueType(t *testing.T) { for name, src := range genTestEncodingValuesValueType() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() dest := NewValueType() CopyValueType(dest, src) assert.Equal(t, src, dest) CopyValueType(dest, dest) assert.Equal(t, src, dest) }) } } } func TestCopyValueTypeSlice(t *testing.T) { src := []ValueType{} dest := []ValueType{} // Test CopyTo empty dest = CopyValueTypeSlice(dest, src) assert.Equal(t, []ValueType{}, dest) // Test CopyTo larger slice src = GenTestValueTypeSlice() dest = CopyValueTypeSlice(dest, src) assert.Equal(t, GenTestValueTypeSlice(), dest) // Test CopyTo same size slice dest = CopyValueTypeSlice(dest, src) assert.Equal(t, GenTestValueTypeSlice(), dest) // Test CopyTo smaller size slice dest = CopyValueTypeSlice(dest, []ValueType{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyValueTypeSlice(dest, src) assert.Equal(t, GenTestValueTypeSlice(), dest) } func TestCopyValueTypePtrSlice(t *testing.T) { src := []*ValueType{} dest := []*ValueType{} // Test CopyTo empty dest = CopyValueTypePtrSlice(dest, src) assert.Equal(t, []*ValueType{}, dest) // Test CopyTo larger slice src = GenTestValueTypePtrSlice() dest = CopyValueTypePtrSlice(dest, src) assert.Equal(t, GenTestValueTypePtrSlice(), dest) // Test CopyTo same size slice dest = CopyValueTypePtrSlice(dest, src) assert.Equal(t, GenTestValueTypePtrSlice(), dest) // Test CopyTo smaller size slice dest = CopyValueTypePtrSlice(dest, []*ValueType{}) assert.Len(t, dest, 0) // Test CopyTo larger slice with enough capacity dest = CopyValueTypePtrSlice(dest, src) assert.Equal(t, GenTestValueTypePtrSlice(), dest) } func TestMarshalAndUnmarshalJSONValueTypeUnknown(t *testing.T) { iter := json.BorrowIterator([]byte(`{"unknown": "string"}`)) defer json.ReturnIterator(iter) dest := NewValueType() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, NewValueType(), dest) } func TestMarshalAndUnmarshalJSONValueType(t *testing.T) { for name, src := range genTestEncodingValuesValueType() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := NewValueType() dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) DeleteValueType(dest, true) }) } } } func TestMarshalAndUnmarshalProtoValueTypeFailing(t *testing.T) { for name, buf := range genTestFailingUnmarshalProtoValuesValueType() { t.Run(name, func(t *testing.T) { dest := NewValueType() require.Error(t, dest.UnmarshalProto(buf)) }) } } func TestMarshalAndUnmarshalProtoValueTypeUnknown(t *testing.T) { dest := NewValueType() // message Test { required int64 field = 1313; } encoding { "field": "1234" } require.NoError(t, dest.UnmarshalProto([]byte{0x88, 0x52, 0xD2, 0x09})) assert.Equal(t, NewValueType(), dest) } func TestMarshalAndUnmarshalProtoValueType(t *testing.T) { for name, src := range genTestEncodingValuesValueType() { for _, pooling := range []bool{true, false} { t.Run(name+"/Pooling="+strconv.FormatBool(pooling), func(t *testing.T) { prevPooling := UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), pooling)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(UseProtoPooling.ID(), prevPooling)) }() buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) dest := NewValueType() require.NoError(t, dest.UnmarshalProto(buf)) assert.Equal(t, src, dest) DeleteValueType(dest, true) }) } } } func TestMarshalAndUnmarshalProtoViaProtobufValueType(t *testing.T) { for name, src := range genTestEncodingValuesValueType() { t.Run(name, func(t *testing.T) { buf := make([]byte, src.SizeProto()) gotSize := src.MarshalProto(buf) assert.Equal(t, len(buf), gotSize) goDest := &gootlpprofiles.ValueType{} require.NoError(t, proto.Unmarshal(buf, goDest)) goBuf, err := proto.Marshal(goDest) require.NoError(t, err) dest := NewValueType() require.NoError(t, dest.UnmarshalProto(goBuf)) assert.Equal(t, src, dest) }) } } func genTestFailingUnmarshalProtoValuesValueType() map[string][]byte { return map[string][]byte{ "invalid_field": {0x02}, "TypeStrindex/wrong_wire_type": {0xc}, "TypeStrindex/missing_value": {0x8}, "UnitStrindex/wrong_wire_type": {0x14}, "UnitStrindex/missing_value": {0x10}, } } func genTestEncodingValuesValueType() map[string]*ValueType { return map[string]*ValueType{ "empty": NewValueType(), "TypeStrindex/test": {TypeStrindex: int32(13)}, "UnitStrindex/test": {UnitStrindex: int32(13)}, } } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_anyvalueslice.go000066400000000000000000000012061511331344600304130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type SliceWrapper struct { orig *[]AnyValue state *State } func GetSliceOrig(ms SliceWrapper) *[]AnyValue { return ms.orig } func GetSliceState(ms SliceWrapper) *State { return ms.state } func NewSliceWrapper(orig *[]AnyValue, state *State) SliceWrapper { return SliceWrapper{orig: orig, state: state} } func GenTestSliceWrapper() SliceWrapper { orig := GenTestAnyValueSlice() return NewSliceWrapper(&orig, NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_byteslice.go000066400000000000000000000013331511331344600275330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type ByteSliceWrapper struct { orig *[]byte state *State } func GetByteSliceOrig(ms ByteSliceWrapper) *[]byte { return ms.orig } func GetByteSliceState(ms ByteSliceWrapper) *State { return ms.state } func NewByteSliceWrapper(orig *[]byte, state *State) ByteSliceWrapper { return ByteSliceWrapper{orig: orig, state: state} } func GenTestByteSliceWrapper() ByteSliceWrapper { orig := []byte{1, 2, 3} return NewByteSliceWrapper(&orig, NewState()) } func GenTestByteSlice() []byte { return []byte{1, 2, 3} } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_entityref.go000066400000000000000000000012341511331344600275610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type EntityRefWrapper struct { orig *EntityRef state *State } func GetEntityRefOrig(ms EntityRefWrapper) *EntityRef { return ms.orig } func GetEntityRefState(ms EntityRefWrapper) *State { return ms.state } func NewEntityRefWrapper(orig *EntityRef, state *State) EntityRefWrapper { return EntityRefWrapper{orig: orig, state: state} } func GenTestEntityRefWrapper() EntityRefWrapper { return NewEntityRefWrapper(GenTestEntityRef(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_entityrefslice.go000066400000000000000000000013631511331344600306040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type EntityRefSliceWrapper struct { orig *[]*EntityRef state *State } func GetEntityRefSliceOrig(ms EntityRefSliceWrapper) *[]*EntityRef { return ms.orig } func GetEntityRefSliceState(ms EntityRefSliceWrapper) *State { return ms.state } func NewEntityRefSliceWrapper(orig *[]*EntityRef, state *State) EntityRefSliceWrapper { return EntityRefSliceWrapper{orig: orig, state: state} } func GenTestEntityRefSliceWrapper() EntityRefSliceWrapper { orig := GenTestEntityRefPtrSlice() return NewEntityRefSliceWrapper(&orig, NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_exportlogsservicerequest.go000066400000000000000000000012411511331344600327460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type LogsWrapper struct { orig *ExportLogsServiceRequest state *State } func GetLogsOrig(ms LogsWrapper) *ExportLogsServiceRequest { return ms.orig } func GetLogsState(ms LogsWrapper) *State { return ms.state } func NewLogsWrapper(orig *ExportLogsServiceRequest, state *State) LogsWrapper { return LogsWrapper{orig: orig, state: state} } func GenTestLogsWrapper() LogsWrapper { return NewLogsWrapper(GenTestExportLogsServiceRequest(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_exportmetricsservicerequest.go000066400000000000000000000013161511331344600334530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type MetricsWrapper struct { orig *ExportMetricsServiceRequest state *State } func GetMetricsOrig(ms MetricsWrapper) *ExportMetricsServiceRequest { return ms.orig } func GetMetricsState(ms MetricsWrapper) *State { return ms.state } func NewMetricsWrapper(orig *ExportMetricsServiceRequest, state *State) MetricsWrapper { return MetricsWrapper{orig: orig, state: state} } func GenTestMetricsWrapper() MetricsWrapper { return NewMetricsWrapper(GenTestExportMetricsServiceRequest(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_exportprofilesservicerequest.go000066400000000000000000000013351511331344600336310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type ProfilesWrapper struct { orig *ExportProfilesServiceRequest state *State } func GetProfilesOrig(ms ProfilesWrapper) *ExportProfilesServiceRequest { return ms.orig } func GetProfilesState(ms ProfilesWrapper) *State { return ms.state } func NewProfilesWrapper(orig *ExportProfilesServiceRequest, state *State) ProfilesWrapper { return ProfilesWrapper{orig: orig, state: state} } func GenTestProfilesWrapper() ProfilesWrapper { return NewProfilesWrapper(GenTestExportProfilesServiceRequest(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_exporttraceservicerequest.go000066400000000000000000000012731511331344600331050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type TracesWrapper struct { orig *ExportTraceServiceRequest state *State } func GetTracesOrig(ms TracesWrapper) *ExportTraceServiceRequest { return ms.orig } func GetTracesState(ms TracesWrapper) *State { return ms.state } func NewTracesWrapper(orig *ExportTraceServiceRequest, state *State) TracesWrapper { return TracesWrapper{orig: orig, state: state} } func GenTestTracesWrapper() TracesWrapper { return NewTracesWrapper(GenTestExportTraceServiceRequest(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_float64slice.go000066400000000000000000000014351511331344600300520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type Float64SliceWrapper struct { orig *[]float64 state *State } func GetFloat64SliceOrig(ms Float64SliceWrapper) *[]float64 { return ms.orig } func GetFloat64SliceState(ms Float64SliceWrapper) *State { return ms.state } func NewFloat64SliceWrapper(orig *[]float64, state *State) Float64SliceWrapper { return Float64SliceWrapper{orig: orig, state: state} } func GenTestFloat64SliceWrapper() Float64SliceWrapper { orig := []float64{1.1, 2.2, 3.3} return NewFloat64SliceWrapper(&orig, NewState()) } func GenTestFloat64Slice() []float64 { return []float64{1.1, 2.2, 3.3} } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_instrumentationscope.go000066400000000000000000000015011511331344600320420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type InstrumentationScopeWrapper struct { orig *InstrumentationScope state *State } func GetInstrumentationScopeOrig(ms InstrumentationScopeWrapper) *InstrumentationScope { return ms.orig } func GetInstrumentationScopeState(ms InstrumentationScopeWrapper) *State { return ms.state } func NewInstrumentationScopeWrapper(orig *InstrumentationScope, state *State) InstrumentationScopeWrapper { return InstrumentationScopeWrapper{orig: orig, state: state} } func GenTestInstrumentationScopeWrapper() InstrumentationScopeWrapper { return NewInstrumentationScopeWrapper(GenTestInstrumentationScope(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_int32slice.go000066400000000000000000000013551511331344600275330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type Int32SliceWrapper struct { orig *[]int32 state *State } func GetInt32SliceOrig(ms Int32SliceWrapper) *[]int32 { return ms.orig } func GetInt32SliceState(ms Int32SliceWrapper) *State { return ms.state } func NewInt32SliceWrapper(orig *[]int32, state *State) Int32SliceWrapper { return Int32SliceWrapper{orig: orig, state: state} } func GenTestInt32SliceWrapper() Int32SliceWrapper { orig := []int32{1, 2, 3} return NewInt32SliceWrapper(&orig, NewState()) } func GenTestInt32Slice() []int32 { return []int32{1, 2, 3} } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_int64slice.go000066400000000000000000000013551511331344600275400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type Int64SliceWrapper struct { orig *[]int64 state *State } func GetInt64SliceOrig(ms Int64SliceWrapper) *[]int64 { return ms.orig } func GetInt64SliceState(ms Int64SliceWrapper) *State { return ms.state } func NewInt64SliceWrapper(orig *[]int64, state *State) Int64SliceWrapper { return Int64SliceWrapper{orig: orig, state: state} } func GenTestInt64SliceWrapper() Int64SliceWrapper { orig := []int64{1, 2, 3} return NewInt64SliceWrapper(&orig, NewState()) } func GenTestInt64Slice() []int64 { return []int64{1, 2, 3} } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_profilesdata.go000066400000000000000000000013111511331344600302210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type ProfilesDataWrapper struct { orig *ProfilesData state *State } func GetProfilesDataOrig(ms ProfilesDataWrapper) *ProfilesData { return ms.orig } func GetProfilesDataState(ms ProfilesDataWrapper) *State { return ms.state } func NewProfilesDataWrapper(orig *ProfilesData, state *State) ProfilesDataWrapper { return ProfilesDataWrapper{orig: orig, state: state} } func GenTestProfilesDataWrapper() ProfilesDataWrapper { return NewProfilesDataWrapper(GenTestProfilesData(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_resource.go000066400000000000000000000012151511331344600273760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type ResourceWrapper struct { orig *Resource state *State } func GetResourceOrig(ms ResourceWrapper) *Resource { return ms.orig } func GetResourceState(ms ResourceWrapper) *State { return ms.state } func NewResourceWrapper(orig *Resource, state *State) ResourceWrapper { return ResourceWrapper{orig: orig, state: state} } func GenTestResourceWrapper() ResourceWrapper { return NewResourceWrapper(GenTestResource(), NewState()) } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_stringslice.go000066400000000000000000000014131511331344600300750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type StringSliceWrapper struct { orig *[]string state *State } func GetStringSliceOrig(ms StringSliceWrapper) *[]string { return ms.orig } func GetStringSliceState(ms StringSliceWrapper) *State { return ms.state } func NewStringSliceWrapper(orig *[]string, state *State) StringSliceWrapper { return StringSliceWrapper{orig: orig, state: state} } func GenTestStringSliceWrapper() StringSliceWrapper { orig := []string{"a", "b", "c"} return NewStringSliceWrapper(&orig, NewState()) } func GenTestStringSlice() []string { return []string{"a", "b", "c"} } opentelemetry-collector-0.141.0/pdata/internal/generated_wrapper_uint64slice.go000066400000000000000000000013771511331344600277310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package internal type UInt64SliceWrapper struct { orig *[]uint64 state *State } func GetUInt64SliceOrig(ms UInt64SliceWrapper) *[]uint64 { return ms.orig } func GetUInt64SliceState(ms UInt64SliceWrapper) *State { return ms.state } func NewUInt64SliceWrapper(orig *[]uint64, state *State) UInt64SliceWrapper { return UInt64SliceWrapper{orig: orig, state: state} } func GenTestUInt64SliceWrapper() UInt64SliceWrapper { orig := []uint64{1, 2, 3} return NewUInt64SliceWrapper(&orig, NewState()) } func GenTestUint64Slice() []uint64 { return []uint64{1, 2, 3} } opentelemetry-collector-0.141.0/pdata/internal/json/000077500000000000000000000000001511331344600224145ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal/json/iterator.go000066400000000000000000000141511511331344600245760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package json // import "go.opentelemetry.io/collector/pdata/internal/json" import ( "encoding/base64" "strconv" jsoniter "github.com/json-iterator/go" ) func BorrowIterator(data []byte) *Iterator { return &Iterator{ delegate: jsoniter.ConfigFastest.BorrowIterator(data), } } func ReturnIterator(s *Iterator) { jsoniter.ConfigFastest.ReturnIterator(s.delegate) } type Iterator struct { delegate *jsoniter.Iterator } // ReadInt32 unmarshalls JSON data into an int32. Accepts both numbers and strings decimal. // See https://developers.google.com/protocol-buffers/docs/proto3#json. func (iter *Iterator) ReadInt32() int32 { switch iter.delegate.WhatIsNext() { case jsoniter.NumberValue: return iter.delegate.ReadInt32() case jsoniter.StringValue: val, err := strconv.ParseInt(iter.ReadString(), 10, 32) if err != nil { iter.ReportError("ReadInt32", err.Error()) return 0 } return int32(val) default: iter.ReportError("ReadInt32", "unsupported value type") return 0 } } // ReadUint32 unmarshalls JSON data into an uint32. Accepts both numbers and strings decimal. // See https://developers.google.com/protocol-buffers/docs/proto3#json. func (iter *Iterator) ReadUint32() uint32 { switch iter.delegate.WhatIsNext() { case jsoniter.NumberValue: return iter.delegate.ReadUint32() case jsoniter.StringValue: val, err := strconv.ParseUint(iter.ReadString(), 10, 32) if err != nil { iter.ReportError("ReadUint32", err.Error()) return 0 } return uint32(val) default: iter.ReportError("ReadUint32", "unsupported value type") return 0 } } // ReadInt64 unmarshalls JSON data into an int64. Accepts both numbers and strings decimal. // See https://developers.google.com/protocol-buffers/docs/proto3#json. func (iter *Iterator) ReadInt64() int64 { switch iter.delegate.WhatIsNext() { case jsoniter.NumberValue: return iter.delegate.ReadInt64() case jsoniter.StringValue: val, err := strconv.ParseInt(iter.ReadString(), 10, 64) if err != nil { iter.ReportError("ReadInt64", err.Error()) return 0 } return val default: iter.ReportError("ReadInt64", "unsupported value type") return 0 } } // ReadUint64 unmarshalls JSON data into an uint64. Accepts both numbers and strings decimal. // See https://developers.google.com/protocol-buffers/docs/proto3#json. func (iter *Iterator) ReadUint64() uint64 { switch iter.delegate.WhatIsNext() { case jsoniter.NumberValue: return iter.delegate.ReadUint64() case jsoniter.StringValue: val, err := strconv.ParseUint(iter.ReadString(), 10, 64) if err != nil { iter.ReportError("ReadUint64", err.Error()) return 0 } return val default: iter.ReportError("ReadUint64", "unsupported value type") return 0 } } func (iter *Iterator) ReadFloat32() float32 { switch iter.delegate.WhatIsNext() { case jsoniter.NumberValue: return iter.delegate.ReadFloat32() case jsoniter.StringValue: val, err := strconv.ParseFloat(iter.ReadString(), 32) if err != nil { iter.ReportError("ReadUint64", err.Error()) return 0 } return float32(val) default: iter.ReportError("ReadUint64", "unsupported value type") return 0 } } func (iter *Iterator) ReadFloat64() float64 { switch iter.delegate.WhatIsNext() { case jsoniter.NumberValue: return iter.delegate.ReadFloat64() case jsoniter.StringValue: val, err := strconv.ParseFloat(iter.ReadString(), 64) if err != nil { iter.ReportError("ReadUint64", err.Error()) return 0 } return val default: iter.ReportError("ReadUint64", "unsupported value type") return 0 } } // ReadBool reads a json object as BoolValue func (iter *Iterator) ReadBool() bool { return iter.delegate.ReadBool() } // ReadString read string from iterator func (iter *Iterator) ReadString() string { return iter.delegate.ReadString() } // ReadBytes read base64 encoded bytes from iterator. func (iter *Iterator) ReadBytes() []byte { buf := iter.ReadStringAsSlice() if len(buf) == 0 { return nil } orig := make([]byte, base64.StdEncoding.DecodedLen(len(buf))) n, err := base64.StdEncoding.Decode(orig, buf) if err != nil { iter.ReportError("base64.Decode", err.Error()) } return orig[:n] } // ReadStringAsSlice read string from iterator without copying into string form. // The []byte cannot be kept, as it will change after next iterator call. func (iter *Iterator) ReadStringAsSlice() []byte { return iter.delegate.ReadStringAsSlice() } // ReportError record a error in iterator instance with current position. func (iter *Iterator) ReportError(operation, msg string) { iter.delegate.ReportError(operation, msg) } // Error returns any recorded error if any otherwise it returns nil. func (iter *Iterator) Error() error { return iter.delegate.Error } // Skip skips a json object and positions to relatively the next json object func (iter *Iterator) Skip() { iter.delegate.Skip() } // ReadArray read array element, returns true if the array has more element to read. func (iter *Iterator) ReadArray() bool { return iter.delegate.ReadArray() } // ReadObject read one field from object. // If object ended, returns empty string. Otherwise, returns the field name. func (iter *Iterator) ReadObject() string { return iter.delegate.ReadObject() } // ReadEnumValue returns the enum integer value representation. Accepts both enum names and enum integer values. // See https://developers.google.com/protocol-buffers/docs/proto3#json. func (iter *Iterator) ReadEnumValue(valueMap map[string]int32) int32 { switch iter.delegate.WhatIsNext() { case jsoniter.NumberValue: return iter.ReadInt32() case jsoniter.StringValue: val, ok := valueMap[iter.ReadString()] // Same behavior with official protobuf JSON decoder, // see https://github.com/open-telemetry/opentelemetry-proto-go/pull/81 if !ok { iter.ReportError("ReadEnumValue", "unknown string value") return 0 } return val default: iter.ReportError("ReadEnumValue", "unsupported value type") return 0 } } // ResetBytes reuse iterator instance by specifying another byte array as input func (iter *Iterator) ResetBytes(input []byte) *Iterator { iter.delegate.ResetBytes(input) return iter } opentelemetry-collector-0.141.0/pdata/internal/json/iterator_test.go000066400000000000000000000173021511331344600256360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package json import ( "math" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestReadInt32(t *testing.T) { tests := []struct { name string jsonStr string want int32 wantErr bool }{ { name: "number", jsonStr: `1 `, want: 1, }, { name: "string", jsonStr: `"1"`, want: 1, }, { name: "negative number", jsonStr: `-1 `, want: -1, }, { name: "negative string", jsonStr: `"-1"`, want: -1, }, { name: "wrong string", jsonStr: `"3.f14"`, wantErr: true, }, { name: "wrong type", jsonStr: `true`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { iter := BorrowIterator([]byte(tt.jsonStr)) defer ReturnIterator(iter) val := iter.ReadInt32() if tt.wantErr { require.Error(t, iter.Error()) return } require.NoError(t, iter.Error()) assert.Equal(t, tt.want, val) }) } } func TestReadUint32(t *testing.T) { tests := []struct { name string jsonStr string want uint32 wantErr bool }{ { name: "number", jsonStr: `1 `, want: 1, }, { name: "string", jsonStr: `"1"`, want: 1, }, { name: "negative number", jsonStr: `-1 `, wantErr: true, }, { name: "negative string", jsonStr: `"-1"`, wantErr: true, }, { name: "wrong string", jsonStr: `"3.f14"`, wantErr: true, }, { name: "wrong type", jsonStr: `true`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { iter := BorrowIterator([]byte(tt.jsonStr)) defer ReturnIterator(iter) val := iter.ReadUint32() if tt.wantErr { require.Error(t, iter.Error()) return } require.NoError(t, iter.Error()) assert.Equal(t, tt.want, val) }) } } func TestReadInt64(t *testing.T) { tests := []struct { name string jsonStr string want int64 wantErr bool }{ { name: "number", jsonStr: `1 `, want: 1, }, { name: "string", jsonStr: `"1"`, want: 1, }, { name: "negative number", jsonStr: `-1 `, want: -1, }, { name: "negative string", jsonStr: `"-1"`, want: -1, }, { name: "wrong string", jsonStr: `"3.f14"`, wantErr: true, }, { name: "wrong type", jsonStr: `true`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { iter := BorrowIterator([]byte(tt.jsonStr)) defer ReturnIterator(iter) val := iter.ReadInt64() if tt.wantErr { require.Error(t, iter.Error()) return } require.NoError(t, iter.Error()) assert.Equal(t, tt.want, val) }) } } func TestReadUint64(t *testing.T) { tests := []struct { name string jsonStr string want uint64 wantErr bool }{ { name: "number", jsonStr: `1 `, want: 1, }, { name: "string", jsonStr: `"1"`, want: 1, }, { name: "negative number", jsonStr: `-1 `, wantErr: true, }, { name: "negative string", jsonStr: `"-1"`, wantErr: true, }, { name: "wrong string", jsonStr: `"3.f14"`, wantErr: true, }, { name: "wrong type", jsonStr: `true`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { iter := BorrowIterator([]byte(tt.jsonStr)) defer ReturnIterator(iter) val := iter.ReadUint64() if tt.wantErr { require.Error(t, iter.Error()) return } require.NoError(t, iter.Error()) assert.Equal(t, tt.want, val) }) } } func TestReadFloat32(t *testing.T) { tests := []struct { name string jsonStr string want float32 wantErr bool }{ { name: "number", jsonStr: `3.14 `, want: 3.14, }, { name: "string", jsonStr: `"3.14"`, want: 3.14, }, { name: "negative number", jsonStr: `-3.14 `, want: -3.14, }, { name: "negative string", jsonStr: `"-3.14"`, want: -3.14, }, { name: "wrong string", jsonStr: `"3.f14"`, wantErr: true, }, { name: "wrong type", jsonStr: `true`, wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { iter := BorrowIterator([]byte(tt.jsonStr)) defer ReturnIterator(iter) val := iter.ReadFloat32() if tt.wantErr { require.Error(t, iter.Error()) return } require.NoError(t, iter.Error()) assert.InDelta(t, tt.want, val, 0.01) }) } } func TestReadFloat32MaxValue(t *testing.T) { iter := BorrowIterator([]byte(`{"value": 3.4028234663852886e+38}`)) defer ReturnIterator(iter) for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { assert.Equal(t, "value", f) assert.InDelta(t, math.MaxFloat32, iter.ReadFloat64(), 0.01) } require.NoError(t, iter.Error()) } func TestReadFloat64(t *testing.T) { tests := []struct { name string jsonStr string want float64 wantErr bool }{ { name: "number", jsonStr: `3.14 `, want: 3.14, }, { name: "string", jsonStr: `"3.14"`, want: 3.14, }, { name: "negative number", jsonStr: `-3.14 `, want: -3.14, }, { name: "negative string", jsonStr: `"-3.14"`, want: -3.14, }, { name: "wrong string", jsonStr: `"3.f14"`, wantErr: true, }, { name: "wrong type", jsonStr: `true`, wantErr: true, }, { name: "positive infinity", jsonStr: `"Infinity"`, want: math.Inf(1), }, { name: "negative infinity", jsonStr: `"-Infinity"`, want: math.Inf(-1), }, { name: "not-a-number", jsonStr: `"NaN"`, want: math.NaN(), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { iter := BorrowIterator([]byte(tt.jsonStr)) defer ReturnIterator(iter) val := iter.ReadFloat64() if tt.wantErr { require.Error(t, iter.Error()) return } require.NoError(t, iter.Error()) assert.InDelta(t, tt.want, val, 0.01) }) } } func TestReadFloat64MaxValue(t *testing.T) { iter := BorrowIterator([]byte(`{"value": 1.7976931348623157e+308}`)) defer ReturnIterator(iter) for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { assert.Equal(t, "value", f) assert.InDelta(t, math.MaxFloat64, iter.ReadFloat64(), 0.01) } require.NoError(t, iter.Error()) } func TestReadEnumValue(t *testing.T) { valueMap := map[string]int32{ "undefined": 0, "foo": 1, "bar": 2, } tests := []struct { name string jsonStr string want int32 wantErr bool }{ { name: "foo string", jsonStr: "\"foo\"\n", want: 1, }, { name: "foo number", jsonStr: "1\n", want: 1, }, { name: "unknown number", jsonStr: "5\n", want: 5, }, { name: "bar string", jsonStr: "\"bar\"\n", want: 2, }, { name: "bar number", jsonStr: "2\n", want: 2, }, { name: "unknown string", jsonStr: "\"baz\"\n", wantErr: true, }, { name: "wrong type", jsonStr: "true", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { iter := BorrowIterator([]byte(tt.jsonStr)) defer ReturnIterator(iter) val := iter.ReadEnumValue(valueMap) if tt.wantErr { assert.Error(t, iter.Error()) return } require.NoError(t, iter.Error()) assert.Equal(t, tt.want, val) }) } } func TestReadBytes(t *testing.T) { iter := BorrowIterator([]byte(`{"value": "dGVzdA=="}`)) defer ReturnIterator(iter) for f := iter.ReadObject(); f != ""; f = iter.ReadObject() { assert.Equal(t, "value", f) assert.Equal(t, "test", string(iter.ReadBytes())) } require.NoError(t, iter.Error()) } opentelemetry-collector-0.141.0/pdata/internal/json/package_test.go000066400000000000000000000003051511331344600253730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package json import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/internal/json/stream.go000066400000000000000000000056361511331344600242500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package json // import "go.opentelemetry.io/collector/pdata/internal/json" import ( "encoding/base64" "errors" "io" "math" "strconv" jsoniter "github.com/json-iterator/go" ) func BorrowStream(writer io.Writer) *Stream { return &Stream{ Stream: jsoniter.ConfigFastest.BorrowStream(writer), wmTracker: make([]bool, 32), } } func ReturnStream(s *Stream) { jsoniter.ConfigFastest.ReturnStream(s.Stream) } // Stream avoids the need to explicitly call the `Stream.WriteMore` method while marshaling objects by // checking if a field was previously written inside the current object and automatically appending a "," // if so before writing the next field. type Stream struct { *jsoniter.Stream // wmTracker acts like a stack which pushes a new value when an object is started and removes the // top when it is ended. The value added for every object tracks if there is any written field // already for that object, and if it is then automatically add a "," before any new field. wmTracker []bool } func (ots *Stream) WriteObjectStart() { ots.Stream.WriteObjectStart() ots.wmTracker = append(ots.wmTracker, false) } func (ots *Stream) WriteObjectField(field string) { if ots.wmTracker[len(ots.wmTracker)-1] { ots.WriteMore() } ots.Stream.WriteObjectField(field) ots.wmTracker[len(ots.wmTracker)-1] = true } func (ots *Stream) WriteObjectEnd() { ots.Stream.WriteObjectEnd() ots.wmTracker = ots.wmTracker[:len(ots.wmTracker)-1] } // WriteInt64 writes the values as a decimal string. This is per the protobuf encoding rules for int64, fixed64, uint64. func (ots *Stream) WriteInt64(val int64) { ots.WriteString(strconv.FormatInt(val, 10)) } // WriteUint64 writes the values as a decimal string. This is per the protobuf encoding rules for int64, fixed64, uint64. func (ots *Stream) WriteUint64(val uint64) { ots.WriteString(strconv.FormatUint(val, 10)) } // WriteBytes writes the values as a base64 encoded string. This is per the protobuf encoding rules for bytes. func (ots *Stream) WriteBytes(val []byte) { if len(val) == 0 { ots.WriteString("") return } ots.WriteString(base64.StdEncoding.EncodeToString(val)) } // WriteFloat64 writes the JSON value that will be a number or one of the special string // values "NaN", "Infinity", and "-Infinity". Either numbers or strings are accepted. // Empty strings are invalid. Exponent notation is also accepted. // See https://protobuf.dev/programming-guides/json/. func (ots *Stream) WriteFloat64(val float64) { if math.IsNaN(val) { ots.WriteString("NaN") return } if math.IsInf(val, 1) { ots.WriteString("Infinity") return } if math.IsInf(val, -1) { ots.WriteString("-Infinity") return } ots.Stream.WriteFloat64(val) } func (ots *Stream) ReportError(err error) { ots.Stream.Error = errors.Join(ots.Stream.Error, err) } func (ots *Stream) Error() error { return ots.Stream.Error } opentelemetry-collector-0.141.0/pdata/internal/json/stream_test.go000066400000000000000000000035411511331344600253000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package json import ( "math" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestNestedObject(t *testing.T) { s := BorrowStream(nil) defer ReturnStream(s) s.WriteObjectStart() s.WriteObjectField("field1") s.WriteString("val1") s.WriteObjectField("field2") s.WriteObjectStart() s.WriteObjectField("field3") s.WriteObjectStart() s.WriteObjectField("field4") s.WriteString("val4") s.WriteObjectField("field5") s.WriteString("val5") s.WriteObjectEnd() s.WriteObjectField("field6") s.WriteString("val6") s.WriteObjectField("field7") s.WriteObjectStart() s.WriteObjectEnd() s.WriteObjectEnd() s.WriteObjectEnd() expected := `{ "field1": "val1", "field2": { "field3": { "field4": "val4", "field5": "val5" }, "field6": "val6", "field7": {} } }` assert.JSONEq(t, expected, string(s.Buffer())) } func TestMarshalFloat(t *testing.T) { tests := []struct { name string inputFloat float64 expected string }{ { name: "positive infinity", inputFloat: math.Inf(1), expected: `"Infinity"`, }, { name: "negative infinity", inputFloat: math.Inf(-1), expected: `"-Infinity"`, }, { name: "not-a-number", inputFloat: math.NaN(), expected: `"NaN"`, }, { name: "regular float", inputFloat: math.MaxFloat64, expected: "1.7976931348623157e+308", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := BorrowStream(nil) defer ReturnStream(s) s.WriteFloat64(tt.inputFloat) require.Equal(t, tt.expected, string(s.Buffer())) }) } } func TestWriteBytes(t *testing.T) { s := BorrowStream(nil) defer ReturnStream(s) s.WriteBytes([]byte("test")) require.Equal(t, `"dGVzdA=="`, string(s.Buffer())) } opentelemetry-collector-0.141.0/pdata/internal/otelgrpc/000077500000000000000000000000001511331344600232625ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal/otelgrpc/encoding.go000066400000000000000000000041551511331344600254040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelgrpc // import "go.opentelemetry.io/collector/pdata/internal/otelgrpc" import ( "google.golang.org/grpc/encoding" "google.golang.org/grpc/mem" ) var ( defaultBufferPoolSizes = []int{ 256, 4 << 10, // 4KB (go page size) 16 << 10, // 16KB (max HTTP/2 frame size used by gRPC) 32 << 10, // 32KB (default buffer size for io.Copy) 512 << 10, // 512KB 1 << 20, // 1MB 4 << 20, // 4MB 16 << 20, // 16MB } otelBufferPool = mem.NewTieredBufferPool(defaultBufferPoolSizes...) ) // DefaultBufferPool returns the current default buffer pool. It is a BufferPool // created with mem.NewTieredBufferPool that uses a set of default sizes optimized for // expected telemetry workflows. func DefaultBufferPool() mem.BufferPool { return otelBufferPool } // Name is the name registered for the proto compressor. const Name = "proto" func init() { encoding.RegisterCodecV2(&codecV2{delegate: encoding.GetCodecV2(Name)}) } // codecV2 is a custom proto encoding that uses a different tier schema for the TieredBufferPool as well // as it call into the custom marshal/unmarshal logic that works with memory pooling. // If not an otlp payload fallback on the default grpc/proto encoding. type codecV2 struct { delegate encoding.CodecV2 } type otelEncoder interface { SizeProto() int MarshalProto([]byte) int UnmarshalProto([]byte) error } func (c *codecV2) Marshal(v any) (mem.BufferSlice, error) { if m, ok := v.(otelEncoder); ok { size := m.SizeProto() buf := otelBufferPool.Get(size) n := m.MarshalProto((*buf)[:size]) *buf = (*buf)[:n] return []mem.Buffer{mem.NewBuffer(buf, otelBufferPool)}, nil } return c.delegate.Marshal(v) } func (c *codecV2) Unmarshal(data mem.BufferSlice, v any) (err error) { if m, ok := v.(otelEncoder); ok { // TODO: Upgrade custom Unmarshal logic to support reading from mem.BufferSlice. buf := data.MaterializeToBuffer(otelBufferPool) defer buf.Free() return m.UnmarshalProto(buf.ReadOnlyData()) } return c.delegate.Unmarshal(data, v) } func (c *codecV2) Name() string { return Name } opentelemetry-collector-0.141.0/pdata/internal/otelgrpc/logs_service.go000066400000000000000000000057531511331344600263070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelgrpc // import "go.opentelemetry.io/collector/pdata/internal/otelgrpc" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" ) // LogsServiceClient is the client API for LogsService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type LogsServiceClient interface { Export(context.Context, *internal.ExportLogsServiceRequest, ...grpc.CallOption) (*internal.ExportLogsServiceResponse, error) } type logsServiceClient struct { cc *grpc.ClientConn } func NewLogsServiceClient(cc *grpc.ClientConn) LogsServiceClient { return &logsServiceClient{cc} } func (c *logsServiceClient) Export(ctx context.Context, in *internal.ExportLogsServiceRequest, opts ...grpc.CallOption) (*internal.ExportLogsServiceResponse, error) { out := new(internal.ExportLogsServiceResponse) err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.logs.v1.LogsService/Export", in, out, opts...) if err != nil { return nil, err } return out, nil } // LogsServiceServer is the server API for LogsService service. type LogsServiceServer interface { Export(context.Context, *internal.ExportLogsServiceRequest) (*internal.ExportLogsServiceResponse, error) } // UnimplementedLogsServiceServer can be embedded to have forward compatible implementations. type UnimplementedLogsServiceServer struct{} func (*UnimplementedLogsServiceServer) Export(context.Context, *internal.ExportLogsServiceRequest) (*internal.ExportLogsServiceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Export not implemented") } func RegisterLogsServiceServer(s *grpc.Server, srv LogsServiceServer) { s.RegisterService(&logsServiceServiceDesc, srv) } // Context cannot be the first parameter of the function because gRPC definition. // //nolint:revive func logsServiceExportHandler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(internal.ExportLogsServiceRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(LogsServiceServer).Export(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/opentelemetry.proto.collector.logs.v1.LogsService/Export", } handler := func(ctx context.Context, req any) (any, error) { return srv.(LogsServiceServer).Export(ctx, req.(*internal.ExportLogsServiceRequest)) } return interceptor(ctx, in, info, handler) } var logsServiceServiceDesc = grpc.ServiceDesc{ ServiceName: "opentelemetry.proto.collector.logs.v1.LogsService", HandlerType: (*LogsServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Export", Handler: logsServiceExportHandler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "opentelemetry/proto/collector/logs/v1/logs_service.proto", } opentelemetry-collector-0.141.0/pdata/internal/otelgrpc/metrics_service.go000066400000000000000000000061511511331344600270020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelgrpc // import "go.opentelemetry.io/collector/pdata/internal/otelgrpc" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" ) // MetricsServiceClient is the client API for MetricsService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type MetricsServiceClient interface { Export(context.Context, *internal.ExportMetricsServiceRequest, ...grpc.CallOption) (*internal.ExportMetricsServiceResponse, error) } type metricsServiceClient struct { cc *grpc.ClientConn } func NewMetricsServiceClient(cc *grpc.ClientConn) MetricsServiceClient { return &metricsServiceClient{cc} } func (c *metricsServiceClient) Export(ctx context.Context, in *internal.ExportMetricsServiceRequest, opts ...grpc.CallOption) (*internal.ExportMetricsServiceResponse, error) { out := new(internal.ExportMetricsServiceResponse) err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", in, out, opts...) if err != nil { return nil, err } return out, nil } // MetricsServiceServer is the server API for MetricsService service. type MetricsServiceServer interface { Export(context.Context, *internal.ExportMetricsServiceRequest) (*internal.ExportMetricsServiceResponse, error) } // UnimplementedMetricsServiceServer can be embedded to have forward compatible implementations. type UnimplementedMetricsServiceServer struct{} func (*UnimplementedMetricsServiceServer) Export(context.Context, *internal.ExportMetricsServiceRequest) (*internal.ExportMetricsServiceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Export not implemented") } func RegisterMetricsServiceServer(s *grpc.Server, srv MetricsServiceServer) { s.RegisterService(&metricsServiceServiceDesc, srv) } // Context cannot be the first parameter of the function because gRPC definition. // //nolint:revive func metricsServiceExportHandler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(internal.ExportMetricsServiceRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(MetricsServiceServer).Export(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/opentelemetry.proto.collector.metrics.v1.MetricsService/Export", } handler := func(ctx context.Context, req any) (any, error) { return srv.(MetricsServiceServer).Export(ctx, req.(*internal.ExportMetricsServiceRequest)) } return interceptor(ctx, in, info, handler) } var metricsServiceServiceDesc = grpc.ServiceDesc{ ServiceName: "opentelemetry.proto.collector.metrics.v1.MetricsService", HandlerType: (*MetricsServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Export", Handler: metricsServiceExportHandler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "opentelemetry/proto/collector/metrics/v1/metrics_service.proto", } opentelemetry-collector-0.141.0/pdata/internal/otelgrpc/profiles_service.go000066400000000000000000000062771511331344600271700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelgrpc // import "go.opentelemetry.io/collector/pdata/internal/otelgrpc" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" ) // ProfilesServiceClient is the client API for ProfilesService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type ProfilesServiceClient interface { Export(context.Context, *internal.ExportProfilesServiceRequest, ...grpc.CallOption) (*internal.ExportProfilesServiceResponse, error) } type profilesServiceClient struct { cc *grpc.ClientConn } func NewProfilesServiceClient(cc *grpc.ClientConn) ProfilesServiceClient { return &profilesServiceClient{cc} } func (c *profilesServiceClient) Export(ctx context.Context, in *internal.ExportProfilesServiceRequest, opts ...grpc.CallOption) (*internal.ExportProfilesServiceResponse, error) { out := new(internal.ExportProfilesServiceResponse) err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.profiles.v1development.ProfilesService/Export", in, out, opts...) if err != nil { return nil, err } return out, nil } // ProfilesServiceServer is the server API for ProfilesService service. type ProfilesServiceServer interface { Export(context.Context, *internal.ExportProfilesServiceRequest) (*internal.ExportProfilesServiceResponse, error) } // UnimplementedProfilesServiceServer can be embedded to have forward compatible implementations. type UnimplementedProfilesServiceServer struct{} func (*UnimplementedProfilesServiceServer) Export(context.Context, *internal.ExportProfilesServiceRequest) (*internal.ExportProfilesServiceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Export not implemented") } func RegisterProfilesServiceServer(s *grpc.Server, srv ProfilesServiceServer) { s.RegisterService(&profilesServiceServiceDesc, srv) } // Context cannot be the first parameter of the function because gRPC definition. // //nolint:revive func profilesServiceExportHandler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(internal.ExportProfilesServiceRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(ProfilesServiceServer).Export(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/opentelemetry.proto.collector.profiles.v1development.ProfilesService/Export", } handler := func(ctx context.Context, req any) (any, error) { return srv.(ProfilesServiceServer).Export(ctx, req.(*internal.ExportProfilesServiceRequest)) } return interceptor(ctx, in, info, handler) } var profilesServiceServiceDesc = grpc.ServiceDesc{ ServiceName: "opentelemetry.proto.collector.profiles.v1development.ProfilesService", HandlerType: (*ProfilesServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Export", Handler: profilesServiceExportHandler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "opentelemetry/proto/collector/profiles/v1development/profiles_service.proto", } opentelemetry-collector-0.141.0/pdata/internal/otelgrpc/trace_service.go000066400000000000000000000060251511331344600264320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelgrpc // import "go.opentelemetry.io/collector/pdata/internal/otelgrpc" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" ) // TraceServiceClient is the client API for TraceService service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type TraceServiceClient interface { Export(context.Context, *internal.ExportTraceServiceRequest, ...grpc.CallOption) (*internal.ExportTraceServiceResponse, error) } type traceServiceClient struct { cc *grpc.ClientConn } func NewTraceServiceClient(cc *grpc.ClientConn) TraceServiceClient { return &traceServiceClient{cc} } func (c *traceServiceClient) Export(ctx context.Context, in *internal.ExportTraceServiceRequest, opts ...grpc.CallOption) (*internal.ExportTraceServiceResponse, error) { out := new(internal.ExportTraceServiceResponse) err := c.cc.Invoke(ctx, "/opentelemetry.proto.collector.trace.v1.TraceService/Export", in, out, opts...) if err != nil { return nil, err } return out, nil } // TraceServiceServer is the server API for TraceService service. type TraceServiceServer interface { Export(context.Context, *internal.ExportTraceServiceRequest) (*internal.ExportTraceServiceResponse, error) } // UnimplementedTraceServiceServer can be embedded to have forward compatible implementations. type UnimplementedTraceServiceServer struct{} func (*UnimplementedTraceServiceServer) Export(context.Context, *internal.ExportTraceServiceRequest) (*internal.ExportTraceServiceResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method Export not implemented") } func RegisterTraceServiceServer(s *grpc.Server, srv TraceServiceServer) { s.RegisterService(&traceServiceServiceDesc, srv) } // Context cannot be the first parameter of the function because gRPC definition. // //nolint:revive func traceServiceExportHandler(srv any, ctx context.Context, dec func(any) error, interceptor grpc.UnaryServerInterceptor) (any, error) { in := new(internal.ExportTraceServiceRequest) if err := dec(in); err != nil { return nil, err } if interceptor == nil { return srv.(TraceServiceServer).Export(ctx, in) } info := &grpc.UnaryServerInfo{ Server: srv, FullMethod: "/opentelemetry.proto.collector.trace.v1.TraceService/Export", } handler := func(ctx context.Context, req any) (any, error) { return srv.(TraceServiceServer).Export(ctx, req.(*internal.ExportTraceServiceRequest)) } return interceptor(ctx, in, info, handler) } var traceServiceServiceDesc = grpc.ServiceDesc{ ServiceName: "opentelemetry.proto.collector.trace.v1.TraceService", HandlerType: (*TraceServiceServer)(nil), Methods: []grpc.MethodDesc{ { MethodName: "Export", Handler: traceServiceExportHandler, }, }, Streams: []grpc.StreamDesc{}, Metadata: "opentelemetry/proto/collector/trace/v1/trace_service.proto", } opentelemetry-collector-0.141.0/pdata/internal/otlp/000077500000000000000000000000001511331344600224215ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal/otlp/logs.go000066400000000000000000000011361511331344600237150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp // import "go.opentelemetry.io/collector/pdata/internal/otlp" import ( "go.opentelemetry.io/collector/pdata/internal" ) // MigrateLogs implements any translation needed due to deprecation in OTLP logs protocol. // Any plog.Unmarshaler implementation from OTLP (proto/json) MUST call this, and the gRPC Server implementation. func MigrateLogs(rls []*internal.ResourceLogs) { for _, rl := range rls { if len(rl.ScopeLogs) == 0 { rl.ScopeLogs = rl.DeprecatedScopeLogs } rl.DeprecatedScopeLogs = nil } } opentelemetry-collector-0.141.0/pdata/internal/otlp/logs_test.go000066400000000000000000000013261511331344600247550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestDeprecatedScopeLogs(t *testing.T) { sl := new(internal.ScopeLogs) rls := []*internal.ResourceLogs{ { ScopeLogs: []*internal.ScopeLogs{sl}, DeprecatedScopeLogs: []*internal.ScopeLogs{sl}, }, { ScopeLogs: []*internal.ScopeLogs{}, DeprecatedScopeLogs: []*internal.ScopeLogs{sl}, }, } MigrateLogs(rls) assert.Same(t, sl, rls[0].ScopeLogs[0]) assert.Same(t, sl, rls[1].ScopeLogs[0]) assert.Nil(t, rls[0].DeprecatedScopeLogs) assert.Nil(t, rls[0].DeprecatedScopeLogs) } opentelemetry-collector-0.141.0/pdata/internal/otlp/metrics.go000066400000000000000000000011711511331344600244160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp // import "go.opentelemetry.io/collector/pdata/internal/otlp" import ( "go.opentelemetry.io/collector/pdata/internal" ) // MigrateMetrics implements any translation needed due to deprecation in OTLP metrics protocol. // Any pmetric.Unmarshaler implementation from OTLP (proto/json) MUST call this, and the gRPC Server implementation. func MigrateMetrics(rms []*internal.ResourceMetrics) { for _, rm := range rms { if len(rm.ScopeMetrics) == 0 { rm.ScopeMetrics = rm.DeprecatedScopeMetrics } rm.DeprecatedScopeMetrics = nil } } opentelemetry-collector-0.141.0/pdata/internal/otlp/metrics_test.go000066400000000000000000000014061511331344600254560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestDeprecatedScopeMetrics(t *testing.T) { sm := new(internal.ScopeMetrics) rms := []*internal.ResourceMetrics{ { ScopeMetrics: []*internal.ScopeMetrics{sm}, DeprecatedScopeMetrics: []*internal.ScopeMetrics{sm}, }, { ScopeMetrics: []*internal.ScopeMetrics{}, DeprecatedScopeMetrics: []*internal.ScopeMetrics{sm}, }, } MigrateMetrics(rms) assert.Same(t, sm, rms[0].ScopeMetrics[0]) assert.Same(t, sm, rms[1].ScopeMetrics[0]) assert.Nil(t, rms[0].DeprecatedScopeMetrics) assert.Nil(t, rms[0].DeprecatedScopeMetrics) } opentelemetry-collector-0.141.0/pdata/internal/otlp/package_test.go000066400000000000000000000003051511331344600254000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/internal/otlp/profiles.go000066400000000000000000000007501511331344600245750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp // import "go.opentelemetry.io/collector/pdata/internal/otlp" import ( "go.opentelemetry.io/collector/pdata/internal" ) // MigrateProfiles implements any translation needed due to deprecation in OTLP profiles protocol. // Any pprofile.Unmarshaler implementation from OTLP (proto/json) MUST call this, and the gRPC Server implementation. func MigrateProfiles(_ []*internal.ResourceProfiles) {} opentelemetry-collector-0.141.0/pdata/internal/otlp/profiles_test.go000066400000000000000000000004261511331344600256340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp import ( "testing" "go.opentelemetry.io/collector/pdata/internal" ) func TestMigrateProfiles(_ *testing.T) { rps := []*internal.ResourceProfiles{ {}, } MigrateProfiles(rps) } opentelemetry-collector-0.141.0/pdata/internal/otlp/traces.go000066400000000000000000000011531511331344600242310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp // import "go.opentelemetry.io/collector/pdata/internal/otlp" import ( "go.opentelemetry.io/collector/pdata/internal" ) // MigrateTraces implements any translation needed due to deprecation in OTLP traces protocol. // Any ptrace.Unmarshaler implementation from OTLP (proto/json) MUST call this, and the gRPC Server implementation. func MigrateTraces(rss []*internal.ResourceSpans) { for _, rs := range rss { if len(rs.ScopeSpans) == 0 { rs.ScopeSpans = rs.DeprecatedScopeSpans } rs.DeprecatedScopeSpans = nil } } opentelemetry-collector-0.141.0/pdata/internal/otlp/traces_test.go000066400000000000000000000013471511331344600252750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestDeprecatedScopeSpans(t *testing.T) { ss := new(internal.ScopeSpans) rss := []*internal.ResourceSpans{ { ScopeSpans: []*internal.ScopeSpans{ss}, DeprecatedScopeSpans: []*internal.ScopeSpans{ss}, }, { ScopeSpans: []*internal.ScopeSpans{}, DeprecatedScopeSpans: []*internal.ScopeSpans{ss}, }, } MigrateTraces(rss) assert.Same(t, ss, rss[0].ScopeSpans[0]) assert.Same(t, ss, rss[1].ScopeSpans[0]) assert.Nil(t, rss[0].DeprecatedScopeSpans) assert.Nil(t, rss[0].DeprecatedScopeSpans) } opentelemetry-collector-0.141.0/pdata/internal/profileid.go000066400000000000000000000036661511331344600237620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" import ( "encoding/hex" "errors" "go.opentelemetry.io/collector/pdata/internal/json" ) const profileIDSize = 16 var errUnmarshalProfileID = errors.New("unmarshal: invalid ProfileID length") // ProfileID is a custom data type that is used for all profile_id fields in OTLP // Protobuf messages. type ProfileID [profileIDSize]byte func DeleteProfileID(*ProfileID, bool) {} func CopyProfileID(dest, src *ProfileID) { *dest = *src } // IsEmpty returns true if id contains at leas one non-zero byte. func (pid ProfileID) IsEmpty() bool { return pid == [profileIDSize]byte{} } // SizeProto returns the size of the data to serialize in proto format. func (pid ProfileID) SizeProto() int { if pid.IsEmpty() { return 0 } return profileIDSize } // MarshalProto converts profile ID into a binary representation. Called by Protobuf serialization. func (pid ProfileID) MarshalProto(buf []byte) int { if pid.IsEmpty() { return 0 } return copy(buf[len(buf)-profileIDSize:], pid[:]) } // UnmarshalProto inflates this profile ID from binary representation. Called by Protobuf serialization. func (pid *ProfileID) UnmarshalProto(buf []byte) error { if len(buf) == 0 { *pid = [profileIDSize]byte{} return nil } if len(buf) != profileIDSize { return errUnmarshalProfileID } copy(pid[:], buf) return nil } // MarshalJSON converts ProfileID into a hex string. // //nolint:govet func (pid ProfileID) MarshalJSON(dest *json.Stream) { dest.WriteString(hex.EncodeToString(pid[:])) } // UnmarshalJSON decodes ProfileID from hex string. // //nolint:govet func (pid *ProfileID) UnmarshalJSON(iter *json.Iterator) { *pid = [profileIDSize]byte{} unmarshalJSON(pid[:], iter) } func GenTestProfileID() *ProfileID { pid := ProfileID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) return &pid } opentelemetry-collector-0.141.0/pdata/internal/profileid_test.go000066400000000000000000000041511511331344600250070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestProfileID(t *testing.T) { tid := ProfileID([profileIDSize]byte{}) assert.EqualValues(t, [profileIDSize]byte{}, tid) assert.Equal(t, 0, tid.SizeProto()) b := [profileIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} tid = b assert.EqualValues(t, b, tid) assert.Equal(t, profileIDSize, tid.SizeProto()) } func TestProfileIDMarshal(t *testing.T) { buf := make([]byte, profileIDSize) tid := ProfileID([profileIDSize]byte{}) n := tid.MarshalProto(buf) assert.Equal(t, 0, n) tid = [profileIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} n = tid.MarshalProto(buf) assert.Equal(t, profileIDSize, n) assert.Equal(t, []byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78}, buf[0:profileIDSize]) } func TestProfileIDUnmarshal(t *testing.T) { buf := [profileIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} tid := ProfileID{} err := tid.UnmarshalProto(buf[:]) require.NoError(t, err) assert.EqualValues(t, buf, tid) err = tid.UnmarshalProto(buf[0:0]) require.NoError(t, err) assert.EqualValues(t, [profileIDSize]byte{}, tid) err = tid.UnmarshalProto(nil) require.NoError(t, err) assert.EqualValues(t, [profileIDSize]byte{}, tid) } func TestProfileIDMarshalAndUnmarshalJSON(t *testing.T) { stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src := ProfileID([profileIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78}) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := ProfileID{} dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) } opentelemetry-collector-0.141.0/pdata/internal/proto/000077500000000000000000000000001511331344600226065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/internal/proto/marshal.go000066400000000000000000000006541511331344600245710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/pdata/internal/proto" // EncodeVarint encodes the variant at the end of the buffer. func EncodeVarint(buf []byte, offset int, v uint64) int { offset -= Sov(v) base := offset for v >= 1<<7 { buf[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } buf[offset] = uint8(v) return base } opentelemetry-collector-0.141.0/pdata/internal/proto/size.go000066400000000000000000000005101511331344600241030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/pdata/internal/proto" import ( "math/bits" ) func Sov(x uint64) (n int) { return (bits.Len64(x|1) + 6) / 7 } func Soz(x uint64) (n int) { return Sov((x << 1) ^ uint64((int64(x) >> 63))) } opentelemetry-collector-0.141.0/pdata/internal/proto/unmarshal.go000066400000000000000000000073331511331344600251350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proto // import "go.opentelemetry.io/collector/pdata/internal/proto" import ( "encoding/binary" "errors" "fmt" "io" ) // WireType represents the proto wire type. type WireType int8 const ( WireTypeVarint WireType = 0 WireTypeI64 WireType = 1 WireTypeLen WireType = 2 WireTypeStartGroup WireType = 3 WireTypeEndGroup WireType = 4 WireTypeI32 WireType = 5 ) var ( ErrInvalidLength = errors.New("proto: negative length found during unmarshaling") ErrIntOverflow = errors.New("proto: integer overflow") ErrUnexpectedEndOfGroup = errors.New("proto: unexpected end of group") ) // ConsumeUnknown parses buf starting at pos as a wireType field, reporting the new position. func ConsumeUnknown(buf []byte, pos int, wireType WireType) (int, error) { var err error l := len(buf) depth := 0 for pos < l { switch wireType { case WireTypeVarint: _, pos, err = ConsumeVarint(buf, pos) return pos, err case WireTypeI64: _, pos, err = ConsumeI64(buf, pos) return pos, err case WireTypeLen: _, pos, err = ConsumeLen(buf, pos) return pos, err case WireTypeStartGroup: depth++ case WireTypeEndGroup: if depth == 0 { return 0, ErrUnexpectedEndOfGroup } depth-- case WireTypeI32: _, pos, err = ConsumeI32(buf, pos) return pos, err default: return 0, fmt.Errorf("proto: illegal wireType %d", wireType) } // Only when parsing a group can be here, if done return otherwise parse more tags. if depth == 0 { return pos, nil } // If in a group parsing, move to the next tag. _, wireType, pos, err = ConsumeTag(buf, pos) if err != nil { return 0, err } } return 0, io.ErrUnexpectedEOF } // ConsumeI64 parses buf starting at pos as a WireTypeI64 field, reporting the value and the new position. func ConsumeI64(buf []byte, pos int) (uint64, int, error) { pos += 8 if pos < 0 || pos > len(buf) { return 0, 0, io.ErrUnexpectedEOF } return binary.LittleEndian.Uint64(buf[pos-8:]), pos, nil } // ConsumeLen parses buf starting at pos as a WireTypeLen field, reporting the len and the new position. func ConsumeLen(buf []byte, pos int) (int, int, error) { var num uint64 var err error num, pos, err = ConsumeVarint(buf, pos) if err != nil { return 0, 0, err } length := int(num) if length < 0 { return 0, 0, ErrInvalidLength } pos += length if pos < 0 || pos > len(buf) { return 0, 0, io.ErrUnexpectedEOF } return length, pos, nil } // ConsumeI32 parses buf starting at pos as a WireTypeI32 field, reporting the value and the new position. func ConsumeI32(buf []byte, pos int) (uint32, int, error) { pos += 4 if pos < 0 || pos > len(buf) { return 0, 0, io.ErrUnexpectedEOF } return binary.LittleEndian.Uint32(buf[pos-4:]), pos, nil } // ConsumeTag parses buf starting at pos as a varint-encoded tag, reporting the new position. func ConsumeTag(buf []byte, pos int) (int32, WireType, int, error) { tag, pos, err := ConsumeVarint(buf, pos) if err != nil { return 0, 0, 0, err } fieldNum := int32(tag >> 3) wireType := int8(tag & 0x7) if fieldNum <= 0 { return 0, 0, 0, fmt.Errorf("proto: Link: illegal field=%d (tag=%d, pos=%d)", fieldNum, tag, pos) } return fieldNum, WireType(wireType), pos, nil } // ConsumeVarint parses buf starting at pos as a varint-encoded uint64, reporting the new position. func ConsumeVarint(buf []byte, pos int) (uint64, int, error) { l := len(buf) var num uint64 for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, 0, ErrIntOverflow } if pos >= l { return 0, 0, io.ErrUnexpectedEOF } b := buf[pos] pos++ num |= uint64(b&0x7F) << shift if b < 0x80 { break } } return num, pos, nil } opentelemetry-collector-0.141.0/pdata/internal/spanid.go000066400000000000000000000035031511331344600232510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" import ( "encoding/hex" "errors" "go.opentelemetry.io/collector/pdata/internal/json" ) const spanIDSize = 8 var errUnmarshalSpanID = errors.New("unmarshal: invalid SpanID length") // SpanID is a custom data type that is used for all span_id fields in OTLP // Protobuf messages. type SpanID [spanIDSize]byte func DeleteSpanID(*SpanID, bool) {} func CopySpanID(dest, src *SpanID) { *dest = *src } // IsEmpty returns true if id contains at least one non-zero byte. func (sid SpanID) IsEmpty() bool { return sid == [spanIDSize]byte{} } // SizeProto returns the size of the data to serialize in proto format. func (sid SpanID) SizeProto() int { if sid.IsEmpty() { return 0 } return spanIDSize } // MarshalProto converts span ID into a binary representation. Called by Protobuf serialization. func (sid SpanID) MarshalProto(buf []byte) int { if sid.IsEmpty() { return 0 } return copy(buf[len(buf)-spanIDSize:], sid[:]) } // UnmarshalProto inflates this span ID from binary representation. Called by Protobuf serialization. func (sid *SpanID) UnmarshalProto(data []byte) error { if len(data) == 0 { *sid = [spanIDSize]byte{} return nil } if len(data) != spanIDSize { return errUnmarshalSpanID } copy(sid[:], data) return nil } // MarshalJSON converts SpanID into a hex string. // //nolint:govet func (sid SpanID) MarshalJSON(dest *json.Stream) { dest.WriteString(hex.EncodeToString(sid[:])) } // UnmarshalJSON decodes SpanID from hex string. // //nolint:govet func (sid *SpanID) UnmarshalJSON(iter *json.Iterator) { *sid = [spanIDSize]byte{} unmarshalJSON(sid[:], iter) } func GenTestSpanID() *SpanID { sid := SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1}) return &sid } opentelemetry-collector-0.141.0/pdata/internal/spanid_test.go000066400000000000000000000035361511331344600243160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestSpanID(t *testing.T) { sid := SpanID([spanIDSize]byte{}) assert.EqualValues(t, [spanIDSize]byte{}, sid) assert.Equal(t, 0, sid.SizeProto()) b := [spanIDSize]byte{1, 2, 3, 4, 5, 6, 7, 8} sid = b assert.EqualValues(t, b, sid) assert.Equal(t, 8, sid.SizeProto()) } func TestSpanIDMarshal(t *testing.T) { buf := make([]byte, spanIDSize) sid := SpanID([spanIDSize]byte{}) n := sid.MarshalProto(buf) assert.Equal(t, 0, n) sid = [spanIDSize]byte{1, 2, 3, 4, 5, 6, 7, 8} n = sid.MarshalProto(buf) assert.Equal(t, spanIDSize, n) assert.Equal(t, []byte{1, 2, 3, 4, 5, 6, 7, 8}, buf[0:spanIDSize]) } func TestSpanIDUnmarshal(t *testing.T) { buf := [spanIDSize]byte{0x12, 0x23, 0xAD, 0x12, 0x23, 0xAD, 0x12, 0x23} sid := SpanID{} err := sid.UnmarshalProto(buf[:]) require.NoError(t, err) assert.EqualValues(t, [spanIDSize]byte{0x12, 0x23, 0xAD, 0x12, 0x23, 0xAD, 0x12, 0x23}, sid) err = sid.UnmarshalProto(buf[0:0]) require.NoError(t, err) assert.EqualValues(t, [spanIDSize]byte{}, sid) err = sid.UnmarshalProto(nil) require.NoError(t, err) assert.EqualValues(t, [spanIDSize]byte{}, sid) err = sid.UnmarshalProto(buf[0:3]) assert.Error(t, err) } func TestSpanIDMarshalAndUnmarshalJSON(t *testing.T) { stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src := SpanID([spanIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78}) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := SpanID{} dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) } opentelemetry-collector-0.141.0/pdata/internal/state.go000066400000000000000000000047411511331344600231200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" import ( "sync/atomic" "go.opentelemetry.io/collector/featuregate" ) var _ = featuregate.GlobalRegistry().MustRegister( "pdata.useCustomProtoEncoding", featuregate.StageStable, featuregate.WithRegisterDescription("When enabled, enable custom proto encoding. This is required step to enable featuregate pdata.useProtoPooling."), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/issues/13631"), featuregate.WithRegisterFromVersion("v0.133.0"), featuregate.WithRegisterToVersion("v0.137.0"), ) var UseProtoPooling = featuregate.GlobalRegistry().MustRegister( "pdata.useProtoPooling", featuregate.StageAlpha, featuregate.WithRegisterDescription("When enabled, enable using local memory pools for underlying data that the pdata messages are pushed to."), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/issues/13631"), featuregate.WithRegisterFromVersion("v0.133.0"), ) // State defines an ownership state of pmetric.Metrics, plog.Logs or ptrace.Traces. type State struct { refs atomic.Int32 state uint32 } const ( defaultState uint32 = 0 stateReadOnlyBit = uint32(1 << 0) statePipelineOwnedBit = uint32(1 << 1) ) func NewState() *State { st := &State{ state: defaultState, } st.refs.Store(1) return st } func (st *State) MarkReadOnly() { st.state |= stateReadOnlyBit } func (st *State) IsReadOnly() bool { return st.state&stateReadOnlyBit != 0 } // AssertMutable panics if the state is not StateMutable. func (st *State) AssertMutable() { if st.state&stateReadOnlyBit != 0 { panic("invalid access to shared data") } } // MarkPipelineOwned marks the data as owned by the pipeline, returns true if the data were // previously not owned by the pipeline, otherwise false. func (st *State) MarkPipelineOwned() bool { if st.state&statePipelineOwnedBit != 0 { return false } st.state |= statePipelineOwnedBit return true } // Ref add one to the count of active references. func (st *State) Ref() { st.refs.Add(1) } // Unref returns true if reference count got to 0 which means no more active references, // otherwise it returns false. func (st *State) Unref() bool { refs := st.refs.Add(-1) switch { case refs > 0: return false case refs == 0: return true default: panic("Cannot unref freed data") } } opentelemetry-collector-0.141.0/pdata/internal/state_test.go000066400000000000000000000010771511331344600241560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/internal/testutil" ) func TestAssertMutable(t *testing.T) { assert.NotPanics(t, func() { NewState().AssertMutable() }) assert.Panics(t, func() { state := NewState() state.MarkReadOnly() state.AssertMutable() }) } func BenchmarkAssertMutable(b *testing.B) { testutil.SkipMemoryBench(b) b.ReportAllocs() mutable := NewState() for b.Loop() { mutable.AssertMutable() } } opentelemetry-collector-0.141.0/pdata/internal/traceid.go000066400000000000000000000035721511331344600234140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" import ( "encoding/hex" "errors" "go.opentelemetry.io/collector/pdata/internal/json" ) const traceIDSize = 16 var errUnmarshalTraceID = errors.New("unmarshal: invalid TraceID length") // TraceID is a custom data type that is used for all trace_id fields in OTLP // Protobuf messages. type TraceID [traceIDSize]byte func DeleteTraceID(*TraceID, bool) {} func CopyTraceID(dest, src *TraceID) { *dest = *src } // IsEmpty returns true if id contains at leas one non-zero byte. func (tid TraceID) IsEmpty() bool { return tid == [traceIDSize]byte{} } // SizeProto returns the size of the data to serialize in proto format. func (tid TraceID) SizeProto() int { if tid.IsEmpty() { return 0 } return traceIDSize } // MarshalProto converts trace ID into a binary representation. Called by Protobuf serialization. func (tid TraceID) MarshalProto(buf []byte) int { if tid.IsEmpty() { return 0 } return copy(buf[len(buf)-traceIDSize:], tid[:]) } // UnmarshalProto inflates this trace ID from binary representation. Called by Protobuf serialization. func (tid *TraceID) UnmarshalProto(buf []byte) error { if len(buf) == 0 { *tid = [traceIDSize]byte{} return nil } if len(buf) != traceIDSize { return errUnmarshalTraceID } copy(tid[:], buf) return nil } // MarshalJSON converts TraceID into a hex string. // //nolint:govet func (tid TraceID) MarshalJSON(dest *json.Stream) { dest.WriteString(hex.EncodeToString(tid[:])) } // UnmarshalJSON decodes TraceID from hex string. // //nolint:govet func (tid *TraceID) UnmarshalJSON(iter *json.Iterator) { *tid = [profileIDSize]byte{} unmarshalJSON(tid[:], iter) } func GenTestTraceID() *TraceID { tid := TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) return &tid } opentelemetry-collector-0.141.0/pdata/internal/traceid_test.go000066400000000000000000000040641511331344600244500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal/json" ) func TestTraceID(t *testing.T) { tid := TraceID([traceIDSize]byte{}) assert.EqualValues(t, [traceIDSize]byte{}, tid) assert.Equal(t, 0, tid.SizeProto()) b := [traceIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} tid = b assert.EqualValues(t, b, tid) assert.Equal(t, traceIDSize, tid.SizeProto()) } func TestTraceIDMarshal(t *testing.T) { buf := make([]byte, traceIDSize) tid := TraceID([traceIDSize]byte{}) n := tid.MarshalProto(buf) assert.Equal(t, 0, n) tid = [traceIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} n = tid.MarshalProto(buf) assert.Equal(t, traceIDSize, n) assert.Equal(t, []byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78}, buf[0:traceIDSize]) } func TestTraceIDUnmarshal(t *testing.T) { buf := [16]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} tid := TraceID{} err := tid.UnmarshalProto(buf[:]) require.NoError(t, err) assert.EqualValues(t, buf, tid) err = tid.UnmarshalProto(buf[0:0]) require.NoError(t, err) assert.EqualValues(t, [traceIDSize]byte{}, tid) err = tid.UnmarshalProto(nil) require.NoError(t, err) assert.EqualValues(t, [traceIDSize]byte{}, tid) } func TestTraceIDMarshalAndUnmarshalJSON(t *testing.T) { stream := json.BorrowStream(nil) defer json.ReturnStream(stream) src := TraceID([traceIDSize]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78}) src.MarshalJSON(stream) require.NoError(t, stream.Error()) iter := json.BorrowIterator(stream.Buffer()) defer json.ReturnIterator(iter) dest := TraceID{} dest.UnmarshalJSON(iter) require.NoError(t, iter.Error()) assert.Equal(t, src, dest) } opentelemetry-collector-0.141.0/pdata/internal/unpacked_unmarshal_test.go000066400000000000000000000033701511331344600267000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "encoding/binary" "math" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal/proto" ) // For each repeated field in the OTLP proto that should be packed, check that we can unmarshal // payloads where it is encoded as unpacked. // The Protobuf spec recommends this for backwards compatibility purposes. // We do not test profiles payloads since their proto definition is currently in development. func appendTag(buf []byte, fieldNo byte, wireType proto.WireType) []byte { return append(buf, (fieldNo<<3)|byte(wireType)) } func appendVarint(buf []byte, v uint64) []byte { n := proto.Sov(v) for range n { buf = append(buf, 0) } _ = proto.EncodeVarint(buf, len(buf), v) return buf } func TestUnmarshalUnpackedHistogramDataPoint(t *testing.T) { var pb []byte pb = appendTag(pb, 6, proto.WireTypeI64) // bucket_counts pb = binary.LittleEndian.AppendUint64(pb, 42) pb = appendTag(pb, 7, proto.WireTypeI64) // explicit_bounds pb = binary.LittleEndian.AppendUint64(pb, math.Float64bits(42.0)) var hdp HistogramDataPoint err := hdp.UnmarshalProto(pb) require.NoError(t, err) assert.Equal(t, HistogramDataPoint{ BucketCounts: []uint64{42}, ExplicitBounds: []float64{42.0}, }, hdp) } func TestUnmarshalUnpackedExponentialHistogramDataPoint_Buckets(t *testing.T) { var pb []byte pb = appendTag(pb, 2, proto.WireTypeVarint) // bucket_counts pb = appendVarint(pb, 42) var ehdpb ExponentialHistogramDataPointBuckets err := ehdpb.UnmarshalProto(pb) require.NoError(t, err) assert.Equal(t, ExponentialHistogramDataPointBuckets{ BucketCounts: []uint64{42}, }, ehdpb) } opentelemetry-collector-0.141.0/pdata/internal/wrapper_logs.go000066400000000000000000000012041511331344600244730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" // LogsToProto internal helper to convert Logs to protobuf representation. func LogsToProto(l LogsWrapper) LogsData { return LogsData{ ResourceLogs: l.orig.ResourceLogs, } } // LogsFromProto internal helper to convert protobuf representation to Logs. // This function set exclusive state assuming that it's called only once per Logs. func LogsFromProto(orig LogsData) LogsWrapper { return NewLogsWrapper(&ExportLogsServiceRequest{ ResourceLogs: orig.ResourceLogs, }, NewState()) } opentelemetry-collector-0.141.0/pdata/internal/wrapper_map.go000066400000000000000000000010651511331344600243110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" type MapWrapper struct { orig *[]KeyValue state *State } func GetMapOrig(ms MapWrapper) *[]KeyValue { return ms.orig } func GetMapState(ms MapWrapper) *State { return ms.state } func NewMapWrapper(orig *[]KeyValue, state *State) MapWrapper { return MapWrapper{orig: orig, state: state} } func GenTestMapWrapper() MapWrapper { orig := GenTestKeyValueSlice() return NewMapWrapper(&orig, NewState()) } opentelemetry-collector-0.141.0/pdata/internal/wrapper_metrics.go000066400000000000000000000012721511331344600252020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" // MetricsToProto internal helper to convert Metrics to protobuf representation. func MetricsToProto(l MetricsWrapper) MetricsData { return MetricsData{ ResourceMetrics: l.orig.ResourceMetrics, } } // MetricsFromProto internal helper to convert protobuf representation to Metrics. // This function set exclusive state assuming that it's called only once per Metrics. func MetricsFromProto(orig MetricsData) MetricsWrapper { return NewMetricsWrapper(&ExportMetricsServiceRequest{ ResourceMetrics: orig.ResourceMetrics, }, NewState()) } opentelemetry-collector-0.141.0/pdata/internal/wrapper_profiles.go000066400000000000000000000014301511331344600253530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" // ProfilesToProto internal helper to convert Profiles to protobuf representation. func ProfilesToProto(l ProfilesWrapper) ProfilesData { return ProfilesData{ ResourceProfiles: l.orig.ResourceProfiles, Dictionary: l.orig.Dictionary, } } // ProfilesFromProto internal helper to convert protobuf representation to Profiles. // This function set exclusive state assuming that it's called only once per Profiles. func ProfilesFromProto(orig ProfilesData) ProfilesWrapper { return NewProfilesWrapper(&ExportProfilesServiceRequest{ ResourceProfiles: orig.ResourceProfiles, Dictionary: orig.Dictionary, }, NewState()) } opentelemetry-collector-0.141.0/pdata/internal/wrapper_traces.go000066400000000000000000000012431511331344600250130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" // TracesToProto internal helper to convert Traces to protobuf representation. func TracesToProto(l TracesWrapper) TracesData { return TracesData{ ResourceSpans: l.orig.ResourceSpans, } } // TracesFromProto internal helper to convert protobuf representation to Traces. // This function set exclusive state assuming that it's called only once per Traces. func TracesFromProto(orig TracesData) TracesWrapper { return NewTracesWrapper(&ExportTraceServiceRequest{ ResourceSpans: orig.ResourceSpans, }, NewState()) } opentelemetry-collector-0.141.0/pdata/internal/wrapper_tracestate.go000066400000000000000000000013151511331344600256710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" type TraceStateWrapper struct { orig *string state *State } func GetTraceStateOrig(ms TraceStateWrapper) *string { return ms.orig } func GetTraceStateState(ms TraceStateWrapper) *State { return ms.state } func NewTraceStateWrapper(orig *string, state *State) TraceStateWrapper { return TraceStateWrapper{orig: orig, state: state} } func GenTestTraceStateWrapper() TraceStateWrapper { return NewTraceStateWrapper(GenTestTraceState(), NewState()) } func GenTestTraceState() *string { orig := new(string) *orig = "rojo=00f067aa0ba902b7" return orig } opentelemetry-collector-0.141.0/pdata/internal/wrapper_value.go000066400000000000000000000035701511331344600246530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/pdata/internal" type ValueWrapper struct { orig *AnyValue state *State } func GetValueOrig(ms ValueWrapper) *AnyValue { return ms.orig } func GetValueState(ms ValueWrapper) *State { return ms.state } func NewValueWrapper(orig *AnyValue, state *State) ValueWrapper { return ValueWrapper{orig: orig, state: state} } func GenTestValueWrapper() ValueWrapper { orig := GenTestAnyValue() return NewValueWrapper(orig, NewState()) } func NewAnyValueStringValue() *AnyValue_StringValue { if !UseProtoPooling.IsEnabled() { return &AnyValue_StringValue{} } return ProtoPoolAnyValue_StringValue.Get().(*AnyValue_StringValue) } func NewAnyValueIntValue() *AnyValue_IntValue { if !UseProtoPooling.IsEnabled() { return &AnyValue_IntValue{} } return ProtoPoolAnyValue_IntValue.Get().(*AnyValue_IntValue) } func NewAnyValueBoolValue() *AnyValue_BoolValue { if !UseProtoPooling.IsEnabled() { return &AnyValue_BoolValue{} } return ProtoPoolAnyValue_BoolValue.Get().(*AnyValue_BoolValue) } func NewAnyValueDoubleValue() *AnyValue_DoubleValue { if !UseProtoPooling.IsEnabled() { return &AnyValue_DoubleValue{} } return ProtoPoolAnyValue_DoubleValue.Get().(*AnyValue_DoubleValue) } func NewAnyValueBytesValue() *AnyValue_BytesValue { if !UseProtoPooling.IsEnabled() { return &AnyValue_BytesValue{} } return ProtoPoolAnyValue_BytesValue.Get().(*AnyValue_BytesValue) } func NewAnyValueArrayValue() *AnyValue_ArrayValue { if !UseProtoPooling.IsEnabled() { return &AnyValue_ArrayValue{} } return ProtoPoolAnyValue_ArrayValue.Get().(*AnyValue_ArrayValue) } func NewAnyValueKvlistValue() *AnyValue_KvlistValue { if !UseProtoPooling.IsEnabled() { return &AnyValue_KvlistValue{} } return ProtoPoolAnyValue_KvlistValue.Get().(*AnyValue_KvlistValue) } opentelemetry-collector-0.141.0/pdata/internal/wrapper_value_test.go000066400000000000000000000011711511331344600257050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal import ( "testing" "github.com/stretchr/testify/require" gootlpcommon "go.opentelemetry.io/proto/slim/otlp/common/v1" goproto "google.golang.org/protobuf/proto" ) func TestAnyValueBytes(t *testing.T) { av := &gootlpcommon.AnyValue{Value: &gootlpcommon.AnyValue_BytesValue{BytesValue: nil}} buf, err := goproto.Marshal(av) require.NoError(t, err) pav := &AnyValue{Value: &AnyValue_BytesValue{BytesValue: nil}} pbuf := make([]byte, pav.SizeProto()) n := pav.MarshalProto(pbuf) pbuf = pbuf[:n] require.Equal(t, buf, pbuf) } opentelemetry-collector-0.141.0/pdata/metadata.yaml000066400000000000000000000003471511331344600222770ustar00rootroot00000000000000type: pdata github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg codeowners: active: - bogdandrutu - dmitryax stability: stable: [traces, metrics, logs] opentelemetry-collector-0.141.0/pdata/pcommon/000077500000000000000000000000001511331344600212775ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/pcommon/generated_byteslice.go000066400000000000000000000113321511331344600256270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "iter" "slices" "go.opentelemetry.io/collector/pdata/internal" ) // ByteSlice represents a []byte slice. // The instance of ByteSlice can be assigned to multiple objects since it's immutable. // // Must use NewByteSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ByteSlice internal.ByteSliceWrapper func (ms ByteSlice) getOrig() *[]byte { return internal.GetByteSliceOrig(internal.ByteSliceWrapper(ms)) } func (ms ByteSlice) getState() *internal.State { return internal.GetByteSliceState(internal.ByteSliceWrapper(ms)) } // NewByteSlice creates a new empty ByteSlice. func NewByteSlice() ByteSlice { orig := []byte(nil) return ByteSlice(internal.NewByteSliceWrapper(&orig, internal.NewState())) } // AsRaw returns a copy of the []byte slice. func (ms ByteSlice) AsRaw() []byte { return copyByteSlice(nil, *ms.getOrig()) } // FromRaw copies raw []byte into the slice ByteSlice. func (ms ByteSlice) FromRaw(val []byte) { ms.getState().AssertMutable() *ms.getOrig() = copyByteSlice(*ms.getOrig(), val) } // Len returns length of the []byte slice value. // Equivalent of len(byteSlice). func (ms ByteSlice) Len() int { return len(*ms.getOrig()) } // At returns an item from particular index. // Equivalent of byteSlice[i]. func (ms ByteSlice) At(i int) byte { return (*ms.getOrig())[i] } // All returns an iterator over index-value pairs in the slice. func (ms ByteSlice) All() iter.Seq2[int, byte] { return func(yield func(int, byte) bool) { for i := 0; i < ms.Len(); i++ { if !yield(i, ms.At(i)) { return } } } } // SetAt sets byte item at particular index. // Equivalent of byteSlice[i] = val func (ms ByteSlice) SetAt(i int, val byte) { ms.getState().AssertMutable() (*ms.getOrig())[i] = val } // EnsureCapacity ensures ByteSlice has at least the specified capacity. // 1. If the newCap <= cap, then is no change in capacity. // 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of: // buf := make([]byte, len(byteSlice), newCap) // copy(buf, byteSlice) // byteSlice = buf func (ms ByteSlice) EnsureCapacity(newCap int) { ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return } newOrig := make([]byte, len(*ms.getOrig()), newCap) copy(newOrig, *ms.getOrig()) *ms.getOrig() = newOrig } // Append appends extra elements to ByteSlice. // Equivalent of byteSlice = append(byteSlice, elms...) func (ms ByteSlice) Append(elms ...byte) { ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms ByteSlice) MoveTo(dest ByteSlice) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (ms ByteSlice) MoveAndAppendTo(dest ByteSlice) { ms.getState().AssertMutable() dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *ms.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *ms.getOrig()...) } *ms.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (ms ByteSlice) RemoveIf(f func(byte) bool) { ms.getState().AssertMutable() newLen := 0 for i := 0; i < len(*ms.getOrig()); i++ { if f((*ms.getOrig())[i]) { continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*ms.getOrig())[newLen] = (*ms.getOrig())[i] var zero byte (*ms.getOrig())[i] = zero newLen++ } *ms.getOrig() = (*ms.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (ms ByteSlice) CopyTo(dest ByteSlice) { dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = copyByteSlice(*dest.getOrig(), *ms.getOrig()) } // Equal checks equality with another ByteSlice func (ms ByteSlice) Equal(val ByteSlice) bool { return slices.Equal(*ms.getOrig(), *val.getOrig()) } func copyByteSlice(dst, src []byte) []byte { return append(dst[:0], src...) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_byteslice_test.go000066400000000000000000000076441511331344600267010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestNewByteSlice(t *testing.T) { ms := NewByteSlice() assert.Equal(t, 0, ms.Len()) ms.FromRaw([]byte{1, 2, 3}) assert.Equal(t, 3, ms.Len()) assert.Equal(t, []byte{1, 2, 3}, ms.AsRaw()) ms.SetAt(1, byte(5)) assert.Equal(t, []byte{1, 5, 3}, ms.AsRaw()) ms.FromRaw([]byte{3}) assert.Equal(t, 1, ms.Len()) assert.Equal(t, byte(3), ms.At(0)) cp := NewByteSlice() ms.CopyTo(cp) ms.SetAt(0, byte(2)) assert.Equal(t, byte(2), ms.At(0)) assert.Equal(t, byte(3), cp.At(0)) ms.CopyTo(cp) assert.Equal(t, byte(2), cp.At(0)) mv := NewByteSlice() ms.MoveTo(mv) assert.Equal(t, 0, ms.Len()) assert.Equal(t, 1, mv.Len()) assert.Equal(t, byte(2), mv.At(0)) ms.FromRaw([]byte{1, 2, 3}) ms.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, byte(1), mv.At(0)) mv.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, byte(1), mv.At(0)) } func TestByteSliceReadOnly(t *testing.T) { raw := []byte{1, 2, 3} sharedState := internal.NewState() sharedState.MarkReadOnly() ms := ByteSlice(internal.NewByteSliceWrapper(&raw, sharedState)) assert.Equal(t, 3, ms.Len()) assert.Equal(t, byte(1), ms.At(0)) assert.Panics(t, func() { ms.Append(1) }) assert.Panics(t, func() { ms.EnsureCapacity(2) }) assert.Equal(t, raw, ms.AsRaw()) assert.Panics(t, func() { ms.FromRaw(raw) }) ms2 := NewByteSlice() ms.CopyTo(ms2) assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) assert.Panics(t, func() { ms2.CopyTo(ms) }) assert.Panics(t, func() { ms.MoveTo(ms2) }) assert.Panics(t, func() { ms2.MoveTo(ms) }) } func TestByteSliceAppend(t *testing.T) { ms := NewByteSlice() ms.FromRaw([]byte{1, 2, 3}) ms.Append(5, 5) assert.Equal(t, 5, ms.Len()) assert.Equal(t, byte(5), ms.At(4)) } func TestByteSliceEnsureCapacity(t *testing.T) { ms := NewByteSlice() ms.EnsureCapacity(4) assert.Equal(t, 4, cap(*ms.getOrig())) ms.EnsureCapacity(2) assert.Equal(t, 4, cap(*ms.getOrig())) } func TestByteSliceAll(t *testing.T) { ms := NewByteSlice() ms.FromRaw([]byte{1, 2, 3}) assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestByteSliceMoveAndAppendTo(t *testing.T) { // Test moving from an empty slice ms := NewByteSlice() ms2 := NewByteSlice() ms.MoveAndAppendTo(ms2) assert.Equal(t, NewByteSlice(), ms2) assert.Equal(t, ms.Len(), 0) // Test moving to empty slice ms.FromRaw([]byte{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 3) // Test moving to a non empty slice ms.FromRaw([]byte{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 6) } func TestByteSliceRemoveIf(t *testing.T) { emptySlice := NewByteSlice() emptySlice.RemoveIf(func(el byte) bool { t.Fail() return false }) ms := NewByteSlice() ms.FromRaw([]byte{1, 2, 3}) pos := 0 ms.RemoveIf(func(el byte) bool { pos++ return pos%2 == 1 }) assert.Equal(t, pos/2, ms.Len()) } func TestByteSliceRemoveIfAll(t *testing.T) { ms := NewByteSlice() ms.FromRaw([]byte{1, 2, 3}) ms.RemoveIf(func(el byte) bool { return true }) assert.Equal(t, 0, ms.Len()) } func TestByteSliceEqual(t *testing.T) { ms := NewByteSlice() ms2 := NewByteSlice() assert.True(t, ms.Equal(ms2)) ms.Append(1, 2, 3) assert.False(t, ms.Equal(ms2)) ms2.Append(1, 2, 3) assert.True(t, ms.Equal(ms2)) } func BenchmarkByteSliceEqual(b *testing.B) { testutil.SkipMemoryBench(b) ms := NewByteSlice() ms.Append(1, 2, 3) cmp := NewByteSlice() cmp.Append(1, 2, 3) b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { _ = ms.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/generated_float64slice.go000066400000000000000000000116541511331344600261520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "iter" "slices" "go.opentelemetry.io/collector/pdata/internal" ) // Float64Slice represents a []float64 slice. // The instance of Float64Slice can be assigned to multiple objects since it's immutable. // // Must use NewFloat64Slice function to create new instances. // Important: zero-initialized instance is not valid for use. type Float64Slice internal.Float64SliceWrapper func (ms Float64Slice) getOrig() *[]float64 { return internal.GetFloat64SliceOrig(internal.Float64SliceWrapper(ms)) } func (ms Float64Slice) getState() *internal.State { return internal.GetFloat64SliceState(internal.Float64SliceWrapper(ms)) } // NewFloat64Slice creates a new empty Float64Slice. func NewFloat64Slice() Float64Slice { orig := []float64(nil) return Float64Slice(internal.NewFloat64SliceWrapper(&orig, internal.NewState())) } // AsRaw returns a copy of the []float64 slice. func (ms Float64Slice) AsRaw() []float64 { return copyFloat64Slice(nil, *ms.getOrig()) } // FromRaw copies raw []float64 into the slice Float64Slice. func (ms Float64Slice) FromRaw(val []float64) { ms.getState().AssertMutable() *ms.getOrig() = copyFloat64Slice(*ms.getOrig(), val) } // Len returns length of the []float64 slice value. // Equivalent of len(float64Slice). func (ms Float64Slice) Len() int { return len(*ms.getOrig()) } // At returns an item from particular index. // Equivalent of float64Slice[i]. func (ms Float64Slice) At(i int) float64 { return (*ms.getOrig())[i] } // All returns an iterator over index-value pairs in the slice. func (ms Float64Slice) All() iter.Seq2[int, float64] { return func(yield func(int, float64) bool) { for i := 0; i < ms.Len(); i++ { if !yield(i, ms.At(i)) { return } } } } // SetAt sets float64 item at particular index. // Equivalent of float64Slice[i] = val func (ms Float64Slice) SetAt(i int, val float64) { ms.getState().AssertMutable() (*ms.getOrig())[i] = val } // EnsureCapacity ensures Float64Slice has at least the specified capacity. // 1. If the newCap <= cap, then is no change in capacity. // 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of: // buf := make([]float64, len(float64Slice), newCap) // copy(buf, float64Slice) // float64Slice = buf func (ms Float64Slice) EnsureCapacity(newCap int) { ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return } newOrig := make([]float64, len(*ms.getOrig()), newCap) copy(newOrig, *ms.getOrig()) *ms.getOrig() = newOrig } // Append appends extra elements to Float64Slice. // Equivalent of float64Slice = append(float64Slice, elms...) func (ms Float64Slice) Append(elms ...float64) { ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms Float64Slice) MoveTo(dest Float64Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (ms Float64Slice) MoveAndAppendTo(dest Float64Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *ms.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *ms.getOrig()...) } *ms.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (ms Float64Slice) RemoveIf(f func(float64) bool) { ms.getState().AssertMutable() newLen := 0 for i := 0; i < len(*ms.getOrig()); i++ { if f((*ms.getOrig())[i]) { continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*ms.getOrig())[newLen] = (*ms.getOrig())[i] var zero float64 (*ms.getOrig())[i] = zero newLen++ } *ms.getOrig() = (*ms.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (ms Float64Slice) CopyTo(dest Float64Slice) { dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = copyFloat64Slice(*dest.getOrig(), *ms.getOrig()) } // Equal checks equality with another Float64Slice func (ms Float64Slice) Equal(val Float64Slice) bool { return slices.Equal(*ms.getOrig(), *val.getOrig()) } func copyFloat64Slice(dst, src []float64) []float64 { return append(dst[:0], src...) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_float64slice_test.go000066400000000000000000000104111511331344600271770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestNewFloat64Slice(t *testing.T) { ms := NewFloat64Slice() assert.Equal(t, 0, ms.Len()) ms.FromRaw([]float64{1.1, 2.2, 3.3}) assert.Equal(t, 3, ms.Len()) assert.Equal(t, []float64{1.1, 2.2, 3.3}, ms.AsRaw()) ms.SetAt(1, float64(5.5)) assert.Equal(t, []float64{1.1, 5.5, 3.3}, ms.AsRaw()) ms.FromRaw([]float64{3.3}) assert.Equal(t, 1, ms.Len()) assert.InDelta(t, float64(3.3), ms.At(0), 0.01) cp := NewFloat64Slice() ms.CopyTo(cp) ms.SetAt(0, float64(2.2)) assert.InDelta(t, float64(2.2), ms.At(0), 0.01) assert.InDelta(t, float64(3.3), cp.At(0), 0.01) ms.CopyTo(cp) assert.InDelta(t, float64(2.2), cp.At(0), 0.01) mv := NewFloat64Slice() ms.MoveTo(mv) assert.Equal(t, 0, ms.Len()) assert.Equal(t, 1, mv.Len()) assert.InDelta(t, float64(2.2), mv.At(0), 0.01) ms.FromRaw([]float64{1.1, 2.2, 3.3}) ms.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.InDelta(t, float64(1.1), mv.At(0), 0.01) mv.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.InDelta(t, float64(1.1), mv.At(0), 0.01) } func TestFloat64SliceReadOnly(t *testing.T) { raw := []float64{1.1, 2.2, 3.3} sharedState := internal.NewState() sharedState.MarkReadOnly() ms := Float64Slice(internal.NewFloat64SliceWrapper(&raw, sharedState)) assert.Equal(t, 3, ms.Len()) assert.InDelta(t, float64(1.1), ms.At(0), 0.01) assert.Panics(t, func() { ms.Append(1.1) }) assert.Panics(t, func() { ms.EnsureCapacity(2) }) assert.Equal(t, raw, ms.AsRaw()) assert.Panics(t, func() { ms.FromRaw(raw) }) ms2 := NewFloat64Slice() ms.CopyTo(ms2) assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) assert.Panics(t, func() { ms2.CopyTo(ms) }) assert.Panics(t, func() { ms.MoveTo(ms2) }) assert.Panics(t, func() { ms2.MoveTo(ms) }) } func TestFloat64SliceAppend(t *testing.T) { ms := NewFloat64Slice() ms.FromRaw([]float64{1.1, 2.2, 3.3}) ms.Append(5.5, 5.5) assert.Equal(t, 5, ms.Len()) assert.InDelta(t, float64(5.5), ms.At(4), 0.01) } func TestFloat64SliceEnsureCapacity(t *testing.T) { ms := NewFloat64Slice() ms.EnsureCapacity(4) assert.Equal(t, 4, cap(*ms.getOrig())) ms.EnsureCapacity(2) assert.Equal(t, 4, cap(*ms.getOrig())) } func TestFloat64SliceAll(t *testing.T) { ms := NewFloat64Slice() ms.FromRaw([]float64{1.1, 2.2, 3.3}) assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestFloat64SliceMoveAndAppendTo(t *testing.T) { // Test moving from an empty slice ms := NewFloat64Slice() ms2 := NewFloat64Slice() ms.MoveAndAppendTo(ms2) assert.Equal(t, NewFloat64Slice(), ms2) assert.Equal(t, ms.Len(), 0) // Test moving to empty slice ms.FromRaw([]float64{1.1, 2.2, 3.3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 3) // Test moving to a non empty slice ms.FromRaw([]float64{1.1, 2.2, 3.3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 6) } func TestFloat64SliceRemoveIf(t *testing.T) { emptySlice := NewFloat64Slice() emptySlice.RemoveIf(func(el float64) bool { t.Fail() return false }) ms := NewFloat64Slice() ms.FromRaw([]float64{1.1, 2.2, 3.3}) pos := 0 ms.RemoveIf(func(el float64) bool { pos++ return pos%2 == 1 }) assert.Equal(t, pos/2, ms.Len()) } func TestFloat64SliceRemoveIfAll(t *testing.T) { ms := NewFloat64Slice() ms.FromRaw([]float64{1.1, 2.2, 3.3}) ms.RemoveIf(func(el float64) bool { return true }) assert.Equal(t, 0, ms.Len()) } func TestFloat64SliceEqual(t *testing.T) { ms := NewFloat64Slice() ms2 := NewFloat64Slice() assert.True(t, ms.Equal(ms2)) ms.Append(1.1, 2.2, 3.3) assert.False(t, ms.Equal(ms2)) ms2.Append(1.1, 2.2, 3.3) assert.True(t, ms.Equal(ms2)) } func BenchmarkFloat64SliceEqual(b *testing.B) { testutil.SkipMemoryBench(b) ms := NewFloat64Slice() ms.Append(1.1, 2.2, 3.3) cmp := NewFloat64Slice() cmp.Append(1.1, 2.2, 3.3) b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { _ = ms.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/generated_instrumentationscope.go000066400000000000000000000071531511331344600301470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "go.opentelemetry.io/collector/pdata/internal" ) // InstrumentationScope is a message representing the instrumentation scope information. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewInstrumentationScope function to create new instances. // Important: zero-initialized instance is not valid for use. type InstrumentationScope internal.InstrumentationScopeWrapper func newInstrumentationScope(orig *internal.InstrumentationScope, state *internal.State) InstrumentationScope { return InstrumentationScope(internal.NewInstrumentationScopeWrapper(orig, state)) } // NewInstrumentationScope creates a new empty InstrumentationScope. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewInstrumentationScope() InstrumentationScope { return newInstrumentationScope(internal.NewInstrumentationScope(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms InstrumentationScope) MoveTo(dest InstrumentationScope) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteInstrumentationScope(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // Name returns the name associated with this InstrumentationScope. func (ms InstrumentationScope) Name() string { return ms.getOrig().Name } // SetName replaces the name associated with this InstrumentationScope. func (ms InstrumentationScope) SetName(v string) { ms.getState().AssertMutable() ms.getOrig().Name = v } // Version returns the version associated with this InstrumentationScope. func (ms InstrumentationScope) Version() string { return ms.getOrig().Version } // SetVersion replaces the version associated with this InstrumentationScope. func (ms InstrumentationScope) SetVersion(v string) { ms.getState().AssertMutable() ms.getOrig().Version = v } // Attributes returns the Attributes associated with this InstrumentationScope. func (ms InstrumentationScope) Attributes() Map { return Map(internal.NewMapWrapper(&ms.getOrig().Attributes, ms.getState())) } // DroppedAttributesCount returns the droppedattributescount associated with this InstrumentationScope. func (ms InstrumentationScope) DroppedAttributesCount() uint32 { return ms.getOrig().DroppedAttributesCount } // SetDroppedAttributesCount replaces the droppedattributescount associated with this InstrumentationScope. func (ms InstrumentationScope) SetDroppedAttributesCount(v uint32) { ms.getState().AssertMutable() ms.getOrig().DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms InstrumentationScope) CopyTo(dest InstrumentationScope) { dest.getState().AssertMutable() internal.CopyInstrumentationScope(dest.getOrig(), ms.getOrig()) } func (ms InstrumentationScope) getOrig() *internal.InstrumentationScope { return internal.GetInstrumentationScopeOrig(internal.InstrumentationScopeWrapper(ms)) } func (ms InstrumentationScope) getState() *internal.State { return internal.GetInstrumentationScopeState(internal.InstrumentationScopeWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_instrumentationscope_test.go000066400000000000000000000057431511331344600312110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestInstrumentationScope_MoveTo(t *testing.T) { ms := generateTestInstrumentationScope() dest := NewInstrumentationScope() ms.MoveTo(dest) assert.Equal(t, NewInstrumentationScope(), ms) assert.Equal(t, generateTestInstrumentationScope(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestInstrumentationScope(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newInstrumentationScope(internal.NewInstrumentationScope(), sharedState)) }) assert.Panics(t, func() { newInstrumentationScope(internal.NewInstrumentationScope(), sharedState).MoveTo(dest) }) } func TestInstrumentationScope_CopyTo(t *testing.T) { ms := NewInstrumentationScope() orig := NewInstrumentationScope() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestInstrumentationScope() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newInstrumentationScope(internal.NewInstrumentationScope(), sharedState)) }) } func TestInstrumentationScope_Name(t *testing.T) { ms := NewInstrumentationScope() assert.Empty(t, ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newInstrumentationScope(internal.NewInstrumentationScope(), sharedState).SetName("test_name") }) } func TestInstrumentationScope_Version(t *testing.T) { ms := NewInstrumentationScope() assert.Empty(t, ms.Version()) ms.SetVersion("test_version") assert.Equal(t, "test_version", ms.Version()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newInstrumentationScope(internal.NewInstrumentationScope(), sharedState).SetVersion("test_version") }) } func TestInstrumentationScope_Attributes(t *testing.T) { ms := NewInstrumentationScope() assert.Equal(t, NewMap(), ms.Attributes()) ms.getOrig().Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestInstrumentationScope_DroppedAttributesCount(t *testing.T) { ms := NewInstrumentationScope() assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedAttributesCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newInstrumentationScope(internal.NewInstrumentationScope(), sharedState).SetDroppedAttributesCount(uint32(13)) }) } func generateTestInstrumentationScope() InstrumentationScope { return newInstrumentationScope(internal.GenTestInstrumentationScope(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_int32slice.go000066400000000000000000000114401511331344600256230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "iter" "slices" "go.opentelemetry.io/collector/pdata/internal" ) // Int32Slice represents a []int32 slice. // The instance of Int32Slice can be assigned to multiple objects since it's immutable. // // Must use NewInt32Slice function to create new instances. // Important: zero-initialized instance is not valid for use. type Int32Slice internal.Int32SliceWrapper func (ms Int32Slice) getOrig() *[]int32 { return internal.GetInt32SliceOrig(internal.Int32SliceWrapper(ms)) } func (ms Int32Slice) getState() *internal.State { return internal.GetInt32SliceState(internal.Int32SliceWrapper(ms)) } // NewInt32Slice creates a new empty Int32Slice. func NewInt32Slice() Int32Slice { orig := []int32(nil) return Int32Slice(internal.NewInt32SliceWrapper(&orig, internal.NewState())) } // AsRaw returns a copy of the []int32 slice. func (ms Int32Slice) AsRaw() []int32 { return copyInt32Slice(nil, *ms.getOrig()) } // FromRaw copies raw []int32 into the slice Int32Slice. func (ms Int32Slice) FromRaw(val []int32) { ms.getState().AssertMutable() *ms.getOrig() = copyInt32Slice(*ms.getOrig(), val) } // Len returns length of the []int32 slice value. // Equivalent of len(int32Slice). func (ms Int32Slice) Len() int { return len(*ms.getOrig()) } // At returns an item from particular index. // Equivalent of int32Slice[i]. func (ms Int32Slice) At(i int) int32 { return (*ms.getOrig())[i] } // All returns an iterator over index-value pairs in the slice. func (ms Int32Slice) All() iter.Seq2[int, int32] { return func(yield func(int, int32) bool) { for i := 0; i < ms.Len(); i++ { if !yield(i, ms.At(i)) { return } } } } // SetAt sets int32 item at particular index. // Equivalent of int32Slice[i] = val func (ms Int32Slice) SetAt(i int, val int32) { ms.getState().AssertMutable() (*ms.getOrig())[i] = val } // EnsureCapacity ensures Int32Slice has at least the specified capacity. // 1. If the newCap <= cap, then is no change in capacity. // 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of: // buf := make([]int32, len(int32Slice), newCap) // copy(buf, int32Slice) // int32Slice = buf func (ms Int32Slice) EnsureCapacity(newCap int) { ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return } newOrig := make([]int32, len(*ms.getOrig()), newCap) copy(newOrig, *ms.getOrig()) *ms.getOrig() = newOrig } // Append appends extra elements to Int32Slice. // Equivalent of int32Slice = append(int32Slice, elms...) func (ms Int32Slice) Append(elms ...int32) { ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms Int32Slice) MoveTo(dest Int32Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (ms Int32Slice) MoveAndAppendTo(dest Int32Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *ms.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *ms.getOrig()...) } *ms.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (ms Int32Slice) RemoveIf(f func(int32) bool) { ms.getState().AssertMutable() newLen := 0 for i := 0; i < len(*ms.getOrig()); i++ { if f((*ms.getOrig())[i]) { continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*ms.getOrig())[newLen] = (*ms.getOrig())[i] var zero int32 (*ms.getOrig())[i] = zero newLen++ } *ms.getOrig() = (*ms.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (ms Int32Slice) CopyTo(dest Int32Slice) { dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = copyInt32Slice(*dest.getOrig(), *ms.getOrig()) } // Equal checks equality with another Int32Slice func (ms Int32Slice) Equal(val Int32Slice) bool { return slices.Equal(*ms.getOrig(), *val.getOrig()) } func copyInt32Slice(dst, src []int32) []int32 { return append(dst[:0], src...) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_int32slice_test.go000066400000000000000000000077331511331344600266740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestNewInt32Slice(t *testing.T) { ms := NewInt32Slice() assert.Equal(t, 0, ms.Len()) ms.FromRaw([]int32{1, 2, 3}) assert.Equal(t, 3, ms.Len()) assert.Equal(t, []int32{1, 2, 3}, ms.AsRaw()) ms.SetAt(1, int32(5)) assert.Equal(t, []int32{1, 5, 3}, ms.AsRaw()) ms.FromRaw([]int32{3}) assert.Equal(t, 1, ms.Len()) assert.Equal(t, int32(3), ms.At(0)) cp := NewInt32Slice() ms.CopyTo(cp) ms.SetAt(0, int32(2)) assert.Equal(t, int32(2), ms.At(0)) assert.Equal(t, int32(3), cp.At(0)) ms.CopyTo(cp) assert.Equal(t, int32(2), cp.At(0)) mv := NewInt32Slice() ms.MoveTo(mv) assert.Equal(t, 0, ms.Len()) assert.Equal(t, 1, mv.Len()) assert.Equal(t, int32(2), mv.At(0)) ms.FromRaw([]int32{1, 2, 3}) ms.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, int32(1), mv.At(0)) mv.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, int32(1), mv.At(0)) } func TestInt32SliceReadOnly(t *testing.T) { raw := []int32{1, 2, 3} sharedState := internal.NewState() sharedState.MarkReadOnly() ms := Int32Slice(internal.NewInt32SliceWrapper(&raw, sharedState)) assert.Equal(t, 3, ms.Len()) assert.Equal(t, int32(1), ms.At(0)) assert.Panics(t, func() { ms.Append(1) }) assert.Panics(t, func() { ms.EnsureCapacity(2) }) assert.Equal(t, raw, ms.AsRaw()) assert.Panics(t, func() { ms.FromRaw(raw) }) ms2 := NewInt32Slice() ms.CopyTo(ms2) assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) assert.Panics(t, func() { ms2.CopyTo(ms) }) assert.Panics(t, func() { ms.MoveTo(ms2) }) assert.Panics(t, func() { ms2.MoveTo(ms) }) } func TestInt32SliceAppend(t *testing.T) { ms := NewInt32Slice() ms.FromRaw([]int32{1, 2, 3}) ms.Append(5, 5) assert.Equal(t, 5, ms.Len()) assert.Equal(t, int32(5), ms.At(4)) } func TestInt32SliceEnsureCapacity(t *testing.T) { ms := NewInt32Slice() ms.EnsureCapacity(4) assert.Equal(t, 4, cap(*ms.getOrig())) ms.EnsureCapacity(2) assert.Equal(t, 4, cap(*ms.getOrig())) } func TestInt32SliceAll(t *testing.T) { ms := NewInt32Slice() ms.FromRaw([]int32{1, 2, 3}) assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestInt32SliceMoveAndAppendTo(t *testing.T) { // Test moving from an empty slice ms := NewInt32Slice() ms2 := NewInt32Slice() ms.MoveAndAppendTo(ms2) assert.Equal(t, NewInt32Slice(), ms2) assert.Equal(t, ms.Len(), 0) // Test moving to empty slice ms.FromRaw([]int32{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 3) // Test moving to a non empty slice ms.FromRaw([]int32{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 6) } func TestInt32SliceRemoveIf(t *testing.T) { emptySlice := NewInt32Slice() emptySlice.RemoveIf(func(el int32) bool { t.Fail() return false }) ms := NewInt32Slice() ms.FromRaw([]int32{1, 2, 3}) pos := 0 ms.RemoveIf(func(el int32) bool { pos++ return pos%2 == 1 }) assert.Equal(t, pos/2, ms.Len()) } func TestInt32SliceRemoveIfAll(t *testing.T) { ms := NewInt32Slice() ms.FromRaw([]int32{1, 2, 3}) ms.RemoveIf(func(el int32) bool { return true }) assert.Equal(t, 0, ms.Len()) } func TestInt32SliceEqual(t *testing.T) { ms := NewInt32Slice() ms2 := NewInt32Slice() assert.True(t, ms.Equal(ms2)) ms.Append(1, 2, 3) assert.False(t, ms.Equal(ms2)) ms2.Append(1, 2, 3) assert.True(t, ms.Equal(ms2)) } func BenchmarkInt32SliceEqual(b *testing.B) { testutil.SkipMemoryBench(b) ms := NewInt32Slice() ms.Append(1, 2, 3) cmp := NewInt32Slice() cmp.Append(1, 2, 3) b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { _ = ms.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/generated_int64slice.go000066400000000000000000000114401511331344600256300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "iter" "slices" "go.opentelemetry.io/collector/pdata/internal" ) // Int64Slice represents a []int64 slice. // The instance of Int64Slice can be assigned to multiple objects since it's immutable. // // Must use NewInt64Slice function to create new instances. // Important: zero-initialized instance is not valid for use. type Int64Slice internal.Int64SliceWrapper func (ms Int64Slice) getOrig() *[]int64 { return internal.GetInt64SliceOrig(internal.Int64SliceWrapper(ms)) } func (ms Int64Slice) getState() *internal.State { return internal.GetInt64SliceState(internal.Int64SliceWrapper(ms)) } // NewInt64Slice creates a new empty Int64Slice. func NewInt64Slice() Int64Slice { orig := []int64(nil) return Int64Slice(internal.NewInt64SliceWrapper(&orig, internal.NewState())) } // AsRaw returns a copy of the []int64 slice. func (ms Int64Slice) AsRaw() []int64 { return copyInt64Slice(nil, *ms.getOrig()) } // FromRaw copies raw []int64 into the slice Int64Slice. func (ms Int64Slice) FromRaw(val []int64) { ms.getState().AssertMutable() *ms.getOrig() = copyInt64Slice(*ms.getOrig(), val) } // Len returns length of the []int64 slice value. // Equivalent of len(int64Slice). func (ms Int64Slice) Len() int { return len(*ms.getOrig()) } // At returns an item from particular index. // Equivalent of int64Slice[i]. func (ms Int64Slice) At(i int) int64 { return (*ms.getOrig())[i] } // All returns an iterator over index-value pairs in the slice. func (ms Int64Slice) All() iter.Seq2[int, int64] { return func(yield func(int, int64) bool) { for i := 0; i < ms.Len(); i++ { if !yield(i, ms.At(i)) { return } } } } // SetAt sets int64 item at particular index. // Equivalent of int64Slice[i] = val func (ms Int64Slice) SetAt(i int, val int64) { ms.getState().AssertMutable() (*ms.getOrig())[i] = val } // EnsureCapacity ensures Int64Slice has at least the specified capacity. // 1. If the newCap <= cap, then is no change in capacity. // 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of: // buf := make([]int64, len(int64Slice), newCap) // copy(buf, int64Slice) // int64Slice = buf func (ms Int64Slice) EnsureCapacity(newCap int) { ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return } newOrig := make([]int64, len(*ms.getOrig()), newCap) copy(newOrig, *ms.getOrig()) *ms.getOrig() = newOrig } // Append appends extra elements to Int64Slice. // Equivalent of int64Slice = append(int64Slice, elms...) func (ms Int64Slice) Append(elms ...int64) { ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms Int64Slice) MoveTo(dest Int64Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (ms Int64Slice) MoveAndAppendTo(dest Int64Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *ms.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *ms.getOrig()...) } *ms.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (ms Int64Slice) RemoveIf(f func(int64) bool) { ms.getState().AssertMutable() newLen := 0 for i := 0; i < len(*ms.getOrig()); i++ { if f((*ms.getOrig())[i]) { continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*ms.getOrig())[newLen] = (*ms.getOrig())[i] var zero int64 (*ms.getOrig())[i] = zero newLen++ } *ms.getOrig() = (*ms.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (ms Int64Slice) CopyTo(dest Int64Slice) { dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = copyInt64Slice(*dest.getOrig(), *ms.getOrig()) } // Equal checks equality with another Int64Slice func (ms Int64Slice) Equal(val Int64Slice) bool { return slices.Equal(*ms.getOrig(), *val.getOrig()) } func copyInt64Slice(dst, src []int64) []int64 { return append(dst[:0], src...) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_int64slice_test.go000066400000000000000000000077331511331344600267010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestNewInt64Slice(t *testing.T) { ms := NewInt64Slice() assert.Equal(t, 0, ms.Len()) ms.FromRaw([]int64{1, 2, 3}) assert.Equal(t, 3, ms.Len()) assert.Equal(t, []int64{1, 2, 3}, ms.AsRaw()) ms.SetAt(1, int64(5)) assert.Equal(t, []int64{1, 5, 3}, ms.AsRaw()) ms.FromRaw([]int64{3}) assert.Equal(t, 1, ms.Len()) assert.Equal(t, int64(3), ms.At(0)) cp := NewInt64Slice() ms.CopyTo(cp) ms.SetAt(0, int64(2)) assert.Equal(t, int64(2), ms.At(0)) assert.Equal(t, int64(3), cp.At(0)) ms.CopyTo(cp) assert.Equal(t, int64(2), cp.At(0)) mv := NewInt64Slice() ms.MoveTo(mv) assert.Equal(t, 0, ms.Len()) assert.Equal(t, 1, mv.Len()) assert.Equal(t, int64(2), mv.At(0)) ms.FromRaw([]int64{1, 2, 3}) ms.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, int64(1), mv.At(0)) mv.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, int64(1), mv.At(0)) } func TestInt64SliceReadOnly(t *testing.T) { raw := []int64{1, 2, 3} sharedState := internal.NewState() sharedState.MarkReadOnly() ms := Int64Slice(internal.NewInt64SliceWrapper(&raw, sharedState)) assert.Equal(t, 3, ms.Len()) assert.Equal(t, int64(1), ms.At(0)) assert.Panics(t, func() { ms.Append(1) }) assert.Panics(t, func() { ms.EnsureCapacity(2) }) assert.Equal(t, raw, ms.AsRaw()) assert.Panics(t, func() { ms.FromRaw(raw) }) ms2 := NewInt64Slice() ms.CopyTo(ms2) assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) assert.Panics(t, func() { ms2.CopyTo(ms) }) assert.Panics(t, func() { ms.MoveTo(ms2) }) assert.Panics(t, func() { ms2.MoveTo(ms) }) } func TestInt64SliceAppend(t *testing.T) { ms := NewInt64Slice() ms.FromRaw([]int64{1, 2, 3}) ms.Append(5, 5) assert.Equal(t, 5, ms.Len()) assert.Equal(t, int64(5), ms.At(4)) } func TestInt64SliceEnsureCapacity(t *testing.T) { ms := NewInt64Slice() ms.EnsureCapacity(4) assert.Equal(t, 4, cap(*ms.getOrig())) ms.EnsureCapacity(2) assert.Equal(t, 4, cap(*ms.getOrig())) } func TestInt64SliceAll(t *testing.T) { ms := NewInt64Slice() ms.FromRaw([]int64{1, 2, 3}) assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestInt64SliceMoveAndAppendTo(t *testing.T) { // Test moving from an empty slice ms := NewInt64Slice() ms2 := NewInt64Slice() ms.MoveAndAppendTo(ms2) assert.Equal(t, NewInt64Slice(), ms2) assert.Equal(t, ms.Len(), 0) // Test moving to empty slice ms.FromRaw([]int64{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 3) // Test moving to a non empty slice ms.FromRaw([]int64{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 6) } func TestInt64SliceRemoveIf(t *testing.T) { emptySlice := NewInt64Slice() emptySlice.RemoveIf(func(el int64) bool { t.Fail() return false }) ms := NewInt64Slice() ms.FromRaw([]int64{1, 2, 3}) pos := 0 ms.RemoveIf(func(el int64) bool { pos++ return pos%2 == 1 }) assert.Equal(t, pos/2, ms.Len()) } func TestInt64SliceRemoveIfAll(t *testing.T) { ms := NewInt64Slice() ms.FromRaw([]int64{1, 2, 3}) ms.RemoveIf(func(el int64) bool { return true }) assert.Equal(t, 0, ms.Len()) } func TestInt64SliceEqual(t *testing.T) { ms := NewInt64Slice() ms2 := NewInt64Slice() assert.True(t, ms.Equal(ms2)) ms.Append(1, 2, 3) assert.False(t, ms.Equal(ms2)) ms2.Append(1, 2, 3) assert.True(t, ms.Equal(ms2)) } func BenchmarkInt64SliceEqual(b *testing.B) { testutil.SkipMemoryBench(b) ms := NewInt64Slice() ms.Append(1, 2, 3) cmp := NewInt64Slice() cmp.Append(1, 2, 3) b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { _ = ms.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/generated_resource.go000066400000000000000000000050461511331344600255000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "go.opentelemetry.io/collector/pdata/internal" ) // Resource is a message representing the resource information. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewResource function to create new instances. // Important: zero-initialized instance is not valid for use. type Resource internal.ResourceWrapper func newResource(orig *internal.Resource, state *internal.State) Resource { return Resource(internal.NewResourceWrapper(orig, state)) } // NewResource creates a new empty Resource. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResource() Resource { return newResource(internal.NewResource(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Resource) MoveTo(dest Resource) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteResource(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // Attributes returns the Attributes associated with this Resource. func (ms Resource) Attributes() Map { return Map(internal.NewMapWrapper(&ms.getOrig().Attributes, ms.getState())) } // DroppedAttributesCount returns the droppedattributescount associated with this Resource. func (ms Resource) DroppedAttributesCount() uint32 { return ms.getOrig().DroppedAttributesCount } // SetDroppedAttributesCount replaces the droppedattributescount associated with this Resource. func (ms Resource) SetDroppedAttributesCount(v uint32) { ms.getState().AssertMutable() ms.getOrig().DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms Resource) CopyTo(dest Resource) { dest.getState().AssertMutable() internal.CopyResource(dest.getOrig(), ms.getOrig()) } func (ms Resource) getOrig() *internal.Resource { return internal.GetResourceOrig(internal.ResourceWrapper(ms)) } func (ms Resource) getState() *internal.State { return internal.GetResourceState(internal.ResourceWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_resource_test.go000066400000000000000000000036531511331344600265410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestResource_MoveTo(t *testing.T) { ms := generateTestResource() dest := NewResource() ms.MoveTo(dest) assert.Equal(t, NewResource(), ms) assert.Equal(t, generateTestResource(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestResource(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newResource(internal.NewResource(), sharedState)) }) assert.Panics(t, func() { newResource(internal.NewResource(), sharedState).MoveTo(dest) }) } func TestResource_CopyTo(t *testing.T) { ms := NewResource() orig := NewResource() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestResource() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newResource(internal.NewResource(), sharedState)) }) } func TestResource_Attributes(t *testing.T) { ms := NewResource() assert.Equal(t, NewMap(), ms.Attributes()) ms.getOrig().Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestResource_DroppedAttributesCount(t *testing.T) { ms := NewResource() assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedAttributesCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newResource(internal.NewResource(), sharedState).SetDroppedAttributesCount(uint32(13)) }) } func generateTestResource() Resource { return newResource(internal.GenTestResource(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_slice.go000066400000000000000000000105171511331344600247470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "iter" "go.opentelemetry.io/collector/pdata/internal" ) // Slice logically represents a slice of Value. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type Slice internal.SliceWrapper func newSlice(orig *[]internal.AnyValue, state *internal.State) Slice { return Slice(internal.NewSliceWrapper(orig, state)) } // NewSlice creates a SliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSlice() Slice { orig := []internal.AnyValue(nil) return newSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewSlice()". func (es Slice) Len() int { return len(*es.getOrig()) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es Slice) At(i int) Value { return newValue(&(*es.getOrig())[i], es.getState()) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es Slice) All() iter.Seq2[int, Value] { return func(yield func(int, Value) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new Slice can be initialized: // // es := NewSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es Slice) EnsureCapacity(newCap int) { es.getState().AssertMutable() oldCap := cap(*es.getOrig()) if newCap <= oldCap { return } newOrig := make([]internal.AnyValue, len(*es.getOrig()), newCap) copy(newOrig, *es.getOrig()) *es.getOrig() = newOrig } // AppendEmpty will append to the end of the slice an empty Value. // It returns the newly added Value. func (es Slice) AppendEmpty() Value { es.getState().AssertMutable() *es.getOrig() = append(*es.getOrig(), internal.AnyValue{}) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es Slice) MoveAndAppendTo(dest Slice) { es.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.getOrig() == dest.getOrig() { return } if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *es.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *es.getOrig()...) } *es.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es Slice) RemoveIf(f func(Value) bool) { es.getState().AssertMutable() newLen := 0 for i := 0; i < len(*es.getOrig()); i++ { if f(es.At(i)) { internal.DeleteAnyValue(&(*es.getOrig())[i], false) continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.getOrig())[newLen] = (*es.getOrig())[i] (*es.getOrig())[i].Reset() newLen++ } *es.getOrig() = (*es.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es Slice) CopyTo(dest Slice) { dest.getState().AssertMutable() if es.getOrig() == dest.getOrig() { return } *dest.getOrig() = internal.CopyAnyValueSlice(*dest.getOrig(), *es.getOrig()) } func (ms Slice) getOrig() *[]internal.AnyValue { return internal.GetSliceOrig(internal.SliceWrapper(ms)) } func (ms Slice) getState() *internal.State { return internal.GetSliceState(internal.SliceWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_slice_test.go000066400000000000000000000076101511331344600260060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSlice(t *testing.T) { es := NewSlice() assert.Equal(t, 0, es.Len()) es = newSlice(&[]internal.AnyValue{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewValueEmpty() testVal := Value(internal.GenTestValueWrapper()) for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.getOrig())[i] = *internal.GenTestAnyValue() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newSlice(&[]internal.AnyValue{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestSlice_CopyTo(t *testing.T) { dest := NewSlice() src := generateTestSlice() src.CopyTo(dest) assert.Equal(t, generateTestSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestSlice(), dest) } func TestSlice_EnsureCapacity(t *testing.T) { es := generateTestSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.getOrig())) assert.Equal(t, generateTestSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.getOrig())) assert.Equal(t, generateTestSlice(), es) } func TestSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestSlice() dest := NewSlice() src := generateTestSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewSlice() emptySlice.RemoveIf(func(el Value) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestSlice() pos := 0 filtered.RemoveIf(func(el Value) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestSlice_RemoveIfAll(t *testing.T) { got := generateTestSlice() got.RemoveIf(func(el Value) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestSliceAll(t *testing.T) { ms := generateTestSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func generateTestSlice() Slice { ms := NewSlice() *ms.getOrig() = internal.GenTestAnyValueSlice() return ms } opentelemetry-collector-0.141.0/pdata/pcommon/generated_stringslice.go000066400000000000000000000115461511331344600262010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "iter" "slices" "go.opentelemetry.io/collector/pdata/internal" ) // StringSlice represents a []string slice. // The instance of StringSlice can be assigned to multiple objects since it's immutable. // // Must use NewStringSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type StringSlice internal.StringSliceWrapper func (ms StringSlice) getOrig() *[]string { return internal.GetStringSliceOrig(internal.StringSliceWrapper(ms)) } func (ms StringSlice) getState() *internal.State { return internal.GetStringSliceState(internal.StringSliceWrapper(ms)) } // NewStringSlice creates a new empty StringSlice. func NewStringSlice() StringSlice { orig := []string(nil) return StringSlice(internal.NewStringSliceWrapper(&orig, internal.NewState())) } // AsRaw returns a copy of the []string slice. func (ms StringSlice) AsRaw() []string { return copyStringSlice(nil, *ms.getOrig()) } // FromRaw copies raw []string into the slice StringSlice. func (ms StringSlice) FromRaw(val []string) { ms.getState().AssertMutable() *ms.getOrig() = copyStringSlice(*ms.getOrig(), val) } // Len returns length of the []string slice value. // Equivalent of len(stringSlice). func (ms StringSlice) Len() int { return len(*ms.getOrig()) } // At returns an item from particular index. // Equivalent of stringSlice[i]. func (ms StringSlice) At(i int) string { return (*ms.getOrig())[i] } // All returns an iterator over index-value pairs in the slice. func (ms StringSlice) All() iter.Seq2[int, string] { return func(yield func(int, string) bool) { for i := 0; i < ms.Len(); i++ { if !yield(i, ms.At(i)) { return } } } } // SetAt sets string item at particular index. // Equivalent of stringSlice[i] = val func (ms StringSlice) SetAt(i int, val string) { ms.getState().AssertMutable() (*ms.getOrig())[i] = val } // EnsureCapacity ensures StringSlice has at least the specified capacity. // 1. If the newCap <= cap, then is no change in capacity. // 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of: // buf := make([]string, len(stringSlice), newCap) // copy(buf, stringSlice) // stringSlice = buf func (ms StringSlice) EnsureCapacity(newCap int) { ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return } newOrig := make([]string, len(*ms.getOrig()), newCap) copy(newOrig, *ms.getOrig()) *ms.getOrig() = newOrig } // Append appends extra elements to StringSlice. // Equivalent of stringSlice = append(stringSlice, elms...) func (ms StringSlice) Append(elms ...string) { ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms StringSlice) MoveTo(dest StringSlice) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (ms StringSlice) MoveAndAppendTo(dest StringSlice) { ms.getState().AssertMutable() dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *ms.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *ms.getOrig()...) } *ms.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (ms StringSlice) RemoveIf(f func(string) bool) { ms.getState().AssertMutable() newLen := 0 for i := 0; i < len(*ms.getOrig()); i++ { if f((*ms.getOrig())[i]) { continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*ms.getOrig())[newLen] = (*ms.getOrig())[i] var zero string (*ms.getOrig())[i] = zero newLen++ } *ms.getOrig() = (*ms.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (ms StringSlice) CopyTo(dest StringSlice) { dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = copyStringSlice(*dest.getOrig(), *ms.getOrig()) } // Equal checks equality with another StringSlice func (ms StringSlice) Equal(val StringSlice) bool { return slices.Equal(*ms.getOrig(), *val.getOrig()) } func copyStringSlice(dst, src []string) []string { return append(dst[:0], src...) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_stringslice_test.go000066400000000000000000000102121511331344600272250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestNewStringSlice(t *testing.T) { ms := NewStringSlice() assert.Equal(t, 0, ms.Len()) ms.FromRaw([]string{"a", "b", "c"}) assert.Equal(t, 3, ms.Len()) assert.Equal(t, []string{"a", "b", "c"}, ms.AsRaw()) ms.SetAt(1, string("d")) assert.Equal(t, []string{"a", "d", "c"}, ms.AsRaw()) ms.FromRaw([]string{"c"}) assert.Equal(t, 1, ms.Len()) assert.Equal(t, string("c"), ms.At(0)) cp := NewStringSlice() ms.CopyTo(cp) ms.SetAt(0, string("b")) assert.Equal(t, string("b"), ms.At(0)) assert.Equal(t, string("c"), cp.At(0)) ms.CopyTo(cp) assert.Equal(t, string("b"), cp.At(0)) mv := NewStringSlice() ms.MoveTo(mv) assert.Equal(t, 0, ms.Len()) assert.Equal(t, 1, mv.Len()) assert.Equal(t, string("b"), mv.At(0)) ms.FromRaw([]string{"a", "b", "c"}) ms.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, string("a"), mv.At(0)) mv.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, string("a"), mv.At(0)) } func TestStringSliceReadOnly(t *testing.T) { raw := []string{"a", "b", "c"} sharedState := internal.NewState() sharedState.MarkReadOnly() ms := StringSlice(internal.NewStringSliceWrapper(&raw, sharedState)) assert.Equal(t, 3, ms.Len()) assert.Equal(t, string("a"), ms.At(0)) assert.Panics(t, func() { ms.Append("a") }) assert.Panics(t, func() { ms.EnsureCapacity(2) }) assert.Equal(t, raw, ms.AsRaw()) assert.Panics(t, func() { ms.FromRaw(raw) }) ms2 := NewStringSlice() ms.CopyTo(ms2) assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) assert.Panics(t, func() { ms2.CopyTo(ms) }) assert.Panics(t, func() { ms.MoveTo(ms2) }) assert.Panics(t, func() { ms2.MoveTo(ms) }) } func TestStringSliceAppend(t *testing.T) { ms := NewStringSlice() ms.FromRaw([]string{"a", "b", "c"}) ms.Append("d", "d") assert.Equal(t, 5, ms.Len()) assert.Equal(t, string("d"), ms.At(4)) } func TestStringSliceEnsureCapacity(t *testing.T) { ms := NewStringSlice() ms.EnsureCapacity(4) assert.Equal(t, 4, cap(*ms.getOrig())) ms.EnsureCapacity(2) assert.Equal(t, 4, cap(*ms.getOrig())) } func TestStringSliceAll(t *testing.T) { ms := NewStringSlice() ms.FromRaw([]string{"a", "b", "c"}) assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestStringSliceMoveAndAppendTo(t *testing.T) { // Test moving from an empty slice ms := NewStringSlice() ms2 := NewStringSlice() ms.MoveAndAppendTo(ms2) assert.Equal(t, NewStringSlice(), ms2) assert.Equal(t, ms.Len(), 0) // Test moving to empty slice ms.FromRaw([]string{"a", "b", "c"}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 3) // Test moving to a non empty slice ms.FromRaw([]string{"a", "b", "c"}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 6) } func TestStringSliceRemoveIf(t *testing.T) { emptySlice := NewStringSlice() emptySlice.RemoveIf(func(el string) bool { t.Fail() return false }) ms := NewStringSlice() ms.FromRaw([]string{"a", "b", "c"}) pos := 0 ms.RemoveIf(func(el string) bool { pos++ return pos%2 == 1 }) assert.Equal(t, pos/2, ms.Len()) } func TestStringSliceRemoveIfAll(t *testing.T) { ms := NewStringSlice() ms.FromRaw([]string{"a", "b", "c"}) ms.RemoveIf(func(el string) bool { return true }) assert.Equal(t, 0, ms.Len()) } func TestStringSliceEqual(t *testing.T) { ms := NewStringSlice() ms2 := NewStringSlice() assert.True(t, ms.Equal(ms2)) ms.Append("a", "b", "c") assert.False(t, ms.Equal(ms2)) ms2.Append("a", "b", "c") assert.True(t, ms.Equal(ms2)) } func BenchmarkStringSliceEqual(b *testing.B) { testutil.SkipMemoryBench(b) ms := NewStringSlice() ms.Append("a", "b", "c") cmp := NewStringSlice() cmp.Append("a", "b", "c") b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { _ = ms.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/generated_uint64slice.go000066400000000000000000000115461511331344600260240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "iter" "slices" "go.opentelemetry.io/collector/pdata/internal" ) // UInt64Slice represents a []uint64 slice. // The instance of UInt64Slice can be assigned to multiple objects since it's immutable. // // Must use NewUInt64Slice function to create new instances. // Important: zero-initialized instance is not valid for use. type UInt64Slice internal.UInt64SliceWrapper func (ms UInt64Slice) getOrig() *[]uint64 { return internal.GetUInt64SliceOrig(internal.UInt64SliceWrapper(ms)) } func (ms UInt64Slice) getState() *internal.State { return internal.GetUInt64SliceState(internal.UInt64SliceWrapper(ms)) } // NewUInt64Slice creates a new empty UInt64Slice. func NewUInt64Slice() UInt64Slice { orig := []uint64(nil) return UInt64Slice(internal.NewUInt64SliceWrapper(&orig, internal.NewState())) } // AsRaw returns a copy of the []uint64 slice. func (ms UInt64Slice) AsRaw() []uint64 { return copyUint64Slice(nil, *ms.getOrig()) } // FromRaw copies raw []uint64 into the slice UInt64Slice. func (ms UInt64Slice) FromRaw(val []uint64) { ms.getState().AssertMutable() *ms.getOrig() = copyUint64Slice(*ms.getOrig(), val) } // Len returns length of the []uint64 slice value. // Equivalent of len(uInt64Slice). func (ms UInt64Slice) Len() int { return len(*ms.getOrig()) } // At returns an item from particular index. // Equivalent of uInt64Slice[i]. func (ms UInt64Slice) At(i int) uint64 { return (*ms.getOrig())[i] } // All returns an iterator over index-value pairs in the slice. func (ms UInt64Slice) All() iter.Seq2[int, uint64] { return func(yield func(int, uint64) bool) { for i := 0; i < ms.Len(); i++ { if !yield(i, ms.At(i)) { return } } } } // SetAt sets uint64 item at particular index. // Equivalent of uInt64Slice[i] = val func (ms UInt64Slice) SetAt(i int, val uint64) { ms.getState().AssertMutable() (*ms.getOrig())[i] = val } // EnsureCapacity ensures UInt64Slice has at least the specified capacity. // 1. If the newCap <= cap, then is no change in capacity. // 2. If the newCap > cap, then the slice capacity will be expanded to the provided value which will be equivalent of: // buf := make([]uint64, len(uInt64Slice), newCap) // copy(buf, uInt64Slice) // uInt64Slice = buf func (ms UInt64Slice) EnsureCapacity(newCap int) { ms.getState().AssertMutable() oldCap := cap(*ms.getOrig()) if newCap <= oldCap { return } newOrig := make([]uint64, len(*ms.getOrig()), newCap) copy(newOrig, *ms.getOrig()) *ms.getOrig() = newOrig } // Append appends extra elements to UInt64Slice. // Equivalent of uInt64Slice = append(uInt64Slice, elms...) func (ms UInt64Slice) Append(elms ...uint64) { ms.getState().AssertMutable() *ms.getOrig() = append(*ms.getOrig(), elms...) } // MoveTo moves all elements from the current slice overriding the destination and // resetting the current instance to its zero value. func (ms UInt64Slice) MoveTo(dest UInt64Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = nil } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (ms UInt64Slice) MoveAndAppendTo(dest UInt64Slice) { ms.getState().AssertMutable() dest.getState().AssertMutable() if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *ms.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *ms.getOrig()...) } *ms.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (ms UInt64Slice) RemoveIf(f func(uint64) bool) { ms.getState().AssertMutable() newLen := 0 for i := 0; i < len(*ms.getOrig()); i++ { if f((*ms.getOrig())[i]) { continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*ms.getOrig())[newLen] = (*ms.getOrig())[i] var zero uint64 (*ms.getOrig())[i] = zero newLen++ } *ms.getOrig() = (*ms.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (ms UInt64Slice) CopyTo(dest UInt64Slice) { dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = copyUint64Slice(*dest.getOrig(), *ms.getOrig()) } // Equal checks equality with another UInt64Slice func (ms UInt64Slice) Equal(val UInt64Slice) bool { return slices.Equal(*ms.getOrig(), *val.getOrig()) } func copyUint64Slice(dst, src []uint64) []uint64 { return append(dst[:0], src...) } opentelemetry-collector-0.141.0/pdata/pcommon/generated_uint64slice_test.go000066400000000000000000000100221511331344600270470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestNewUInt64Slice(t *testing.T) { ms := NewUInt64Slice() assert.Equal(t, 0, ms.Len()) ms.FromRaw([]uint64{1, 2, 3}) assert.Equal(t, 3, ms.Len()) assert.Equal(t, []uint64{1, 2, 3}, ms.AsRaw()) ms.SetAt(1, uint64(5)) assert.Equal(t, []uint64{1, 5, 3}, ms.AsRaw()) ms.FromRaw([]uint64{3}) assert.Equal(t, 1, ms.Len()) assert.Equal(t, uint64(3), ms.At(0)) cp := NewUInt64Slice() ms.CopyTo(cp) ms.SetAt(0, uint64(2)) assert.Equal(t, uint64(2), ms.At(0)) assert.Equal(t, uint64(3), cp.At(0)) ms.CopyTo(cp) assert.Equal(t, uint64(2), cp.At(0)) mv := NewUInt64Slice() ms.MoveTo(mv) assert.Equal(t, 0, ms.Len()) assert.Equal(t, 1, mv.Len()) assert.Equal(t, uint64(2), mv.At(0)) ms.FromRaw([]uint64{1, 2, 3}) ms.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, uint64(1), mv.At(0)) mv.MoveTo(mv) assert.Equal(t, 3, mv.Len()) assert.Equal(t, uint64(1), mv.At(0)) } func TestUInt64SliceReadOnly(t *testing.T) { raw := []uint64{1, 2, 3} sharedState := internal.NewState() sharedState.MarkReadOnly() ms := UInt64Slice(internal.NewUInt64SliceWrapper(&raw, sharedState)) assert.Equal(t, 3, ms.Len()) assert.Equal(t, uint64(1), ms.At(0)) assert.Panics(t, func() { ms.Append(1) }) assert.Panics(t, func() { ms.EnsureCapacity(2) }) assert.Equal(t, raw, ms.AsRaw()) assert.Panics(t, func() { ms.FromRaw(raw) }) ms2 := NewUInt64Slice() ms.CopyTo(ms2) assert.Equal(t, ms.AsRaw(), ms2.AsRaw()) assert.Panics(t, func() { ms2.CopyTo(ms) }) assert.Panics(t, func() { ms.MoveTo(ms2) }) assert.Panics(t, func() { ms2.MoveTo(ms) }) } func TestUInt64SliceAppend(t *testing.T) { ms := NewUInt64Slice() ms.FromRaw([]uint64{1, 2, 3}) ms.Append(5, 5) assert.Equal(t, 5, ms.Len()) assert.Equal(t, uint64(5), ms.At(4)) } func TestUInt64SliceEnsureCapacity(t *testing.T) { ms := NewUInt64Slice() ms.EnsureCapacity(4) assert.Equal(t, 4, cap(*ms.getOrig())) ms.EnsureCapacity(2) assert.Equal(t, 4, cap(*ms.getOrig())) } func TestUInt64SliceAll(t *testing.T) { ms := NewUInt64Slice() ms.FromRaw([]uint64{1, 2, 3}) assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestUInt64SliceMoveAndAppendTo(t *testing.T) { // Test moving from an empty slice ms := NewUInt64Slice() ms2 := NewUInt64Slice() ms.MoveAndAppendTo(ms2) assert.Equal(t, NewUInt64Slice(), ms2) assert.Equal(t, ms.Len(), 0) // Test moving to empty slice ms.FromRaw([]uint64{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 3) // Test moving to a non empty slice ms.FromRaw([]uint64{1, 2, 3}) ms.MoveAndAppendTo(ms2) assert.Equal(t, ms2.Len(), 6) } func TestUInt64SliceRemoveIf(t *testing.T) { emptySlice := NewUInt64Slice() emptySlice.RemoveIf(func(el uint64) bool { t.Fail() return false }) ms := NewUInt64Slice() ms.FromRaw([]uint64{1, 2, 3}) pos := 0 ms.RemoveIf(func(el uint64) bool { pos++ return pos%2 == 1 }) assert.Equal(t, pos/2, ms.Len()) } func TestUInt64SliceRemoveIfAll(t *testing.T) { ms := NewUInt64Slice() ms.FromRaw([]uint64{1, 2, 3}) ms.RemoveIf(func(el uint64) bool { return true }) assert.Equal(t, 0, ms.Len()) } func TestUInt64SliceEqual(t *testing.T) { ms := NewUInt64Slice() ms2 := NewUInt64Slice() assert.True(t, ms.Equal(ms2)) ms.Append(1, 2, 3) assert.False(t, ms.Equal(ms2)) ms2.Append(1, 2, 3) assert.True(t, ms.Equal(ms2)) } func BenchmarkUInt64SliceEqual(b *testing.B) { testutil.SkipMemoryBench(b) ms := NewUInt64Slice() ms.Append(1, 2, 3) cmp := NewUInt64Slice() cmp.Append(1, 2, 3) b.ResetTimer() b.ReportAllocs() for n := 0; n < b.N; n++ { _ = ms.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/map.go000066400000000000000000000245271511331344600224150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "iter" "go.uber.org/multierr" "go.opentelemetry.io/collector/pdata/internal" ) // Map stores a map of string keys to elements of Value type. // // Must use NewMap function to create new instances. // Important: zero-initialized instance is not valid for use. type Map internal.MapWrapper // NewMap creates a Map with 0 elements. func NewMap() Map { orig := []internal.KeyValue(nil) return Map(internal.NewMapWrapper(&orig, internal.NewState())) } func (m Map) getOrig() *[]internal.KeyValue { return internal.GetMapOrig(internal.MapWrapper(m)) } func (m Map) getState() *internal.State { return internal.GetMapState(internal.MapWrapper(m)) } func newMap(orig *[]internal.KeyValue, state *internal.State) Map { return Map(internal.NewMapWrapper(orig, state)) } // Clear erases any existing entries in this Map instance. func (m Map) Clear() { m.getState().AssertMutable() *m.getOrig() = nil } // EnsureCapacity increases the capacity of this Map instance, if necessary, // to ensure that it can hold at least the number of elements specified by the capacity argument. func (m Map) EnsureCapacity(capacity int) { m.getState().AssertMutable() oldOrig := *m.getOrig() if capacity <= cap(oldOrig) { return } *m.getOrig() = make([]internal.KeyValue, len(oldOrig), capacity) copy(*m.getOrig(), oldOrig) } // Get returns the Value associated with the key and true. The returned // Value is not a copy, it is a reference to the value stored in this map. // It is allowed to modify the returned value using Value.Set* functions. // Such modification will be applied to the value stored in this map. // Accessing the returned value after modifying the underlying map // (removing or adding new values) is an undefined behavior. // // If the key does not exist, returns a zero-initialized KeyValue and false. // Calling any functions on the returned invalid instance may cause a panic. func (m Map) Get(key string) (Value, bool) { for i := range *m.getOrig() { akv := &(*m.getOrig())[i] if akv.Key == key { return newValue(&akv.Value, m.getState()), true } } return newValue(nil, m.getState()), false } // Remove removes the entry associated with the key and returns true if the key // was present in the map, otherwise returns false. func (m Map) Remove(key string) bool { m.getState().AssertMutable() for i := range *m.getOrig() { akv := &(*m.getOrig())[i] if akv.Key == key { *akv = (*m.getOrig())[len(*m.getOrig())-1] *m.getOrig() = (*m.getOrig())[:len(*m.getOrig())-1] return true } } return false } // RemoveIf removes the entries for which the function in question returns true func (m Map) RemoveIf(f func(string, Value) bool) { m.getState().AssertMutable() newLen := 0 for i := 0; i < len(*m.getOrig()); i++ { if f((*m.getOrig())[i].Key, newValue(&(*m.getOrig())[i].Value, m.getState())) { (*m.getOrig())[i] = internal.KeyValue{} continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*m.getOrig())[newLen] = (*m.getOrig())[i] (*m.getOrig())[i] = internal.KeyValue{} newLen++ } *m.getOrig() = (*m.getOrig())[:newLen] } // PutEmpty inserts or updates an empty value to the map under given key // and return the updated/inserted value. func (m Map) PutEmpty(k string) Value { m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.getOrig().Value = nil return newValue(av.getOrig(), m.getState()) } *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k}) return newValue(&(*m.getOrig())[len(*m.getOrig())-1].Value, m.getState()) } // GetOrPutEmpty returns the Value associated with the key and true (loaded) if the key exists in the map, // otherwise inserts an empty value to the map under the given key and returns the inserted value // and false (loaded). func (m Map) GetOrPutEmpty(k string) (Value, bool) { m.getState().AssertMutable() if av, existing := m.Get(k); existing { return av, true } *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k}) return newValue(&(*m.getOrig())[len(*m.getOrig())-1].Value, m.getState()), false } // PutStr performs the Insert or Update action. The Value is // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutStr(k, v string) { m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetStr(v) return } ov := internal.NewAnyValueStringValue() ov.StringValue = v *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k, Value: internal.AnyValue{Value: ov}}) } // PutInt performs the Insert or Update action. The int Value is // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutInt(k string, v int64) { m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetInt(v) return } ov := internal.NewAnyValueIntValue() ov.IntValue = v *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k, Value: internal.AnyValue{Value: ov}}) } // PutDouble performs the Insert or Update action. The double Value is // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutDouble(k string, v float64) { m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetDouble(v) return } ov := internal.NewAnyValueDoubleValue() ov.DoubleValue = v *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k, Value: internal.AnyValue{Value: ov}}) } // PutBool performs the Insert or Update action. The bool Value is // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. func (m Map) PutBool(k string, v bool) { m.getState().AssertMutable() if av, existing := m.Get(k); existing { av.SetBool(v) return } ov := internal.NewAnyValueBoolValue() ov.BoolValue = v *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k, Value: internal.AnyValue{Value: ov}}) } // PutEmptyBytes inserts or updates an empty byte slice under given key and returns it. func (m Map) PutEmptyBytes(k string) ByteSlice { m.getState().AssertMutable() if av, existing := m.Get(k); existing { return av.SetEmptyBytes() } ov := internal.NewAnyValueBytesValue() *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k, Value: internal.AnyValue{Value: ov}}) return ByteSlice(internal.NewByteSliceWrapper(&ov.BytesValue, m.getState())) } // PutEmptyMap inserts or updates an empty map under given key and returns it. func (m Map) PutEmptyMap(k string) Map { m.getState().AssertMutable() if av, existing := m.Get(k); existing { return av.SetEmptyMap() } ov := internal.NewAnyValueKvlistValue() ov.KvlistValue = internal.NewKeyValueList() *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k, Value: internal.AnyValue{Value: ov}}) return Map(internal.NewMapWrapper(&ov.KvlistValue.Values, m.getState())) } // PutEmptySlice inserts or updates an empty slice under given key and returns it. func (m Map) PutEmptySlice(k string) Slice { m.getState().AssertMutable() if av, existing := m.Get(k); existing { return av.SetEmptySlice() } ov := internal.NewAnyValueArrayValue() ov.ArrayValue = internal.NewArrayValue() *m.getOrig() = append(*m.getOrig(), internal.KeyValue{Key: k, Value: internal.AnyValue{Value: ov}}) return Slice(internal.NewSliceWrapper(&ov.ArrayValue.Values, m.getState())) } // Len returns the length of this map. // // Because the Map is represented internally by a slice of pointers, and the data are comping from the wire, // it is possible that when iterating using "Range" to get access to fewer elements because nil elements are skipped. func (m Map) Len() int { return len(*m.getOrig()) } // Range calls f sequentially for each key and value present in the map. If f returns false, range stops the iteration. // // Example: // // sm.Range(func(k string, v Value) bool { // ... // }) func (m Map) Range(f func(k string, v Value) bool) { for i := range *m.getOrig() { kv := &(*m.getOrig())[i] if !f(kv.Key, Value(internal.NewValueWrapper(&kv.Value, m.getState()))) { break } } } // All returns an iterator over key-value pairs in the Map. // // for k, v := range es.All() { // ... // Do something with key-value pair // } func (m Map) All() iter.Seq2[string, Value] { return func(yield func(string, Value) bool) { for i := range *m.getOrig() { kv := &(*m.getOrig())[i] if !yield(kv.Key, Value(internal.NewValueWrapper(&kv.Value, m.getState()))) { return } } } } // MoveTo moves all key/values from the current map overriding the destination and // resetting the current instance to its zero value func (m Map) MoveTo(dest Map) { m.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if m.getOrig() == dest.getOrig() { return } *dest.getOrig() = *m.getOrig() *m.getOrig() = nil } // CopyTo copies all elements from the current map overriding the destination. func (m Map) CopyTo(dest Map) { dest.getState().AssertMutable() if m.getOrig() == dest.getOrig() { return } *dest.getOrig() = internal.CopyKeyValueSlice(*dest.getOrig(), *m.getOrig()) } // AsRaw returns a standard go map representation of this Map. func (m Map) AsRaw() map[string]any { rawMap := make(map[string]any, m.Len()) m.Range(func(k string, v Value) bool { rawMap[k] = v.AsRaw() return true }) return rawMap } // FromRaw overrides this Map instance from a standard go map. func (m Map) FromRaw(rawMap map[string]any) error { m.getState().AssertMutable() if len(rawMap) == 0 { *m.getOrig() = nil return nil } var errs error origs := make([]internal.KeyValue, len(rawMap)) ix := 0 for k, iv := range rawMap { origs[ix].Key = k errs = multierr.Append(errs, newValue(&origs[ix].Value, m.getState()).FromRaw(iv)) ix++ } *m.getOrig() = origs return errs } // Equal checks equality with another Map func (m Map) Equal(val Map) bool { if m.Len() != val.Len() { return false } fullEqual := true m.Range(func(k string, v Value) bool { vv, ok := val.Get(k) if !ok { fullEqual = false return fullEqual } if !v.Equal(vv) { fullEqual = false } return fullEqual }) return fullEqual } opentelemetry-collector-0.141.0/pdata/pcommon/map_test.go000066400000000000000000000445071511331344600234540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestMap(t *testing.T) { assert.Equal(t, 0, NewMap().Len()) val, exist := NewMap().Get("test_key") assert.False(t, exist) assert.Equal(t, newValue(nil, internal.NewState()), val) putString := NewMap() putString.PutStr("k", "v") assert.Equal(t, generateTestStringMap(t), putString) putInt := NewMap() putInt.PutInt("k", 123) assert.Equal(t, generateTestIntMap(t), putInt) putDouble := NewMap() putDouble.PutDouble("k", 12.3) assert.Equal(t, generateTestDoubleMap(t), putDouble) putBool := NewMap() putBool.PutBool("k", true) assert.Equal(t, generateTestBoolMap(t), putBool) putBytes := NewMap() putBytes.PutEmptyBytes("k").FromRaw([]byte{1, 2, 3, 4, 5}) assert.Equal(t, generateTestBytesMap(t), putBytes) putMap := NewMap() putMap.PutEmptyMap("k") assert.Equal(t, generateTestEmptyMap(t), putMap) putSlice := NewMap() putSlice.PutEmptySlice("k") assert.Equal(t, generateTestEmptySlice(t), putSlice) removeMap := NewMap() assert.False(t, removeMap.Remove("k")) assert.Equal(t, NewMap(), removeMap) } func TestMapReadOnly(t *testing.T) { state := internal.NewState() state.MarkReadOnly() m := newMap(&[]internal.KeyValue{ {Key: "k1", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "v1"}}}, }, state) assert.Equal(t, 1, m.Len()) v, ok := m.Get("k1") assert.True(t, ok) assert.Equal(t, "v1", v.Str()) m.Range(func(k string, v Value) bool { assert.Equal(t, "k1", k) assert.Equal(t, "v1", v.Str()) return true }) assert.Panics(t, func() { m.PutStr("k2", "v2") }) assert.Panics(t, func() { m.PutInt("k2", 123) }) assert.Panics(t, func() { m.PutDouble("k2", 1.23) }) assert.Panics(t, func() { m.PutBool("k2", true) }) assert.Panics(t, func() { m.PutEmpty("foo") }) assert.Panics(t, func() { m.GetOrPutEmpty("foo") }) assert.Panics(t, func() { m.PutEmptyBytes("k2") }) assert.Panics(t, func() { m.PutEmptyMap("k2") }) assert.Panics(t, func() { m.PutEmptySlice("k2") }) assert.Panics(t, func() { m.Remove("k1") }) assert.Panics(t, func() { m.RemoveIf(func(string, Value) bool { return true }) }) assert.Panics(t, func() { m.EnsureCapacity(2) }) m2 := NewMap() m.CopyTo(m2) assert.Equal(t, m2.AsRaw(), m.AsRaw()) assert.Panics(t, func() { NewMap().CopyTo(m) }) assert.Equal(t, map[string]any{"k1": "v1"}, m.AsRaw()) assert.Panics(t, func() { _ = m.FromRaw(map[string]any{"k1": "v1"}) }) } func TestMapPutEmpty(t *testing.T) { m := NewMap() v := m.PutEmpty("k1") assert.Equal(t, map[string]any{ "k1": nil, }, m.AsRaw()) v.SetBool(true) assert.Equal(t, map[string]any{ "k1": true, }, m.AsRaw()) v = m.PutEmpty("k1") v.SetInt(1) v2, ok := m.Get("k1") assert.True(t, ok) assert.Equal(t, int64(1), v2.Int()) } func TestMapGetOrPutEmpty(t *testing.T) { m := NewMap() v := m.PutEmpty("k1") v.SetStr("test") assert.Equal(t, map[string]any{ "k1": "test", }, m.AsRaw()) v, found := m.GetOrPutEmpty("k1") assert.True(t, found) require.Equal(t, ValueTypeStr, v.Type()) assert.Equal(t, "test", v.Str()) v, found = m.GetOrPutEmpty("k2") assert.False(t, found) require.Equal(t, ValueTypeEmpty, v.Type()) } func TestMapPutEmptyMap(t *testing.T) { m := NewMap() childMap := m.PutEmptyMap("k1") assert.Equal(t, map[string]any{ "k1": map[string]any{}, }, m.AsRaw()) childMap.PutEmptySlice("k2").AppendEmpty().SetStr("val") assert.Equal(t, map[string]any{ "k1": map[string]any{ "k2": []any{"val"}, }, }, m.AsRaw()) childMap.PutEmptyMap("k2").PutInt("k3", 1) assert.Equal(t, map[string]any{ "k1": map[string]any{ "k2": map[string]any{"k3": int64(1)}, }, }, m.AsRaw()) } func TestMapPutEmptySlice(t *testing.T) { m := NewMap() childSlice := m.PutEmptySlice("k") assert.Equal(t, map[string]any{ "k": []any{}, }, m.AsRaw()) childSlice.AppendEmpty().SetDouble(1.1) assert.Equal(t, map[string]any{ "k": []any{1.1}, }, m.AsRaw()) m.PutEmptySlice("k") assert.Equal(t, map[string]any{ "k": []any{}, }, m.AsRaw()) childSliceVal, ok := m.Get("k") assert.True(t, ok) childSliceVal.Slice().AppendEmpty().SetEmptySlice().AppendEmpty().SetStr("val") assert.Equal(t, map[string]any{ "k": []any{[]any{"val"}}, }, m.AsRaw()) } func TestMapPutEmptyBytes(t *testing.T) { m := NewMap() b := m.PutEmptyBytes("k") bv, ok := m.Get("k") assert.True(t, ok) assert.Equal(t, []byte(nil), bv.Bytes().AsRaw()) b.FromRaw([]byte{1, 2, 3}) bv, ok = m.Get("k") assert.True(t, ok) assert.Equal(t, []byte{1, 2, 3}, bv.Bytes().AsRaw()) m.PutEmptyBytes("k") bv, ok = m.Get("k") assert.True(t, ok) assert.Equal(t, []byte(nil), bv.Bytes().AsRaw()) bv.Bytes().FromRaw([]byte{3, 2, 1}) bv, ok = m.Get("k") assert.True(t, ok) assert.Equal(t, []byte{3, 2, 1}, bv.Bytes().AsRaw()) } func TestMapWithEmpty(t *testing.T) { origWithNil := []internal.KeyValue{ {}, { Key: "test_key", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "test_value"}}, }, { Key: "test_key2", Value: internal.AnyValue{Value: nil}, }, } sm := newMap(&origWithNil, internal.NewState()) val, exist := sm.Get("test_key") assert.True(t, exist) assert.Equal(t, ValueTypeStr, val.Type()) assert.Equal(t, "test_value", val.Str()) val, exist = sm.Get("test_key2") assert.True(t, exist) assert.Equal(t, ValueTypeEmpty, val.Type()) assert.Empty(t, val.Str()) sm.PutStr("other_key_string", "other_value") val, exist = sm.Get("other_key_string") assert.True(t, exist) assert.Equal(t, ValueTypeStr, val.Type()) assert.Equal(t, "other_value", val.Str()) sm.PutInt("other_key_int", 123) val, exist = sm.Get("other_key_int") assert.True(t, exist) assert.Equal(t, ValueTypeInt, val.Type()) assert.EqualValues(t, 123, val.Int()) sm.PutDouble("other_key_double", 1.23) val, exist = sm.Get("other_key_double") assert.True(t, exist) assert.Equal(t, ValueTypeDouble, val.Type()) assert.InDelta(t, 1.23, val.Double(), 0.01) sm.PutBool("other_key_bool", true) val, exist = sm.Get("other_key_bool") assert.True(t, exist) assert.Equal(t, ValueTypeBool, val.Type()) assert.True(t, val.Bool()) sm.PutEmptyBytes("other_key_bytes").FromRaw([]byte{7, 8, 9}) val, exist = sm.Get("other_key_bytes") assert.True(t, exist) assert.Equal(t, ValueTypeBytes, val.Type()) assert.Equal(t, []byte{7, 8, 9}, val.Bytes().AsRaw()) sm.PutStr("another_key_string", "another_value") val, exist = sm.Get("another_key_string") assert.True(t, exist) assert.Equal(t, ValueTypeStr, val.Type()) assert.Equal(t, "another_value", val.Str()) sm.PutInt("another_key_int", 456) val, exist = sm.Get("another_key_int") assert.True(t, exist) assert.Equal(t, ValueTypeInt, val.Type()) assert.EqualValues(t, 456, val.Int()) sm.PutDouble("another_key_double", 4.56) val, exist = sm.Get("another_key_double") assert.True(t, exist) assert.Equal(t, ValueTypeDouble, val.Type()) assert.InDelta(t, 4.56, val.Double(), 0.01) sm.PutBool("another_key_bool", false) val, exist = sm.Get("another_key_bool") assert.True(t, exist) assert.Equal(t, ValueTypeBool, val.Type()) assert.False(t, val.Bool()) sm.PutEmptyBytes("another_key_bytes").FromRaw([]byte{1}) val, exist = sm.Get("another_key_bytes") assert.True(t, exist) assert.Equal(t, ValueTypeBytes, val.Type()) assert.Equal(t, []byte{1}, val.Bytes().AsRaw()) assert.True(t, sm.Remove("other_key_string")) assert.True(t, sm.Remove("other_key_int")) assert.True(t, sm.Remove("other_key_double")) assert.True(t, sm.Remove("other_key_bool")) assert.True(t, sm.Remove("other_key_bytes")) assert.True(t, sm.Remove("another_key_string")) assert.True(t, sm.Remove("another_key_int")) assert.True(t, sm.Remove("another_key_double")) assert.True(t, sm.Remove("another_key_bool")) assert.True(t, sm.Remove("another_key_bytes")) assert.False(t, sm.Remove("other_key_string")) assert.False(t, sm.Remove("another_key_string")) // Test that the initial key is still there. val, exist = sm.Get("test_key") assert.True(t, exist) assert.Equal(t, ValueTypeStr, val.Type()) assert.Equal(t, "test_value", val.Str()) val, exist = sm.Get("test_key2") assert.True(t, exist) assert.Equal(t, ValueTypeEmpty, val.Type()) assert.Empty(t, val.Str()) _, exist = sm.Get("test_key3") assert.False(t, exist) } func TestMapIterationNil(t *testing.T) { NewMap().Range(func(string, Value) bool { // Fail if any element is returned t.Fail() return true }) } func TestMap_Range(t *testing.T) { rawMap := map[string]any{ "k_string": "123", "k_int": int64(123), "k_double": float64(1.23), "k_bool": true, "k_empty": nil, } am := NewMap() require.NoError(t, am.FromRaw(rawMap)) assert.Equal(t, 5, am.Len()) calls := 0 am.Range(func(string, Value) bool { calls++ return false }) assert.Equal(t, 1, calls) am.Range(func(k string, v Value) bool { assert.Equal(t, rawMap[k], v.AsRaw()) delete(rawMap, k) return true }) assert.Empty(t, rawMap) } func TestMap_All(t *testing.T) { rawMap := map[string]any{ "k_string": "123", "k_int": int64(123), "k_double": float64(1.23), "k_bool": true, "k_empty": nil, } am := NewMap() require.NoError(t, am.FromRaw(rawMap)) assert.Equal(t, 5, am.Len()) calls := 0 for range am.All() { calls++ } assert.Equal(t, am.Len(), calls) for k, v := range am.All() { assert.Equal(t, rawMap[k], v.AsRaw()) delete(rawMap, k) } assert.Empty(t, rawMap) } func TestMap_FromRaw(t *testing.T) { am := NewMap() require.NoError(t, am.FromRaw(map[string]any{})) assert.Equal(t, 0, am.Len()) am.PutEmpty("k") assert.Equal(t, 1, am.Len()) require.NoError(t, am.FromRaw(nil)) assert.Equal(t, 0, am.Len()) am.PutEmpty("k") assert.Equal(t, 1, am.Len()) require.NoError(t, am.FromRaw(map[string]any{ "k_string": "123", "k_int": 123, "k_double": 1.23, "k_bool": true, "k_null": nil, "k_bytes": []byte{1, 2, 3}, "k_slice": []any{1, 2.1, "val"}, "k_map": map[string]any{ "k_int": 1, "k_string": "val", }, })) assert.Equal(t, 8, am.Len()) v, ok := am.Get("k_string") assert.True(t, ok) assert.Equal(t, "123", v.Str()) v, ok = am.Get("k_int") assert.True(t, ok) assert.Equal(t, int64(123), v.Int()) v, ok = am.Get("k_double") assert.True(t, ok) assert.InDelta(t, 1.23, v.Double(), 0.01) v, ok = am.Get("k_null") assert.True(t, ok) assert.Equal(t, ValueTypeEmpty, v.Type()) v, ok = am.Get("k_bytes") assert.True(t, ok) assert.Equal(t, []byte{1, 2, 3}, v.Bytes().AsRaw()) v, ok = am.Get("k_slice") assert.True(t, ok) assert.Equal(t, []any{int64(1), 2.1, "val"}, v.Slice().AsRaw()) v, ok = am.Get("k_map") assert.True(t, ok) assert.Equal(t, map[string]any{ "k_int": int64(1), "k_string": "val", }, v.Map().AsRaw()) } func TestMap_MoveTo(t *testing.T) { dest := NewMap() // Test MoveTo to empty NewMap().MoveTo(dest) assert.Equal(t, 0, dest.Len()) // Test MoveTo larger slice src := Map(internal.GenTestMapWrapper()) src.MoveTo(dest) assert.Equal(t, Map(internal.GenTestMapWrapper()), dest) assert.Equal(t, 0, src.Len()) // Test MoveTo from empty to non-empty NewMap().MoveTo(dest) assert.Equal(t, 0, dest.Len()) dest.PutStr("k", "v") dest.MoveTo(dest) assert.Equal(t, 1, dest.Len()) assert.Equal(t, map[string]any{"k": "v"}, dest.AsRaw()) } func TestMap_CopyTo(t *testing.T) { dest := NewMap() // Test CopyTo to empty NewMap().CopyTo(dest) assert.Equal(t, 0, dest.Len()) // Test CopyTo larger slice Map(internal.GenTestMapWrapper()).CopyTo(dest) assert.Equal(t, Map(internal.GenTestMapWrapper()), dest) // Test CopyTo same size slice Map(internal.GenTestMapWrapper()).CopyTo(dest) assert.Equal(t, Map(internal.GenTestMapWrapper()), dest) // Test CopyTo with an empty Value in the destination (*dest.getOrig())[0].Value = internal.AnyValue{} Map(internal.GenTestMapWrapper()).CopyTo(dest) assert.Equal(t, Map(internal.GenTestMapWrapper()), dest) // Test CopyTo same size slice dest.CopyTo(dest) assert.Equal(t, Map(internal.GenTestMapWrapper()), dest) } func TestMap_CopyToAndEnsureCapacity(t *testing.T) { dest := NewMap() src := Map(internal.GenTestMapWrapper()) dest.EnsureCapacity(src.Len()) src.CopyTo(dest) assert.Equal(t, Map(internal.GenTestMapWrapper()), dest) } func TestMap_EnsureCapacity_Zero(t *testing.T) { am := NewMap() am.EnsureCapacity(0) assert.Equal(t, 0, am.Len()) assert.Equal(t, 0, cap(*am.getOrig())) } func TestMap_EnsureCapacity(t *testing.T) { am := NewMap() am.EnsureCapacity(5) assert.Equal(t, 0, am.Len()) assert.Equal(t, 5, cap(*am.getOrig())) am.EnsureCapacity(3) assert.Equal(t, 0, am.Len()) assert.Equal(t, 5, cap(*am.getOrig())) am.EnsureCapacity(8) assert.Equal(t, 0, am.Len()) assert.Equal(t, 8, cap(*am.getOrig())) } func TestMap_EnsureCapacity_Existing(t *testing.T) { am := NewMap() am.PutStr("foo", "bar") assert.Equal(t, 1, am.Len()) // Add more capacity. am.EnsureCapacity(5) // Ensure previously existing element is still there. assert.Equal(t, 1, am.Len()) v, ok := am.Get("foo") assert.Equal(t, "bar", v.Str()) assert.True(t, ok) assert.Equal(t, 5, cap(*am.getOrig())) // Add one more element. am.PutStr("abc", "xyz") // Verify that both elements are there. assert.Equal(t, 2, am.Len()) v, ok = am.Get("foo") assert.Equal(t, "bar", v.Str()) assert.True(t, ok) v, ok = am.Get("abc") assert.Equal(t, "xyz", v.Str()) assert.True(t, ok) } func TestMap_Clear(t *testing.T) { am := NewMap() assert.Nil(t, *am.getOrig()) am.Clear() assert.Nil(t, *am.getOrig()) am.EnsureCapacity(5) assert.NotNil(t, *am.getOrig()) am.Clear() assert.Nil(t, *am.getOrig()) } func TestMap_RemoveIf(t *testing.T) { am := NewMap() am.PutStr("k_string", "123") am.PutInt("k_int", int64(123)) am.PutDouble("k_double", float64(1.23)) am.PutBool("k_bool", true) am.PutEmpty("k_empty") assert.Equal(t, 5, am.Len()) am.RemoveIf(func(key string, val Value) bool { return key == "k_int" || val.Type() == ValueTypeBool }) assert.Equal(t, 3, am.Len()) _, exists := am.Get("k_string") assert.True(t, exists) _, exists = am.Get("k_int") assert.False(t, exists) _, exists = am.Get("k_double") assert.True(t, exists) _, exists = am.Get("k_bool") assert.False(t, exists) _, exists = am.Get("k_empty") assert.True(t, exists) } func TestMap_RemoveIfAll(t *testing.T) { am := Map(internal.GenTestMapWrapper()) assert.Equal(t, 5, am.Len()) am.RemoveIf(func(string, Value) bool { return true }) assert.Equal(t, 0, am.Len()) } func generateTestEmptyMap(t *testing.T) Map { m := NewMap() assert.NoError(t, m.FromRaw(map[string]any{"k": map[string]any(nil)})) return m } func generateTestEmptySlice(t *testing.T) Map { m := NewMap() assert.NoError(t, m.FromRaw(map[string]any{"k": []any(nil)})) return m } func generateTestStringMap(t *testing.T) Map { m := NewMap() assert.NoError(t, m.FromRaw(map[string]any{"k": "v"})) return m } func generateTestIntMap(t *testing.T) Map { m := NewMap() assert.NoError(t, m.FromRaw(map[string]any{"k": 123})) return m } func generateTestDoubleMap(t *testing.T) Map { m := NewMap() assert.NoError(t, m.FromRaw(map[string]any{"k": 12.3})) return m } func generateTestBoolMap(t *testing.T) Map { m := NewMap() assert.NoError(t, m.FromRaw(map[string]any{"k": true})) return m } func generateTestBytesMap(t *testing.T) Map { m := NewMap() assert.NoError(t, m.FromRaw(map[string]any{"k": []byte{1, 2, 3, 4, 5}})) return m } func TestInvalidMap(t *testing.T) { v := Map{} testFunc := func(string, Value) bool { return true } assert.Panics(t, func() { v.Clear() }) assert.Panics(t, func() { v.EnsureCapacity(1) }) assert.Panics(t, func() { v.Get("foo") }) assert.Panics(t, func() { v.Remove("foo") }) assert.Panics(t, func() { v.RemoveIf(testFunc) }) assert.Panics(t, func() { v.PutEmpty("foo") }) assert.Panics(t, func() { v.GetOrPutEmpty("foo") }) assert.Panics(t, func() { v.PutStr("foo", "bar") }) assert.Panics(t, func() { v.PutInt("foo", 1) }) assert.Panics(t, func() { v.PutDouble("foo", 1.1) }) assert.Panics(t, func() { v.PutBool("foo", true) }) assert.Panics(t, func() { v.PutEmptyBytes("foo") }) assert.Panics(t, func() { v.PutEmptyMap("foo") }) assert.Panics(t, func() { v.PutEmptySlice("foo") }) assert.Panics(t, func() { v.Len() }) assert.Panics(t, func() { v.Range(testFunc) }) assert.Panics(t, func() { v.CopyTo(NewMap()) }) assert.Panics(t, func() { v.AsRaw() }) assert.Panics(t, func() { _ = v.FromRaw(map[string]any{"foo": "bar"}) }) } func TestMapEqual(t *testing.T) { for _, tt := range []struct { name string val Map comparison Map expected bool }{ { name: "with two empty maps", val: NewMap(), comparison: NewMap(), expected: true, }, { name: "with two equal values", val: func() Map { m := NewMap() m.PutStr("hello", "world") return m }(), comparison: func() Map { m := NewMap() m.PutStr("hello", "world") return m }(), expected: true, }, { name: "with multiple equal values", val: func() Map { m := NewMap() m.PutStr("hello", "world") m.PutStr("bonjour", "monde") return m }(), comparison: func() Map { m := NewMap() m.PutStr("hello", "world") m.PutStr("bonjour", "monde") return m }(), expected: true, }, { name: "with two different values", val: func() Map { m := NewMap() m.PutStr("hello", "world") return m }(), comparison: func() Map { m := NewMap() m.PutStr("bonjour", "monde") return m }(), expected: false, }, { name: "with the same key and different values", val: func() Map { m := NewMap() m.PutStr("hello", "world") return m }(), comparison: func() Map { m := NewMap() m.PutStr("hello", "monde") return m }(), expected: false, }, { name: "with multiple different values", val: func() Map { m := NewMap() m.PutStr("hello", "world") m.PutStr("bonjour", "monde") return m }(), comparison: func() Map { m := NewMap() m.PutStr("question", "unknown") m.PutStr("answer", "42") return m }(), expected: false, }, } { t.Run(tt.name, func(t *testing.T) { assert.Equal(t, tt.expected, tt.val.Equal(tt.comparison)) }) } } func BenchmarkMapEqual(b *testing.B) { testutil.SkipMemoryBench(b) m := NewMap() m.PutStr("hello", "world") cmp := NewMap() cmp.PutStr("hello", "world") b.ReportAllocs() for b.Loop() { _ = m.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/package_test.go000066400000000000000000000003101511331344600242520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/pcommon/slice.go000066400000000000000000000021031511331344600227210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "go.uber.org/multierr" "go.opentelemetry.io/collector/pdata/internal" ) // AsRaw return []any copy of the Slice. func (es Slice) AsRaw() []any { rawSlice := make([]any, 0, es.Len()) for i := 0; i < es.Len(); i++ { rawSlice = append(rawSlice, es.At(i).AsRaw()) } return rawSlice } // FromRaw copies []any into the Slice. func (es Slice) FromRaw(rawSlice []any) error { es.getState().AssertMutable() if len(rawSlice) == 0 { *es.getOrig() = nil return nil } var errs error origs := make([]internal.AnyValue, len(rawSlice)) for ix, iv := range rawSlice { errs = multierr.Append(errs, newValue(&origs[ix], es.getState()).FromRaw(iv)) } *es.getOrig() = origs return errs } // Equal checks equality with another Slice func (es Slice) Equal(val Slice) bool { if es.Len() != val.Len() { return false } for i := 0; i < es.Len(); i++ { if !es.At(i).Equal(val.At(i)) { return false } } return true } opentelemetry-collector-0.141.0/pdata/pcommon/slice_test.go000066400000000000000000000030521511331344600237640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestSlice_AsFromRaw(t *testing.T) { es := NewSlice() assert.Equal(t, 0, es.Len()) raw := []any{int64(1), float64(2.3), true, "test", []any{"other"}, map[string]any{"key": "value", "int": int64(2)}} require.NoError(t, es.FromRaw(raw)) assert.Equal(t, 6, es.Len()) assert.Equal(t, raw, es.AsRaw()) } func TestInvalidSlice(t *testing.T) { es := Slice{} assert.Panics(t, func() { es.Len() }) assert.Panics(t, func() { es.At(0) }) assert.Panics(t, func() { es.CopyTo(Slice{}) }) assert.Panics(t, func() { es.EnsureCapacity(1) }) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.MoveAndAppendTo(Slice{}) }) assert.Panics(t, func() { es.RemoveIf(func(Value) bool { return false }) }) assert.Panics(t, func() { es.AsRaw() }) assert.Panics(t, func() { _ = es.FromRaw([]any{3}) }) } func TestSliceEqual(t *testing.T) { es := NewSlice() es2 := NewSlice() assert.True(t, es.Equal(es2)) v := es.AppendEmpty() v.SetStr("test") assert.False(t, es.Equal(es2)) v = es2.AppendEmpty() v.SetStr("test") assert.True(t, es.Equal(es2)) } func BenchmarkSliceEqual(b *testing.B) { testutil.SkipMemoryBench(b) es := NewSlice() v := es.AppendEmpty() v.SetStr("test") cmp := NewSlice() v = cmp.AppendEmpty() v.SetStr("test") b.ReportAllocs() for b.Loop() { _ = es.Equal(cmp) } } opentelemetry-collector-0.141.0/pdata/pcommon/spanid.go000066400000000000000000000016651511331344600231140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "encoding/hex" "go.opentelemetry.io/collector/pdata/internal" ) var emptySpanID = SpanID([8]byte{}) // SpanID is span identifier. type SpanID [8]byte // NewSpanIDEmpty returns a new empty (all zero bytes) SpanID. func NewSpanIDEmpty() SpanID { return emptySpanID } // String returns string representation of the SpanID. // // Important: Don't rely on this method to get a string identifier of SpanID, // Use hex.EncodeToString explicitly instead. // This method meant to implement Stringer interface for display purposes only. func (ms SpanID) String() string { if ms.IsEmpty() { return "" } return hex.EncodeToString(ms[:]) } // IsEmpty returns true if id doesn't contain at least one non-zero byte. func (ms SpanID) IsEmpty() bool { return internal.SpanID(ms).IsEmpty() } opentelemetry-collector-0.141.0/pdata/pcommon/spanid_test.go000066400000000000000000000020151511331344600241410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "testing" "github.com/stretchr/testify/assert" ) func TestSpanID(t *testing.T) { sid := SpanID([8]byte{1, 2, 3, 4, 4, 3, 2, 1}) assert.Equal(t, [8]byte{1, 2, 3, 4, 4, 3, 2, 1}, [8]byte(sid)) assert.False(t, sid.IsEmpty()) } func TestNewSpanIDEmpty(t *testing.T) { sid := NewSpanIDEmpty() assert.Equal(t, [8]byte{}, [8]byte(sid)) assert.True(t, sid.IsEmpty()) } func TestSpanIDString(t *testing.T) { sid := SpanID([8]byte{}) assert.Empty(t, sid.String()) sid = SpanID([8]byte{0x12, 0x23, 0xAD, 0x12, 0x23, 0xAD, 0x12, 0x23}) assert.Equal(t, "1223ad1223ad1223", sid.String()) } func TestSpanIDImmutable(t *testing.T) { initialBytes := [8]byte{0x12, 0x23, 0xAD, 0x12, 0x23, 0xAD, 0x12, 0x23} sid := SpanID(initialBytes) assert.Equal(t, SpanID(initialBytes), sid) // Get the bytes and try to mutate. sid[4] = 0x89 // Does not change the already created SpanID. assert.NotEqual(t, SpanID(initialBytes), sid) } opentelemetry-collector-0.141.0/pdata/pcommon/timestamp.go000066400000000000000000000013271511331344600236340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "time" ) // Timestamp is a time specified as UNIX Epoch time in nanoseconds since // 1970-01-01 00:00:00 +0000 UTC. type Timestamp uint64 // NewTimestampFromTime constructs a new Timestamp from the provided time.Time. func NewTimestampFromTime(t time.Time) Timestamp { return Timestamp(uint64(t.UnixNano())) } // AsTime converts this to a time.Time. func (ts Timestamp) AsTime() time.Time { return time.Unix(0, int64(ts)).UTC() } // String returns the string representation of this in UTC. func (ts Timestamp) String() string { return ts.AsTime().String() } opentelemetry-collector-0.141.0/pdata/pcommon/timestamp_test.go000066400000000000000000000014101511331344600246640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestUnixNanosConverters(t *testing.T) { t1 := time.Date(2020, 3, 24, 1, 13, 23, 789, time.UTC) tun := Timestamp(t1.UnixNano()) assert.EqualValues(t, uint64(1585012403000000789), tun) assert.Equal(t, tun, NewTimestampFromTime(t1)) assert.Equal(t, t1, NewTimestampFromTime(t1).AsTime()) assert.Equal(t, "2020-03-24 01:13:23.000000789 +0000 UTC", t1.String()) } func TestZeroTimestamp(t *testing.T) { assert.Equal(t, time.Unix(0, 0).UTC(), Timestamp(0).AsTime()) assert.Zero(t, NewTimestampFromTime(time.Unix(0, 0).UTC())) assert.Equal(t, "1970-01-01 00:00:00 +0000 UTC", Timestamp(0).String()) } opentelemetry-collector-0.141.0/pdata/pcommon/trace_state.go000066400000000000000000000034231511331344600241260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "go.opentelemetry.io/collector/pdata/internal" ) // TraceState represents the trace state from the w3c-trace-context. // // Must use NewTraceState function to create new instances. // Important: zero-initialized instance is not valid for use. type TraceState internal.TraceStateWrapper func NewTraceState() TraceState { return TraceState(internal.NewTraceStateWrapper(new(string), internal.NewState())) } func (ms TraceState) getOrig() *string { return internal.GetTraceStateOrig(internal.TraceStateWrapper(ms)) } func (ms TraceState) getState() *internal.State { return internal.GetTraceStateState(internal.TraceStateWrapper(ms)) } // AsRaw returns the string representation of the tracestate in w3c-trace-context format: https://www.w3.org/TR/trace-context/#tracestate-header func (ms TraceState) AsRaw() string { return *ms.getOrig() } // FromRaw copies the string representation in w3c-trace-context format of the tracestate into this TraceState. func (ms TraceState) FromRaw(v string) { ms.getState().AssertMutable() *ms.getOrig() = v } // MoveTo moves the TraceState instance overriding the destination // and resetting the current instance to its zero value. func (ms TraceState) MoveTo(dest TraceState) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } *dest.getOrig() = *ms.getOrig() *ms.getOrig() = "" } // CopyTo copies the TraceState instance overriding the destination. func (ms TraceState) CopyTo(dest TraceState) { dest.getState().AssertMutable() *dest.getOrig() = *ms.getOrig() } opentelemetry-collector-0.141.0/pdata/pcommon/trace_state_test.go000066400000000000000000000023211511331344600251610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestTraceState_MoveTo(t *testing.T) { ms := TraceState(internal.GenTestTraceStateWrapper()) dest := NewTraceState() ms.MoveTo(dest) assert.Equal(t, NewTraceState(), ms) assert.Equal(t, TraceState(internal.GenTestTraceStateWrapper()), dest) dest.MoveTo(dest) assert.Equal(t, TraceState(internal.GenTestTraceStateWrapper()), dest) } func TestTraceState_CopyTo(t *testing.T) { ms := NewTraceState() orig := NewTraceState() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = TraceState(internal.GenTestTraceStateWrapper()) orig.CopyTo(ms) assert.Equal(t, orig, ms) } func TestTraceState_FromRaw_AsRaw(t *testing.T) { ms := NewTraceState() assert.Empty(t, ms.AsRaw()) ms.FromRaw("congo=t61rcWkgMzE") assert.Equal(t, "congo=t61rcWkgMzE", ms.AsRaw()) } func TestInvalidTraceState(t *testing.T) { v := TraceState{} assert.Panics(t, func() { v.AsRaw() }) assert.Panics(t, func() { v.FromRaw("") }) assert.Panics(t, func() { v.MoveTo(TraceState{}) }) assert.Panics(t, func() { v.CopyTo(TraceState{}) }) } opentelemetry-collector-0.141.0/pdata/pcommon/traceid.go000066400000000000000000000017111511331344600232410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "encoding/hex" "go.opentelemetry.io/collector/pdata/internal" ) var emptyTraceID = TraceID([16]byte{}) // TraceID is a trace identifier. type TraceID [16]byte // NewTraceIDEmpty returns a new empty (all zero bytes) TraceID. func NewTraceIDEmpty() TraceID { return emptyTraceID } // String returns string representation of the TraceID. // // Important: Don't rely on this method to get a string identifier of TraceID. // Use hex.EncodeToString explicitly instead. // This method meant to implement Stringer interface for display purposes only. func (ms TraceID) String() string { if ms.IsEmpty() { return "" } return hex.EncodeToString(ms[:]) } // IsEmpty returns true if id doesn't contain at least one non-zero byte. func (ms TraceID) IsEmpty() bool { return internal.TraceID(ms).IsEmpty() } opentelemetry-collector-0.141.0/pdata/pcommon/traceid_test.go000066400000000000000000000022701511331344600243010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "testing" "github.com/stretchr/testify/assert" ) func TestTraceID(t *testing.T) { tid := TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) assert.Equal(t, [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}, [16]byte(tid)) assert.False(t, tid.IsEmpty()) } func TestNewTraceIDEmpty(t *testing.T) { tid := NewTraceIDEmpty() assert.Equal(t, [16]byte{}, [16]byte(tid)) assert.True(t, tid.IsEmpty()) } func TestTraceIDString(t *testing.T) { tid := TraceID([16]byte{}) assert.Empty(t, tid.String()) tid = [16]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} assert.Equal(t, "12345678123456781234567812345678", tid.String()) } func TestTraceIDImmutable(t *testing.T) { initialBytes := [16]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} tid := TraceID(initialBytes) assert.Equal(t, TraceID(initialBytes), tid) // Get the bytes and try to mutate. tid[4] = 0x23 // Does not change the already created TraceID. assert.NotEqual(t, TraceID(initialBytes), tid) } opentelemetry-collector-0.141.0/pdata/pcommon/value.go000066400000000000000000000343041511331344600227460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon // import "go.opentelemetry.io/collector/pdata/pcommon" import ( "encoding/base64" "encoding/json" "fmt" "math" "strconv" "go.opentelemetry.io/collector/pdata/internal" ) // ValueType specifies the type of Value. type ValueType int32 const ( ValueTypeEmpty ValueType = iota ValueTypeStr ValueTypeInt ValueTypeDouble ValueTypeBool ValueTypeMap ValueTypeSlice ValueTypeBytes ) // String returns the string representation of the ValueType. func (avt ValueType) String() string { switch avt { case ValueTypeEmpty: return "Empty" case ValueTypeStr: return "Str" case ValueTypeBool: return "Bool" case ValueTypeInt: return "Int" case ValueTypeDouble: return "Double" case ValueTypeMap: return "Map" case ValueTypeSlice: return "Slice" case ValueTypeBytes: return "Bytes" } return "" } // Value is a mutable cell containing any value. Typically used as an element of Map or Slice. // Must use one of NewValue+ functions below to create new instances. // // Intended to be passed by value since internally it is just a pointer to actual // value representation. For the same reason passing by value and calling setters // will modify the original, e.g.: // // func f1(val Value) { val.SetInt(234) } // func f2() { // v := NewValueStr("a string") // f1(v) // _ := v.Type() // this will return ValueTypeInt // } // // Important: zero-initialized instance is not valid for use. All Value functions below must // be called only on instances that are created via NewValue+ functions. type Value internal.ValueWrapper // NewValueEmpty creates a new Value with an empty value. func NewValueEmpty() Value { return newValue(&internal.AnyValue{}, internal.NewState()) } // NewValueStr creates a new Value with the given string value. func NewValueStr(v string) Value { ov := internal.NewAnyValueStringValue() ov.StringValue = v orig := internal.NewAnyValue() orig.Value = ov return newValue(orig, internal.NewState()) } // NewValueInt creates a new Value with the given int64 value. func NewValueInt(v int64) Value { ov := internal.NewAnyValueIntValue() ov.IntValue = v orig := internal.NewAnyValue() orig.Value = ov return newValue(orig, internal.NewState()) } // NewValueDouble creates a new Value with the given float64 value. func NewValueDouble(v float64) Value { ov := internal.NewAnyValueDoubleValue() ov.DoubleValue = v orig := internal.NewAnyValue() orig.Value = ov return newValue(orig, internal.NewState()) } // NewValueBool creates a new Value with the given bool value. func NewValueBool(v bool) Value { ov := internal.NewAnyValueBoolValue() ov.BoolValue = v orig := internal.NewAnyValue() orig.Value = ov return newValue(orig, internal.NewState()) } // NewValueMap creates a new Value of map type. func NewValueMap() Value { ov := internal.NewAnyValueKvlistValue() ov.KvlistValue = internal.NewKeyValueList() orig := internal.NewAnyValue() orig.Value = ov return newValue(orig, internal.NewState()) } // NewValueSlice creates a new Value of array type. func NewValueSlice() Value { ov := internal.NewAnyValueArrayValue() ov.ArrayValue = internal.NewArrayValue() orig := internal.NewAnyValue() orig.Value = ov return newValue(orig, internal.NewState()) } // NewValueBytes creates a new empty Value of byte type. func NewValueBytes() Value { ov := internal.NewAnyValueBytesValue() orig := internal.NewAnyValue() orig.Value = ov return newValue(orig, internal.NewState()) } func newValue(orig *internal.AnyValue, state *internal.State) Value { return Value(internal.NewValueWrapper(orig, state)) } func (v Value) getOrig() *internal.AnyValue { return internal.GetValueOrig(internal.ValueWrapper(v)) } func (v Value) getState() *internal.State { return internal.GetValueState(internal.ValueWrapper(v)) } // FromRaw sets the value from the given raw value. // Calling this function on zero-initialized Value will cause a panic. func (v Value) FromRaw(iv any) error { switch tv := iv.(type) { case nil: v.getOrig().Value = nil case string: v.SetStr(tv) case int: v.SetInt(int64(tv)) case int8: v.SetInt(int64(tv)) case int16: v.SetInt(int64(tv)) case int32: v.SetInt(int64(tv)) case int64: v.SetInt(tv) case uint: v.SetInt(int64(tv)) case uint8: v.SetInt(int64(tv)) case uint16: v.SetInt(int64(tv)) case uint32: v.SetInt(int64(tv)) case uint64: v.SetInt(int64(tv)) case float32: v.SetDouble(float64(tv)) case float64: v.SetDouble(tv) case bool: v.SetBool(tv) case []byte: v.SetEmptyBytes().FromRaw(tv) case map[string]any: return v.SetEmptyMap().FromRaw(tv) case []any: return v.SetEmptySlice().FromRaw(tv) default: return fmt.Errorf("", tv) } return nil } // Type returns the type of the value for this Value. // Calling this function on zero-initialized Value will cause a panic. func (v Value) Type() ValueType { switch v.getOrig().Value.(type) { case *internal.AnyValue_StringValue: return ValueTypeStr case *internal.AnyValue_BoolValue: return ValueTypeBool case *internal.AnyValue_IntValue: return ValueTypeInt case *internal.AnyValue_DoubleValue: return ValueTypeDouble case *internal.AnyValue_KvlistValue: return ValueTypeMap case *internal.AnyValue_ArrayValue: return ValueTypeSlice case *internal.AnyValue_BytesValue: return ValueTypeBytes } return ValueTypeEmpty } // Str returns the string value associated with this Value. // The shorter name is used instead of String to avoid implementing fmt.Stringer interface. // If the Type() is not ValueTypeStr then returns empty string. func (v Value) Str() string { return v.getOrig().GetStringValue() } // Int returns the int64 value associated with this Value. // If the Type() is not ValueTypeInt then returns int64(0). func (v Value) Int() int64 { return v.getOrig().GetIntValue() } // Double returns the float64 value associated with this Value. // If the Type() is not ValueTypeDouble then returns float64(0). func (v Value) Double() float64 { return v.getOrig().GetDoubleValue() } // Bool returns the bool value associated with this Value. // If the Type() is not ValueTypeBool then returns false. func (v Value) Bool() bool { return v.getOrig().GetBoolValue() } // Map returns the map value associated with this Value. // If the function is called on zero-initialized Value or if the Type() is not ValueTypeMap // then it returns an invalid map. Note that using such map can cause panic. func (v Value) Map() Map { kvlist := v.getOrig().GetKvlistValue() if kvlist == nil { return Map{} } return newMap(&kvlist.Values, internal.GetValueState(internal.ValueWrapper(v))) } // Slice returns the slice value associated with this Value. // If the function is called on zero-initialized Value or if the Type() is not ValueTypeSlice // then returns an invalid slice. Note that using such slice can cause panic. func (v Value) Slice() Slice { arr := v.getOrig().GetArrayValue() if arr == nil { return Slice{} } return newSlice(&arr.Values, internal.GetValueState(internal.ValueWrapper(v))) } // Bytes returns the ByteSlice value associated with this Value. // If the function is called on zero-initialized Value or if the Type() is not ValueTypeBytes // then returns an invalid ByteSlice object. Note that using such slice can cause panic. func (v Value) Bytes() ByteSlice { bv, ok := v.getOrig().GetValue().(*internal.AnyValue_BytesValue) if !ok { return ByteSlice{} } return ByteSlice(internal.NewByteSliceWrapper(&bv.BytesValue, internal.GetValueState(internal.ValueWrapper(v)))) } // SetStr replaces the string value associated with this Value, // it also changes the type to be ValueTypeStr. // The shorter name is used instead of SetString to avoid implementing // fmt.Stringer interface by the corresponding getter method. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetStr(sv string) { v.getState().AssertMutable() // Delete everything but the AnyValue object itself. internal.DeleteAnyValue(v.getOrig(), false) ov := internal.NewAnyValueStringValue() ov.StringValue = sv v.getOrig().Value = ov } // SetInt replaces the int64 value associated with this Value, // it also changes the type to be ValueTypeInt. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetInt(iv int64) { v.getState().AssertMutable() // Delete everything but the AnyValue object itself. internal.DeleteAnyValue(v.getOrig(), false) ov := internal.NewAnyValueIntValue() ov.IntValue = iv v.getOrig().Value = ov } // SetDouble replaces the float64 value associated with this Value, // it also changes the type to be ValueTypeDouble. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetDouble(dv float64) { v.getState().AssertMutable() // Delete everything but the AnyValue object itself. internal.DeleteAnyValue(v.getOrig(), false) ov := internal.NewAnyValueDoubleValue() ov.DoubleValue = dv v.getOrig().Value = ov } // SetBool replaces the bool value associated with this Value, // it also changes the type to be ValueTypeBool. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetBool(bv bool) { v.getState().AssertMutable() // Delete everything but the AnyValue object itself. internal.DeleteAnyValue(v.getOrig(), false) ov := internal.NewAnyValueBoolValue() ov.BoolValue = bv v.getOrig().Value = ov } // SetEmptyBytes sets value to an empty byte slice and returns it. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetEmptyBytes() ByteSlice { v.getState().AssertMutable() // Delete everything but the AnyValue object itself. internal.DeleteAnyValue(v.getOrig(), false) bv := internal.NewAnyValueBytesValue() v.getOrig().Value = bv return ByteSlice(internal.NewByteSliceWrapper(&bv.BytesValue, v.getState())) } // SetEmptyMap sets value to an empty map and returns it. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetEmptyMap() Map { v.getState().AssertMutable() // Delete everything but the AnyValue object itself. internal.DeleteAnyValue(v.getOrig(), false) ov := internal.NewAnyValueKvlistValue() ov.KvlistValue = internal.NewKeyValueList() v.getOrig().Value = ov return newMap(&ov.KvlistValue.Values, v.getState()) } // SetEmptySlice sets value to an empty slice and returns it. // Calling this function on zero-initialized Value will cause a panic. func (v Value) SetEmptySlice() Slice { v.getState().AssertMutable() // Delete everything but the AnyValue object itself. internal.DeleteAnyValue(v.getOrig(), false) ov := internal.NewAnyValueArrayValue() ov.ArrayValue = internal.NewArrayValue() v.getOrig().Value = ov return newSlice(&ov.ArrayValue.Values, v.getState()) } // MoveTo moves the Value from current overriding the destination and // resetting the current instance to empty value. // Calling this function on zero-initialized Value will cause a panic. func (v Value) MoveTo(dest Value) { v.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if v.getOrig() == dest.getOrig() { return } *dest.getOrig() = *v.getOrig() v.getOrig().Value = nil } // CopyTo copies the Value instance overriding the destination. // Calling this function on zero-initialized Value will cause a panic. func (v Value) CopyTo(dest Value) { dest.getState().AssertMutable() internal.CopyAnyValue(dest.getOrig(), v.getOrig()) } // AsString converts an OTLP Value object of any type to its equivalent string // representation. This differs from Str which only returns a non-empty value // if the ValueType is ValueTypeStr. // Calling this function on zero-initialized Value will cause a panic. func (v Value) AsString() string { switch v.Type() { case ValueTypeEmpty: return "" case ValueTypeStr: return v.Str() case ValueTypeBool: return strconv.FormatBool(v.Bool()) case ValueTypeDouble: return float64AsString(v.Double()) case ValueTypeInt: return strconv.FormatInt(v.Int(), 10) case ValueTypeMap: jsonStr, _ := json.Marshal(v.Map().AsRaw()) return string(jsonStr) case ValueTypeBytes: return base64.StdEncoding.EncodeToString(*v.Bytes().getOrig()) case ValueTypeSlice: jsonStr, _ := json.Marshal(v.Slice().AsRaw()) return string(jsonStr) default: return fmt.Sprintf("", v.Type()) } } // See https://cs.opensource.google/go/go/+/refs/tags/go1.17.7:src/encoding/json/encode.go;l=585. // This allows us to avoid using reflection. func float64AsString(f float64) string { if math.IsInf(f, 0) || math.IsNaN(f) { return "json: unsupported value: " + strconv.FormatFloat(f, 'g', -1, 64) } // Convert as if by ES6 number to string conversion. // This matches most other JSON generators. // See golang.org/issue/6384 and golang.org/issue/14135. // Like fmt %g, but the exponent cutoffs are different // and exponents themselves are not padded to two digits. scratch := [64]byte{} b := scratch[:0] abs := math.Abs(f) fmt := byte('f') if abs != 0 && (abs < 1e-6 || abs >= 1e21) { fmt = 'e' } b = strconv.AppendFloat(b, f, fmt, -1, 64) if fmt == 'e' { // clean up e-09 to e-9 n := len(b) if n >= 4 && b[n-4] == 'e' && b[n-3] == '-' && b[n-2] == '0' { b[n-2] = b[n-1] b = b[:n-1] } } return string(b) } func (v Value) AsRaw() any { switch v.Type() { case ValueTypeEmpty: return nil case ValueTypeStr: return v.Str() case ValueTypeBool: return v.Bool() case ValueTypeDouble: return v.Double() case ValueTypeInt: return v.Int() case ValueTypeBytes: return v.Bytes().AsRaw() case ValueTypeMap: return v.Map().AsRaw() case ValueTypeSlice: return v.Slice().AsRaw() } return fmt.Sprintf("", v.Type()) } func (v Value) Equal(c Value) bool { if v.Type() != c.Type() { return false } switch v.Type() { case ValueTypeEmpty: return true case ValueTypeStr: return v.Str() == c.Str() case ValueTypeBool: return v.Bool() == c.Bool() case ValueTypeDouble: return v.Double() == c.Double() case ValueTypeInt: return v.Int() == c.Int() case ValueTypeBytes: return v.Bytes().Equal(c.Bytes()) case ValueTypeMap: return v.Map().Equal(c.Map()) case ValueTypeSlice: return v.Slice().Equal(c.Slice()) } return false } opentelemetry-collector-0.141.0/pdata/pcommon/value_test.go000066400000000000000000000476701511331344600240170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pcommon import ( "encoding/base64" "math" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" ) func TestValue(t *testing.T) { v := NewValueStr("abc") assert.Equal(t, ValueTypeStr, v.Type()) assert.Equal(t, "abc", v.Str()) v = NewValueInt(123) assert.Equal(t, ValueTypeInt, v.Type()) assert.EqualValues(t, 123, v.Int()) v = NewValueDouble(3.4) assert.Equal(t, ValueTypeDouble, v.Type()) assert.InDelta(t, 3.4, v.Double(), 0.01) v = NewValueBool(true) assert.Equal(t, ValueTypeBool, v.Type()) assert.True(t, v.Bool()) v = NewValueBytes() assert.Equal(t, ValueTypeBytes, v.Type()) v = NewValueEmpty() assert.Equal(t, ValueTypeEmpty, v.Type()) v = NewValueMap() assert.Equal(t, ValueTypeMap, v.Type()) v = NewValueSlice() assert.Equal(t, ValueTypeSlice, v.Type()) } func TestValueReadOnly(t *testing.T) { state := internal.NewState() state.MarkReadOnly() v := newValue(&internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "v"}}, state) assert.Equal(t, ValueTypeStr, v.Type()) assert.Equal(t, "v", v.Str()) assert.EqualValues(t, 0, v.Int()) assert.InDelta(t, 0, v.Double(), 0.01) assert.False(t, v.Bool()) assert.Equal(t, ByteSlice{}, v.Bytes()) assert.Equal(t, Map{}, v.Map()) assert.Equal(t, Slice{}, v.Slice()) assert.Equal(t, "v", v.AsString()) assert.Panics(t, func() { v.SetStr("abc") }) assert.Panics(t, func() { v.SetInt(123) }) assert.Panics(t, func() { v.SetDouble(3.4) }) assert.Panics(t, func() { v.SetBool(true) }) assert.Panics(t, func() { v.SetEmptyBytes() }) assert.Panics(t, func() { v.SetEmptyMap() }) assert.Panics(t, func() { v.SetEmptySlice() }) v2 := NewValueEmpty() v.CopyTo(v2) assert.Equal(t, v.AsRaw(), v2.AsRaw()) assert.Panics(t, func() { v2.CopyTo(v) }) } func TestValueType(t *testing.T) { assert.Equal(t, "Empty", ValueTypeEmpty.String()) assert.Equal(t, "Str", ValueTypeStr.String()) assert.Equal(t, "Bool", ValueTypeBool.String()) assert.Equal(t, "Int", ValueTypeInt.String()) assert.Equal(t, "Double", ValueTypeDouble.String()) assert.Equal(t, "Map", ValueTypeMap.String()) assert.Equal(t, "Slice", ValueTypeSlice.String()) assert.Equal(t, "Bytes", ValueTypeBytes.String()) assert.Empty(t, ValueType(100).String()) } func TestValueMap(t *testing.T) { m1 := NewValueMap() assert.Equal(t, ValueTypeMap, m1.Type()) assert.Equal(t, NewMap(), m1.Map()) assert.Equal(t, 0, m1.Map().Len()) m1.Map().PutDouble("double_key", 123) assert.Equal(t, 1, m1.Map().Len()) got, exists := m1.Map().Get("double_key") assert.True(t, exists) assert.Equal(t, NewValueDouble(123), got) // Create a second map. m2 := m1.Map().PutEmptyMap("child_map") assert.Equal(t, 0, m2.Len()) // Modify the source map that was inserted. m2.PutStr("key_in_child", "somestr") assert.Equal(t, 1, m2.Len()) got, exists = m2.Get("key_in_child") assert.True(t, exists) assert.Equal(t, NewValueStr("somestr"), got) // Insert the second map as a child. This should perform a deep copy. assert.Equal(t, 2, m1.Map().Len()) got, exists = m1.Map().Get("double_key") assert.True(t, exists) assert.Equal(t, NewValueDouble(123), got) got, exists = m1.Map().Get("child_map") assert.True(t, exists) assert.Equal(t, m2, got.Map()) // Modify the source map m2 that was inserted into m1. m2.PutStr("key_in_child", "somestr2") assert.Equal(t, 1, m2.Len()) got, exists = m2.Get("key_in_child") assert.True(t, exists) assert.Equal(t, NewValueStr("somestr2"), got) // The child map inside m1 should be modified. childMap, childMapExists := m1.Map().Get("child_map") require.True(t, childMapExists) got, exists = childMap.Map().Get("key_in_child") require.True(t, exists) assert.Equal(t, NewValueStr("somestr2"), got) // Now modify the inserted map (not the source) childMap.Map().PutStr("key_in_child", "somestr3") assert.Equal(t, 1, childMap.Map().Len()) got, exists = childMap.Map().Get("key_in_child") require.True(t, exists) assert.Equal(t, NewValueStr("somestr3"), got) // The source child map should be modified. got, exists = m2.Get("key_in_child") require.True(t, exists) assert.Equal(t, NewValueStr("somestr3"), got) removed := m1.Map().Remove("double_key") assert.True(t, removed) assert.Equal(t, 1, m1.Map().Len()) _, exists = m1.Map().Get("double_key") assert.False(t, exists) removed = m1.Map().Remove("child_map") assert.True(t, removed) assert.Equal(t, 0, m1.Map().Len()) _, exists = m1.Map().Get("child_map") assert.False(t, exists) // Test nil KvlistValue case for MapWrapper() func. orig := &internal.AnyValue{Value: &internal.AnyValue_KvlistValue{KvlistValue: nil}} m1 = newValue(orig, internal.NewState()) assert.Equal(t, Map{}, m1.Map()) } func TestValueSlice(t *testing.T) { a1 := NewValueSlice() assert.Equal(t, ValueTypeSlice, a1.Type()) assert.Equal(t, NewSlice(), a1.Slice()) assert.Equal(t, 0, a1.Slice().Len()) a1.Slice().AppendEmpty().SetDouble(123) assert.Equal(t, 1, a1.Slice().Len()) assert.Equal(t, NewValueDouble(123), a1.Slice().At(0)) // Create a second array. a2 := NewValueSlice() assert.Equal(t, 0, a2.Slice().Len()) a2.Slice().AppendEmpty().SetStr("somestr") assert.Equal(t, 1, a2.Slice().Len()) assert.Equal(t, NewValueStr("somestr"), a2.Slice().At(0)) // Insert the second array as a child. a2.CopyTo(a1.Slice().AppendEmpty()) assert.Equal(t, 2, a1.Slice().Len()) assert.Equal(t, NewValueDouble(123), a1.Slice().At(0)) assert.Equal(t, a2, a1.Slice().At(1)) // Check that the array was correctly inserted. childArray := a1.Slice().At(1) assert.Equal(t, ValueTypeSlice, childArray.Type()) assert.Equal(t, 1, childArray.Slice().Len()) v := childArray.Slice().At(0) assert.Equal(t, ValueTypeStr, v.Type()) assert.Equal(t, "somestr", v.Str()) // Test nil values case for Slice() func. a1 = newValue(&internal.AnyValue{Value: &internal.AnyValue_ArrayValue{ArrayValue: nil}}, internal.NewState()) assert.Equal(t, newSlice(nil, nil), a1.Slice()) } func TestNilOrigSetValue(t *testing.T) { av := NewValueEmpty() av.SetStr("abc") assert.Equal(t, "abc", av.Str()) av = NewValueEmpty() av.SetInt(123) assert.EqualValues(t, 123, av.Int()) av = NewValueEmpty() av.SetBool(true) assert.True(t, av.Bool()) av = NewValueEmpty() av.SetDouble(1.23) assert.InDelta(t, 1.23, av.Double(), 0.01) av = NewValueEmpty() av.SetEmptyBytes().FromRaw([]byte{1, 2, 3}) assert.Equal(t, []byte{1, 2, 3}, av.Bytes().AsRaw()) av = NewValueEmpty() require.NoError(t, av.SetEmptyMap().FromRaw(map[string]any{"k": "v"})) assert.Equal(t, map[string]any{"k": "v"}, av.Map().AsRaw()) av = NewValueEmpty() require.NoError(t, av.SetEmptySlice().FromRaw([]any{int64(1), "val"})) assert.Equal(t, []any{int64(1), "val"}, av.Slice().AsRaw()) } func TestValue_MoveTo(t *testing.T) { src := NewValueMap() src.Map().PutStr("key", "value") dest := NewValueEmpty() assert.True(t, dest.Equal(NewValueEmpty())) src.MoveTo(dest) assert.True(t, src.Equal(NewValueEmpty())) expected := NewValueMap() expected.Map().PutStr("key", "value") assert.True(t, dest.Equal(expected)) dest.MoveTo(dest) assert.True(t, dest.Equal(expected)) } func TestValue_CopyTo(t *testing.T) { dest := NewValueEmpty() orig := internal.GenTestAnyValue() newValue(orig, internal.NewState()).CopyTo(dest) assert.Equal(t, internal.GenTestAnyValue(), dest.getOrig()) } func TestSliceWithNilValues(t *testing.T) { origWithNil := []internal.AnyValue{ {}, {Value: &internal.AnyValue_StringValue{StringValue: "test_value"}}, } sm := newSlice(&origWithNil, internal.NewState()) val := sm.At(0) assert.Equal(t, ValueTypeEmpty, val.Type()) assert.Empty(t, val.Str()) val = sm.At(1) assert.Equal(t, ValueTypeStr, val.Type()) assert.Equal(t, "test_value", val.Str()) sm.AppendEmpty().SetStr("other_value") val = sm.At(2) assert.Equal(t, ValueTypeStr, val.Type()) assert.Equal(t, "other_value", val.Str()) } func TestValueAsString(t *testing.T) { tests := []struct { name string input Value expected string }{ { name: "string", input: NewValueStr("string value"), expected: "string value", }, { name: "int64", input: NewValueInt(42), expected: "42", }, { name: "float64", input: NewValueDouble(1.61803399), expected: "1.61803399", }, { name: "small float64", input: NewValueDouble(.000000009), expected: "9e-9", }, { name: "bad float64", input: NewValueDouble(math.Inf(1)), expected: "json: unsupported value: +Inf", }, { name: "boolean", input: NewValueBool(true), expected: "true", }, { name: "empty_map", input: NewValueMap(), expected: "{}", }, { name: "simple_map", input: generateTestValueMap(), expected: "{\"arrKey\":[\"strOne\",\"strTwo\"],\"boolKey\":false,\"floatKey\":18.6,\"intKey\":7,\"mapKey\":{\"keyOne\":\"valOne\",\"keyTwo\":\"valTwo\"},\"nullKey\":null,\"strKey\":\"strVal\"}", }, { name: "empty_array", input: NewValueSlice(), expected: "[]", }, { name: "simple_array", input: generateTestValueSlice(), expected: "[\"strVal\",7,18.6,false,null]", }, { name: "empty", input: NewValueEmpty(), expected: "", }, { name: "bytes", input: generateTestValueBytes(), expected: base64.StdEncoding.EncodeToString([]byte("String bytes")), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { actual := tt.input.AsString() assert.Equal(t, tt.expected, actual) }) } } func TestValueAsRaw(t *testing.T) { tests := []struct { name string input Value expected any }{ { name: "string", input: NewValueStr("value"), expected: "value", }, { name: "int", input: NewValueInt(11), expected: int64(11), }, { name: "double", input: NewValueDouble(1.2), expected: 1.2, }, { name: "bytes", input: generateTestValueBytes(), expected: []byte("String bytes"), }, { name: "empty", input: NewValueEmpty(), expected: nil, }, { name: "slice", input: generateTestValueSlice(), expected: []any{"strVal", int64(7), 18.6, false, nil}, }, { name: "map", input: generateTestValueMap(), expected: map[string]any{ "mapKey": map[string]any{"keyOne": "valOne", "keyTwo": "valTwo"}, "nullKey": nil, "strKey": "strVal", "arrKey": []any{"strOne", "strTwo"}, "boolKey": false, "floatKey": 18.6, "intKey": int64(7), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { actual := tt.input.AsRaw() assert.Equal(t, tt.expected, actual) }) } } func TestNewValueFromRaw(t *testing.T) { tests := []struct { name string input any expected Value }{ { name: "nil", input: nil, expected: NewValueEmpty(), }, { name: "string", input: "text", expected: NewValueStr("text"), }, { name: "int", input: 123, expected: NewValueInt(int64(123)), }, { name: "int8", input: int8(12), expected: NewValueInt(int64(12)), }, { name: "int16", input: int16(23), expected: NewValueInt(int64(23)), }, { name: "int32", input: int32(34), expected: NewValueInt(int64(34)), }, { name: "int64", input: int64(45), expected: NewValueInt(45), }, { name: "uint", input: uint(56), expected: NewValueInt(int64(56)), }, { name: "uint8", input: uint8(67), expected: NewValueInt(int64(67)), }, { name: "uint16", input: uint16(78), expected: NewValueInt(int64(78)), }, { name: "uint32", input: uint32(89), expected: NewValueInt(int64(89)), }, { name: "uint64", input: uint64(90), expected: NewValueInt(int64(90)), }, { name: "float32", input: float32(1.234), expected: NewValueDouble(float64(float32(1.234))), }, { name: "float64", input: float64(2.345), expected: NewValueDouble(float64(2.345)), }, { name: "bool", input: true, expected: NewValueBool(true), }, { name: "bytes", input: []byte{1, 2, 3}, expected: func() Value { m := NewValueBytes() m.Bytes().FromRaw([]byte{1, 2, 3}) return m }(), }, { name: "map", input: map[string]any{ "k": "v", }, expected: func() Value { m := NewValueMap() assert.NoError(t, m.Map().FromRaw(map[string]any{"k": "v"})) return m }(), }, { name: "empty map", input: map[string]any{}, expected: func() Value { m := NewValueMap() assert.NoError(t, m.Map().FromRaw(map[string]any{})) return m }(), }, { name: "slice", input: []any{"v1", "v2"}, expected: (func() Value { s := NewValueSlice() assert.NoError(t, s.Slice().FromRaw([]any{"v1", "v2"})) return s })(), }, { name: "empty slice", input: []any{}, expected: (func() Value { s := NewValueSlice() assert.NoError(t, s.Slice().FromRaw([]any{})) return s })(), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { actual := NewValueEmpty() require.NoError(t, actual.FromRaw(tt.input)) assert.Equal(t, tt.expected, actual) }) } } func TestNewValueFromRawInvalid(t *testing.T) { actual := NewValueEmpty() assert.EqualError(t, actual.FromRaw(ValueTypeDouble), "") } func TestInvalidValue(t *testing.T) { v := Value{} assert.False(t, v.Bool()) assert.Equal(t, int64(0), v.Int()) assert.InDelta(t, float64(0), v.Double(), 0.01) assert.Empty(t, v.Str()) assert.Equal(t, ByteSlice{}, v.Bytes()) assert.Equal(t, Map{}, v.Map()) assert.Equal(t, Slice{}, v.Slice()) assert.Panics(t, func() { v.AsString() }) assert.Panics(t, func() { v.AsRaw() }) assert.Panics(t, func() { _ = v.FromRaw(1) }) assert.Panics(t, func() { v.Type() }) assert.Panics(t, func() { v.SetStr("") }) assert.Panics(t, func() { v.SetInt(0) }) assert.Panics(t, func() { v.SetDouble(0) }) assert.Panics(t, func() { v.SetBool(false) }) assert.Panics(t, func() { v.SetEmptyBytes() }) assert.Panics(t, func() { v.SetEmptyMap() }) assert.Panics(t, func() { v.SetEmptySlice() }) nv := NewValueEmpty() v.CopyTo(nv) assert.Nil(t, nv.getOrig().Value) } func TestValueEqual(t *testing.T) { for _, tt := range []struct { name string value Value comparison Value expected bool }{ { name: "different types", value: NewValueEmpty(), comparison: NewValueStr("test"), expected: false, }, { name: "same empty", value: NewValueEmpty(), comparison: NewValueEmpty(), expected: true, }, { name: "same strings", value: NewValueStr("test"), comparison: NewValueStr("test"), expected: true, }, { name: "different strings", value: NewValueStr("test"), comparison: NewValueStr("non-test"), expected: false, }, { name: "same booleans", value: NewValueBool(true), comparison: NewValueBool(true), expected: true, }, { name: "different booleans", value: NewValueBool(true), comparison: NewValueBool(false), expected: false, }, { name: "same int", value: NewValueInt(42), comparison: NewValueInt(42), expected: true, }, { name: "different ints", value: NewValueInt(42), comparison: NewValueInt(1701), expected: false, }, { name: "same double", value: NewValueDouble(13.37), comparison: NewValueDouble(13.37), expected: true, }, { name: "different doubles", value: NewValueDouble(13.37), comparison: NewValueDouble(17.01), expected: false, }, { name: "same byte slice", value: func() Value { m := NewValueBytes() m.Bytes().FromRaw([]byte{1, 3, 3, 7}) return m }(), comparison: func() Value { m := NewValueBytes() m.Bytes().FromRaw([]byte{1, 3, 3, 7}) return m }(), expected: true, }, { name: "different byte slice", value: func() Value { m := NewValueBytes() m.Bytes().FromRaw([]byte{1, 3, 3, 7}) return m }(), comparison: func() Value { m := NewValueBytes() m.Bytes().FromRaw([]byte{1, 7, 0, 1}) return m }(), expected: false, }, { name: "same slice", value: func() Value { m := NewValueSlice() require.NoError(t, m.Slice().FromRaw([]any{1337})) return m }(), comparison: func() Value { m := NewValueSlice() require.NoError(t, m.Slice().FromRaw([]any{1337})) return m }(), expected: true, }, { name: "different slice", value: func() Value { m := NewValueSlice() require.NoError(t, m.Slice().FromRaw([]any{1337})) return m }(), comparison: func() Value { m := NewValueSlice() require.NoError(t, m.Slice().FromRaw([]any{1701})) return m }(), expected: false, }, { name: "same map", value: func() Value { m := NewValueMap() m.Map().PutStr("hello", "world") return m }(), comparison: func() Value { m := NewValueMap() m.Map().PutStr("hello", "world") return m }(), expected: true, }, { name: "different maps", value: func() Value { m := NewValueMap() m.Map().PutStr("hello", "world") return m }(), comparison: func() Value { m := NewValueMap() m.Map().PutStr("bonjour", "monde") return m }(), expected: false, }, } { t.Run(tt.name, func(t *testing.T) { assert.Equal(t, tt.expected, tt.value.Equal(tt.comparison)) }) } } func BenchmarkValueEqual(b *testing.B) { testutil.SkipMemoryBench(b) for _, bb := range []struct { name string value Value comparison Value }{ { name: "nil", value: NewValueEmpty(), comparison: NewValueEmpty(), }, { name: "strings", value: NewValueStr("test"), comparison: NewValueStr("test"), }, { name: "booleans", value: NewValueBool(true), comparison: NewValueBool(true), }, { name: "ints", value: NewValueInt(42), comparison: NewValueInt(42), }, { name: "doubles", value: NewValueDouble(13.37), comparison: NewValueDouble(13.37), }, { name: "byte slices", value: func() Value { m := NewValueBytes() m.Bytes().FromRaw([]byte{1, 3, 3, 7}) return m }(), comparison: func() Value { m := NewValueBytes() m.Bytes().FromRaw([]byte{1, 3, 3, 7}) return m }(), }, { name: "slices", value: func() Value { m := NewValueSlice() require.NoError(b, m.Slice().FromRaw([]any{1337})) return m }(), comparison: func() Value { m := NewValueSlice() require.NoError(b, m.Slice().FromRaw([]any{1337})) return m }(), }, { name: "maps", value: func() Value { m := NewValueMap() m.Map().PutStr("hello", "world") return m }(), comparison: func() Value { m := NewValueMap() m.Map().PutStr("hello", "world") return m }(), }, } { b.Run(bb.name, func(b *testing.B) { b.ResetTimer() b.ReportAllocs() for b.Loop() { _ = bb.value.Equal(bb.comparison) } }) } } func generateTestValueMap() Value { ret := NewValueMap() attrMap := ret.Map() attrMap.PutStr("strKey", "strVal") attrMap.PutInt("intKey", 7) attrMap.PutDouble("floatKey", 18.6) attrMap.PutBool("boolKey", false) attrMap.PutEmpty("nullKey") m := attrMap.PutEmptyMap("mapKey") m.PutStr("keyOne", "valOne") m.PutStr("keyTwo", "valTwo") s := attrMap.PutEmptySlice("arrKey") s.AppendEmpty().SetStr("strOne") s.AppendEmpty().SetStr("strTwo") return ret } func generateTestValueSlice() Value { ret := NewValueSlice() attrArr := ret.Slice() attrArr.AppendEmpty().SetStr("strVal") attrArr.AppendEmpty().SetInt(7) attrArr.AppendEmpty().SetDouble(18.6) attrArr.AppendEmpty().SetBool(false) attrArr.AppendEmpty() return ret } func generateTestValueBytes() Value { v := NewValueBytes() v.Bytes().FromRaw([]byte("String bytes")) return v } opentelemetry-collector-0.141.0/pdata/plog/000077500000000000000000000000001511331344600205705ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/plog/doc_test.go000066400000000000000000000250271511331344600227310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog_test import ( "fmt" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" ) func ExampleNewLogs() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() resourceLogs.Resource().Attributes().PutStr("service.name", "my-service") resourceLogs.Resource().Attributes().PutStr("service.version", "1.0.0") resourceLogs.Resource().Attributes().PutStr("host.name", "server-01") scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() scopeLogs.Scope().SetName("my-logger") scopeLogs.Scope().SetVersion("1.0.0") logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.SetTimestamp(pcommon.Timestamp(1640995200000000000)) logRecord.SetSeverityNumber(plog.SeverityNumberInfo) logRecord.SetSeverityText("INFO") logRecord.Body().SetStr("User login successful") logRecord.Attributes().PutStr("user.id", "user123") logRecord.Attributes().PutStr("session.id", "session456") logRecord.Attributes().PutStr("action", "login") fmt.Printf("Resource logs count: %d\n", logs.ResourceLogs().Len()) fmt.Printf("Log records count: %d\n", scopeLogs.LogRecords().Len()) fmt.Printf("Log message: %s\n", logRecord.Body().Str()) fmt.Printf("Severity: %s\n", logRecord.SeverityText()) // Output: // Resource logs count: 1 // Log records count: 1 // Log message: User login successful // Severity: INFO } func ExampleLogRecord_SetSeverityNumber() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() severities := []struct { level plog.SeverityNumber text string msg string }{ {plog.SeverityNumberDebug, "DEBUG", "Debug information"}, {plog.SeverityNumberInfo, "INFO", "Application started"}, {plog.SeverityNumberWarn, "WARN", "Configuration file not found, using defaults"}, {plog.SeverityNumberError, "ERROR", "Failed to connect to database"}, {plog.SeverityNumberFatal, "FATAL", "Critical system failure"}, } for _, s := range severities { logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.SetSeverityNumber(s.level) logRecord.SetSeverityText(s.text) logRecord.Body().SetStr(s.msg) logRecord.SetTimestamp(pcommon.Timestamp(1640995200000000000)) } fmt.Printf("Total log records: %d\n", scopeLogs.LogRecords().Len()) first := scopeLogs.LogRecords().At(0) last := scopeLogs.LogRecords().At(scopeLogs.LogRecords().Len() - 1) fmt.Printf("First log: %s - %s\n", first.SeverityText(), first.Body().Str()) fmt.Printf("Last log: %s - %s\n", last.SeverityText(), last.Body().Str()) // Output: // Total log records: 5 // First log: DEBUG - Debug information // Last log: FATAL - Critical system failure } func ExampleLogRecord_Body() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() logRecord1 := scopeLogs.LogRecords().AppendEmpty() logRecord1.Body().SetStr("Simple string message") logRecord1.SetSeverityNumber(plog.SeverityNumberInfo) logRecord2 := scopeLogs.LogRecords().AppendEmpty() body := logRecord2.Body().SetEmptyMap() body.PutStr("event", "user_action") body.PutStr("user_id", "user123") body.PutInt("timestamp", 1640995200) body.PutBool("success", true) logRecord2.SetSeverityNumber(plog.SeverityNumberInfo) logRecord3 := scopeLogs.LogRecords().AppendEmpty() bodySlice := logRecord3.Body().SetEmptySlice() bodySlice.AppendEmpty().SetStr("Step 1: Initialize connection") bodySlice.AppendEmpty().SetStr("Step 2: Authenticate user") bodySlice.AppendEmpty().SetStr("Step 3: Load configuration") logRecord3.SetSeverityNumber(plog.SeverityNumberDebug) fmt.Printf("Log 1 body type: %s\n", logRecord1.Body().Type()) fmt.Printf("Log 2 body type: %s\n", logRecord2.Body().Type()) fmt.Printf("Log 3 body type: %s\n", logRecord3.Body().Type()) fmt.Printf("Log 3 steps count: %d\n", logRecord3.Body().Slice().Len()) // Output: // Log 1 body type: Str // Log 2 body type: Map // Log 3 body type: Slice // Log 3 steps count: 3 } func ExampleLogRecord_TraceID() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.Body().SetStr("Processing request") logRecord.SetSeverityNumber(plog.SeverityNumberInfo) traceID := pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) spanID := pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) logRecord.SetTraceID(traceID) logRecord.SetSpanID(spanID) logRecord.SetFlags(plog.DefaultLogRecordFlags.WithIsSampled(true)) fmt.Printf("Log message: %s\n", logRecord.Body().Str()) fmt.Printf("TraceID: %s\n", logRecord.TraceID()) fmt.Printf("SpanID: %s\n", logRecord.SpanID()) fmt.Printf("Is sampled: %t\n", logRecord.Flags().IsSampled()) // Output: // Log message: Processing request // TraceID: 0102030405060708090a0b0c0d0e0f10 // SpanID: 0102030405060708 // Is sampled: true } func ExampleLogRecord_ObservedTimestamp() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.Body().SetStr("Log entry with observation time") logRecord.SetSeverityNumber(plog.SeverityNumberInfo) // Set both original timestamp and observed timestamp originalTime := pcommon.Timestamp(1640995200000000000) // 2022-01-01 00:00:00 UTC observedTime := pcommon.Timestamp(1640995200500000000) // 2022-01-01 00:00:00.5 UTC logRecord.SetTimestamp(originalTime) logRecord.SetObservedTimestamp(observedTime) fmt.Printf("Original timestamp: %d\n", logRecord.Timestamp()) fmt.Printf("Observed timestamp: %d\n", logRecord.ObservedTimestamp()) fmt.Printf("Delay (ns): %d\n", logRecord.ObservedTimestamp()-logRecord.Timestamp()) // Output: // Original timestamp: 1640995200000000000 // Observed timestamp: 1640995200500000000 // Delay (ns): 500000000 } func ExampleLogRecord_EventName() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.SetEventName("user.login") logRecord.Body().SetStr("User authentication event") logRecord.SetSeverityNumber(plog.SeverityNumberInfo) logRecord.Attributes().PutStr("user.id", "user123") logRecord.Attributes().PutStr("session.id", "session456") logRecord.Attributes().PutBool("success", true) fmt.Printf("Event name: %s\n", logRecord.EventName()) fmt.Printf("Log body: %s\n", logRecord.Body().Str()) // Output: // Event name: user.login // Log body: User authentication event } func ExampleLogRecordFlags() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.Body().SetStr("Log with flags") logRecord.SetSeverityNumber(plog.SeverityNumberInfo) // Test default flags defaultFlags := plog.DefaultLogRecordFlags logRecord.SetFlags(defaultFlags) fmt.Printf("Default flags IsSampled: %t\n", logRecord.Flags().IsSampled()) // Test with sampled flag flagsWithSampled := defaultFlags.WithIsSampled(true) logRecord.SetFlags(flagsWithSampled) fmt.Printf("With sampled flag: %t\n", logRecord.Flags().IsSampled()) // Test removing sampled flag flagsWithoutSampled := flagsWithSampled.WithIsSampled(false) logRecord.SetFlags(flagsWithoutSampled) fmt.Printf("Without sampled flag: %t\n", logRecord.Flags().IsSampled()) // Output: // Default flags IsSampled: false // With sampled flag: true // Without sampled flag: false } func ExampleSeverityNumber() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() // Test all severity levels severityLevels := []struct { level plog.SeverityNumber name string }{ {plog.SeverityNumberUnspecified, "Unspecified"}, {plog.SeverityNumberTrace, "Trace"}, {plog.SeverityNumberTrace2, "Trace2"}, {plog.SeverityNumberTrace3, "Trace3"}, {plog.SeverityNumberTrace4, "Trace4"}, {plog.SeverityNumberDebug, "Debug"}, {plog.SeverityNumberDebug2, "Debug2"}, {plog.SeverityNumberDebug3, "Debug3"}, {plog.SeverityNumberDebug4, "Debug4"}, {plog.SeverityNumberInfo, "Info"}, {plog.SeverityNumberInfo2, "Info2"}, {plog.SeverityNumberInfo3, "Info3"}, {plog.SeverityNumberInfo4, "Info4"}, {plog.SeverityNumberWarn, "Warn"}, {plog.SeverityNumberWarn2, "Warn2"}, {plog.SeverityNumberWarn3, "Warn3"}, {plog.SeverityNumberWarn4, "Warn4"}, {plog.SeverityNumberError, "Error"}, {plog.SeverityNumberError2, "Error2"}, {plog.SeverityNumberError3, "Error3"}, {plog.SeverityNumberError4, "Error4"}, {plog.SeverityNumberFatal, "Fatal"}, {plog.SeverityNumberFatal2, "Fatal2"}, {plog.SeverityNumberFatal3, "Fatal3"}, {plog.SeverityNumberFatal4, "Fatal4"}, } for i, s := range severityLevels { if i < 5 { // Only create first 5 to keep output manageable logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.SetSeverityNumber(s.level) logRecord.SetSeverityText(s.name) logRecord.Body().SetStr("Log at " + s.name + " level") } } fmt.Printf("Total severity levels tested: %d\n", len(severityLevels)) fmt.Printf("Created log records: %d\n", scopeLogs.LogRecords().Len()) fmt.Printf("First severity: %s\n", scopeLogs.LogRecords().At(0).SeverityText()) fmt.Printf("Last severity: %s\n", scopeLogs.LogRecords().At(4).SeverityText()) // Output: // Total severity levels tested: 25 // Created log records: 5 // First severity: Unspecified // Last severity: Trace4 } func ExampleLogRecord_DroppedAttributesCount() { logs := plog.NewLogs() resourceLogs := logs.ResourceLogs().AppendEmpty() scopeLogs := resourceLogs.ScopeLogs().AppendEmpty() logRecord := scopeLogs.LogRecords().AppendEmpty() logRecord.Body().SetStr("Log with some attributes dropped") logRecord.SetSeverityNumber(plog.SeverityNumberWarn) // Add some attributes logRecord.Attributes().PutStr("included.attr1", "value1") logRecord.Attributes().PutStr("included.attr2", "value2") logRecord.Attributes().PutInt("included.count", 42) // Set dropped attributes count logRecord.SetDroppedAttributesCount(7) fmt.Printf("Current attributes: %d\n", logRecord.Attributes().Len()) fmt.Printf("Dropped attributes: %d\n", logRecord.DroppedAttributesCount()) fmt.Printf("Total original attributes: %d\n", logRecord.Attributes().Len()+int(logRecord.DroppedAttributesCount())) // Output: // Current attributes: 3 // Dropped attributes: 7 // Total original attributes: 10 } opentelemetry-collector-0.141.0/pdata/plog/encoding.go000066400000000000000000000016571511331344600227160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" // MarshalSizer is the interface that groups the basic Marshal and Size methods type MarshalSizer interface { Marshaler Sizer } // Marshaler marshals Logs into bytes. type Marshaler interface { // MarshalLogs the given Logs into bytes. // If the error is not nil, the returned bytes slice cannot be used. MarshalLogs(ld Logs) ([]byte, error) } // Unmarshaler unmarshalls bytes into Logs. type Unmarshaler interface { // UnmarshalLogs the given bytes into Logs. // If the error is not nil, the returned Logs cannot be used. UnmarshalLogs(buf []byte) (Logs, error) } // Sizer is an optional interface implemented by the Marshaler, // that calculates the size of a marshaled Logs. type Sizer interface { // LogsSize returns the size in bytes of a marshaled Logs. LogsSize(ld Logs) int } opentelemetry-collector-0.141.0/pdata/plog/fuzz_test.go000066400000000000000000000030741511331344600231600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" import ( "bytes" "testing" "github.com/stretchr/testify/require" ) var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." func FuzzUnmarshalJsonLogs(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { u1 := &JSONUnmarshaler{} ld1, err := u1.UnmarshalLogs(data) if err != nil { return } m1 := &JSONMarshaler{} b1, err := m1.MarshalLogs(ld1) require.NoError(t, err, "failed to marshal valid struct") u2 := &JSONUnmarshaler{} ld2, err := u2.UnmarshalLogs(b1) require.NoError(t, err, "failed to unmarshal valid bytes") m2 := &JSONMarshaler{} b2, err := m2.MarshalLogs(ld2) require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzUnmarshalPBLogs(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { u1 := &ProtoUnmarshaler{} ld1, err := u1.UnmarshalLogs(data) if err != nil { return } m1 := &ProtoMarshaler{} b1, err := m1.MarshalLogs(ld1) require.NoError(t, err, "failed to marshal valid struct") u2 := &ProtoUnmarshaler{} ld2, err := u2.UnmarshalLogs(b1) require.NoError(t, err, "failed to unmarshal valid bytes") m2 := &ProtoMarshaler{} b2, err := m2.MarshalLogs(ld2) require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } opentelemetry-collector-0.141.0/pdata/plog/generated_logrecord.go000066400000000000000000000124031511331344600251150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // LogRecord are experimental implementation of OpenTelemetry Log Data Model. // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewLogRecord function to create new instances. // Important: zero-initialized instance is not valid for use. type LogRecord struct { orig *internal.LogRecord state *internal.State } func newLogRecord(orig *internal.LogRecord, state *internal.State) LogRecord { return LogRecord{orig: orig, state: state} } // NewLogRecord creates a new empty LogRecord. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewLogRecord() LogRecord { return newLogRecord(internal.NewLogRecord(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms LogRecord) MoveTo(dest LogRecord) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteLogRecord(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Timestamp returns the timestamp associated with this LogRecord. func (ms LogRecord) Timestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTimestamp replaces the timestamp associated with this LogRecord. func (ms LogRecord) SetTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // ObservedTimestamp returns the observedtimestamp associated with this LogRecord. func (ms LogRecord) ObservedTimestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.ObservedTimeUnixNano) } // SetObservedTimestamp replaces the observedtimestamp associated with this LogRecord. func (ms LogRecord) SetObservedTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.ObservedTimeUnixNano = uint64(v) } // SeverityNumber returns the severitynumber associated with this LogRecord. func (ms LogRecord) SeverityNumber() SeverityNumber { return SeverityNumber(ms.orig.SeverityNumber) } // SetSeverityNumber replaces the severitynumber associated with this LogRecord. func (ms LogRecord) SetSeverityNumber(v SeverityNumber) { ms.state.AssertMutable() ms.orig.SeverityNumber = internal.SeverityNumber(v) } // SeverityText returns the severitytext associated with this LogRecord. func (ms LogRecord) SeverityText() string { return ms.orig.SeverityText } // SetSeverityText replaces the severitytext associated with this LogRecord. func (ms LogRecord) SetSeverityText(v string) { ms.state.AssertMutable() ms.orig.SeverityText = v } // Body returns the body associated with this LogRecord. func (ms LogRecord) Body() pcommon.Value { return pcommon.Value(internal.NewValueWrapper(&ms.orig.Body, ms.state)) } // Attributes returns the Attributes associated with this LogRecord. func (ms LogRecord) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this LogRecord. func (ms LogRecord) DroppedAttributesCount() uint32 { return ms.orig.DroppedAttributesCount } // SetDroppedAttributesCount replaces the droppedattributescount associated with this LogRecord. func (ms LogRecord) SetDroppedAttributesCount(v uint32) { ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // Flags returns the flags associated with this LogRecord. func (ms LogRecord) Flags() LogRecordFlags { return LogRecordFlags(ms.orig.Flags) } // SetFlags replaces the flags associated with this LogRecord. func (ms LogRecord) SetFlags(v LogRecordFlags) { ms.state.AssertMutable() ms.orig.Flags = uint32(v) } // TraceID returns the traceid associated with this LogRecord. func (ms LogRecord) TraceID() pcommon.TraceID { return pcommon.TraceID(ms.orig.TraceId) } // SetTraceID replaces the traceid associated with this LogRecord. func (ms LogRecord) SetTraceID(v pcommon.TraceID) { ms.state.AssertMutable() ms.orig.TraceId = internal.TraceID(v) } // SpanID returns the spanid associated with this LogRecord. func (ms LogRecord) SpanID() pcommon.SpanID { return pcommon.SpanID(ms.orig.SpanId) } // SetSpanID replaces the spanid associated with this LogRecord. func (ms LogRecord) SetSpanID(v pcommon.SpanID) { ms.state.AssertMutable() ms.orig.SpanId = internal.SpanID(v) } // EventName returns the eventname associated with this LogRecord. func (ms LogRecord) EventName() string { return ms.orig.EventName } // SetEventName replaces the eventname associated with this LogRecord. func (ms LogRecord) SetEventName(v string) { ms.state.AssertMutable() ms.orig.EventName = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms LogRecord) CopyTo(dest LogRecord) { dest.state.AssertMutable() internal.CopyLogRecord(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/plog/generated_logrecord_test.go000066400000000000000000000113531511331344600261570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestLogRecord_MoveTo(t *testing.T) { ms := generateTestLogRecord() dest := NewLogRecord() ms.MoveTo(dest) assert.Equal(t, NewLogRecord(), ms) assert.Equal(t, generateTestLogRecord(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestLogRecord(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newLogRecord(internal.NewLogRecord(), sharedState)) }) assert.Panics(t, func() { newLogRecord(internal.NewLogRecord(), sharedState).MoveTo(dest) }) } func TestLogRecord_CopyTo(t *testing.T) { ms := NewLogRecord() orig := NewLogRecord() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestLogRecord() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newLogRecord(internal.NewLogRecord(), sharedState)) }) } func TestLogRecord_Timestamp(t *testing.T) { ms := NewLogRecord() assert.Equal(t, pcommon.Timestamp(0), ms.Timestamp()) testValTimestamp := pcommon.Timestamp(1234567890) ms.SetTimestamp(testValTimestamp) assert.Equal(t, testValTimestamp, ms.Timestamp()) } func TestLogRecord_ObservedTimestamp(t *testing.T) { ms := NewLogRecord() assert.Equal(t, pcommon.Timestamp(0), ms.ObservedTimestamp()) testValObservedTimestamp := pcommon.Timestamp(1234567890) ms.SetObservedTimestamp(testValObservedTimestamp) assert.Equal(t, testValObservedTimestamp, ms.ObservedTimestamp()) } func TestLogRecord_SeverityNumber(t *testing.T) { ms := NewLogRecord() assert.Equal(t, SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_UNSPECIFIED), ms.SeverityNumber()) testValSeverityNumber := SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_DEBUG) ms.SetSeverityNumber(testValSeverityNumber) assert.Equal(t, testValSeverityNumber, ms.SeverityNumber()) } func TestLogRecord_SeverityText(t *testing.T) { ms := NewLogRecord() assert.Empty(t, ms.SeverityText()) ms.SetSeverityText("test_severitytext") assert.Equal(t, "test_severitytext", ms.SeverityText()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLogRecord(internal.NewLogRecord(), sharedState).SetSeverityText("test_severitytext") }) } func TestLogRecord_Body(t *testing.T) { ms := NewLogRecord() assert.Equal(t, pcommon.NewValueEmpty(), ms.Body()) ms.orig.Body = *internal.GenTestAnyValue() assert.Equal(t, pcommon.Value(internal.GenTestValueWrapper()), ms.Body()) } func TestLogRecord_Attributes(t *testing.T) { ms := NewLogRecord() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestLogRecord_DroppedAttributesCount(t *testing.T) { ms := NewLogRecord() assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedAttributesCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLogRecord(internal.NewLogRecord(), sharedState).SetDroppedAttributesCount(uint32(13)) }) } func TestLogRecord_Flags(t *testing.T) { ms := NewLogRecord() assert.Equal(t, LogRecordFlags(0), ms.Flags()) testValFlags := LogRecordFlags(1) ms.SetFlags(testValFlags) assert.Equal(t, testValFlags, ms.Flags()) } func TestLogRecord_TraceID(t *testing.T) { ms := NewLogRecord() assert.Equal(t, pcommon.TraceID(internal.TraceID([16]byte{})), ms.TraceID()) testValTraceID := pcommon.TraceID(internal.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})) ms.SetTraceID(testValTraceID) assert.Equal(t, testValTraceID, ms.TraceID()) } func TestLogRecord_SpanID(t *testing.T) { ms := NewLogRecord() assert.Equal(t, pcommon.SpanID(internal.SpanID([8]byte{})), ms.SpanID()) testValSpanID := pcommon.SpanID(internal.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})) ms.SetSpanID(testValSpanID) assert.Equal(t, testValSpanID, ms.SpanID()) } func TestLogRecord_EventName(t *testing.T) { ms := NewLogRecord() assert.Empty(t, ms.EventName()) ms.SetEventName("test_eventname") assert.Equal(t, "test_eventname", ms.EventName()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLogRecord(internal.NewLogRecord(), sharedState).SetEventName("test_eventname") }) } func generateTestLogRecord() LogRecord { return newLogRecord(internal.GenTestLogRecord(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/plog/generated_logrecordslice.go000066400000000000000000000112771511331344600261450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // LogRecordSlice logically represents a slice of LogRecord. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewLogRecordSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type LogRecordSlice struct { orig *[]*internal.LogRecord state *internal.State } func newLogRecordSlice(orig *[]*internal.LogRecord, state *internal.State) LogRecordSlice { return LogRecordSlice{orig: orig, state: state} } // NewLogRecordSlice creates a LogRecordSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewLogRecordSlice() LogRecordSlice { orig := []*internal.LogRecord(nil) return newLogRecordSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewLogRecordSlice()". func (es LogRecordSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es LogRecordSlice) At(i int) LogRecord { return newLogRecord((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es LogRecordSlice) All() iter.Seq2[int, LogRecord] { return func(yield func(int, LogRecord) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new LogRecordSlice can be initialized: // // es := NewLogRecordSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es LogRecordSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.LogRecord, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty LogRecord. // It returns the newly added LogRecord. func (es LogRecordSlice) AppendEmpty() LogRecord { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewLogRecord()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es LogRecordSlice) MoveAndAppendTo(dest LogRecordSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es LogRecordSlice) RemoveIf(f func(LogRecord) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteLogRecord((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es LogRecordSlice) CopyTo(dest LogRecordSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyLogRecordPtrSlice(*dest.orig, *es.orig) } // Sort sorts the LogRecord elements within LogRecordSlice given the // provided less function so that two instances of LogRecordSlice // can be compared. func (es LogRecordSlice) Sort(less func(a, b LogRecord) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/plog/generated_logrecordslice_test.go000066400000000000000000000113661511331344600272030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestLogRecordSlice(t *testing.T) { es := NewLogRecordSlice() assert.Equal(t, 0, es.Len()) es = newLogRecordSlice(&[]*internal.LogRecord{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewLogRecord() testVal := generateTestLogRecord() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestLogRecord() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestLogRecordSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newLogRecordSlice(&[]*internal.LogRecord{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewLogRecordSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestLogRecordSlice_CopyTo(t *testing.T) { dest := NewLogRecordSlice() src := generateTestLogRecordSlice() src.CopyTo(dest) assert.Equal(t, generateTestLogRecordSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestLogRecordSlice(), dest) } func TestLogRecordSlice_EnsureCapacity(t *testing.T) { es := generateTestLogRecordSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestLogRecordSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestLogRecordSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestLogRecordSlice(), es) } func TestLogRecordSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestLogRecordSlice() dest := NewLogRecordSlice() src := generateTestLogRecordSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLogRecordSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLogRecordSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestLogRecordSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestLogRecordSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewLogRecordSlice() emptySlice.RemoveIf(func(el LogRecord) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestLogRecordSlice() pos := 0 filtered.RemoveIf(func(el LogRecord) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestLogRecordSlice_RemoveIfAll(t *testing.T) { got := generateTestLogRecordSlice() got.RemoveIf(func(el LogRecord) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestLogRecordSliceAll(t *testing.T) { ms := generateTestLogRecordSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestLogRecordSlice_Sort(t *testing.T) { es := generateTestLogRecordSlice() es.Sort(func(a, b LogRecord) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b LogRecord) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestLogRecordSlice() LogRecordSlice { ms := NewLogRecordSlice() *ms.orig = internal.GenTestLogRecordPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/plog/generated_logs.go000066400000000000000000000043431511331344600241050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "go.opentelemetry.io/collector/pdata/internal" ) // Logs is the top-level struct that is propagated through the logs pipeline. // Use NewLogs to create new instance, zero-initialized instance is not valid for use. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewLogs function to create new instances. // Important: zero-initialized instance is not valid for use. type Logs internal.LogsWrapper func newLogs(orig *internal.ExportLogsServiceRequest, state *internal.State) Logs { return Logs(internal.NewLogsWrapper(orig, state)) } // NewLogs creates a new empty Logs. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewLogs() Logs { return newLogs(internal.NewExportLogsServiceRequest(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Logs) MoveTo(dest Logs) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteExportLogsServiceRequest(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // ResourceLogs returns the ResourceLogs associated with this Logs. func (ms Logs) ResourceLogs() ResourceLogsSlice { return newResourceLogsSlice(&ms.getOrig().ResourceLogs, ms.getState()) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Logs) CopyTo(dest Logs) { dest.getState().AssertMutable() internal.CopyExportLogsServiceRequest(dest.getOrig(), ms.getOrig()) } func (ms Logs) getOrig() *internal.ExportLogsServiceRequest { return internal.GetLogsOrig(internal.LogsWrapper(ms)) } func (ms Logs) getState() *internal.State { return internal.GetLogsState(internal.LogsWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/plog/generated_logs_test.go000066400000000000000000000030301511331344600251340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestLogs_MoveTo(t *testing.T) { ms := generateTestLogs() dest := NewLogs() ms.MoveTo(dest) assert.Equal(t, NewLogs(), ms) assert.Equal(t, generateTestLogs(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestLogs(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newLogs(internal.NewExportLogsServiceRequest(), sharedState)) }) assert.Panics(t, func() { newLogs(internal.NewExportLogsServiceRequest(), sharedState).MoveTo(dest) }) } func TestLogs_CopyTo(t *testing.T) { ms := NewLogs() orig := NewLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newLogs(internal.NewExportLogsServiceRequest(), sharedState)) }) } func TestLogs_ResourceLogs(t *testing.T) { ms := NewLogs() assert.Equal(t, NewResourceLogsSlice(), ms.ResourceLogs()) ms.getOrig().ResourceLogs = internal.GenTestResourceLogsPtrSlice() assert.Equal(t, generateTestResourceLogsSlice(), ms.ResourceLogs()) } func generateTestLogs() Logs { return newLogs(internal.GenTestExportLogsServiceRequest(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/plog/generated_resourcelogs.go000066400000000000000000000047521511331344600256610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceLogs is a collection of logs from a Resource. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewResourceLogs function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceLogs struct { orig *internal.ResourceLogs state *internal.State } func newResourceLogs(orig *internal.ResourceLogs, state *internal.State) ResourceLogs { return ResourceLogs{orig: orig, state: state} } // NewResourceLogs creates a new empty ResourceLogs. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResourceLogs() ResourceLogs { return newResourceLogs(internal.NewResourceLogs(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ResourceLogs) MoveTo(dest ResourceLogs) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteResourceLogs(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Resource returns the resource associated with this ResourceLogs. func (ms ResourceLogs) Resource() pcommon.Resource { return pcommon.Resource(internal.NewResourceWrapper(&ms.orig.Resource, ms.state)) } // ScopeLogs returns the ScopeLogs associated with this ResourceLogs. func (ms ResourceLogs) ScopeLogs() ScopeLogsSlice { return newScopeLogsSlice(&ms.orig.ScopeLogs, ms.state) } // SchemaUrl returns the schemaurl associated with this ResourceLogs. func (ms ResourceLogs) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ResourceLogs. func (ms ResourceLogs) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ResourceLogs) CopyTo(dest ResourceLogs) { dest.state.AssertMutable() internal.CopyResourceLogs(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/plog/generated_resourcelogs_test.go000066400000000000000000000044151511331344600267140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestResourceLogs_MoveTo(t *testing.T) { ms := generateTestResourceLogs() dest := NewResourceLogs() ms.MoveTo(dest) assert.Equal(t, NewResourceLogs(), ms) assert.Equal(t, generateTestResourceLogs(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestResourceLogs(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newResourceLogs(internal.NewResourceLogs(), sharedState)) }) assert.Panics(t, func() { newResourceLogs(internal.NewResourceLogs(), sharedState).MoveTo(dest) }) } func TestResourceLogs_CopyTo(t *testing.T) { ms := NewResourceLogs() orig := NewResourceLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestResourceLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newResourceLogs(internal.NewResourceLogs(), sharedState)) }) } func TestResourceLogs_Resource(t *testing.T) { ms := NewResourceLogs() assert.Equal(t, pcommon.NewResource(), ms.Resource()) ms.orig.Resource = *internal.GenTestResource() assert.Equal(t, pcommon.Resource(internal.GenTestResourceWrapper()), ms.Resource()) } func TestResourceLogs_ScopeLogs(t *testing.T) { ms := NewResourceLogs() assert.Equal(t, NewScopeLogsSlice(), ms.ScopeLogs()) ms.orig.ScopeLogs = internal.GenTestScopeLogsPtrSlice() assert.Equal(t, generateTestScopeLogsSlice(), ms.ScopeLogs()) } func TestResourceLogs_SchemaUrl(t *testing.T) { ms := NewResourceLogs() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newResourceLogs(internal.NewResourceLogs(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestResourceLogs() ResourceLogs { return newResourceLogs(internal.GenTestResourceLogs(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/plog/generated_resourcelogsslice.go000066400000000000000000000115061511331344600266740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ResourceLogsSlice logically represents a slice of ResourceLogs. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewResourceLogsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceLogsSlice struct { orig *[]*internal.ResourceLogs state *internal.State } func newResourceLogsSlice(orig *[]*internal.ResourceLogs, state *internal.State) ResourceLogsSlice { return ResourceLogsSlice{orig: orig, state: state} } // NewResourceLogsSlice creates a ResourceLogsSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewResourceLogsSlice() ResourceLogsSlice { orig := []*internal.ResourceLogs(nil) return newResourceLogsSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewResourceLogsSlice()". func (es ResourceLogsSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ResourceLogsSlice) At(i int) ResourceLogs { return newResourceLogs((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ResourceLogsSlice) All() iter.Seq2[int, ResourceLogs] { return func(yield func(int, ResourceLogs) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ResourceLogsSlice can be initialized: // // es := NewResourceLogsSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ResourceLogsSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ResourceLogs, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ResourceLogs. // It returns the newly added ResourceLogs. func (es ResourceLogsSlice) AppendEmpty() ResourceLogs { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewResourceLogs()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceLogsSlice) MoveAndAppendTo(dest ResourceLogsSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ResourceLogsSlice) RemoveIf(f func(ResourceLogs) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteResourceLogs((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ResourceLogsSlice) CopyTo(dest ResourceLogsSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyResourceLogsPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ResourceLogs elements within ResourceLogsSlice given the // provided less function so that two instances of ResourceLogsSlice // can be compared. func (es ResourceLogsSlice) Sort(less func(a, b ResourceLogs) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/plog/generated_resourcelogsslice_test.go000066400000000000000000000116001511331344600277260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestResourceLogsSlice(t *testing.T) { es := NewResourceLogsSlice() assert.Equal(t, 0, es.Len()) es = newResourceLogsSlice(&[]*internal.ResourceLogs{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewResourceLogs() testVal := generateTestResourceLogs() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestResourceLogs() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestResourceLogsSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newResourceLogsSlice(&[]*internal.ResourceLogs{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewResourceLogsSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestResourceLogsSlice_CopyTo(t *testing.T) { dest := NewResourceLogsSlice() src := generateTestResourceLogsSlice() src.CopyTo(dest) assert.Equal(t, generateTestResourceLogsSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestResourceLogsSlice(), dest) } func TestResourceLogsSlice_EnsureCapacity(t *testing.T) { es := generateTestResourceLogsSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestResourceLogsSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestResourceLogsSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestResourceLogsSlice(), es) } func TestResourceLogsSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestResourceLogsSlice() dest := NewResourceLogsSlice() src := generateTestResourceLogsSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceLogsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceLogsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestResourceLogsSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestResourceLogsSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewResourceLogsSlice() emptySlice.RemoveIf(func(el ResourceLogs) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestResourceLogsSlice() pos := 0 filtered.RemoveIf(func(el ResourceLogs) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestResourceLogsSlice_RemoveIfAll(t *testing.T) { got := generateTestResourceLogsSlice() got.RemoveIf(func(el ResourceLogs) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestResourceLogsSliceAll(t *testing.T) { ms := generateTestResourceLogsSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestResourceLogsSlice_Sort(t *testing.T) { es := generateTestResourceLogsSlice() es.Sort(func(a, b ResourceLogs) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ResourceLogs) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestResourceLogsSlice() ResourceLogsSlice { ms := NewResourceLogsSlice() *ms.orig = internal.GenTestResourceLogsPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/plog/generated_scopelogs.go000066400000000000000000000047001511331344600251340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ScopeLogs is a collection of logs from a LibraryInstrumentation. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewScopeLogs function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeLogs struct { orig *internal.ScopeLogs state *internal.State } func newScopeLogs(orig *internal.ScopeLogs, state *internal.State) ScopeLogs { return ScopeLogs{orig: orig, state: state} } // NewScopeLogs creates a new empty ScopeLogs. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewScopeLogs() ScopeLogs { return newScopeLogs(internal.NewScopeLogs(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ScopeLogs) MoveTo(dest ScopeLogs) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteScopeLogs(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Scope returns the scope associated with this ScopeLogs. func (ms ScopeLogs) Scope() pcommon.InstrumentationScope { return pcommon.InstrumentationScope(internal.NewInstrumentationScopeWrapper(&ms.orig.Scope, ms.state)) } // LogRecords returns the LogRecords associated with this ScopeLogs. func (ms ScopeLogs) LogRecords() LogRecordSlice { return newLogRecordSlice(&ms.orig.LogRecords, ms.state) } // SchemaUrl returns the schemaurl associated with this ScopeLogs. func (ms ScopeLogs) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ScopeLogs. func (ms ScopeLogs) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ScopeLogs) CopyTo(dest ScopeLogs) { dest.state.AssertMutable() internal.CopyScopeLogs(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/plog/generated_scopelogs_test.go000066400000000000000000000043411511331344600261740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestScopeLogs_MoveTo(t *testing.T) { ms := generateTestScopeLogs() dest := NewScopeLogs() ms.MoveTo(dest) assert.Equal(t, NewScopeLogs(), ms) assert.Equal(t, generateTestScopeLogs(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestScopeLogs(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newScopeLogs(internal.NewScopeLogs(), sharedState)) }) assert.Panics(t, func() { newScopeLogs(internal.NewScopeLogs(), sharedState).MoveTo(dest) }) } func TestScopeLogs_CopyTo(t *testing.T) { ms := NewScopeLogs() orig := NewScopeLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestScopeLogs() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newScopeLogs(internal.NewScopeLogs(), sharedState)) }) } func TestScopeLogs_Scope(t *testing.T) { ms := NewScopeLogs() assert.Equal(t, pcommon.NewInstrumentationScope(), ms.Scope()) ms.orig.Scope = *internal.GenTestInstrumentationScope() assert.Equal(t, pcommon.InstrumentationScope(internal.GenTestInstrumentationScopeWrapper()), ms.Scope()) } func TestScopeLogs_LogRecords(t *testing.T) { ms := NewScopeLogs() assert.Equal(t, NewLogRecordSlice(), ms.LogRecords()) ms.orig.LogRecords = internal.GenTestLogRecordPtrSlice() assert.Equal(t, generateTestLogRecordSlice(), ms.LogRecords()) } func TestScopeLogs_SchemaUrl(t *testing.T) { ms := NewScopeLogs() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newScopeLogs(internal.NewScopeLogs(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestScopeLogs() ScopeLogs { return newScopeLogs(internal.GenTestScopeLogs(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/plog/generated_scopelogsslice.go000066400000000000000000000112771511331344600261630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ScopeLogsSlice logically represents a slice of ScopeLogs. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewScopeLogsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeLogsSlice struct { orig *[]*internal.ScopeLogs state *internal.State } func newScopeLogsSlice(orig *[]*internal.ScopeLogs, state *internal.State) ScopeLogsSlice { return ScopeLogsSlice{orig: orig, state: state} } // NewScopeLogsSlice creates a ScopeLogsSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewScopeLogsSlice() ScopeLogsSlice { orig := []*internal.ScopeLogs(nil) return newScopeLogsSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewScopeLogsSlice()". func (es ScopeLogsSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ScopeLogsSlice) At(i int) ScopeLogs { return newScopeLogs((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ScopeLogsSlice) All() iter.Seq2[int, ScopeLogs] { return func(yield func(int, ScopeLogs) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ScopeLogsSlice can be initialized: // // es := NewScopeLogsSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ScopeLogsSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ScopeLogs, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ScopeLogs. // It returns the newly added ScopeLogs. func (es ScopeLogsSlice) AppendEmpty() ScopeLogs { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewScopeLogs()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ScopeLogsSlice) MoveAndAppendTo(dest ScopeLogsSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ScopeLogsSlice) RemoveIf(f func(ScopeLogs) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteScopeLogs((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ScopeLogsSlice) CopyTo(dest ScopeLogsSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyScopeLogsPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ScopeLogs elements within ScopeLogsSlice given the // provided less function so that two instances of ScopeLogsSlice // can be compared. func (es ScopeLogsSlice) Sort(less func(a, b ScopeLogs) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/plog/generated_scopelogsslice_test.go000066400000000000000000000113661511331344600272210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plog import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestScopeLogsSlice(t *testing.T) { es := NewScopeLogsSlice() assert.Equal(t, 0, es.Len()) es = newScopeLogsSlice(&[]*internal.ScopeLogs{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewScopeLogs() testVal := generateTestScopeLogs() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestScopeLogs() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestScopeLogsSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newScopeLogsSlice(&[]*internal.ScopeLogs{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewScopeLogsSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestScopeLogsSlice_CopyTo(t *testing.T) { dest := NewScopeLogsSlice() src := generateTestScopeLogsSlice() src.CopyTo(dest) assert.Equal(t, generateTestScopeLogsSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestScopeLogsSlice(), dest) } func TestScopeLogsSlice_EnsureCapacity(t *testing.T) { es := generateTestScopeLogsSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestScopeLogsSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestScopeLogsSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestScopeLogsSlice(), es) } func TestScopeLogsSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestScopeLogsSlice() dest := NewScopeLogsSlice() src := generateTestScopeLogsSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeLogsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeLogsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestScopeLogsSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestScopeLogsSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewScopeLogsSlice() emptySlice.RemoveIf(func(el ScopeLogs) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestScopeLogsSlice() pos := 0 filtered.RemoveIf(func(el ScopeLogs) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestScopeLogsSlice_RemoveIfAll(t *testing.T) { got := generateTestScopeLogsSlice() got.RemoveIf(func(el ScopeLogs) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestScopeLogsSliceAll(t *testing.T) { ms := generateTestScopeLogsSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestScopeLogsSlice_Sort(t *testing.T) { es := generateTestScopeLogsSlice() es.Sort(func(a, b ScopeLogs) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ScopeLogs) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestScopeLogsSlice() ScopeLogsSlice { ms := NewScopeLogsSlice() *ms.orig = internal.GenTestScopeLogsPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/plog/json.go000066400000000000000000000022221511331344600220660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" ) // JSONMarshaler marshals Logs to JSON bytes using the OTLP/JSON format. type JSONMarshaler struct{} // MarshalLogs to the OTLP/JSON format. func (*JSONMarshaler) MarshalLogs(ld Logs) ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ld.getOrig().MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } var _ Unmarshaler = (*JSONUnmarshaler)(nil) // JSONUnmarshaler unmarshals OTLP/JSON formatted-bytes to Logs. type JSONUnmarshaler struct{} // UnmarshalLogs from OTLP/JSON format into Logs. func (*JSONUnmarshaler) UnmarshalLogs(buf []byte) (Logs, error) { iter := json.BorrowIterator(buf) defer json.ReturnIterator(iter) ld := NewLogs() ld.getOrig().UnmarshalJSON(iter) if iter.Error() != nil { return Logs{}, iter.Error() } otlp.MigrateLogs(ld.getOrig().ResourceLogs) return ld, nil } opentelemetry-collector-0.141.0/pdata/plog/log_record_flags.go000066400000000000000000000016121511331344600244120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" const isSampledMask = uint32(1) var DefaultLogRecordFlags = LogRecordFlags(0) // LogRecordFlags defines flags for the LogRecord. The 8 least significant bits are the trace flags as // defined in W3C Trace Context specification. 24 most significant bits are reserved and must be set to 0. type LogRecordFlags uint32 // IsSampled returns true if the LogRecordFlags contains the IsSampled flag. func (ms LogRecordFlags) IsSampled() bool { return uint32(ms)&isSampledMask != 0 } // WithIsSampled returns a new LogRecordFlags, with the IsSampled flag set to the given value. func (ms LogRecordFlags) WithIsSampled(b bool) LogRecordFlags { orig := uint32(ms) if b { orig |= isSampledMask } else { orig &^= isSampledMask } return LogRecordFlags(orig) } opentelemetry-collector-0.141.0/pdata/plog/log_record_flags_test.go000066400000000000000000000012561511331344600254550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog import ( "testing" "github.com/stretchr/testify/assert" ) func TestLogRecordFlags(t *testing.T) { flags := LogRecordFlags(1) assert.True(t, flags.IsSampled()) assert.EqualValues(t, uint32(1), flags) flags = flags.WithIsSampled(false) assert.False(t, flags.IsSampled()) assert.EqualValues(t, uint32(0), flags) flags = flags.WithIsSampled(true) assert.True(t, flags.IsSampled()) assert.EqualValues(t, uint32(1), flags) } func TestDefaultLogRecordFlags(t *testing.T) { flags := DefaultLogRecordFlags assert.False(t, flags.IsSampled()) assert.EqualValues(t, uint32(0), flags) } opentelemetry-collector-0.141.0/pdata/plog/logs.go000066400000000000000000000014121511331344600220610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" // MarkReadOnly marks the Logs as shared so that no further modifications can be done on it. func (ms Logs) MarkReadOnly() { ms.getState().MarkReadOnly() } // IsReadOnly returns true if this Logs instance is read-only. func (ms Logs) IsReadOnly() bool { return ms.getState().IsReadOnly() } // LogRecordCount calculates the total number of log records. func (ms Logs) LogRecordCount() int { logCount := 0 rss := ms.ResourceLogs() for i := 0; i < rss.Len(); i++ { rs := rss.At(i) ill := rs.ScopeLogs() for i := 0; i < ill.Len(); i++ { logs := ill.At(i) logCount += logs.LogRecords().Len() } } return logCount } opentelemetry-collector-0.141.0/pdata/plog/logs_test.go000066400000000000000000000067241511331344600231330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestLogRecordCount(t *testing.T) { logs := NewLogs() assert.Equal(t, 0, logs.LogRecordCount()) rl := logs.ResourceLogs().AppendEmpty() assert.Equal(t, 0, logs.LogRecordCount()) ill := rl.ScopeLogs().AppendEmpty() assert.Equal(t, 0, logs.LogRecordCount()) ill.LogRecords().AppendEmpty() assert.Equal(t, 1, logs.LogRecordCount()) rms := logs.ResourceLogs() rms.EnsureCapacity(3) rms.AppendEmpty().ScopeLogs().AppendEmpty() illl := rms.AppendEmpty().ScopeLogs().AppendEmpty().LogRecords() for range 5 { illl.AppendEmpty() } // 5 + 1 (from rms.At(0) initialized first) assert.Equal(t, 6, logs.LogRecordCount()) } func TestLogRecordCountWithEmpty(t *testing.T) { assert.Zero(t, NewLogs().LogRecordCount()) assert.Zero(t, newLogs(&internal.ExportLogsServiceRequest{ ResourceLogs: []*internal.ResourceLogs{{}}, }, new(internal.State)).LogRecordCount()) assert.Zero(t, newLogs(&internal.ExportLogsServiceRequest{ ResourceLogs: []*internal.ResourceLogs{ { ScopeLogs: []*internal.ScopeLogs{{}}, }, }, }, new(internal.State)).LogRecordCount()) assert.Equal(t, 1, newLogs(&internal.ExportLogsServiceRequest{ ResourceLogs: []*internal.ResourceLogs{ { ScopeLogs: []*internal.ScopeLogs{ { LogRecords: []*internal.LogRecord{{}}, }, }, }, }, }, new(internal.State)).LogRecordCount()) } func TestReadOnlyLogsInvalidUsage(t *testing.T) { ld := NewLogs() assert.False(t, ld.IsReadOnly()) res := ld.ResourceLogs().AppendEmpty().Resource() res.Attributes().PutStr("k1", "v1") ld.MarkReadOnly() assert.True(t, ld.IsReadOnly()) assert.Panics(t, func() { res.Attributes().PutStr("k2", "v2") }) } func BenchmarkLogsUsage(b *testing.B) { ld := generateTestLogs() ts := pcommon.NewTimestampFromTime(time.Now()) b.ReportAllocs() for b.Loop() { for i := 0; i < ld.ResourceLogs().Len(); i++ { rl := ld.ResourceLogs().At(i) res := rl.Resource() res.Attributes().PutStr("foo", "bar") v, ok := res.Attributes().Get("foo") assert.True(b, ok) assert.Equal(b, "bar", v.Str()) v.SetStr("new-bar") assert.Equal(b, "new-bar", v.Str()) res.Attributes().Remove("foo") for j := 0; j < rl.ScopeLogs().Len(); j++ { sl := rl.ScopeLogs().At(j) sl.Scope().SetName("new_test_name") assert.Equal(b, "new_test_name", sl.Scope().Name()) for k := 0; k < sl.LogRecords().Len(); k++ { lr := sl.LogRecords().At(k) lr.Body().SetStr("new_body") assert.Equal(b, "new_body", lr.Body().Str()) lr.SetTimestamp(ts) assert.Equal(b, ts, lr.Timestamp()) } lr := sl.LogRecords().AppendEmpty() lr.Body().SetStr("another_log_record") lr.SetTimestamp(ts) lr.SetObservedTimestamp(ts) lr.SetSeverityText("info") lr.SetSeverityNumber(SeverityNumberInfo) lr.Attributes().PutStr("foo", "bar") lr.SetSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) sl.LogRecords().RemoveIf(func(lr LogRecord) bool { return lr.Body().Str() == "another_log_record" }) } } } } func BenchmarkLogsMarshalJSON(b *testing.B) { ld := generateTestLogs() encoder := &JSONMarshaler{} b.ReportAllocs() for b.Loop() { jsonBuf, err := encoder.MarshalLogs(ld) require.NoError(b, err) require.NotNil(b, jsonBuf) } } opentelemetry-collector-0.141.0/pdata/plog/package_test.go000066400000000000000000000003051511331344600235470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/plog/pb.go000066400000000000000000000020031511331344600215130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" var _ MarshalSizer = (*ProtoMarshaler)(nil) type ProtoMarshaler struct{} func (e *ProtoMarshaler) MarshalLogs(ld Logs) ([]byte, error) { size := ld.getOrig().SizeProto() buf := make([]byte, size) _ = ld.getOrig().MarshalProto(buf) return buf, nil } func (e *ProtoMarshaler) LogsSize(ld Logs) int { return ld.getOrig().SizeProto() } func (e *ProtoMarshaler) ResourceLogsSize(ld ResourceLogs) int { return ld.orig.SizeProto() } func (e *ProtoMarshaler) ScopeLogsSize(ld ScopeLogs) int { return ld.orig.SizeProto() } func (e *ProtoMarshaler) LogRecordSize(ld LogRecord) int { return ld.orig.SizeProto() } var _ Unmarshaler = (*ProtoUnmarshaler)(nil) type ProtoUnmarshaler struct{} func (d *ProtoUnmarshaler) UnmarshalLogs(buf []byte) (Logs, error) { ld := NewLogs() err := ld.getOrig().UnmarshalProto(buf) if err != nil { return Logs{}, err } return ld, nil } opentelemetry-collector-0.141.0/pdata/plog/pb_test.go000066400000000000000000000060671511331344600225700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlplogs "go.opentelemetry.io/proto/slim/otlp/logs/v1" goproto "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestLogsProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Logs as pdata struct. td := generateTestLogs() // Marshal its underlying ProtoBuf to wire. marshaler := &ProtoMarshaler{} wire1, err := marshaler.MarshalLogs(td) require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlplogs.LogsData err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. var td2 Logs unmarshaler := &ProtoUnmarshaler{} td2, err = unmarshaler.UnmarshalLogs(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. assert.Equal(t, td, td2) } func TestProtoLogsUnmarshalerError(t *testing.T) { p := &ProtoUnmarshaler{} _, err := p.UnmarshalLogs([]byte("+$%")) assert.Error(t, err) } func TestProtoSizer(t *testing.T) { marshaler := &ProtoMarshaler{} ld := NewLogs() ld.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().SetSeverityText("error") size := marshaler.LogsSize(ld) bytes, err := marshaler.MarshalLogs(ld) require.NoError(t, err) assert.Equal(t, len(bytes), size) } func TestProtoSizerEmptyLogs(t *testing.T) { sizer := &ProtoMarshaler{} assert.Equal(t, 0, sizer.LogsSize(NewLogs())) } func BenchmarkLogsToProto(b *testing.B) { marshaler := &ProtoMarshaler{} logs := generateBenchmarkLogs(128) for b.Loop() { buf, err := marshaler.MarshalLogs(logs) require.NoError(b, err) assert.NotEmpty(b, buf) } } func BenchmarkLogsFromProto(b *testing.B) { marshaler := &ProtoMarshaler{} unmarshaler := &ProtoUnmarshaler{} baseLogs := generateBenchmarkLogs(128) buf, err := marshaler.MarshalLogs(baseLogs) require.NoError(b, err) assert.NotEmpty(b, buf) b.ReportAllocs() for b.Loop() { logs, err := unmarshaler.UnmarshalLogs(buf) require.NoError(b, err) assert.Equal(b, baseLogs.ResourceLogs().Len(), logs.ResourceLogs().Len()) } } func generateBenchmarkLogs(logsCount int) Logs { endTime := pcommon.NewTimestampFromTime(time.Now()) md := NewLogs() ilm := md.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty() ilm.LogRecords().EnsureCapacity(logsCount) for range logsCount { im := ilm.LogRecords().AppendEmpty() im.SetTimestamp(endTime) } return md } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/000077500000000000000000000000001511331344600224305ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/plog/plogotlp/fuzz_test.go000066400000000000000000000050601511331344600250150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp // import "go.opentelemetry.io/collector/pdata/plog/plogotlp" import ( "bytes" "testing" "github.com/stretchr/testify/require" ) var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." func FuzzRequestUnmarshalJSON(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportRequest() err := er.UnmarshalJSON(data) if err != nil { return } b1, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") er = NewExportRequest() require.NoError(t, er.UnmarshalJSON(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzResponseUnmarshalJSON(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportResponse() err := er.UnmarshalJSON(data) if err != nil { return } b1, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") er = NewExportResponse() require.NoError(t, er.UnmarshalJSON(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzRequestUnmarshalProto(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportRequest() err := er.UnmarshalProto(data) if err != nil { return } b1, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") er = NewExportRequest() require.NoError(t, er.UnmarshalProto(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzResponseUnmarshalProto(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportResponse() err := er.UnmarshalProto(data) if err != nil { return } b1, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") er = NewExportResponse() require.NoError(t, er.UnmarshalProto(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/generated_exportpartialsuccess.go000066400000000000000000000053421511331344600312700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plogotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportPartialSuccess represents the details of a partially successful export request. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportPartialSuccess function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportPartialSuccess struct { orig *internal.ExportLogsPartialSuccess state *internal.State } func newExportPartialSuccess(orig *internal.ExportLogsPartialSuccess, state *internal.State) ExportPartialSuccess { return ExportPartialSuccess{orig: orig, state: state} } // NewExportPartialSuccess creates a new empty ExportPartialSuccess. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.NewExportLogsPartialSuccess(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportPartialSuccess) MoveTo(dest ExportPartialSuccess) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportLogsPartialSuccess(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // RejectedLogRecords returns the rejectedlogrecords associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) RejectedLogRecords() int64 { return ms.orig.RejectedLogRecords } // SetRejectedLogRecords replaces the rejectedlogrecords associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetRejectedLogRecords(v int64) { ms.state.AssertMutable() ms.orig.RejectedLogRecords = v } // ErrorMessage returns the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) ErrorMessage() string { return ms.orig.ErrorMessage } // SetErrorMessage replaces the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetErrorMessage(v string) { ms.state.AssertMutable() ms.orig.ErrorMessage = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportPartialSuccess) CopyTo(dest ExportPartialSuccess) { dest.state.AssertMutable() internal.CopyExportLogsPartialSuccess(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/generated_exportpartialsuccess_test.go000066400000000000000000000046221511331344600323270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plogotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportPartialSuccess_MoveTo(t *testing.T) { ms := generateTestExportPartialSuccess() dest := NewExportPartialSuccess() ms.MoveTo(dest) assert.Equal(t, NewExportPartialSuccess(), ms) assert.Equal(t, generateTestExportPartialSuccess(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportPartialSuccess(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportPartialSuccess(internal.NewExportLogsPartialSuccess(), sharedState)) }) assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportLogsPartialSuccess(), sharedState).MoveTo(dest) }) } func TestExportPartialSuccess_CopyTo(t *testing.T) { ms := NewExportPartialSuccess() orig := NewExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportPartialSuccess(internal.NewExportLogsPartialSuccess(), sharedState)) }) } func TestExportPartialSuccess_RejectedLogRecords(t *testing.T) { ms := NewExportPartialSuccess() assert.Equal(t, int64(0), ms.RejectedLogRecords()) ms.SetRejectedLogRecords(int64(13)) assert.Equal(t, int64(13), ms.RejectedLogRecords()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportLogsPartialSuccess(), sharedState).SetRejectedLogRecords(int64(13)) }) } func TestExportPartialSuccess_ErrorMessage(t *testing.T) { ms := NewExportPartialSuccess() assert.Empty(t, ms.ErrorMessage()) ms.SetErrorMessage("test_errormessage") assert.Equal(t, "test_errormessage", ms.ErrorMessage()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportLogsPartialSuccess(), sharedState).SetErrorMessage("test_errormessage") }) } func generateTestExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.GenTestExportLogsPartialSuccess(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/generated_exportresponse.go000066400000000000000000000041021511331344600300720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plogotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportResponse represents the response for gRPC/HTTP client/server. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportResponse function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportResponse struct { orig *internal.ExportLogsServiceResponse state *internal.State } func newExportResponse(orig *internal.ExportLogsServiceResponse, state *internal.State) ExportResponse { return ExportResponse{orig: orig, state: state} } // NewExportResponse creates a new empty ExportResponse. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportResponse() ExportResponse { return newExportResponse(internal.NewExportLogsServiceResponse(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportResponse) MoveTo(dest ExportResponse) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportLogsServiceResponse(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // PartialSuccess returns the partialsuccess associated with this ExportResponse. func (ms ExportResponse) PartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(&ms.orig.PartialSuccess, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportResponse) CopyTo(dest ExportResponse) { dest.state.AssertMutable() internal.CopyExportLogsServiceResponse(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/generated_exportresponse_test.go000066400000000000000000000033421511331344600311360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package plogotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportResponse_MoveTo(t *testing.T) { ms := generateTestExportResponse() dest := NewExportResponse() ms.MoveTo(dest) assert.Equal(t, NewExportResponse(), ms) assert.Equal(t, generateTestExportResponse(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportResponse(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportResponse(internal.NewExportLogsServiceResponse(), sharedState)) }) assert.Panics(t, func() { newExportResponse(internal.NewExportLogsServiceResponse(), sharedState).MoveTo(dest) }) } func TestExportResponse_CopyTo(t *testing.T) { ms := NewExportResponse() orig := NewExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportResponse(internal.NewExportLogsServiceResponse(), sharedState)) }) } func TestExportResponse_PartialSuccess(t *testing.T) { ms := NewExportResponse() assert.Equal(t, NewExportPartialSuccess(), ms.PartialSuccess()) ms.orig.PartialSuccess = *internal.GenTestExportLogsPartialSuccess() assert.Equal(t, generateTestExportPartialSuccess(), ms.PartialSuccess()) } func generateTestExportResponse() ExportResponse { return newExportResponse(internal.GenTestExportLogsServiceResponse(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/grpc.go000066400000000000000000000057271511331344600237250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp // import "go.opentelemetry.io/collector/pdata/plog/plogotlp" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otelgrpc" "go.opentelemetry.io/collector/pdata/internal/otlp" ) // GRPCClient is the client API for OTLP-GRPC Logs service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type GRPCClient interface { // Export plog.Logs to the server. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) // unexported disallow implementation of the GRPCClient. unexported() } // NewGRPCClient returns a new GRPCClient connected using the given connection. func NewGRPCClient(cc *grpc.ClientConn) GRPCClient { return &grpcClient{rawClient: otelgrpc.NewLogsServiceClient(cc)} } type grpcClient struct { rawClient otelgrpc.LogsServiceClient } func (c *grpcClient) Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) { rsp, err := c.rawClient.Export(ctx, request.orig, opts...) if err != nil { return ExportResponse{}, err } return ExportResponse{orig: rsp, state: internal.NewState()}, err } func (c *grpcClient) unexported() {} // GRPCServer is the server API for OTLP gRPC LogsService service. // Implementations MUST embed UnimplementedGRPCServer. type GRPCServer interface { // Export is called every time a new request is received. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(context.Context, ExportRequest) (ExportResponse, error) // unexported disallow implementation of the GRPCServer. unexported() } var _ GRPCServer = (*UnimplementedGRPCServer)(nil) // UnimplementedGRPCServer MUST be embedded to have forward compatible implementations. type UnimplementedGRPCServer struct{} func (*UnimplementedGRPCServer) Export(context.Context, ExportRequest) (ExportResponse, error) { return ExportResponse{}, status.Errorf(codes.Unimplemented, "method Export not implemented") } func (*UnimplementedGRPCServer) unexported() {} // RegisterGRPCServer registers the Server to the grpc.Server. func RegisterGRPCServer(s *grpc.Server, srv GRPCServer) { otelgrpc.RegisterLogsServiceServer(s, &rawLogsServer{srv: srv}) } type rawLogsServer struct { srv GRPCServer } func (s rawLogsServer) Export(ctx context.Context, request *internal.ExportLogsServiceRequest) (*internal.ExportLogsServiceResponse, error) { otlp.MigrateLogs(request.ResourceLogs) rsp, err := s.srv.Export(ctx, ExportRequest{orig: request, state: internal.NewState()}) return rsp.orig, err } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/grpc_test.go000066400000000000000000000052141511331344600247530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp import ( "context" "errors" "net" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" "go.opentelemetry.io/collector/pdata/plog" ) func TestGrpc(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeLogsServer{t: t}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) resolver.SetDefaultScheme("passthrough") cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateLogsRequest()) require.NoError(t, err) assert.Equal(t, NewExportResponse(), resp) } func TestGrpcError(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeLogsServer{t: t, err: errors.New("my error")}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateLogsRequest()) require.Error(t, err) st, okSt := status.FromError(err) require.True(t, okSt) assert.Equal(t, "my error", st.Message()) assert.Equal(t, codes.Unknown, st.Code()) assert.Equal(t, ExportResponse{}, resp) } type fakeLogsServer struct { UnimplementedGRPCServer t *testing.T err error } func (f fakeLogsServer) Export(_ context.Context, request ExportRequest) (ExportResponse, error) { assert.Equal(f.t, generateLogsRequest(), request) return NewExportResponse(), f.err } func generateLogsRequest() ExportRequest { ld := plog.NewLogs() ld.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Body().SetStr("test_log_record") return NewExportRequestFromLogs(ld) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/package_test.go000066400000000000000000000003111511331344600254040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/request.go000066400000000000000000000044201511331344600244470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp // import "go.opentelemetry.io/collector/pdata/plog/plogotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/plog" ) // ExportRequest represents the request for gRPC/HTTP client/server. // It's a wrapper for plog.Logs data. type ExportRequest struct { orig *internal.ExportLogsServiceRequest state *internal.State } // NewExportRequest returns an empty ExportRequest. func NewExportRequest() ExportRequest { return ExportRequest{ orig: &internal.ExportLogsServiceRequest{}, state: internal.NewState(), } } // NewExportRequestFromLogs returns a ExportRequest from plog.Logs. // Because ExportRequest is a wrapper for plog.Logs, // any changes to the provided Logs struct will be reflected in the ExportRequest and vice versa. func NewExportRequestFromLogs(ld plog.Logs) ExportRequest { return ExportRequest{ orig: internal.GetLogsOrig(internal.LogsWrapper(ld)), state: internal.GetLogsState(internal.LogsWrapper(ld)), } } // MarshalProto marshals ExportRequest into proto bytes. func (ms ExportRequest) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportRequest from proto bytes. func (ms ExportRequest) UnmarshalProto(data []byte) error { err := ms.orig.UnmarshalProto(data) if err != nil { return err } otlp.MigrateLogs(ms.orig.ResourceLogs) return nil } // MarshalJSON marshals ExportRequest into JSON bytes. func (ms ExportRequest) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } // UnmarshalJSON unmarshalls ExportRequest from JSON bytes. func (ms ExportRequest) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } func (ms ExportRequest) Logs() plog.Logs { return plog.Logs(internal.NewLogsWrapper(ms.orig, ms.state)) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/request_test.go000066400000000000000000000053161511331344600255130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp import ( "encoding/json" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorlogs "go.opentelemetry.io/proto/slim/otlp/collector/logs/v1" goproto "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/plog" ) var ( _ json.Unmarshaler = ExportRequest{} _ json.Marshaler = ExportRequest{} ) var logsRequestJSON = []byte(` { "resourceLogs": [ { "resource": {}, "scopeLogs": [ { "scope": {}, "logRecords": [ { "body": { "stringValue": "test_log_record" } } ] } ] } ] }`) func TestRequestToPData(t *testing.T) { tr := NewExportRequest() assert.Equal(t, 0, tr.Logs().LogRecordCount()) tr.Logs().ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() assert.Equal(t, 1, tr.Logs().LogRecordCount()) } func TestRequestJSON(t *testing.T) { lr := NewExportRequest() require.NoError(t, lr.UnmarshalJSON(logsRequestJSON)) assert.Equal(t, "test_log_record", lr.Logs().ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).Body().AsString()) got, err := lr.MarshalJSON() require.NoError(t, err) assert.Equal(t, strings.Join(strings.Fields(string(logsRequestJSON)), ""), string(got)) } func TestLogsProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Logs as pdata struct. ld := NewExportRequestFromLogs(plog.Logs(internal.GenTestLogsWrapper())) // Marshal its underlying ProtoBuf to wire. wire1, err := ld.MarshalProto() require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlpcollectorlogs.ExportLogsServiceRequest err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. ld2 := NewExportRequest() err = ld2.UnmarshalProto(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. // Migration logic will run, so run it on the original message as well. otlp.MigrateLogs(ld.orig.ResourceLogs) assert.Equal(t, ld, ld2) } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/response.go000066400000000000000000000021371511331344600246200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp // import "go.opentelemetry.io/collector/pdata/plog/plogotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" ) // MarshalProto marshals ExportResponse into proto bytes. func (ms ExportResponse) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportResponse from proto bytes. func (ms ExportResponse) UnmarshalProto(data []byte) error { return ms.orig.UnmarshalProto(data) } // MarshalJSON marshals ExportResponse into JSON bytes. func (ms ExportResponse) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) return slices.Clone(dest.Buffer()), dest.Error() } // UnmarshalJSON unmarshalls ExportResponse from JSON bytes. func (ms ExportResponse) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } opentelemetry-collector-0.141.0/pdata/plog/plogotlp/response_test.go000066400000000000000000000020221511331344600256500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plogotlp import ( stdjson "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( _ stdjson.Unmarshaler = ExportResponse{} _ stdjson.Marshaler = ExportResponse{} ) func TestExportResponseJSON(t *testing.T) { jsonStr := `{"partialSuccess": {"rejectedLogRecords":"1", "errorMessage":"nothing"}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) expected := NewExportResponse() expected.PartialSuccess().SetRejectedLogRecords(1) expected.PartialSuccess().SetErrorMessage("nothing") assert.Equal(t, expected, val) buf, err := val.MarshalJSON() require.NoError(t, err) assert.JSONEq(t, jsonStr, string(buf)) } func TestUnmarshalJSONExportResponse(t *testing.T) { jsonStr := `{"extra":"", "partialSuccess": {"extra":""}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) assert.Equal(t, NewExportResponse(), val) } opentelemetry-collector-0.141.0/pdata/plog/severity_number.go000066400000000000000000000074341511331344600243510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" import ( "go.opentelemetry.io/collector/pdata/internal" ) // SeverityNumber represents severity number of a log record. type SeverityNumber int32 const ( SeverityNumberUnspecified = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_UNSPECIFIED) SeverityNumberTrace = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_TRACE) SeverityNumberTrace2 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_TRACE2) SeverityNumberTrace3 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_TRACE3) SeverityNumberTrace4 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_TRACE4) SeverityNumberDebug = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_DEBUG) SeverityNumberDebug2 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_DEBUG2) SeverityNumberDebug3 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_DEBUG3) SeverityNumberDebug4 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_DEBUG4) SeverityNumberInfo = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_INFO) SeverityNumberInfo2 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_INFO2) SeverityNumberInfo3 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_INFO3) SeverityNumberInfo4 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_INFO4) SeverityNumberWarn = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_WARN) SeverityNumberWarn2 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_WARN2) SeverityNumberWarn3 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_WARN3) SeverityNumberWarn4 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_WARN4) SeverityNumberError = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_ERROR) SeverityNumberError2 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_ERROR2) SeverityNumberError3 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_ERROR3) SeverityNumberError4 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_ERROR4) SeverityNumberFatal = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_FATAL) SeverityNumberFatal2 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_FATAL2) SeverityNumberFatal3 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_FATAL3) SeverityNumberFatal4 = SeverityNumber(internal.SeverityNumber_SEVERITY_NUMBER_FATAL4) ) // String returns the string representation of the SeverityNumber. func (sn SeverityNumber) String() string { switch sn { case SeverityNumberUnspecified: return "Unspecified" case SeverityNumberTrace: return "Trace" case SeverityNumberTrace2: return "Trace2" case SeverityNumberTrace3: return "Trace3" case SeverityNumberTrace4: return "Trace4" case SeverityNumberDebug: return "Debug" case SeverityNumberDebug2: return "Debug2" case SeverityNumberDebug3: return "Debug3" case SeverityNumberDebug4: return "Debug4" case SeverityNumberInfo: return "Info" case SeverityNumberInfo2: return "Info2" case SeverityNumberInfo3: return "Info3" case SeverityNumberInfo4: return "Info4" case SeverityNumberWarn: return "Warn" case SeverityNumberWarn2: return "Warn2" case SeverityNumberWarn3: return "Warn3" case SeverityNumberWarn4: return "Warn4" case SeverityNumberError: return "Error" case SeverityNumberError2: return "Error2" case SeverityNumberError3: return "Error3" case SeverityNumberError4: return "Error4" case SeverityNumberFatal: return "Fatal" case SeverityNumberFatal2: return "Fatal2" case SeverityNumberFatal3: return "Fatal3" case SeverityNumberFatal4: return "Fatal4" } return "" } opentelemetry-collector-0.141.0/pdata/plog/severity_number_test.go000066400000000000000000000033071511331344600254030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package plog // import "go.opentelemetry.io/collector/pdata/plog" import ( "testing" "github.com/stretchr/testify/assert" ) func TestSeverityNumberString(t *testing.T) { assert.Equal(t, "Unspecified", SeverityNumberUnspecified.String()) assert.Equal(t, "Trace", SeverityNumberTrace.String()) assert.Equal(t, "Trace2", SeverityNumberTrace2.String()) assert.Equal(t, "Trace3", SeverityNumberTrace3.String()) assert.Equal(t, "Trace4", SeverityNumberTrace4.String()) assert.Equal(t, "Debug", SeverityNumberDebug.String()) assert.Equal(t, "Debug2", SeverityNumberDebug2.String()) assert.Equal(t, "Debug3", SeverityNumberDebug3.String()) assert.Equal(t, "Debug4", SeverityNumberDebug4.String()) assert.Equal(t, "Info", SeverityNumberInfo.String()) assert.Equal(t, "Info2", SeverityNumberInfo2.String()) assert.Equal(t, "Info3", SeverityNumberInfo3.String()) assert.Equal(t, "Info4", SeverityNumberInfo4.String()) assert.Equal(t, "Warn", SeverityNumberWarn.String()) assert.Equal(t, "Warn2", SeverityNumberWarn2.String()) assert.Equal(t, "Warn3", SeverityNumberWarn3.String()) assert.Equal(t, "Warn4", SeverityNumberWarn4.String()) assert.Equal(t, "Error", SeverityNumberError.String()) assert.Equal(t, "Error2", SeverityNumberError2.String()) assert.Equal(t, "Error3", SeverityNumberError3.String()) assert.Equal(t, "Error4", SeverityNumberError4.String()) assert.Equal(t, "Fatal", SeverityNumberFatal.String()) assert.Equal(t, "Fatal2", SeverityNumberFatal2.String()) assert.Equal(t, "Fatal3", SeverityNumberFatal3.String()) assert.Equal(t, "Fatal4", SeverityNumberFatal4.String()) assert.Empty(t, SeverityNumber(100).String()) } opentelemetry-collector-0.141.0/pdata/pmetric/000077500000000000000000000000001511331344600212725ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/pmetric/aggregation_temporality.go000066400000000000000000000027431511331344600265470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" import ( "go.opentelemetry.io/collector/pdata/internal" ) // AggregationTemporality defines how a metric aggregator reports aggregated values. // It describes how those values relate to the time interval over which they are aggregated. type AggregationTemporality int32 const ( // AggregationTemporalityUnspecified is the default AggregationTemporality, it MUST NOT be used. AggregationTemporalityUnspecified = AggregationTemporality(internal.AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED) // AggregationTemporalityDelta is a AggregationTemporality for a metric aggregator which reports changes since last report time. AggregationTemporalityDelta = AggregationTemporality(internal.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA) // AggregationTemporalityCumulative is a AggregationTemporality for a metric aggregator which reports changes since a fixed start time. AggregationTemporalityCumulative = AggregationTemporality(internal.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE) ) // String returns the string representation of the AggregationTemporality. func (at AggregationTemporality) String() string { switch at { case AggregationTemporalityUnspecified: return "Unspecified" case AggregationTemporalityDelta: return "Delta" case AggregationTemporalityCumulative: return "Cumulative" } return "" } opentelemetry-collector-0.141.0/pdata/pmetric/aggregation_temporality_test.go000066400000000000000000000010461511331344600276010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" import ( "testing" "github.com/stretchr/testify/assert" ) func TestAggregationTemporalityString(t *testing.T) { assert.Equal(t, "Unspecified", AggregationTemporalityUnspecified.String()) assert.Equal(t, "Delta", AggregationTemporalityDelta.String()) assert.Equal(t, "Cumulative", AggregationTemporalityCumulative.String()) assert.Empty(t, (AggregationTemporalityCumulative + 1).String()) } opentelemetry-collector-0.141.0/pdata/pmetric/doc_test.go000066400000000000000000000215561511331344600234360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric_test import ( "fmt" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) func ExampleNewMetrics() { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() resourceMetrics.Resource().Attributes().PutStr("service.name", "my-service") resourceMetrics.Resource().Attributes().PutStr("host.name", "server-01") scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() scopeMetrics.Scope().SetName("my-meter") scopeMetrics.Scope().SetVersion("1.0.0") metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("requests_total") metric.SetDescription("Total number of requests") metric.SetUnit("1") sum := metric.SetEmptySum() sum.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) sum.SetIsMonotonic(true) dataPoint := sum.DataPoints().AppendEmpty() dataPoint.SetStartTimestamp(pcommon.Timestamp(1640991600000000000)) // 2022-01-01 00:00:00 UTC dataPoint.SetTimestamp(pcommon.Timestamp(1640995200000000000)) // 2022-01-01 01:00:00 UTC dataPoint.SetIntValue(1234) dataPoint.Attributes().PutStr("endpoint", "/api/v1/users") dataPoint.Attributes().PutStr("method", "GET") fmt.Printf("Resource metrics count: %d\n", metrics.ResourceMetrics().Len()) fmt.Printf("Metrics count: %d\n", scopeMetrics.Metrics().Len()) fmt.Printf("Metric name: %s\n", metric.Name()) fmt.Printf("Data points count: %d\n", sum.DataPoints().Len()) // Output: // Resource metrics count: 1 // Metrics count: 1 // Metric name: requests_total // Data points count: 1 } func ExampleMetric_SetEmptyGauge() { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("cpu_usage_percent") metric.SetDescription("Current CPU usage percentage") metric.SetUnit("%") gauge := metric.SetEmptyGauge() for i := range 4 { dataPoint := gauge.DataPoints().AppendEmpty() dataPoint.SetTimestamp(pcommon.Timestamp(1640995200000000000)) dataPoint.SetDoubleValue(45.5 + float64(i)*2.1) dataPoint.Attributes().PutInt("cpu", int64(i)) } fmt.Printf("Metric type: %s\n", metric.Type()) fmt.Printf("Data points count: %d\n", gauge.DataPoints().Len()) fmt.Printf("First CPU usage: %.1f%%\n", gauge.DataPoints().At(0).DoubleValue()) // Output: // Metric type: Gauge // Data points count: 4 // First CPU usage: 45.5% } func ExampleMetric_SetEmptyHistogram() { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("request_duration_seconds") metric.SetDescription("Request duration in seconds") metric.SetUnit("s") histogram := metric.SetEmptyHistogram() histogram.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) dataPoint := histogram.DataPoints().AppendEmpty() dataPoint.SetStartTimestamp(pcommon.Timestamp(1640995140000000000)) // 2022-01-01 00:59:00 UTC dataPoint.SetTimestamp(pcommon.Timestamp(1640995200000000000)) // 2022-01-01 01:00:00 UTC dataPoint.SetCount(100) dataPoint.SetSum(23.5) dataPoint.SetMin(0.001) dataPoint.SetMax(5.0) dataPoint.ExplicitBounds().FromRaw([]float64{0.01, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0}) dataPoint.BucketCounts().FromRaw([]uint64{5, 10, 20, 25, 20, 15, 3, 2, 0, 0}) dataPoint.Attributes().PutStr("endpoint", "/api/health") dataPoint.SetFlags(pmetric.DefaultDataPointFlags) fmt.Printf("Metric type: %s\n", metric.Type()) fmt.Printf("Total count: %d\n", dataPoint.Count()) fmt.Printf("Total sum: %.1f\n", dataPoint.Sum()) fmt.Printf("Min value: %.3f\n", dataPoint.Min()) fmt.Printf("Max value: %.1f\n", dataPoint.Max()) fmt.Printf("Bucket count: %d\n", dataPoint.BucketCounts().Len()) // Output: // Metric type: Histogram // Total count: 100 // Total sum: 23.5 // Min value: 0.001 // Max value: 5.0 // Bucket count: 10 } func ExampleMetric_SetEmptyExponentialHistogram() { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("response_size_bytes") metric.SetDescription("Response size in bytes") metric.SetUnit("By") expHist := metric.SetEmptyExponentialHistogram() expHist.SetAggregationTemporality(pmetric.AggregationTemporalityDelta) dataPoint := expHist.DataPoints().AppendEmpty() dataPoint.SetStartTimestamp(pcommon.Timestamp(1640995140000000000)) dataPoint.SetTimestamp(pcommon.Timestamp(1640995200000000000)) dataPoint.SetCount(50) dataPoint.SetSum(1024.5) dataPoint.SetScale(4) dataPoint.SetZeroCount(5) dataPoint.SetZeroThreshold(0.001) // Set positive buckets positive := dataPoint.Positive() positive.SetOffset(2) positive.BucketCounts().FromRaw([]uint64{2, 3, 7, 8, 5}) // Set negative buckets negative := dataPoint.Negative() negative.SetOffset(1) negative.BucketCounts().FromRaw([]uint64{1, 2, 3}) dataPoint.Attributes().PutStr("protocol", "http") fmt.Printf("Metric type: %s\n", metric.Type()) fmt.Printf("Scale: %d\n", dataPoint.Scale()) fmt.Printf("Zero count: %d\n", dataPoint.ZeroCount()) fmt.Printf("Positive buckets: %d\n", positive.BucketCounts().Len()) fmt.Printf("Negative buckets: %d\n", negative.BucketCounts().Len()) // Output: // Metric type: ExponentialHistogram // Scale: 4 // Zero count: 5 // Positive buckets: 5 // Negative buckets: 3 } func ExampleMetric_SetEmptySummary() { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("latency_seconds") metric.SetDescription("Request latency in seconds") metric.SetUnit("s") summary := metric.SetEmptySummary() dataPoint := summary.DataPoints().AppendEmpty() dataPoint.SetStartTimestamp(pcommon.Timestamp(1640995140000000000)) dataPoint.SetTimestamp(pcommon.Timestamp(1640995200000000000)) dataPoint.SetCount(1000) dataPoint.SetSum(125.5) // Add quantile values q50 := dataPoint.QuantileValues().AppendEmpty() q50.SetQuantile(0.5) q50.SetValue(0.1) q95 := dataPoint.QuantileValues().AppendEmpty() q95.SetQuantile(0.95) q95.SetValue(0.5) q99 := dataPoint.QuantileValues().AppendEmpty() q99.SetQuantile(0.99) q99.SetValue(1.0) dataPoint.Attributes().PutStr("service", "api") fmt.Printf("Metric type: %s\n", metric.Type()) fmt.Printf("Count: %d\n", dataPoint.Count()) fmt.Printf("Sum: %.1f\n", dataPoint.Sum()) fmt.Printf("Quantiles: %d\n", dataPoint.QuantileValues().Len()) fmt.Printf("P95: %.1f\n", q95.Value()) // Output: // Metric type: Summary // Count: 1000 // Sum: 125.5 // Quantiles: 3 // P95: 0.5 } func ExampleNumberDataPoint_Exemplars() { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("http_requests_total") sum := metric.SetEmptySum() dataPoint := sum.DataPoints().AppendEmpty() dataPoint.SetIntValue(5000) exemplar := dataPoint.Exemplars().AppendEmpty() exemplar.SetTimestamp(pcommon.Timestamp(1640995200000000000)) exemplar.SetIntValue(1) exemplar.FilteredAttributes().PutStr("trace_id", "abc123") exemplar.FilteredAttributes().PutStr("span_id", "def456") fmt.Printf("Data point value: %d\n", dataPoint.IntValue()) fmt.Printf("Exemplars count: %d\n", dataPoint.Exemplars().Len()) fmt.Printf("Exemplar value: %d\n", exemplar.IntValue()) // Output: // Data point value: 5000 // Exemplars count: 1 // Exemplar value: 1 } func ExampleDataPointFlags() { metrics := pmetric.NewMetrics() resourceMetrics := metrics.ResourceMetrics().AppendEmpty() scopeMetrics := resourceMetrics.ScopeMetrics().AppendEmpty() metric := scopeMetrics.Metrics().AppendEmpty() metric.SetName("test_metric") gauge := metric.SetEmptyGauge() dataPoint := gauge.DataPoints().AppendEmpty() // Test default flags defaultFlags := pmetric.DefaultDataPointFlags dataPoint.SetFlags(defaultFlags) fmt.Printf("Default flags NoRecordedValue: %t\n", dataPoint.Flags().NoRecordedValue()) // Test with NoRecordedValue flag flagsWithNoValue := defaultFlags.WithNoRecordedValue(true) dataPoint.SetFlags(flagsWithNoValue) fmt.Printf("With NoRecordedValue flag: %t\n", dataPoint.Flags().NoRecordedValue()) // Test removing NoRecordedValue flag flagsWithoutNoValue := flagsWithNoValue.WithNoRecordedValue(false) dataPoint.SetFlags(flagsWithoutNoValue) fmt.Printf("Without NoRecordedValue flag: %t\n", dataPoint.Flags().NoRecordedValue()) // Output: // Default flags NoRecordedValue: false // With NoRecordedValue flag: true // Without NoRecordedValue flag: false } opentelemetry-collector-0.141.0/pdata/pmetric/encoding.go000066400000000000000000000020121511331344600234020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" // MarshalSizer is the interface that groups the basic Marshal and Size methods type MarshalSizer interface { Marshaler Sizer } // Marshaler marshals pmetric.Metrics into bytes. type Marshaler interface { // MarshalMetrics the given pmetric.Metrics into bytes. // If the error is not nil, the returned bytes slice cannot be used. MarshalMetrics(md Metrics) ([]byte, error) } // Unmarshaler unmarshalls bytes into pmetric.Metrics. type Unmarshaler interface { // UnmarshalMetrics the given bytes into pmetric.Metrics. // If the error is not nil, the returned pmetric.Metrics cannot be used. UnmarshalMetrics(buf []byte) (Metrics, error) } // Sizer is an optional interface implemented by the Marshaler, that calculates the size of a marshaled Metrics. type Sizer interface { // MetricsSize returns the size in bytes of a marshaled Metrics. MetricsSize(md Metrics) int } opentelemetry-collector-0.141.0/pdata/pmetric/exemplar_value_type.go000066400000000000000000000013031511331344600256700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" // ExemplarValueType specifies the type of Exemplar measurement value. type ExemplarValueType int32 const ( // ExemplarValueTypeEmpty means that exemplar value is unset. ExemplarValueTypeEmpty ExemplarValueType = iota ExemplarValueTypeInt ExemplarValueTypeDouble ) // String returns the string representation of the ExemplarValueType. func (nt ExemplarValueType) String() string { switch nt { case ExemplarValueTypeEmpty: return "Empty" case ExemplarValueTypeInt: return "Int" case ExemplarValueTypeDouble: return "Double" } return "" } opentelemetry-collector-0.141.0/pdata/pmetric/exemplar_value_type_test.go000066400000000000000000000007611511331344600267360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" import ( "testing" "github.com/stretchr/testify/assert" ) func TestExemplarValueTypeString(t *testing.T) { assert.Equal(t, "Empty", ExemplarValueTypeEmpty.String()) assert.Equal(t, "Int", ExemplarValueTypeInt.String()) assert.Equal(t, "Double", ExemplarValueTypeDouble.String()) assert.Empty(t, (ExemplarValueTypeDouble + 1).String()) } opentelemetry-collector-0.141.0/pdata/pmetric/fuzz_test.go000066400000000000000000000005051511331344600236560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" import ( "testing" ) func FuzzUnmarshalMetrics(f *testing.F) { f.Fuzz(func(_ *testing.T, data []byte) { u := &JSONUnmarshaler{} _, _ = u.UnmarshalMetrics(data) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exemplar.go000066400000000000000000000107551511331344600254640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Exemplar is a sample input double measurement. // // Exemplars also hold information about the environment when the measurement was recorded, // for example the span and trace ID of the active span when the exemplar was recorded. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExemplar function to create new instances. // Important: zero-initialized instance is not valid for use. type Exemplar struct { orig *internal.Exemplar state *internal.State } func newExemplar(orig *internal.Exemplar, state *internal.State) Exemplar { return Exemplar{orig: orig, state: state} } // NewExemplar creates a new empty Exemplar. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExemplar() Exemplar { return newExemplar(internal.NewExemplar(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Exemplar) MoveTo(dest Exemplar) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExemplar(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // FilteredAttributes returns the FilteredAttributes associated with this Exemplar. func (ms Exemplar) FilteredAttributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.FilteredAttributes, ms.state)) } // Timestamp returns the timestamp associated with this Exemplar. func (ms Exemplar) Timestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTimestamp replaces the timestamp associated with this Exemplar. func (ms Exemplar) SetTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // ValueType returns the type of the value for this Exemplar. // Calling this function on zero-initialized Exemplar will cause a panic. func (ms Exemplar) ValueType() ExemplarValueType { switch ms.orig.Value.(type) { case *internal.Exemplar_AsDouble: return ExemplarValueTypeDouble case *internal.Exemplar_AsInt: return ExemplarValueTypeInt } return ExemplarValueTypeEmpty } // DoubleValue returns the double associated with this Exemplar. func (ms Exemplar) DoubleValue() float64 { return ms.orig.GetAsDouble() } // SetDoubleValue replaces the double associated with this Exemplar. func (ms Exemplar) SetDoubleValue(v float64) { ms.state.AssertMutable() var ov *internal.Exemplar_AsDouble if !internal.UseProtoPooling.IsEnabled() { ov = &internal.Exemplar_AsDouble{} } else { ov = internal.ProtoPoolExemplar_AsDouble.Get().(*internal.Exemplar_AsDouble) } ov.AsDouble = v ms.orig.Value = ov } // IntValue returns the int associated with this Exemplar. func (ms Exemplar) IntValue() int64 { return ms.orig.GetAsInt() } // SetIntValue replaces the int associated with this Exemplar. func (ms Exemplar) SetIntValue(v int64) { ms.state.AssertMutable() var ov *internal.Exemplar_AsInt if !internal.UseProtoPooling.IsEnabled() { ov = &internal.Exemplar_AsInt{} } else { ov = internal.ProtoPoolExemplar_AsInt.Get().(*internal.Exemplar_AsInt) } ov.AsInt = v ms.orig.Value = ov } // TraceID returns the traceid associated with this Exemplar. func (ms Exemplar) TraceID() pcommon.TraceID { return pcommon.TraceID(ms.orig.TraceId) } // SetTraceID replaces the traceid associated with this Exemplar. func (ms Exemplar) SetTraceID(v pcommon.TraceID) { ms.state.AssertMutable() ms.orig.TraceId = internal.TraceID(v) } // SpanID returns the spanid associated with this Exemplar. func (ms Exemplar) SpanID() pcommon.SpanID { return pcommon.SpanID(ms.orig.SpanId) } // SetSpanID replaces the spanid associated with this Exemplar. func (ms Exemplar) SetSpanID(v pcommon.SpanID) { ms.state.AssertMutable() ms.orig.SpanId = internal.SpanID(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Exemplar) CopyTo(dest Exemplar) { dest.state.AssertMutable() internal.CopyExemplar(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exemplar_test.go000066400000000000000000000066671511331344600265320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestExemplar_MoveTo(t *testing.T) { ms := generateTestExemplar() dest := NewExemplar() ms.MoveTo(dest) assert.Equal(t, NewExemplar(), ms) assert.Equal(t, generateTestExemplar(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExemplar(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExemplar(internal.NewExemplar(), sharedState)) }) assert.Panics(t, func() { newExemplar(internal.NewExemplar(), sharedState).MoveTo(dest) }) } func TestExemplar_CopyTo(t *testing.T) { ms := NewExemplar() orig := NewExemplar() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExemplar() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExemplar(internal.NewExemplar(), sharedState)) }) } func TestExemplar_FilteredAttributes(t *testing.T) { ms := NewExemplar() assert.Equal(t, pcommon.NewMap(), ms.FilteredAttributes()) ms.orig.FilteredAttributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.FilteredAttributes()) } func TestExemplar_Timestamp(t *testing.T) { ms := NewExemplar() assert.Equal(t, pcommon.Timestamp(0), ms.Timestamp()) testValTimestamp := pcommon.Timestamp(1234567890) ms.SetTimestamp(testValTimestamp) assert.Equal(t, testValTimestamp, ms.Timestamp()) } func TestExemplar_ValueType(t *testing.T) { tv := NewExemplar() assert.Equal(t, ExemplarValueTypeEmpty, tv.ValueType()) } func TestExemplar_DoubleValue(t *testing.T) { ms := NewExemplar() assert.InDelta(t, float64(0), ms.DoubleValue(), 0.01) ms.SetDoubleValue(float64(3.1415926)) assert.InDelta(t, float64(3.1415926), ms.DoubleValue(), 0.01) assert.Equal(t, ExemplarValueTypeDouble, ms.ValueType()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExemplar(internal.NewExemplar(), sharedState).SetDoubleValue(float64(3.1415926)) }) } func TestExemplar_IntValue(t *testing.T) { ms := NewExemplar() assert.Equal(t, int64(0), ms.IntValue()) ms.SetIntValue(int64(13)) assert.Equal(t, int64(13), ms.IntValue()) assert.Equal(t, ExemplarValueTypeInt, ms.ValueType()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExemplar(internal.NewExemplar(), sharedState).SetIntValue(int64(13)) }) } func TestExemplar_TraceID(t *testing.T) { ms := NewExemplar() assert.Equal(t, pcommon.TraceID(internal.TraceID([16]byte{})), ms.TraceID()) testValTraceID := pcommon.TraceID(internal.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})) ms.SetTraceID(testValTraceID) assert.Equal(t, testValTraceID, ms.TraceID()) } func TestExemplar_SpanID(t *testing.T) { ms := NewExemplar() assert.Equal(t, pcommon.SpanID(internal.SpanID([8]byte{})), ms.SpanID()) testValSpanID := pcommon.SpanID(internal.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})) ms.SetSpanID(testValSpanID) assert.Equal(t, testValSpanID, ms.SpanID()) } func generateTestExemplar() Exemplar { return newExemplar(internal.GenTestExemplar(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exemplarslice.go000066400000000000000000000102721511331344600264760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "go.opentelemetry.io/collector/pdata/internal" ) // ExemplarSlice logically represents a slice of Exemplar. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewExemplarSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ExemplarSlice struct { orig *[]internal.Exemplar state *internal.State } func newExemplarSlice(orig *[]internal.Exemplar, state *internal.State) ExemplarSlice { return ExemplarSlice{orig: orig, state: state} } // NewExemplarSlice creates a ExemplarSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewExemplarSlice() ExemplarSlice { orig := []internal.Exemplar(nil) return newExemplarSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewExemplarSlice()". func (es ExemplarSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ExemplarSlice) At(i int) Exemplar { return newExemplar(&(*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ExemplarSlice) All() iter.Seq2[int, Exemplar] { return func(yield func(int, Exemplar) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ExemplarSlice can be initialized: // // es := NewExemplarSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ExemplarSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]internal.Exemplar, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Exemplar. // It returns the newly added Exemplar. func (es ExemplarSlice) AppendEmpty() Exemplar { es.state.AssertMutable() *es.orig = append(*es.orig, internal.Exemplar{}) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ExemplarSlice) MoveAndAppendTo(dest ExemplarSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ExemplarSlice) RemoveIf(f func(Exemplar) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteExemplar(&(*es.orig)[i], false) continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] (*es.orig)[i].Reset() newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ExemplarSlice) CopyTo(dest ExemplarSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyExemplarSlice(*dest.orig, *es.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exemplarslice_test.go000066400000000000000000000101641511331344600275350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExemplarSlice(t *testing.T) { es := NewExemplarSlice() assert.Equal(t, 0, es.Len()) es = newExemplarSlice(&[]internal.Exemplar{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewExemplar() testVal := generateTestExemplar() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = *internal.GenTestExemplar() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestExemplarSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newExemplarSlice(&[]internal.Exemplar{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewExemplarSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestExemplarSlice_CopyTo(t *testing.T) { dest := NewExemplarSlice() src := generateTestExemplarSlice() src.CopyTo(dest) assert.Equal(t, generateTestExemplarSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestExemplarSlice(), dest) } func TestExemplarSlice_EnsureCapacity(t *testing.T) { es := generateTestExemplarSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestExemplarSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestExemplarSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestExemplarSlice(), es) } func TestExemplarSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestExemplarSlice() dest := NewExemplarSlice() src := generateTestExemplarSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestExemplarSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestExemplarSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestExemplarSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestExemplarSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewExemplarSlice() emptySlice.RemoveIf(func(el Exemplar) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestExemplarSlice() pos := 0 filtered.RemoveIf(func(el Exemplar) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestExemplarSlice_RemoveIfAll(t *testing.T) { got := generateTestExemplarSlice() got.RemoveIf(func(el Exemplar) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestExemplarSliceAll(t *testing.T) { ms := generateTestExemplarSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func generateTestExemplarSlice() ExemplarSlice { ms := NewExemplarSlice() *ms.orig = internal.GenTestExemplarSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogram.go000066400000000000000000000054341511331344600301110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExponentialHistogram represents the type of a metric that is calculated by aggregating // as a ExponentialHistogram of all reported double measurements over a time interval. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExponentialHistogram function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogram struct { orig *internal.ExponentialHistogram state *internal.State } func newExponentialHistogram(orig *internal.ExponentialHistogram, state *internal.State) ExponentialHistogram { return ExponentialHistogram{orig: orig, state: state} } // NewExponentialHistogram creates a new empty ExponentialHistogram. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExponentialHistogram() ExponentialHistogram { return newExponentialHistogram(internal.NewExponentialHistogram(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExponentialHistogram) MoveTo(dest ExponentialHistogram) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExponentialHistogram(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // DataPoints returns the DataPoints associated with this ExponentialHistogram. func (ms ExponentialHistogram) DataPoints() ExponentialHistogramDataPointSlice { return newExponentialHistogramDataPointSlice(&ms.orig.DataPoints, ms.state) } // AggregationTemporality returns the aggregationtemporality associated with this ExponentialHistogram. func (ms ExponentialHistogram) AggregationTemporality() AggregationTemporality { return AggregationTemporality(ms.orig.AggregationTemporality) } // SetAggregationTemporality replaces the aggregationtemporality associated with this ExponentialHistogram. func (ms ExponentialHistogram) SetAggregationTemporality(v AggregationTemporality) { ms.state.AssertMutable() ms.orig.AggregationTemporality = internal.AggregationTemporality(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExponentialHistogram) CopyTo(dest ExponentialHistogram) { dest.state.AssertMutable() internal.CopyExponentialHistogram(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogram_test.go000066400000000000000000000044131511331344600311440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExponentialHistogram_MoveTo(t *testing.T) { ms := generateTestExponentialHistogram() dest := NewExponentialHistogram() ms.MoveTo(dest) assert.Equal(t, NewExponentialHistogram(), ms) assert.Equal(t, generateTestExponentialHistogram(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExponentialHistogram(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExponentialHistogram(internal.NewExponentialHistogram(), sharedState)) }) assert.Panics(t, func() { newExponentialHistogram(internal.NewExponentialHistogram(), sharedState).MoveTo(dest) }) } func TestExponentialHistogram_CopyTo(t *testing.T) { ms := NewExponentialHistogram() orig := NewExponentialHistogram() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExponentialHistogram() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExponentialHistogram(internal.NewExponentialHistogram(), sharedState)) }) } func TestExponentialHistogram_DataPoints(t *testing.T) { ms := NewExponentialHistogram() assert.Equal(t, NewExponentialHistogramDataPointSlice(), ms.DataPoints()) ms.orig.DataPoints = internal.GenTestExponentialHistogramDataPointPtrSlice() assert.Equal(t, generateTestExponentialHistogramDataPointSlice(), ms.DataPoints()) } func TestExponentialHistogram_AggregationTemporality(t *testing.T) { ms := NewExponentialHistogram() assert.Equal(t, AggregationTemporality(internal.AggregationTemporality(0)), ms.AggregationTemporality()) testValAggregationTemporality := AggregationTemporality(internal.AggregationTemporality(1)) ms.SetAggregationTemporality(testValAggregationTemporality) assert.Equal(t, testValAggregationTemporality, ms.AggregationTemporality()) } func generateTestExponentialHistogram() ExponentialHistogram { return newExponentialHistogram(internal.GenTestExponentialHistogram(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogramdatapoint.go000066400000000000000000000204521511331344600320120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ExponentialHistogramDataPoint is a single data point in a timeseries that describes the // time-varying values of a ExponentialHistogram of double values. A ExponentialHistogram contains // summary statistics for a population of values, it may optionally contain the // distribution of those values across a set of buckets. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExponentialHistogramDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogramDataPoint struct { orig *internal.ExponentialHistogramDataPoint state *internal.State } func newExponentialHistogramDataPoint(orig *internal.ExponentialHistogramDataPoint, state *internal.State) ExponentialHistogramDataPoint { return ExponentialHistogramDataPoint{orig: orig, state: state} } // NewExponentialHistogramDataPoint creates a new empty ExponentialHistogramDataPoint. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExponentialHistogramDataPoint() ExponentialHistogramDataPoint { return newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExponentialHistogramDataPoint) MoveTo(dest ExponentialHistogramDataPoint) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExponentialHistogramDataPoint(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Attributes returns the Attributes associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) StartTimestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.StartTimeUnixNano) } // SetStartTimestamp replaces the starttimestamp associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetStartTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } // Timestamp returns the timestamp associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Timestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTimestamp replaces the timestamp associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // Count returns the count associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Count() uint64 { return ms.orig.Count } // SetCount replaces the count associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetCount(v uint64) { ms.state.AssertMutable() ms.orig.Count = v } // Sum returns the sum associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Sum() float64 { return ms.orig.GetSum() } // HasSum returns true if the ExponentialHistogramDataPoint contains a // Sum value otherwise. func (ms ExponentialHistogramDataPoint) HasSum() bool { return ms.orig.Sum_ != nil } // SetSum replaces the sum associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetSum(v float64) { ms.state.AssertMutable() ms.orig.Sum_ = &internal.ExponentialHistogramDataPoint_Sum{Sum: v} } // RemoveSum removes the sum associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) RemoveSum() { ms.state.AssertMutable() ms.orig.Sum_ = nil } // Scale returns the scale associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Scale() int32 { return ms.orig.Scale } // SetScale replaces the scale associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetScale(v int32) { ms.state.AssertMutable() ms.orig.Scale = v } // ZeroCount returns the zerocount associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) ZeroCount() uint64 { return ms.orig.ZeroCount } // SetZeroCount replaces the zerocount associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetZeroCount(v uint64) { ms.state.AssertMutable() ms.orig.ZeroCount = v } // Positive returns the positive associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Positive() ExponentialHistogramDataPointBuckets { return newExponentialHistogramDataPointBuckets(&ms.orig.Positive, ms.state) } // Negative returns the negative associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Negative() ExponentialHistogramDataPointBuckets { return newExponentialHistogramDataPointBuckets(&ms.orig.Negative, ms.state) } // Flags returns the flags associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Flags() DataPointFlags { return DataPointFlags(ms.orig.Flags) } // SetFlags replaces the flags associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetFlags(v DataPointFlags) { ms.state.AssertMutable() ms.orig.Flags = uint32(v) } // Exemplars returns the Exemplars associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Exemplars() ExemplarSlice { return newExemplarSlice(&ms.orig.Exemplars, ms.state) } // Min returns the min associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Min() float64 { return ms.orig.GetMin() } // HasMin returns true if the ExponentialHistogramDataPoint contains a // Min value otherwise. func (ms ExponentialHistogramDataPoint) HasMin() bool { return ms.orig.Min_ != nil } // SetMin replaces the min associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetMin(v float64) { ms.state.AssertMutable() ms.orig.Min_ = &internal.ExponentialHistogramDataPoint_Min{Min: v} } // RemoveMin removes the min associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) RemoveMin() { ms.state.AssertMutable() ms.orig.Min_ = nil } // Max returns the max associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) Max() float64 { return ms.orig.GetMax() } // HasMax returns true if the ExponentialHistogramDataPoint contains a // Max value otherwise. func (ms ExponentialHistogramDataPoint) HasMax() bool { return ms.orig.Max_ != nil } // SetMax replaces the max associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetMax(v float64) { ms.state.AssertMutable() ms.orig.Max_ = &internal.ExponentialHistogramDataPoint_Max{Max: v} } // RemoveMax removes the max associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) RemoveMax() { ms.state.AssertMutable() ms.orig.Max_ = nil } // ZeroThreshold returns the zerothreshold associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) ZeroThreshold() float64 { return ms.orig.ZeroThreshold } // SetZeroThreshold replaces the zerothreshold associated with this ExponentialHistogramDataPoint. func (ms ExponentialHistogramDataPoint) SetZeroThreshold(v float64) { ms.state.AssertMutable() ms.orig.ZeroThreshold = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExponentialHistogramDataPoint) CopyTo(dest ExponentialHistogramDataPoint) { dest.state.AssertMutable() internal.CopyExponentialHistogramDataPoint(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogramdatapoint_test.go000066400000000000000000000155701511331344600330560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestExponentialHistogramDataPoint_MoveTo(t *testing.T) { ms := generateTestExponentialHistogramDataPoint() dest := NewExponentialHistogramDataPoint() ms.MoveTo(dest) assert.Equal(t, NewExponentialHistogramDataPoint(), ms) assert.Equal(t, generateTestExponentialHistogramDataPoint(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExponentialHistogramDataPoint(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), sharedState)) }) assert.Panics(t, func() { newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), sharedState).MoveTo(dest) }) } func TestExponentialHistogramDataPoint_CopyTo(t *testing.T) { ms := NewExponentialHistogramDataPoint() orig := NewExponentialHistogramDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExponentialHistogramDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), sharedState)) }) } func TestExponentialHistogramDataPoint_Attributes(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestExponentialHistogramDataPoint_StartTimestamp(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.StartTimestamp()) testValStartTimestamp := pcommon.Timestamp(1234567890) ms.SetStartTimestamp(testValStartTimestamp) assert.Equal(t, testValStartTimestamp, ms.StartTimestamp()) } func TestExponentialHistogramDataPoint_Timestamp(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.Timestamp()) testValTimestamp := pcommon.Timestamp(1234567890) ms.SetTimestamp(testValTimestamp) assert.Equal(t, testValTimestamp, ms.Timestamp()) } func TestExponentialHistogramDataPoint_Count(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, uint64(0), ms.Count()) ms.SetCount(uint64(13)) assert.Equal(t, uint64(13), ms.Count()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), sharedState).SetCount(uint64(13)) }) } func TestExponentialHistogramDataPoint_Sum(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.InDelta(t, float64(0), ms.Sum(), 0.01) ms.SetSum(float64(3.1415926)) assert.True(t, ms.HasSum()) assert.InDelta(t, float64(3.1415926), ms.Sum(), 0.01) ms.RemoveSum() assert.False(t, ms.HasSum()) dest := NewExponentialHistogramDataPoint() dest.SetSum(float64(3.1415926)) ms.CopyTo(dest) assert.False(t, dest.HasSum()) } func TestExponentialHistogramDataPoint_Scale(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, int32(0), ms.Scale()) ms.SetScale(int32(13)) assert.Equal(t, int32(13), ms.Scale()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), sharedState).SetScale(int32(13)) }) } func TestExponentialHistogramDataPoint_ZeroCount(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, uint64(0), ms.ZeroCount()) ms.SetZeroCount(uint64(13)) assert.Equal(t, uint64(13), ms.ZeroCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), sharedState).SetZeroCount(uint64(13)) }) } func TestExponentialHistogramDataPoint_Positive(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, NewExponentialHistogramDataPointBuckets(), ms.Positive()) ms.orig.Positive = *internal.GenTestExponentialHistogramDataPointBuckets() assert.Equal(t, generateTestExponentialHistogramDataPointBuckets(), ms.Positive()) } func TestExponentialHistogramDataPoint_Negative(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, NewExponentialHistogramDataPointBuckets(), ms.Negative()) ms.orig.Negative = *internal.GenTestExponentialHistogramDataPointBuckets() assert.Equal(t, generateTestExponentialHistogramDataPointBuckets(), ms.Negative()) } func TestExponentialHistogramDataPoint_Flags(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, DataPointFlags(0), ms.Flags()) testValFlags := DataPointFlags(1) ms.SetFlags(testValFlags) assert.Equal(t, testValFlags, ms.Flags()) } func TestExponentialHistogramDataPoint_Exemplars(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.Equal(t, NewExemplarSlice(), ms.Exemplars()) ms.orig.Exemplars = internal.GenTestExemplarSlice() assert.Equal(t, generateTestExemplarSlice(), ms.Exemplars()) } func TestExponentialHistogramDataPoint_Min(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.InDelta(t, float64(0), ms.Min(), 0.01) ms.SetMin(float64(3.1415926)) assert.True(t, ms.HasMin()) assert.InDelta(t, float64(3.1415926), ms.Min(), 0.01) ms.RemoveMin() assert.False(t, ms.HasMin()) dest := NewExponentialHistogramDataPoint() dest.SetMin(float64(3.1415926)) ms.CopyTo(dest) assert.False(t, dest.HasMin()) } func TestExponentialHistogramDataPoint_Max(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.InDelta(t, float64(0), ms.Max(), 0.01) ms.SetMax(float64(3.1415926)) assert.True(t, ms.HasMax()) assert.InDelta(t, float64(3.1415926), ms.Max(), 0.01) ms.RemoveMax() assert.False(t, ms.HasMax()) dest := NewExponentialHistogramDataPoint() dest.SetMax(float64(3.1415926)) ms.CopyTo(dest) assert.False(t, dest.HasMax()) } func TestExponentialHistogramDataPoint_ZeroThreshold(t *testing.T) { ms := NewExponentialHistogramDataPoint() assert.InDelta(t, float64(0), ms.ZeroThreshold(), 0.01) ms.SetZeroThreshold(float64(3.1415926)) assert.InDelta(t, float64(3.1415926), ms.ZeroThreshold(), 0.01) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExponentialHistogramDataPoint(internal.NewExponentialHistogramDataPoint(), sharedState).SetZeroThreshold(float64(3.1415926)) }) } func generateTestExponentialHistogramDataPoint() ExponentialHistogramDataPoint { return newExponentialHistogramDataPoint(internal.GenTestExponentialHistogramDataPoint(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogramdatapointbuckets.go000066400000000000000000000057031511331344600333750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ExponentialHistogramDataPointBuckets are a set of bucket counts, encoded in a contiguous array of counts. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExponentialHistogramDataPointBuckets function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogramDataPointBuckets struct { orig *internal.ExponentialHistogramDataPointBuckets state *internal.State } func newExponentialHistogramDataPointBuckets(orig *internal.ExponentialHistogramDataPointBuckets, state *internal.State) ExponentialHistogramDataPointBuckets { return ExponentialHistogramDataPointBuckets{orig: orig, state: state} } // NewExponentialHistogramDataPointBuckets creates a new empty ExponentialHistogramDataPointBuckets. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExponentialHistogramDataPointBuckets() ExponentialHistogramDataPointBuckets { return newExponentialHistogramDataPointBuckets(internal.NewExponentialHistogramDataPointBuckets(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExponentialHistogramDataPointBuckets) MoveTo(dest ExponentialHistogramDataPointBuckets) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExponentialHistogramDataPointBuckets(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Offset returns the offset associated with this ExponentialHistogramDataPointBuckets. func (ms ExponentialHistogramDataPointBuckets) Offset() int32 { return ms.orig.Offset } // SetOffset replaces the offset associated with this ExponentialHistogramDataPointBuckets. func (ms ExponentialHistogramDataPointBuckets) SetOffset(v int32) { ms.state.AssertMutable() ms.orig.Offset = v } // BucketCounts returns the BucketCounts associated with this ExponentialHistogramDataPointBuckets. func (ms ExponentialHistogramDataPointBuckets) BucketCounts() pcommon.UInt64Slice { return pcommon.UInt64Slice(internal.NewUInt64SliceWrapper(&ms.orig.BucketCounts, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExponentialHistogramDataPointBuckets) CopyTo(dest ExponentialHistogramDataPointBuckets) { dest.state.AssertMutable() internal.CopyExponentialHistogramDataPointBuckets(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogramdatapointbuckets_test.go000066400000000000000000000052231511331344600344310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestExponentialHistogramDataPointBuckets_MoveTo(t *testing.T) { ms := generateTestExponentialHistogramDataPointBuckets() dest := NewExponentialHistogramDataPointBuckets() ms.MoveTo(dest) assert.Equal(t, NewExponentialHistogramDataPointBuckets(), ms) assert.Equal(t, generateTestExponentialHistogramDataPointBuckets(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExponentialHistogramDataPointBuckets(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExponentialHistogramDataPointBuckets(internal.NewExponentialHistogramDataPointBuckets(), sharedState)) }) assert.Panics(t, func() { newExponentialHistogramDataPointBuckets(internal.NewExponentialHistogramDataPointBuckets(), sharedState).MoveTo(dest) }) } func TestExponentialHistogramDataPointBuckets_CopyTo(t *testing.T) { ms := NewExponentialHistogramDataPointBuckets() orig := NewExponentialHistogramDataPointBuckets() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExponentialHistogramDataPointBuckets() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExponentialHistogramDataPointBuckets(internal.NewExponentialHistogramDataPointBuckets(), sharedState)) }) } func TestExponentialHistogramDataPointBuckets_Offset(t *testing.T) { ms := NewExponentialHistogramDataPointBuckets() assert.Equal(t, int32(0), ms.Offset()) ms.SetOffset(int32(13)) assert.Equal(t, int32(13), ms.Offset()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExponentialHistogramDataPointBuckets(internal.NewExponentialHistogramDataPointBuckets(), sharedState).SetOffset(int32(13)) }) } func TestExponentialHistogramDataPointBuckets_BucketCounts(t *testing.T) { ms := NewExponentialHistogramDataPointBuckets() assert.Equal(t, pcommon.NewUInt64Slice(), ms.BucketCounts()) ms.orig.BucketCounts = internal.GenTestUint64Slice() assert.Equal(t, pcommon.UInt64Slice(internal.GenTestUInt64SliceWrapper()), ms.BucketCounts()) } func generateTestExponentialHistogramDataPointBuckets() ExponentialHistogramDataPointBuckets { return newExponentialHistogramDataPointBuckets(internal.GenTestExponentialHistogramDataPointBuckets(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogramdatapointslice.go000066400000000000000000000131061511331344600330300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ExponentialHistogramDataPointSlice logically represents a slice of ExponentialHistogramDataPoint. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewExponentialHistogramDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ExponentialHistogramDataPointSlice struct { orig *[]*internal.ExponentialHistogramDataPoint state *internal.State } func newExponentialHistogramDataPointSlice(orig *[]*internal.ExponentialHistogramDataPoint, state *internal.State) ExponentialHistogramDataPointSlice { return ExponentialHistogramDataPointSlice{orig: orig, state: state} } // NewExponentialHistogramDataPointSlice creates a ExponentialHistogramDataPointSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewExponentialHistogramDataPointSlice() ExponentialHistogramDataPointSlice { orig := []*internal.ExponentialHistogramDataPoint(nil) return newExponentialHistogramDataPointSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewExponentialHistogramDataPointSlice()". func (es ExponentialHistogramDataPointSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ExponentialHistogramDataPointSlice) At(i int) ExponentialHistogramDataPoint { return newExponentialHistogramDataPoint((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ExponentialHistogramDataPointSlice) All() iter.Seq2[int, ExponentialHistogramDataPoint] { return func(yield func(int, ExponentialHistogramDataPoint) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ExponentialHistogramDataPointSlice can be initialized: // // es := NewExponentialHistogramDataPointSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ExponentialHistogramDataPointSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ExponentialHistogramDataPoint, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ExponentialHistogramDataPoint. // It returns the newly added ExponentialHistogramDataPoint. func (es ExponentialHistogramDataPointSlice) AppendEmpty() ExponentialHistogramDataPoint { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewExponentialHistogramDataPoint()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ExponentialHistogramDataPointSlice) MoveAndAppendTo(dest ExponentialHistogramDataPointSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ExponentialHistogramDataPointSlice) RemoveIf(f func(ExponentialHistogramDataPoint) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteExponentialHistogramDataPoint((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ExponentialHistogramDataPointSlice) CopyTo(dest ExponentialHistogramDataPointSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyExponentialHistogramDataPointPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ExponentialHistogramDataPoint elements within ExponentialHistogramDataPointSlice given the // provided less function so that two instances of ExponentialHistogramDataPointSlice // can be compared. func (es ExponentialHistogramDataPointSlice) Sort(less func(a, b ExponentialHistogramDataPoint) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_exponentialhistogramdatapointslice_test.go000066400000000000000000000132211511331344600340650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExponentialHistogramDataPointSlice(t *testing.T) { es := NewExponentialHistogramDataPointSlice() assert.Equal(t, 0, es.Len()) es = newExponentialHistogramDataPointSlice(&[]*internal.ExponentialHistogramDataPoint{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewExponentialHistogramDataPoint() testVal := generateTestExponentialHistogramDataPoint() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestExponentialHistogramDataPoint() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestExponentialHistogramDataPointSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newExponentialHistogramDataPointSlice(&[]*internal.ExponentialHistogramDataPoint{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewExponentialHistogramDataPointSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestExponentialHistogramDataPointSlice_CopyTo(t *testing.T) { dest := NewExponentialHistogramDataPointSlice() src := generateTestExponentialHistogramDataPointSlice() src.CopyTo(dest) assert.Equal(t, generateTestExponentialHistogramDataPointSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestExponentialHistogramDataPointSlice(), dest) } func TestExponentialHistogramDataPointSlice_EnsureCapacity(t *testing.T) { es := generateTestExponentialHistogramDataPointSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestExponentialHistogramDataPointSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestExponentialHistogramDataPointSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestExponentialHistogramDataPointSlice(), es) } func TestExponentialHistogramDataPointSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestExponentialHistogramDataPointSlice() dest := NewExponentialHistogramDataPointSlice() src := generateTestExponentialHistogramDataPointSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestExponentialHistogramDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestExponentialHistogramDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestExponentialHistogramDataPointSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestExponentialHistogramDataPointSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewExponentialHistogramDataPointSlice() emptySlice.RemoveIf(func(el ExponentialHistogramDataPoint) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestExponentialHistogramDataPointSlice() pos := 0 filtered.RemoveIf(func(el ExponentialHistogramDataPoint) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestExponentialHistogramDataPointSlice_RemoveIfAll(t *testing.T) { got := generateTestExponentialHistogramDataPointSlice() got.RemoveIf(func(el ExponentialHistogramDataPoint) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestExponentialHistogramDataPointSliceAll(t *testing.T) { ms := generateTestExponentialHistogramDataPointSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestExponentialHistogramDataPointSlice_Sort(t *testing.T) { es := generateTestExponentialHistogramDataPointSlice() es.Sort(func(a, b ExponentialHistogramDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ExponentialHistogramDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestExponentialHistogramDataPointSlice() ExponentialHistogramDataPointSlice { ms := NewExponentialHistogramDataPointSlice() *ms.orig = internal.GenTestExponentialHistogramDataPointPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_gauge.go000066400000000000000000000035451511331344600247360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" ) // Gauge represents the type of a numeric metric that always exports the "current value" for every data point. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewGauge function to create new instances. // Important: zero-initialized instance is not valid for use. type Gauge struct { orig *internal.Gauge state *internal.State } func newGauge(orig *internal.Gauge, state *internal.State) Gauge { return Gauge{orig: orig, state: state} } // NewGauge creates a new empty Gauge. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewGauge() Gauge { return newGauge(internal.NewGauge(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Gauge) MoveTo(dest Gauge) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteGauge(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // DataPoints returns the DataPoints associated with this Gauge. func (ms Gauge) DataPoints() NumberDataPointSlice { return newNumberDataPointSlice(&ms.orig.DataPoints, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Gauge) CopyTo(dest Gauge) { dest.state.AssertMutable() internal.CopyGauge(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_gauge_test.go000066400000000000000000000027351511331344600257750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestGauge_MoveTo(t *testing.T) { ms := generateTestGauge() dest := NewGauge() ms.MoveTo(dest) assert.Equal(t, NewGauge(), ms) assert.Equal(t, generateTestGauge(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestGauge(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newGauge(internal.NewGauge(), sharedState)) }) assert.Panics(t, func() { newGauge(internal.NewGauge(), sharedState).MoveTo(dest) }) } func TestGauge_CopyTo(t *testing.T) { ms := NewGauge() orig := NewGauge() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestGauge() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newGauge(internal.NewGauge(), sharedState)) }) } func TestGauge_DataPoints(t *testing.T) { ms := NewGauge() assert.Equal(t, NewNumberDataPointSlice(), ms.DataPoints()) ms.orig.DataPoints = internal.GenTestNumberDataPointPtrSlice() assert.Equal(t, generateTestNumberDataPointSlice(), ms.DataPoints()) } func generateTestGauge() Gauge { return newGauge(internal.GenTestGauge(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_histogram.go000066400000000000000000000047231511331344600256420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" ) // Histogram represents the type of a metric that is calculated by aggregating as a Histogram of all reported measurements over a time interval. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewHistogram function to create new instances. // Important: zero-initialized instance is not valid for use. type Histogram struct { orig *internal.Histogram state *internal.State } func newHistogram(orig *internal.Histogram, state *internal.State) Histogram { return Histogram{orig: orig, state: state} } // NewHistogram creates a new empty Histogram. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewHistogram() Histogram { return newHistogram(internal.NewHistogram(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Histogram) MoveTo(dest Histogram) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteHistogram(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // DataPoints returns the DataPoints associated with this Histogram. func (ms Histogram) DataPoints() HistogramDataPointSlice { return newHistogramDataPointSlice(&ms.orig.DataPoints, ms.state) } // AggregationTemporality returns the aggregationtemporality associated with this Histogram. func (ms Histogram) AggregationTemporality() AggregationTemporality { return AggregationTemporality(ms.orig.AggregationTemporality) } // SetAggregationTemporality replaces the aggregationtemporality associated with this Histogram. func (ms Histogram) SetAggregationTemporality(v AggregationTemporality) { ms.state.AssertMutable() ms.orig.AggregationTemporality = internal.AggregationTemporality(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Histogram) CopyTo(dest Histogram) { dest.state.AssertMutable() internal.CopyHistogram(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_histogram_test.go000066400000000000000000000037421511331344600267010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestHistogram_MoveTo(t *testing.T) { ms := generateTestHistogram() dest := NewHistogram() ms.MoveTo(dest) assert.Equal(t, NewHistogram(), ms) assert.Equal(t, generateTestHistogram(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestHistogram(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newHistogram(internal.NewHistogram(), sharedState)) }) assert.Panics(t, func() { newHistogram(internal.NewHistogram(), sharedState).MoveTo(dest) }) } func TestHistogram_CopyTo(t *testing.T) { ms := NewHistogram() orig := NewHistogram() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestHistogram() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newHistogram(internal.NewHistogram(), sharedState)) }) } func TestHistogram_DataPoints(t *testing.T) { ms := NewHistogram() assert.Equal(t, NewHistogramDataPointSlice(), ms.DataPoints()) ms.orig.DataPoints = internal.GenTestHistogramDataPointPtrSlice() assert.Equal(t, generateTestHistogramDataPointSlice(), ms.DataPoints()) } func TestHistogram_AggregationTemporality(t *testing.T) { ms := NewHistogram() assert.Equal(t, AggregationTemporality(internal.AggregationTemporality(0)), ms.AggregationTemporality()) testValAggregationTemporality := AggregationTemporality(internal.AggregationTemporality(1)) ms.SetAggregationTemporality(testValAggregationTemporality) assert.Equal(t, testValAggregationTemporality, ms.AggregationTemporality()) } func generateTestHistogram() Histogram { return newHistogram(internal.GenTestHistogram(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_histogramdatapoint.go000066400000000000000000000143751511331344600275520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // HistogramDataPoint is a single data point in a timeseries that describes the time-varying values of a Histogram of values. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewHistogramDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type HistogramDataPoint struct { orig *internal.HistogramDataPoint state *internal.State } func newHistogramDataPoint(orig *internal.HistogramDataPoint, state *internal.State) HistogramDataPoint { return HistogramDataPoint{orig: orig, state: state} } // NewHistogramDataPoint creates a new empty HistogramDataPoint. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewHistogramDataPoint() HistogramDataPoint { return newHistogramDataPoint(internal.NewHistogramDataPoint(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms HistogramDataPoint) MoveTo(dest HistogramDataPoint) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteHistogramDataPoint(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Attributes returns the Attributes associated with this HistogramDataPoint. func (ms HistogramDataPoint) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this HistogramDataPoint. func (ms HistogramDataPoint) StartTimestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.StartTimeUnixNano) } // SetStartTimestamp replaces the starttimestamp associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetStartTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } // Timestamp returns the timestamp associated with this HistogramDataPoint. func (ms HistogramDataPoint) Timestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTimestamp replaces the timestamp associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // Count returns the count associated with this HistogramDataPoint. func (ms HistogramDataPoint) Count() uint64 { return ms.orig.Count } // SetCount replaces the count associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetCount(v uint64) { ms.state.AssertMutable() ms.orig.Count = v } // Sum returns the sum associated with this HistogramDataPoint. func (ms HistogramDataPoint) Sum() float64 { return ms.orig.GetSum() } // HasSum returns true if the HistogramDataPoint contains a // Sum value otherwise. func (ms HistogramDataPoint) HasSum() bool { return ms.orig.Sum_ != nil } // SetSum replaces the sum associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetSum(v float64) { ms.state.AssertMutable() ms.orig.Sum_ = &internal.HistogramDataPoint_Sum{Sum: v} } // RemoveSum removes the sum associated with this HistogramDataPoint. func (ms HistogramDataPoint) RemoveSum() { ms.state.AssertMutable() ms.orig.Sum_ = nil } // BucketCounts returns the BucketCounts associated with this HistogramDataPoint. func (ms HistogramDataPoint) BucketCounts() pcommon.UInt64Slice { return pcommon.UInt64Slice(internal.NewUInt64SliceWrapper(&ms.orig.BucketCounts, ms.state)) } // ExplicitBounds returns the ExplicitBounds associated with this HistogramDataPoint. func (ms HistogramDataPoint) ExplicitBounds() pcommon.Float64Slice { return pcommon.Float64Slice(internal.NewFloat64SliceWrapper(&ms.orig.ExplicitBounds, ms.state)) } // Exemplars returns the Exemplars associated with this HistogramDataPoint. func (ms HistogramDataPoint) Exemplars() ExemplarSlice { return newExemplarSlice(&ms.orig.Exemplars, ms.state) } // Flags returns the flags associated with this HistogramDataPoint. func (ms HistogramDataPoint) Flags() DataPointFlags { return DataPointFlags(ms.orig.Flags) } // SetFlags replaces the flags associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetFlags(v DataPointFlags) { ms.state.AssertMutable() ms.orig.Flags = uint32(v) } // Min returns the min associated with this HistogramDataPoint. func (ms HistogramDataPoint) Min() float64 { return ms.orig.GetMin() } // HasMin returns true if the HistogramDataPoint contains a // Min value otherwise. func (ms HistogramDataPoint) HasMin() bool { return ms.orig.Min_ != nil } // SetMin replaces the min associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetMin(v float64) { ms.state.AssertMutable() ms.orig.Min_ = &internal.HistogramDataPoint_Min{Min: v} } // RemoveMin removes the min associated with this HistogramDataPoint. func (ms HistogramDataPoint) RemoveMin() { ms.state.AssertMutable() ms.orig.Min_ = nil } // Max returns the max associated with this HistogramDataPoint. func (ms HistogramDataPoint) Max() float64 { return ms.orig.GetMax() } // HasMax returns true if the HistogramDataPoint contains a // Max value otherwise. func (ms HistogramDataPoint) HasMax() bool { return ms.orig.Max_ != nil } // SetMax replaces the max associated with this HistogramDataPoint. func (ms HistogramDataPoint) SetMax(v float64) { ms.state.AssertMutable() ms.orig.Max_ = &internal.HistogramDataPoint_Max{Max: v} } // RemoveMax removes the max associated with this HistogramDataPoint. func (ms HistogramDataPoint) RemoveMax() { ms.state.AssertMutable() ms.orig.Max_ = nil } // CopyTo copies all properties from the current struct overriding the destination. func (ms HistogramDataPoint) CopyTo(dest HistogramDataPoint) { dest.state.AssertMutable() internal.CopyHistogramDataPoint(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_histogramdatapoint_test.go000066400000000000000000000117731511331344600306100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestHistogramDataPoint_MoveTo(t *testing.T) { ms := generateTestHistogramDataPoint() dest := NewHistogramDataPoint() ms.MoveTo(dest) assert.Equal(t, NewHistogramDataPoint(), ms) assert.Equal(t, generateTestHistogramDataPoint(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestHistogramDataPoint(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newHistogramDataPoint(internal.NewHistogramDataPoint(), sharedState)) }) assert.Panics(t, func() { newHistogramDataPoint(internal.NewHistogramDataPoint(), sharedState).MoveTo(dest) }) } func TestHistogramDataPoint_CopyTo(t *testing.T) { ms := NewHistogramDataPoint() orig := NewHistogramDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestHistogramDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newHistogramDataPoint(internal.NewHistogramDataPoint(), sharedState)) }) } func TestHistogramDataPoint_Attributes(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestHistogramDataPoint_StartTimestamp(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.StartTimestamp()) testValStartTimestamp := pcommon.Timestamp(1234567890) ms.SetStartTimestamp(testValStartTimestamp) assert.Equal(t, testValStartTimestamp, ms.StartTimestamp()) } func TestHistogramDataPoint_Timestamp(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.Timestamp()) testValTimestamp := pcommon.Timestamp(1234567890) ms.SetTimestamp(testValTimestamp) assert.Equal(t, testValTimestamp, ms.Timestamp()) } func TestHistogramDataPoint_Count(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, uint64(0), ms.Count()) ms.SetCount(uint64(13)) assert.Equal(t, uint64(13), ms.Count()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newHistogramDataPoint(internal.NewHistogramDataPoint(), sharedState).SetCount(uint64(13)) }) } func TestHistogramDataPoint_Sum(t *testing.T) { ms := NewHistogramDataPoint() assert.InDelta(t, float64(0), ms.Sum(), 0.01) ms.SetSum(float64(3.1415926)) assert.True(t, ms.HasSum()) assert.InDelta(t, float64(3.1415926), ms.Sum(), 0.01) ms.RemoveSum() assert.False(t, ms.HasSum()) dest := NewHistogramDataPoint() dest.SetSum(float64(3.1415926)) ms.CopyTo(dest) assert.False(t, dest.HasSum()) } func TestHistogramDataPoint_BucketCounts(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, pcommon.NewUInt64Slice(), ms.BucketCounts()) ms.orig.BucketCounts = internal.GenTestUint64Slice() assert.Equal(t, pcommon.UInt64Slice(internal.GenTestUInt64SliceWrapper()), ms.BucketCounts()) } func TestHistogramDataPoint_ExplicitBounds(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, pcommon.NewFloat64Slice(), ms.ExplicitBounds()) ms.orig.ExplicitBounds = internal.GenTestFloat64Slice() assert.Equal(t, pcommon.Float64Slice(internal.GenTestFloat64SliceWrapper()), ms.ExplicitBounds()) } func TestHistogramDataPoint_Exemplars(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, NewExemplarSlice(), ms.Exemplars()) ms.orig.Exemplars = internal.GenTestExemplarSlice() assert.Equal(t, generateTestExemplarSlice(), ms.Exemplars()) } func TestHistogramDataPoint_Flags(t *testing.T) { ms := NewHistogramDataPoint() assert.Equal(t, DataPointFlags(0), ms.Flags()) testValFlags := DataPointFlags(1) ms.SetFlags(testValFlags) assert.Equal(t, testValFlags, ms.Flags()) } func TestHistogramDataPoint_Min(t *testing.T) { ms := NewHistogramDataPoint() assert.InDelta(t, float64(0), ms.Min(), 0.01) ms.SetMin(float64(3.1415926)) assert.True(t, ms.HasMin()) assert.InDelta(t, float64(3.1415926), ms.Min(), 0.01) ms.RemoveMin() assert.False(t, ms.HasMin()) dest := NewHistogramDataPoint() dest.SetMin(float64(3.1415926)) ms.CopyTo(dest) assert.False(t, dest.HasMin()) } func TestHistogramDataPoint_Max(t *testing.T) { ms := NewHistogramDataPoint() assert.InDelta(t, float64(0), ms.Max(), 0.01) ms.SetMax(float64(3.1415926)) assert.True(t, ms.HasMax()) assert.InDelta(t, float64(3.1415926), ms.Max(), 0.01) ms.RemoveMax() assert.False(t, ms.HasMax()) dest := NewHistogramDataPoint() dest.SetMax(float64(3.1415926)) ms.CopyTo(dest) assert.False(t, dest.HasMax()) } func generateTestHistogramDataPoint() HistogramDataPoint { return newHistogramDataPoint(internal.GenTestHistogramDataPoint(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_histogramdatapointslice.go000066400000000000000000000121271511331344600305630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // HistogramDataPointSlice logically represents a slice of HistogramDataPoint. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewHistogramDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type HistogramDataPointSlice struct { orig *[]*internal.HistogramDataPoint state *internal.State } func newHistogramDataPointSlice(orig *[]*internal.HistogramDataPoint, state *internal.State) HistogramDataPointSlice { return HistogramDataPointSlice{orig: orig, state: state} } // NewHistogramDataPointSlice creates a HistogramDataPointSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewHistogramDataPointSlice() HistogramDataPointSlice { orig := []*internal.HistogramDataPoint(nil) return newHistogramDataPointSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewHistogramDataPointSlice()". func (es HistogramDataPointSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es HistogramDataPointSlice) At(i int) HistogramDataPoint { return newHistogramDataPoint((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es HistogramDataPointSlice) All() iter.Seq2[int, HistogramDataPoint] { return func(yield func(int, HistogramDataPoint) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new HistogramDataPointSlice can be initialized: // // es := NewHistogramDataPointSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es HistogramDataPointSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.HistogramDataPoint, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty HistogramDataPoint. // It returns the newly added HistogramDataPoint. func (es HistogramDataPointSlice) AppendEmpty() HistogramDataPoint { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewHistogramDataPoint()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es HistogramDataPointSlice) MoveAndAppendTo(dest HistogramDataPointSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es HistogramDataPointSlice) RemoveIf(f func(HistogramDataPoint) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteHistogramDataPoint((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es HistogramDataPointSlice) CopyTo(dest HistogramDataPointSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyHistogramDataPointPtrSlice(*dest.orig, *es.orig) } // Sort sorts the HistogramDataPoint elements within HistogramDataPointSlice given the // provided less function so that two instances of HistogramDataPointSlice // can be compared. func (es HistogramDataPointSlice) Sort(less func(a, b HistogramDataPoint) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_histogramdatapointslice_test.go000066400000000000000000000122271511331344600316230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestHistogramDataPointSlice(t *testing.T) { es := NewHistogramDataPointSlice() assert.Equal(t, 0, es.Len()) es = newHistogramDataPointSlice(&[]*internal.HistogramDataPoint{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewHistogramDataPoint() testVal := generateTestHistogramDataPoint() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestHistogramDataPoint() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestHistogramDataPointSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newHistogramDataPointSlice(&[]*internal.HistogramDataPoint{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewHistogramDataPointSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestHistogramDataPointSlice_CopyTo(t *testing.T) { dest := NewHistogramDataPointSlice() src := generateTestHistogramDataPointSlice() src.CopyTo(dest) assert.Equal(t, generateTestHistogramDataPointSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestHistogramDataPointSlice(), dest) } func TestHistogramDataPointSlice_EnsureCapacity(t *testing.T) { es := generateTestHistogramDataPointSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestHistogramDataPointSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestHistogramDataPointSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestHistogramDataPointSlice(), es) } func TestHistogramDataPointSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestHistogramDataPointSlice() dest := NewHistogramDataPointSlice() src := generateTestHistogramDataPointSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestHistogramDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestHistogramDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestHistogramDataPointSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestHistogramDataPointSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewHistogramDataPointSlice() emptySlice.RemoveIf(func(el HistogramDataPoint) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestHistogramDataPointSlice() pos := 0 filtered.RemoveIf(func(el HistogramDataPoint) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestHistogramDataPointSlice_RemoveIfAll(t *testing.T) { got := generateTestHistogramDataPointSlice() got.RemoveIf(func(el HistogramDataPoint) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestHistogramDataPointSliceAll(t *testing.T) { ms := generateTestHistogramDataPointSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestHistogramDataPointSlice_Sort(t *testing.T) { es := generateTestHistogramDataPointSlice() es.Sort(func(a, b HistogramDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b HistogramDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestHistogramDataPointSlice() HistogramDataPointSlice { ms := NewHistogramDataPointSlice() *ms.orig = internal.GenTestHistogramDataPointPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_metric.go000066400000000000000000000212011511331344600251160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Metric represents one metric as a collection of datapoints. // See Metric definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/metrics/v1/metrics.proto // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewMetric function to create new instances. // Important: zero-initialized instance is not valid for use. type Metric struct { orig *internal.Metric state *internal.State } func newMetric(orig *internal.Metric, state *internal.State) Metric { return Metric{orig: orig, state: state} } // NewMetric creates a new empty Metric. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewMetric() Metric { return newMetric(internal.NewMetric(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Metric) MoveTo(dest Metric) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteMetric(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Name returns the name associated with this Metric. func (ms Metric) Name() string { return ms.orig.Name } // SetName replaces the name associated with this Metric. func (ms Metric) SetName(v string) { ms.state.AssertMutable() ms.orig.Name = v } // Description returns the description associated with this Metric. func (ms Metric) Description() string { return ms.orig.Description } // SetDescription replaces the description associated with this Metric. func (ms Metric) SetDescription(v string) { ms.state.AssertMutable() ms.orig.Description = v } // Unit returns the unit associated with this Metric. func (ms Metric) Unit() string { return ms.orig.Unit } // SetUnit replaces the unit associated with this Metric. func (ms Metric) SetUnit(v string) { ms.state.AssertMutable() ms.orig.Unit = v } // Type returns the type of the data for this Metric. // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) Type() MetricType { switch ms.orig.Data.(type) { case *internal.Metric_Gauge: return MetricTypeGauge case *internal.Metric_Sum: return MetricTypeSum case *internal.Metric_Histogram: return MetricTypeHistogram case *internal.Metric_ExponentialHistogram: return MetricTypeExponentialHistogram case *internal.Metric_Summary: return MetricTypeSummary } return MetricTypeEmpty } // Gauge returns the gauge associated with this Metric. // // Calling this function when Type() != MetricTypeGauge returns an invalid // zero-initialized instance of Gauge. Note that using such Gauge instance can cause panic. // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) Gauge() Gauge { v, ok := ms.orig.GetData().(*internal.Metric_Gauge) if !ok { return Gauge{} } return newGauge(v.Gauge, ms.state) } // SetEmptyGauge sets an empty gauge to this Metric. // // After this, Type() function will return MetricTypeGauge". // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptyGauge() Gauge { ms.state.AssertMutable() var ov *internal.Metric_Gauge if !internal.UseProtoPooling.IsEnabled() { ov = &internal.Metric_Gauge{} } else { ov = internal.ProtoPoolMetric_Gauge.Get().(*internal.Metric_Gauge) } ov.Gauge = internal.NewGauge() ms.orig.Data = ov return newGauge(ov.Gauge, ms.state) } // Sum returns the sum associated with this Metric. // // Calling this function when Type() != MetricTypeSum returns an invalid // zero-initialized instance of Sum. Note that using such Sum instance can cause panic. // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) Sum() Sum { v, ok := ms.orig.GetData().(*internal.Metric_Sum) if !ok { return Sum{} } return newSum(v.Sum, ms.state) } // SetEmptySum sets an empty sum to this Metric. // // After this, Type() function will return MetricTypeSum". // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptySum() Sum { ms.state.AssertMutable() var ov *internal.Metric_Sum if !internal.UseProtoPooling.IsEnabled() { ov = &internal.Metric_Sum{} } else { ov = internal.ProtoPoolMetric_Sum.Get().(*internal.Metric_Sum) } ov.Sum = internal.NewSum() ms.orig.Data = ov return newSum(ov.Sum, ms.state) } // Histogram returns the histogram associated with this Metric. // // Calling this function when Type() != MetricTypeHistogram returns an invalid // zero-initialized instance of Histogram. Note that using such Histogram instance can cause panic. // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) Histogram() Histogram { v, ok := ms.orig.GetData().(*internal.Metric_Histogram) if !ok { return Histogram{} } return newHistogram(v.Histogram, ms.state) } // SetEmptyHistogram sets an empty histogram to this Metric. // // After this, Type() function will return MetricTypeHistogram". // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptyHistogram() Histogram { ms.state.AssertMutable() var ov *internal.Metric_Histogram if !internal.UseProtoPooling.IsEnabled() { ov = &internal.Metric_Histogram{} } else { ov = internal.ProtoPoolMetric_Histogram.Get().(*internal.Metric_Histogram) } ov.Histogram = internal.NewHistogram() ms.orig.Data = ov return newHistogram(ov.Histogram, ms.state) } // ExponentialHistogram returns the exponentialhistogram associated with this Metric. // // Calling this function when Type() != MetricTypeExponentialHistogram returns an invalid // zero-initialized instance of ExponentialHistogram. Note that using such ExponentialHistogram instance can cause panic. // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) ExponentialHistogram() ExponentialHistogram { v, ok := ms.orig.GetData().(*internal.Metric_ExponentialHistogram) if !ok { return ExponentialHistogram{} } return newExponentialHistogram(v.ExponentialHistogram, ms.state) } // SetEmptyExponentialHistogram sets an empty exponentialhistogram to this Metric. // // After this, Type() function will return MetricTypeExponentialHistogram". // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptyExponentialHistogram() ExponentialHistogram { ms.state.AssertMutable() var ov *internal.Metric_ExponentialHistogram if !internal.UseProtoPooling.IsEnabled() { ov = &internal.Metric_ExponentialHistogram{} } else { ov = internal.ProtoPoolMetric_ExponentialHistogram.Get().(*internal.Metric_ExponentialHistogram) } ov.ExponentialHistogram = internal.NewExponentialHistogram() ms.orig.Data = ov return newExponentialHistogram(ov.ExponentialHistogram, ms.state) } // Summary returns the summary associated with this Metric. // // Calling this function when Type() != MetricTypeSummary returns an invalid // zero-initialized instance of Summary. Note that using such Summary instance can cause panic. // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) Summary() Summary { v, ok := ms.orig.GetData().(*internal.Metric_Summary) if !ok { return Summary{} } return newSummary(v.Summary, ms.state) } // SetEmptySummary sets an empty summary to this Metric. // // After this, Type() function will return MetricTypeSummary". // // Calling this function on zero-initialized Metric will cause a panic. func (ms Metric) SetEmptySummary() Summary { ms.state.AssertMutable() var ov *internal.Metric_Summary if !internal.UseProtoPooling.IsEnabled() { ov = &internal.Metric_Summary{} } else { ov = internal.ProtoPoolMetric_Summary.Get().(*internal.Metric_Summary) } ov.Summary = internal.NewSummary() ms.orig.Data = ov return newSummary(ov.Summary, ms.state) } // Metadata returns the Metadata associated with this Metric. func (ms Metric) Metadata() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Metadata, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Metric) CopyTo(dest Metric) { dest.state.AssertMutable() internal.CopyMetric(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_metric_test.go000066400000000000000000000117451511331344600261710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestMetric_MoveTo(t *testing.T) { ms := generateTestMetric() dest := NewMetric() ms.MoveTo(dest) assert.Equal(t, NewMetric(), ms) assert.Equal(t, generateTestMetric(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestMetric(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newMetric(internal.NewMetric(), sharedState)) }) assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).MoveTo(dest) }) } func TestMetric_CopyTo(t *testing.T) { ms := NewMetric() orig := NewMetric() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestMetric() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newMetric(internal.NewMetric(), sharedState)) }) } func TestMetric_Name(t *testing.T) { ms := NewMetric() assert.Empty(t, ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetName("test_name") }) } func TestMetric_Description(t *testing.T) { ms := NewMetric() assert.Empty(t, ms.Description()) ms.SetDescription("test_description") assert.Equal(t, "test_description", ms.Description()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetDescription("test_description") }) } func TestMetric_Unit(t *testing.T) { ms := NewMetric() assert.Empty(t, ms.Unit()) ms.SetUnit("test_unit") assert.Equal(t, "test_unit", ms.Unit()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetUnit("test_unit") }) } func TestMetric_Type(t *testing.T) { tv := NewMetric() assert.Equal(t, MetricTypeEmpty, tv.Type()) } func TestMetric_Gauge(t *testing.T) { ms := NewMetric() ms.SetEmptyGauge() assert.Equal(t, NewGauge(), ms.Gauge()) ms.orig.GetData().(*internal.Metric_Gauge).Gauge = internal.GenTestGauge() assert.Equal(t, MetricTypeGauge, ms.Type()) assert.Equal(t, generateTestGauge(), ms.Gauge()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetEmptyGauge() }) } func TestMetric_Sum(t *testing.T) { ms := NewMetric() ms.SetEmptySum() assert.Equal(t, NewSum(), ms.Sum()) ms.orig.GetData().(*internal.Metric_Sum).Sum = internal.GenTestSum() assert.Equal(t, MetricTypeSum, ms.Type()) assert.Equal(t, generateTestSum(), ms.Sum()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetEmptySum() }) } func TestMetric_Histogram(t *testing.T) { ms := NewMetric() ms.SetEmptyHistogram() assert.Equal(t, NewHistogram(), ms.Histogram()) ms.orig.GetData().(*internal.Metric_Histogram).Histogram = internal.GenTestHistogram() assert.Equal(t, MetricTypeHistogram, ms.Type()) assert.Equal(t, generateTestHistogram(), ms.Histogram()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetEmptyHistogram() }) } func TestMetric_ExponentialHistogram(t *testing.T) { ms := NewMetric() ms.SetEmptyExponentialHistogram() assert.Equal(t, NewExponentialHistogram(), ms.ExponentialHistogram()) ms.orig.GetData().(*internal.Metric_ExponentialHistogram).ExponentialHistogram = internal.GenTestExponentialHistogram() assert.Equal(t, MetricTypeExponentialHistogram, ms.Type()) assert.Equal(t, generateTestExponentialHistogram(), ms.ExponentialHistogram()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetEmptyExponentialHistogram() }) } func TestMetric_Summary(t *testing.T) { ms := NewMetric() ms.SetEmptySummary() assert.Equal(t, NewSummary(), ms.Summary()) ms.orig.GetData().(*internal.Metric_Summary).Summary = internal.GenTestSummary() assert.Equal(t, MetricTypeSummary, ms.Type()) assert.Equal(t, generateTestSummary(), ms.Summary()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMetric(internal.NewMetric(), sharedState).SetEmptySummary() }) } func TestMetric_Metadata(t *testing.T) { ms := NewMetric() assert.Equal(t, pcommon.NewMap(), ms.Metadata()) ms.orig.Metadata = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Metadata()) } func generateTestMetric() Metric { return newMetric(internal.GenTestMetric(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_metrics.go000066400000000000000000000045301511331344600253070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" ) // Metrics is the top-level struct that is propagated through the metrics pipeline. // Use NewMetrics to create new instance, zero-initialized instance is not valid for use. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewMetrics function to create new instances. // Important: zero-initialized instance is not valid for use. type Metrics internal.MetricsWrapper func newMetrics(orig *internal.ExportMetricsServiceRequest, state *internal.State) Metrics { return Metrics(internal.NewMetricsWrapper(orig, state)) } // NewMetrics creates a new empty Metrics. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewMetrics() Metrics { return newMetrics(internal.NewExportMetricsServiceRequest(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Metrics) MoveTo(dest Metrics) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteExportMetricsServiceRequest(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // ResourceMetrics returns the ResourceMetrics associated with this Metrics. func (ms Metrics) ResourceMetrics() ResourceMetricsSlice { return newResourceMetricsSlice(&ms.getOrig().ResourceMetrics, ms.getState()) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Metrics) CopyTo(dest Metrics) { dest.getState().AssertMutable() internal.CopyExportMetricsServiceRequest(dest.getOrig(), ms.getOrig()) } func (ms Metrics) getOrig() *internal.ExportMetricsServiceRequest { return internal.GetMetricsOrig(internal.MetricsWrapper(ms)) } func (ms Metrics) getState() *internal.State { return internal.GetMetricsState(internal.MetricsWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_metrics_test.go000066400000000000000000000031621511331344600263460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestMetrics_MoveTo(t *testing.T) { ms := generateTestMetrics() dest := NewMetrics() ms.MoveTo(dest) assert.Equal(t, NewMetrics(), ms) assert.Equal(t, generateTestMetrics(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestMetrics(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newMetrics(internal.NewExportMetricsServiceRequest(), sharedState)) }) assert.Panics(t, func() { newMetrics(internal.NewExportMetricsServiceRequest(), sharedState).MoveTo(dest) }) } func TestMetrics_CopyTo(t *testing.T) { ms := NewMetrics() orig := NewMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newMetrics(internal.NewExportMetricsServiceRequest(), sharedState)) }) } func TestMetrics_ResourceMetrics(t *testing.T) { ms := NewMetrics() assert.Equal(t, NewResourceMetricsSlice(), ms.ResourceMetrics()) ms.getOrig().ResourceMetrics = internal.GenTestResourceMetricsPtrSlice() assert.Equal(t, generateTestResourceMetricsSlice(), ms.ResourceMetrics()) } func generateTestMetrics() Metrics { return newMetrics(internal.GenTestExportMetricsServiceRequest(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_metricslice.go000066400000000000000000000110731511331344600261440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // MetricSlice logically represents a slice of Metric. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewMetricSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type MetricSlice struct { orig *[]*internal.Metric state *internal.State } func newMetricSlice(orig *[]*internal.Metric, state *internal.State) MetricSlice { return MetricSlice{orig: orig, state: state} } // NewMetricSlice creates a MetricSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewMetricSlice() MetricSlice { orig := []*internal.Metric(nil) return newMetricSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewMetricSlice()". func (es MetricSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es MetricSlice) At(i int) Metric { return newMetric((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es MetricSlice) All() iter.Seq2[int, Metric] { return func(yield func(int, Metric) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new MetricSlice can be initialized: // // es := NewMetricSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es MetricSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Metric, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Metric. // It returns the newly added Metric. func (es MetricSlice) AppendEmpty() Metric { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewMetric()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es MetricSlice) MoveAndAppendTo(dest MetricSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es MetricSlice) RemoveIf(f func(Metric) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteMetric((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es MetricSlice) CopyTo(dest MetricSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyMetricPtrSlice(*dest.orig, *es.orig) } // Sort sorts the Metric elements within MetricSlice given the // provided less function so that two instances of MetricSlice // can be compared. func (es MetricSlice) Sort(less func(a, b Metric) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_metricslice_test.go000066400000000000000000000111571511331344600272060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestMetricSlice(t *testing.T) { es := NewMetricSlice() assert.Equal(t, 0, es.Len()) es = newMetricSlice(&[]*internal.Metric{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewMetric() testVal := generateTestMetric() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestMetric() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestMetricSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newMetricSlice(&[]*internal.Metric{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewMetricSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestMetricSlice_CopyTo(t *testing.T) { dest := NewMetricSlice() src := generateTestMetricSlice() src.CopyTo(dest) assert.Equal(t, generateTestMetricSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestMetricSlice(), dest) } func TestMetricSlice_EnsureCapacity(t *testing.T) { es := generateTestMetricSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestMetricSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestMetricSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestMetricSlice(), es) } func TestMetricSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestMetricSlice() dest := NewMetricSlice() src := generateTestMetricSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestMetricSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestMetricSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestMetricSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestMetricSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewMetricSlice() emptySlice.RemoveIf(func(el Metric) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestMetricSlice() pos := 0 filtered.RemoveIf(func(el Metric) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestMetricSlice_RemoveIfAll(t *testing.T) { got := generateTestMetricSlice() got.RemoveIf(func(el Metric) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestMetricSliceAll(t *testing.T) { ms := generateTestMetricSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestMetricSlice_Sort(t *testing.T) { es := generateTestMetricSlice() es.Sort(func(a, b Metric) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Metric) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestMetricSlice() MetricSlice { ms := NewMetricSlice() *ms.orig = internal.GenTestMetricPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_numberdatapoint.go000066400000000000000000000117201511331344600270340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // NumberDataPoint is a single data point in a timeseries that describes the time-varying value of a number metric. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewNumberDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type NumberDataPoint struct { orig *internal.NumberDataPoint state *internal.State } func newNumberDataPoint(orig *internal.NumberDataPoint, state *internal.State) NumberDataPoint { return NumberDataPoint{orig: orig, state: state} } // NewNumberDataPoint creates a new empty NumberDataPoint. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewNumberDataPoint() NumberDataPoint { return newNumberDataPoint(internal.NewNumberDataPoint(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms NumberDataPoint) MoveTo(dest NumberDataPoint) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteNumberDataPoint(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Attributes returns the Attributes associated with this NumberDataPoint. func (ms NumberDataPoint) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this NumberDataPoint. func (ms NumberDataPoint) StartTimestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.StartTimeUnixNano) } // SetStartTimestamp replaces the starttimestamp associated with this NumberDataPoint. func (ms NumberDataPoint) SetStartTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } // Timestamp returns the timestamp associated with this NumberDataPoint. func (ms NumberDataPoint) Timestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTimestamp replaces the timestamp associated with this NumberDataPoint. func (ms NumberDataPoint) SetTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // ValueType returns the type of the value for this NumberDataPoint. // Calling this function on zero-initialized NumberDataPoint will cause a panic. func (ms NumberDataPoint) ValueType() NumberDataPointValueType { switch ms.orig.Value.(type) { case *internal.NumberDataPoint_AsDouble: return NumberDataPointValueTypeDouble case *internal.NumberDataPoint_AsInt: return NumberDataPointValueTypeInt } return NumberDataPointValueTypeEmpty } // DoubleValue returns the double associated with this NumberDataPoint. func (ms NumberDataPoint) DoubleValue() float64 { return ms.orig.GetAsDouble() } // SetDoubleValue replaces the double associated with this NumberDataPoint. func (ms NumberDataPoint) SetDoubleValue(v float64) { ms.state.AssertMutable() var ov *internal.NumberDataPoint_AsDouble if !internal.UseProtoPooling.IsEnabled() { ov = &internal.NumberDataPoint_AsDouble{} } else { ov = internal.ProtoPoolNumberDataPoint_AsDouble.Get().(*internal.NumberDataPoint_AsDouble) } ov.AsDouble = v ms.orig.Value = ov } // IntValue returns the int associated with this NumberDataPoint. func (ms NumberDataPoint) IntValue() int64 { return ms.orig.GetAsInt() } // SetIntValue replaces the int associated with this NumberDataPoint. func (ms NumberDataPoint) SetIntValue(v int64) { ms.state.AssertMutable() var ov *internal.NumberDataPoint_AsInt if !internal.UseProtoPooling.IsEnabled() { ov = &internal.NumberDataPoint_AsInt{} } else { ov = internal.ProtoPoolNumberDataPoint_AsInt.Get().(*internal.NumberDataPoint_AsInt) } ov.AsInt = v ms.orig.Value = ov } // Exemplars returns the Exemplars associated with this NumberDataPoint. func (ms NumberDataPoint) Exemplars() ExemplarSlice { return newExemplarSlice(&ms.orig.Exemplars, ms.state) } // Flags returns the flags associated with this NumberDataPoint. func (ms NumberDataPoint) Flags() DataPointFlags { return DataPointFlags(ms.orig.Flags) } // SetFlags replaces the flags associated with this NumberDataPoint. func (ms NumberDataPoint) SetFlags(v DataPointFlags) { ms.state.AssertMutable() ms.orig.Flags = uint32(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms NumberDataPoint) CopyTo(dest NumberDataPoint) { dest.state.AssertMutable() internal.CopyNumberDataPoint(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_numberdatapoint_test.go000066400000000000000000000074761511331344600301100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestNumberDataPoint_MoveTo(t *testing.T) { ms := generateTestNumberDataPoint() dest := NewNumberDataPoint() ms.MoveTo(dest) assert.Equal(t, NewNumberDataPoint(), ms) assert.Equal(t, generateTestNumberDataPoint(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestNumberDataPoint(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newNumberDataPoint(internal.NewNumberDataPoint(), sharedState)) }) assert.Panics(t, func() { newNumberDataPoint(internal.NewNumberDataPoint(), sharedState).MoveTo(dest) }) } func TestNumberDataPoint_CopyTo(t *testing.T) { ms := NewNumberDataPoint() orig := NewNumberDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestNumberDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newNumberDataPoint(internal.NewNumberDataPoint(), sharedState)) }) } func TestNumberDataPoint_Attributes(t *testing.T) { ms := NewNumberDataPoint() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestNumberDataPoint_StartTimestamp(t *testing.T) { ms := NewNumberDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.StartTimestamp()) testValStartTimestamp := pcommon.Timestamp(1234567890) ms.SetStartTimestamp(testValStartTimestamp) assert.Equal(t, testValStartTimestamp, ms.StartTimestamp()) } func TestNumberDataPoint_Timestamp(t *testing.T) { ms := NewNumberDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.Timestamp()) testValTimestamp := pcommon.Timestamp(1234567890) ms.SetTimestamp(testValTimestamp) assert.Equal(t, testValTimestamp, ms.Timestamp()) } func TestNumberDataPoint_ValueType(t *testing.T) { tv := NewNumberDataPoint() assert.Equal(t, NumberDataPointValueTypeEmpty, tv.ValueType()) } func TestNumberDataPoint_DoubleValue(t *testing.T) { ms := NewNumberDataPoint() assert.InDelta(t, float64(0), ms.DoubleValue(), 0.01) ms.SetDoubleValue(float64(3.1415926)) assert.InDelta(t, float64(3.1415926), ms.DoubleValue(), 0.01) assert.Equal(t, NumberDataPointValueTypeDouble, ms.ValueType()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newNumberDataPoint(internal.NewNumberDataPoint(), sharedState).SetDoubleValue(float64(3.1415926)) }) } func TestNumberDataPoint_IntValue(t *testing.T) { ms := NewNumberDataPoint() assert.Equal(t, int64(0), ms.IntValue()) ms.SetIntValue(int64(13)) assert.Equal(t, int64(13), ms.IntValue()) assert.Equal(t, NumberDataPointValueTypeInt, ms.ValueType()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newNumberDataPoint(internal.NewNumberDataPoint(), sharedState).SetIntValue(int64(13)) }) } func TestNumberDataPoint_Exemplars(t *testing.T) { ms := NewNumberDataPoint() assert.Equal(t, NewExemplarSlice(), ms.Exemplars()) ms.orig.Exemplars = internal.GenTestExemplarSlice() assert.Equal(t, generateTestExemplarSlice(), ms.Exemplars()) } func TestNumberDataPoint_Flags(t *testing.T) { ms := NewNumberDataPoint() assert.Equal(t, DataPointFlags(0), ms.Flags()) testValFlags := DataPointFlags(1) ms.SetFlags(testValFlags) assert.Equal(t, testValFlags, ms.Flags()) } func generateTestNumberDataPoint() NumberDataPoint { return newNumberDataPoint(internal.GenTestNumberDataPoint(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_numberdatapointslice.go000066400000000000000000000117201511331344600300540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // NumberDataPointSlice logically represents a slice of NumberDataPoint. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewNumberDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type NumberDataPointSlice struct { orig *[]*internal.NumberDataPoint state *internal.State } func newNumberDataPointSlice(orig *[]*internal.NumberDataPoint, state *internal.State) NumberDataPointSlice { return NumberDataPointSlice{orig: orig, state: state} } // NewNumberDataPointSlice creates a NumberDataPointSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewNumberDataPointSlice() NumberDataPointSlice { orig := []*internal.NumberDataPoint(nil) return newNumberDataPointSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewNumberDataPointSlice()". func (es NumberDataPointSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es NumberDataPointSlice) At(i int) NumberDataPoint { return newNumberDataPoint((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es NumberDataPointSlice) All() iter.Seq2[int, NumberDataPoint] { return func(yield func(int, NumberDataPoint) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new NumberDataPointSlice can be initialized: // // es := NewNumberDataPointSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es NumberDataPointSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.NumberDataPoint, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty NumberDataPoint. // It returns the newly added NumberDataPoint. func (es NumberDataPointSlice) AppendEmpty() NumberDataPoint { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewNumberDataPoint()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es NumberDataPointSlice) MoveAndAppendTo(dest NumberDataPointSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es NumberDataPointSlice) RemoveIf(f func(NumberDataPoint) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteNumberDataPoint((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es NumberDataPointSlice) CopyTo(dest NumberDataPointSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyNumberDataPointPtrSlice(*dest.orig, *es.orig) } // Sort sorts the NumberDataPoint elements within NumberDataPointSlice given the // provided less function so that two instances of NumberDataPointSlice // can be compared. func (es NumberDataPointSlice) Sort(less func(a, b NumberDataPoint) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_numberdatapointslice_test.go000066400000000000000000000120151511331344600311110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestNumberDataPointSlice(t *testing.T) { es := NewNumberDataPointSlice() assert.Equal(t, 0, es.Len()) es = newNumberDataPointSlice(&[]*internal.NumberDataPoint{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewNumberDataPoint() testVal := generateTestNumberDataPoint() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestNumberDataPoint() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestNumberDataPointSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newNumberDataPointSlice(&[]*internal.NumberDataPoint{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewNumberDataPointSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestNumberDataPointSlice_CopyTo(t *testing.T) { dest := NewNumberDataPointSlice() src := generateTestNumberDataPointSlice() src.CopyTo(dest) assert.Equal(t, generateTestNumberDataPointSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestNumberDataPointSlice(), dest) } func TestNumberDataPointSlice_EnsureCapacity(t *testing.T) { es := generateTestNumberDataPointSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestNumberDataPointSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestNumberDataPointSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestNumberDataPointSlice(), es) } func TestNumberDataPointSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestNumberDataPointSlice() dest := NewNumberDataPointSlice() src := generateTestNumberDataPointSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestNumberDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestNumberDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestNumberDataPointSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestNumberDataPointSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewNumberDataPointSlice() emptySlice.RemoveIf(func(el NumberDataPoint) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestNumberDataPointSlice() pos := 0 filtered.RemoveIf(func(el NumberDataPoint) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestNumberDataPointSlice_RemoveIfAll(t *testing.T) { got := generateTestNumberDataPointSlice() got.RemoveIf(func(el NumberDataPoint) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestNumberDataPointSliceAll(t *testing.T) { ms := generateTestNumberDataPointSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestNumberDataPointSlice_Sort(t *testing.T) { es := generateTestNumberDataPointSlice() es.Sort(func(a, b NumberDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b NumberDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestNumberDataPointSlice() NumberDataPointSlice { ms := NewNumberDataPointSlice() *ms.orig = internal.GenTestNumberDataPointPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_resourcemetrics.go000066400000000000000000000051261511331344600270610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceMetrics is a collection of metrics from a Resource. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewResourceMetrics function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceMetrics struct { orig *internal.ResourceMetrics state *internal.State } func newResourceMetrics(orig *internal.ResourceMetrics, state *internal.State) ResourceMetrics { return ResourceMetrics{orig: orig, state: state} } // NewResourceMetrics creates a new empty ResourceMetrics. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResourceMetrics() ResourceMetrics { return newResourceMetrics(internal.NewResourceMetrics(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ResourceMetrics) MoveTo(dest ResourceMetrics) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteResourceMetrics(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Resource returns the resource associated with this ResourceMetrics. func (ms ResourceMetrics) Resource() pcommon.Resource { return pcommon.Resource(internal.NewResourceWrapper(&ms.orig.Resource, ms.state)) } // ScopeMetrics returns the ScopeMetrics associated with this ResourceMetrics. func (ms ResourceMetrics) ScopeMetrics() ScopeMetricsSlice { return newScopeMetricsSlice(&ms.orig.ScopeMetrics, ms.state) } // SchemaUrl returns the schemaurl associated with this ResourceMetrics. func (ms ResourceMetrics) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ResourceMetrics. func (ms ResourceMetrics) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ResourceMetrics) CopyTo(dest ResourceMetrics) { dest.state.AssertMutable() internal.CopyResourceMetrics(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_resourcemetrics_test.go000066400000000000000000000045711511331344600301230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestResourceMetrics_MoveTo(t *testing.T) { ms := generateTestResourceMetrics() dest := NewResourceMetrics() ms.MoveTo(dest) assert.Equal(t, NewResourceMetrics(), ms) assert.Equal(t, generateTestResourceMetrics(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestResourceMetrics(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newResourceMetrics(internal.NewResourceMetrics(), sharedState)) }) assert.Panics(t, func() { newResourceMetrics(internal.NewResourceMetrics(), sharedState).MoveTo(dest) }) } func TestResourceMetrics_CopyTo(t *testing.T) { ms := NewResourceMetrics() orig := NewResourceMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestResourceMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newResourceMetrics(internal.NewResourceMetrics(), sharedState)) }) } func TestResourceMetrics_Resource(t *testing.T) { ms := NewResourceMetrics() assert.Equal(t, pcommon.NewResource(), ms.Resource()) ms.orig.Resource = *internal.GenTestResource() assert.Equal(t, pcommon.Resource(internal.GenTestResourceWrapper()), ms.Resource()) } func TestResourceMetrics_ScopeMetrics(t *testing.T) { ms := NewResourceMetrics() assert.Equal(t, NewScopeMetricsSlice(), ms.ScopeMetrics()) ms.orig.ScopeMetrics = internal.GenTestScopeMetricsPtrSlice() assert.Equal(t, generateTestScopeMetricsSlice(), ms.ScopeMetrics()) } func TestResourceMetrics_SchemaUrl(t *testing.T) { ms := NewResourceMetrics() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newResourceMetrics(internal.NewResourceMetrics(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestResourceMetrics() ResourceMetrics { return newResourceMetrics(internal.GenTestResourceMetrics(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_resourcemetricsslice.go000066400000000000000000000117201511331344600300760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ResourceMetricsSlice logically represents a slice of ResourceMetrics. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewResourceMetricsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceMetricsSlice struct { orig *[]*internal.ResourceMetrics state *internal.State } func newResourceMetricsSlice(orig *[]*internal.ResourceMetrics, state *internal.State) ResourceMetricsSlice { return ResourceMetricsSlice{orig: orig, state: state} } // NewResourceMetricsSlice creates a ResourceMetricsSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewResourceMetricsSlice() ResourceMetricsSlice { orig := []*internal.ResourceMetrics(nil) return newResourceMetricsSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewResourceMetricsSlice()". func (es ResourceMetricsSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ResourceMetricsSlice) At(i int) ResourceMetrics { return newResourceMetrics((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ResourceMetricsSlice) All() iter.Seq2[int, ResourceMetrics] { return func(yield func(int, ResourceMetrics) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ResourceMetricsSlice can be initialized: // // es := NewResourceMetricsSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ResourceMetricsSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ResourceMetrics, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ResourceMetrics. // It returns the newly added ResourceMetrics. func (es ResourceMetricsSlice) AppendEmpty() ResourceMetrics { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewResourceMetrics()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceMetricsSlice) MoveAndAppendTo(dest ResourceMetricsSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ResourceMetricsSlice) RemoveIf(f func(ResourceMetrics) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteResourceMetrics((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ResourceMetricsSlice) CopyTo(dest ResourceMetricsSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyResourceMetricsPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ResourceMetrics elements within ResourceMetricsSlice given the // provided less function so that two instances of ResourceMetricsSlice // can be compared. func (es ResourceMetricsSlice) Sort(less func(a, b ResourceMetrics) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_resourcemetricsslice_test.go000066400000000000000000000120151511331344600311330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestResourceMetricsSlice(t *testing.T) { es := NewResourceMetricsSlice() assert.Equal(t, 0, es.Len()) es = newResourceMetricsSlice(&[]*internal.ResourceMetrics{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewResourceMetrics() testVal := generateTestResourceMetrics() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestResourceMetrics() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestResourceMetricsSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newResourceMetricsSlice(&[]*internal.ResourceMetrics{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewResourceMetricsSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestResourceMetricsSlice_CopyTo(t *testing.T) { dest := NewResourceMetricsSlice() src := generateTestResourceMetricsSlice() src.CopyTo(dest) assert.Equal(t, generateTestResourceMetricsSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestResourceMetricsSlice(), dest) } func TestResourceMetricsSlice_EnsureCapacity(t *testing.T) { es := generateTestResourceMetricsSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestResourceMetricsSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestResourceMetricsSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestResourceMetricsSlice(), es) } func TestResourceMetricsSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestResourceMetricsSlice() dest := NewResourceMetricsSlice() src := generateTestResourceMetricsSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceMetricsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceMetricsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestResourceMetricsSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestResourceMetricsSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewResourceMetricsSlice() emptySlice.RemoveIf(func(el ResourceMetrics) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestResourceMetricsSlice() pos := 0 filtered.RemoveIf(func(el ResourceMetrics) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestResourceMetricsSlice_RemoveIfAll(t *testing.T) { got := generateTestResourceMetricsSlice() got.RemoveIf(func(el ResourceMetrics) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestResourceMetricsSliceAll(t *testing.T) { ms := generateTestResourceMetricsSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestResourceMetricsSlice_Sort(t *testing.T) { es := generateTestResourceMetricsSlice() es.Sort(func(a, b ResourceMetrics) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ResourceMetrics) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestResourceMetricsSlice() ResourceMetricsSlice { ms := NewResourceMetricsSlice() *ms.orig = internal.GenTestResourceMetricsPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_scopemetrics.go000066400000000000000000000050101511331344600263330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ScopeMetrics is a collection of metrics from a LibraryInstrumentation. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewScopeMetrics function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeMetrics struct { orig *internal.ScopeMetrics state *internal.State } func newScopeMetrics(orig *internal.ScopeMetrics, state *internal.State) ScopeMetrics { return ScopeMetrics{orig: orig, state: state} } // NewScopeMetrics creates a new empty ScopeMetrics. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewScopeMetrics() ScopeMetrics { return newScopeMetrics(internal.NewScopeMetrics(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ScopeMetrics) MoveTo(dest ScopeMetrics) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteScopeMetrics(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Scope returns the scope associated with this ScopeMetrics. func (ms ScopeMetrics) Scope() pcommon.InstrumentationScope { return pcommon.InstrumentationScope(internal.NewInstrumentationScopeWrapper(&ms.orig.Scope, ms.state)) } // Metrics returns the Metrics associated with this ScopeMetrics. func (ms ScopeMetrics) Metrics() MetricSlice { return newMetricSlice(&ms.orig.Metrics, ms.state) } // SchemaUrl returns the schemaurl associated with this ScopeMetrics. func (ms ScopeMetrics) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ScopeMetrics. func (ms ScopeMetrics) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ScopeMetrics) CopyTo(dest ScopeMetrics) { dest.state.AssertMutable() internal.CopyScopeMetrics(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_scopemetrics_test.go000066400000000000000000000044431511331344600274030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestScopeMetrics_MoveTo(t *testing.T) { ms := generateTestScopeMetrics() dest := NewScopeMetrics() ms.MoveTo(dest) assert.Equal(t, NewScopeMetrics(), ms) assert.Equal(t, generateTestScopeMetrics(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestScopeMetrics(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newScopeMetrics(internal.NewScopeMetrics(), sharedState)) }) assert.Panics(t, func() { newScopeMetrics(internal.NewScopeMetrics(), sharedState).MoveTo(dest) }) } func TestScopeMetrics_CopyTo(t *testing.T) { ms := NewScopeMetrics() orig := NewScopeMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestScopeMetrics() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newScopeMetrics(internal.NewScopeMetrics(), sharedState)) }) } func TestScopeMetrics_Scope(t *testing.T) { ms := NewScopeMetrics() assert.Equal(t, pcommon.NewInstrumentationScope(), ms.Scope()) ms.orig.Scope = *internal.GenTestInstrumentationScope() assert.Equal(t, pcommon.InstrumentationScope(internal.GenTestInstrumentationScopeWrapper()), ms.Scope()) } func TestScopeMetrics_Metrics(t *testing.T) { ms := NewScopeMetrics() assert.Equal(t, NewMetricSlice(), ms.Metrics()) ms.orig.Metrics = internal.GenTestMetricPtrSlice() assert.Equal(t, generateTestMetricSlice(), ms.Metrics()) } func TestScopeMetrics_SchemaUrl(t *testing.T) { ms := NewScopeMetrics() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newScopeMetrics(internal.NewScopeMetrics(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestScopeMetrics() ScopeMetrics { return newScopeMetrics(internal.GenTestScopeMetrics(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_scopemetricsslice.go000066400000000000000000000115111511331344600273560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ScopeMetricsSlice logically represents a slice of ScopeMetrics. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewScopeMetricsSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeMetricsSlice struct { orig *[]*internal.ScopeMetrics state *internal.State } func newScopeMetricsSlice(orig *[]*internal.ScopeMetrics, state *internal.State) ScopeMetricsSlice { return ScopeMetricsSlice{orig: orig, state: state} } // NewScopeMetricsSlice creates a ScopeMetricsSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewScopeMetricsSlice() ScopeMetricsSlice { orig := []*internal.ScopeMetrics(nil) return newScopeMetricsSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewScopeMetricsSlice()". func (es ScopeMetricsSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ScopeMetricsSlice) At(i int) ScopeMetrics { return newScopeMetrics((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ScopeMetricsSlice) All() iter.Seq2[int, ScopeMetrics] { return func(yield func(int, ScopeMetrics) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ScopeMetricsSlice can be initialized: // // es := NewScopeMetricsSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ScopeMetricsSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ScopeMetrics, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ScopeMetrics. // It returns the newly added ScopeMetrics. func (es ScopeMetricsSlice) AppendEmpty() ScopeMetrics { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewScopeMetrics()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ScopeMetricsSlice) MoveAndAppendTo(dest ScopeMetricsSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ScopeMetricsSlice) RemoveIf(f func(ScopeMetrics) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteScopeMetrics((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ScopeMetricsSlice) CopyTo(dest ScopeMetricsSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyScopeMetricsPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ScopeMetrics elements within ScopeMetricsSlice given the // provided less function so that two instances of ScopeMetricsSlice // can be compared. func (es ScopeMetricsSlice) Sort(less func(a, b ScopeMetrics) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_scopemetricsslice_test.go000066400000000000000000000116031511331344600304170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestScopeMetricsSlice(t *testing.T) { es := NewScopeMetricsSlice() assert.Equal(t, 0, es.Len()) es = newScopeMetricsSlice(&[]*internal.ScopeMetrics{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewScopeMetrics() testVal := generateTestScopeMetrics() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestScopeMetrics() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestScopeMetricsSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newScopeMetricsSlice(&[]*internal.ScopeMetrics{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewScopeMetricsSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestScopeMetricsSlice_CopyTo(t *testing.T) { dest := NewScopeMetricsSlice() src := generateTestScopeMetricsSlice() src.CopyTo(dest) assert.Equal(t, generateTestScopeMetricsSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestScopeMetricsSlice(), dest) } func TestScopeMetricsSlice_EnsureCapacity(t *testing.T) { es := generateTestScopeMetricsSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestScopeMetricsSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestScopeMetricsSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestScopeMetricsSlice(), es) } func TestScopeMetricsSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestScopeMetricsSlice() dest := NewScopeMetricsSlice() src := generateTestScopeMetricsSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeMetricsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeMetricsSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestScopeMetricsSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestScopeMetricsSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewScopeMetricsSlice() emptySlice.RemoveIf(func(el ScopeMetrics) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestScopeMetricsSlice() pos := 0 filtered.RemoveIf(func(el ScopeMetrics) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestScopeMetricsSlice_RemoveIfAll(t *testing.T) { got := generateTestScopeMetricsSlice() got.RemoveIf(func(el ScopeMetrics) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestScopeMetricsSliceAll(t *testing.T) { ms := generateTestScopeMetricsSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestScopeMetricsSlice_Sort(t *testing.T) { es := generateTestScopeMetricsSlice() es.Sort(func(a, b ScopeMetrics) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ScopeMetrics) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestScopeMetricsSlice() ScopeMetricsSlice { ms := NewScopeMetricsSlice() *ms.orig = internal.GenTestScopeMetricsPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_sum.go000066400000000000000000000051111511331344600244410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" ) // Sum represents the type of a numeric metric that is calculated as a sum of all reported measurements over a time interval. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSum function to create new instances. // Important: zero-initialized instance is not valid for use. type Sum struct { orig *internal.Sum state *internal.State } func newSum(orig *internal.Sum, state *internal.State) Sum { return Sum{orig: orig, state: state} } // NewSum creates a new empty Sum. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSum() Sum { return newSum(internal.NewSum(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Sum) MoveTo(dest Sum) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSum(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // DataPoints returns the DataPoints associated with this Sum. func (ms Sum) DataPoints() NumberDataPointSlice { return newNumberDataPointSlice(&ms.orig.DataPoints, ms.state) } // AggregationTemporality returns the aggregationtemporality associated with this Sum. func (ms Sum) AggregationTemporality() AggregationTemporality { return AggregationTemporality(ms.orig.AggregationTemporality) } // SetAggregationTemporality replaces the aggregationtemporality associated with this Sum. func (ms Sum) SetAggregationTemporality(v AggregationTemporality) { ms.state.AssertMutable() ms.orig.AggregationTemporality = internal.AggregationTemporality(v) } // IsMonotonic returns the ismonotonic associated with this Sum. func (ms Sum) IsMonotonic() bool { return ms.orig.IsMonotonic } // SetIsMonotonic replaces the ismonotonic associated with this Sum. func (ms Sum) SetIsMonotonic(v bool) { ms.state.AssertMutable() ms.orig.IsMonotonic = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms Sum) CopyTo(dest Sum) { dest.state.AssertMutable() internal.CopySum(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_sum_test.go000066400000000000000000000041751511331344600255110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSum_MoveTo(t *testing.T) { ms := generateTestSum() dest := NewSum() ms.MoveTo(dest) assert.Equal(t, NewSum(), ms) assert.Equal(t, generateTestSum(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSum(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSum(internal.NewSum(), sharedState)) }) assert.Panics(t, func() { newSum(internal.NewSum(), sharedState).MoveTo(dest) }) } func TestSum_CopyTo(t *testing.T) { ms := NewSum() orig := NewSum() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSum() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSum(internal.NewSum(), sharedState)) }) } func TestSum_DataPoints(t *testing.T) { ms := NewSum() assert.Equal(t, NewNumberDataPointSlice(), ms.DataPoints()) ms.orig.DataPoints = internal.GenTestNumberDataPointPtrSlice() assert.Equal(t, generateTestNumberDataPointSlice(), ms.DataPoints()) } func TestSum_AggregationTemporality(t *testing.T) { ms := NewSum() assert.Equal(t, AggregationTemporality(internal.AggregationTemporality(0)), ms.AggregationTemporality()) testValAggregationTemporality := AggregationTemporality(internal.AggregationTemporality(1)) ms.SetAggregationTemporality(testValAggregationTemporality) assert.Equal(t, testValAggregationTemporality, ms.AggregationTemporality()) } func TestSum_IsMonotonic(t *testing.T) { ms := NewSum() assert.False(t, ms.IsMonotonic()) ms.SetIsMonotonic(true) assert.True(t, ms.IsMonotonic()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSum(internal.NewSum(), sharedState).SetIsMonotonic(true) }) } func generateTestSum() Sum { return newSum(internal.GenTestSum(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summary.go000066400000000000000000000036661511331344600253470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" ) // Summary represents the type of a metric that is calculated by aggregating as a Summary of all reported double measurements over a time interval. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSummary function to create new instances. // Important: zero-initialized instance is not valid for use. type Summary struct { orig *internal.Summary state *internal.State } func newSummary(orig *internal.Summary, state *internal.State) Summary { return Summary{orig: orig, state: state} } // NewSummary creates a new empty Summary. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSummary() Summary { return newSummary(internal.NewSummary(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Summary) MoveTo(dest Summary) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSummary(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // DataPoints returns the DataPoints associated with this Summary. func (ms Summary) DataPoints() SummaryDataPointSlice { return newSummaryDataPointSlice(&ms.orig.DataPoints, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Summary) CopyTo(dest Summary) { dest.state.AssertMutable() internal.CopySummary(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summary_test.go000066400000000000000000000030141511331344600263710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSummary_MoveTo(t *testing.T) { ms := generateTestSummary() dest := NewSummary() ms.MoveTo(dest) assert.Equal(t, NewSummary(), ms) assert.Equal(t, generateTestSummary(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSummary(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSummary(internal.NewSummary(), sharedState)) }) assert.Panics(t, func() { newSummary(internal.NewSummary(), sharedState).MoveTo(dest) }) } func TestSummary_CopyTo(t *testing.T) { ms := NewSummary() orig := NewSummary() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSummary() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSummary(internal.NewSummary(), sharedState)) }) } func TestSummary_DataPoints(t *testing.T) { ms := NewSummary() assert.Equal(t, NewSummaryDataPointSlice(), ms.DataPoints()) ms.orig.DataPoints = internal.GenTestSummaryDataPointPtrSlice() assert.Equal(t, generateTestSummaryDataPointSlice(), ms.DataPoints()) } func generateTestSummary() Summary { return newSummary(internal.GenTestSummary(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapoint.go000066400000000000000000000101361511331344600272410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // SummaryDataPoint is a single data point in a timeseries that describes the time-varying values of a Summary of double values. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSummaryDataPoint function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPoint struct { orig *internal.SummaryDataPoint state *internal.State } func newSummaryDataPoint(orig *internal.SummaryDataPoint, state *internal.State) SummaryDataPoint { return SummaryDataPoint{orig: orig, state: state} } // NewSummaryDataPoint creates a new empty SummaryDataPoint. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSummaryDataPoint() SummaryDataPoint { return newSummaryDataPoint(internal.NewSummaryDataPoint(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SummaryDataPoint) MoveTo(dest SummaryDataPoint) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSummaryDataPoint(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Attributes returns the Attributes associated with this SummaryDataPoint. func (ms SummaryDataPoint) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // StartTimestamp returns the starttimestamp associated with this SummaryDataPoint. func (ms SummaryDataPoint) StartTimestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.StartTimeUnixNano) } // SetStartTimestamp replaces the starttimestamp associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetStartTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } // Timestamp returns the timestamp associated with this SummaryDataPoint. func (ms SummaryDataPoint) Timestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTimestamp replaces the timestamp associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // Count returns the count associated with this SummaryDataPoint. func (ms SummaryDataPoint) Count() uint64 { return ms.orig.Count } // SetCount replaces the count associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetCount(v uint64) { ms.state.AssertMutable() ms.orig.Count = v } // Sum returns the sum associated with this SummaryDataPoint. func (ms SummaryDataPoint) Sum() float64 { return ms.orig.Sum } // SetSum replaces the sum associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetSum(v float64) { ms.state.AssertMutable() ms.orig.Sum = v } // QuantileValues returns the QuantileValues associated with this SummaryDataPoint. func (ms SummaryDataPoint) QuantileValues() SummaryDataPointValueAtQuantileSlice { return newSummaryDataPointValueAtQuantileSlice(&ms.orig.QuantileValues, ms.state) } // Flags returns the flags associated with this SummaryDataPoint. func (ms SummaryDataPoint) Flags() DataPointFlags { return DataPointFlags(ms.orig.Flags) } // SetFlags replaces the flags associated with this SummaryDataPoint. func (ms SummaryDataPoint) SetFlags(v DataPointFlags) { ms.state.AssertMutable() ms.orig.Flags = uint32(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms SummaryDataPoint) CopyTo(dest SummaryDataPoint) { dest.state.AssertMutable() internal.CopySummaryDataPoint(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapoint_test.go000066400000000000000000000071711511331344600303050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSummaryDataPoint_MoveTo(t *testing.T) { ms := generateTestSummaryDataPoint() dest := NewSummaryDataPoint() ms.MoveTo(dest) assert.Equal(t, NewSummaryDataPoint(), ms) assert.Equal(t, generateTestSummaryDataPoint(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSummaryDataPoint(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSummaryDataPoint(internal.NewSummaryDataPoint(), sharedState)) }) assert.Panics(t, func() { newSummaryDataPoint(internal.NewSummaryDataPoint(), sharedState).MoveTo(dest) }) } func TestSummaryDataPoint_CopyTo(t *testing.T) { ms := NewSummaryDataPoint() orig := NewSummaryDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSummaryDataPoint() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSummaryDataPoint(internal.NewSummaryDataPoint(), sharedState)) }) } func TestSummaryDataPoint_Attributes(t *testing.T) { ms := NewSummaryDataPoint() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestSummaryDataPoint_StartTimestamp(t *testing.T) { ms := NewSummaryDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.StartTimestamp()) testValStartTimestamp := pcommon.Timestamp(1234567890) ms.SetStartTimestamp(testValStartTimestamp) assert.Equal(t, testValStartTimestamp, ms.StartTimestamp()) } func TestSummaryDataPoint_Timestamp(t *testing.T) { ms := NewSummaryDataPoint() assert.Equal(t, pcommon.Timestamp(0), ms.Timestamp()) testValTimestamp := pcommon.Timestamp(1234567890) ms.SetTimestamp(testValTimestamp) assert.Equal(t, testValTimestamp, ms.Timestamp()) } func TestSummaryDataPoint_Count(t *testing.T) { ms := NewSummaryDataPoint() assert.Equal(t, uint64(0), ms.Count()) ms.SetCount(uint64(13)) assert.Equal(t, uint64(13), ms.Count()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSummaryDataPoint(internal.NewSummaryDataPoint(), sharedState).SetCount(uint64(13)) }) } func TestSummaryDataPoint_Sum(t *testing.T) { ms := NewSummaryDataPoint() assert.InDelta(t, float64(0), ms.Sum(), 0.01) ms.SetSum(float64(3.1415926)) assert.InDelta(t, float64(3.1415926), ms.Sum(), 0.01) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSummaryDataPoint(internal.NewSummaryDataPoint(), sharedState).SetSum(float64(3.1415926)) }) } func TestSummaryDataPoint_QuantileValues(t *testing.T) { ms := NewSummaryDataPoint() assert.Equal(t, NewSummaryDataPointValueAtQuantileSlice(), ms.QuantileValues()) ms.orig.QuantileValues = internal.GenTestSummaryDataPointValueAtQuantilePtrSlice() assert.Equal(t, generateTestSummaryDataPointValueAtQuantileSlice(), ms.QuantileValues()) } func TestSummaryDataPoint_Flags(t *testing.T) { ms := NewSummaryDataPoint() assert.Equal(t, DataPointFlags(0), ms.Flags()) testValFlags := DataPointFlags(1) ms.SetFlags(testValFlags) assert.Equal(t, testValFlags, ms.Flags()) } func generateTestSummaryDataPoint() SummaryDataPoint { return newSummaryDataPoint(internal.GenTestSummaryDataPoint(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapointslice.go000066400000000000000000000117751511331344600302730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // SummaryDataPointSlice logically represents a slice of SummaryDataPoint. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewSummaryDataPointSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPointSlice struct { orig *[]*internal.SummaryDataPoint state *internal.State } func newSummaryDataPointSlice(orig *[]*internal.SummaryDataPoint, state *internal.State) SummaryDataPointSlice { return SummaryDataPointSlice{orig: orig, state: state} } // NewSummaryDataPointSlice creates a SummaryDataPointSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSummaryDataPointSlice() SummaryDataPointSlice { orig := []*internal.SummaryDataPoint(nil) return newSummaryDataPointSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewSummaryDataPointSlice()". func (es SummaryDataPointSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es SummaryDataPointSlice) At(i int) SummaryDataPoint { return newSummaryDataPoint((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es SummaryDataPointSlice) All() iter.Seq2[int, SummaryDataPoint] { return func(yield func(int, SummaryDataPoint) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new SummaryDataPointSlice can be initialized: // // es := NewSummaryDataPointSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es SummaryDataPointSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.SummaryDataPoint, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty SummaryDataPoint. // It returns the newly added SummaryDataPoint. func (es SummaryDataPointSlice) AppendEmpty() SummaryDataPoint { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewSummaryDataPoint()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SummaryDataPointSlice) MoveAndAppendTo(dest SummaryDataPointSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SummaryDataPointSlice) RemoveIf(f func(SummaryDataPoint) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteSummaryDataPoint((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es SummaryDataPointSlice) CopyTo(dest SummaryDataPointSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopySummaryDataPointPtrSlice(*dest.orig, *es.orig) } // Sort sorts the SummaryDataPoint elements within SummaryDataPointSlice given the // provided less function so that two instances of SummaryDataPointSlice // can be compared. func (es SummaryDataPointSlice) Sort(less func(a, b SummaryDataPoint) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapointslice_test.go000066400000000000000000000120731511331344600313220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSummaryDataPointSlice(t *testing.T) { es := NewSummaryDataPointSlice() assert.Equal(t, 0, es.Len()) es = newSummaryDataPointSlice(&[]*internal.SummaryDataPoint{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewSummaryDataPoint() testVal := generateTestSummaryDataPoint() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestSummaryDataPoint() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestSummaryDataPointSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newSummaryDataPointSlice(&[]*internal.SummaryDataPoint{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewSummaryDataPointSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestSummaryDataPointSlice_CopyTo(t *testing.T) { dest := NewSummaryDataPointSlice() src := generateTestSummaryDataPointSlice() src.CopyTo(dest) assert.Equal(t, generateTestSummaryDataPointSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestSummaryDataPointSlice(), dest) } func TestSummaryDataPointSlice_EnsureCapacity(t *testing.T) { es := generateTestSummaryDataPointSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestSummaryDataPointSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestSummaryDataPointSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestSummaryDataPointSlice(), es) } func TestSummaryDataPointSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestSummaryDataPointSlice() dest := NewSummaryDataPointSlice() src := generateTestSummaryDataPointSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSummaryDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSummaryDataPointSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestSummaryDataPointSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestSummaryDataPointSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewSummaryDataPointSlice() emptySlice.RemoveIf(func(el SummaryDataPoint) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestSummaryDataPointSlice() pos := 0 filtered.RemoveIf(func(el SummaryDataPoint) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestSummaryDataPointSlice_RemoveIfAll(t *testing.T) { got := generateTestSummaryDataPointSlice() got.RemoveIf(func(el SummaryDataPoint) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestSummaryDataPointSliceAll(t *testing.T) { ms := generateTestSummaryDataPointSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestSummaryDataPointSlice_Sort(t *testing.T) { es := generateTestSummaryDataPointSlice() es.Sort(func(a, b SummaryDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b SummaryDataPoint) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestSummaryDataPointSlice() SummaryDataPointSlice { ms := NewSummaryDataPointSlice() *ms.orig = internal.GenTestSummaryDataPointPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapointvalueatquantile.go000066400000000000000000000055571511331344600324010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "go.opentelemetry.io/collector/pdata/internal" ) // SummaryDataPointValueAtQuantile is a quantile value within a Summary data point. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSummaryDataPointValueAtQuantile function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPointValueAtQuantile struct { orig *internal.SummaryDataPointValueAtQuantile state *internal.State } func newSummaryDataPointValueAtQuantile(orig *internal.SummaryDataPointValueAtQuantile, state *internal.State) SummaryDataPointValueAtQuantile { return SummaryDataPointValueAtQuantile{orig: orig, state: state} } // NewSummaryDataPointValueAtQuantile creates a new empty SummaryDataPointValueAtQuantile. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSummaryDataPointValueAtQuantile() SummaryDataPointValueAtQuantile { return newSummaryDataPointValueAtQuantile(internal.NewSummaryDataPointValueAtQuantile(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SummaryDataPointValueAtQuantile) MoveTo(dest SummaryDataPointValueAtQuantile) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSummaryDataPointValueAtQuantile(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Quantile returns the quantile associated with this SummaryDataPointValueAtQuantile. func (ms SummaryDataPointValueAtQuantile) Quantile() float64 { return ms.orig.Quantile } // SetQuantile replaces the quantile associated with this SummaryDataPointValueAtQuantile. func (ms SummaryDataPointValueAtQuantile) SetQuantile(v float64) { ms.state.AssertMutable() ms.orig.Quantile = v } // Value returns the value associated with this SummaryDataPointValueAtQuantile. func (ms SummaryDataPointValueAtQuantile) Value() float64 { return ms.orig.Value } // SetValue replaces the value associated with this SummaryDataPointValueAtQuantile. func (ms SummaryDataPointValueAtQuantile) SetValue(v float64) { ms.state.AssertMutable() ms.orig.Value = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms SummaryDataPointValueAtQuantile) CopyTo(dest SummaryDataPointValueAtQuantile) { dest.state.AssertMutable() internal.CopySummaryDataPointValueAtQuantile(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapointvalueatquantile_test.go000066400000000000000000000052471511331344600334340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSummaryDataPointValueAtQuantile_MoveTo(t *testing.T) { ms := generateTestSummaryDataPointValueAtQuantile() dest := NewSummaryDataPointValueAtQuantile() ms.MoveTo(dest) assert.Equal(t, NewSummaryDataPointValueAtQuantile(), ms) assert.Equal(t, generateTestSummaryDataPointValueAtQuantile(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSummaryDataPointValueAtQuantile(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSummaryDataPointValueAtQuantile(internal.NewSummaryDataPointValueAtQuantile(), sharedState)) }) assert.Panics(t, func() { newSummaryDataPointValueAtQuantile(internal.NewSummaryDataPointValueAtQuantile(), sharedState).MoveTo(dest) }) } func TestSummaryDataPointValueAtQuantile_CopyTo(t *testing.T) { ms := NewSummaryDataPointValueAtQuantile() orig := NewSummaryDataPointValueAtQuantile() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSummaryDataPointValueAtQuantile() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSummaryDataPointValueAtQuantile(internal.NewSummaryDataPointValueAtQuantile(), sharedState)) }) } func TestSummaryDataPointValueAtQuantile_Quantile(t *testing.T) { ms := NewSummaryDataPointValueAtQuantile() assert.InDelta(t, float64(0), ms.Quantile(), 0.01) ms.SetQuantile(float64(3.1415926)) assert.InDelta(t, float64(3.1415926), ms.Quantile(), 0.01) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSummaryDataPointValueAtQuantile(internal.NewSummaryDataPointValueAtQuantile(), sharedState).SetQuantile(float64(3.1415926)) }) } func TestSummaryDataPointValueAtQuantile_Value(t *testing.T) { ms := NewSummaryDataPointValueAtQuantile() assert.InDelta(t, float64(0), ms.Value(), 0.01) ms.SetValue(float64(3.1415926)) assert.InDelta(t, float64(3.1415926), ms.Value(), 0.01) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSummaryDataPointValueAtQuantile(internal.NewSummaryDataPointValueAtQuantile(), sharedState).SetValue(float64(3.1415926)) }) } func generateTestSummaryDataPointValueAtQuantile() SummaryDataPointValueAtQuantile { return newSummaryDataPointValueAtQuantile(internal.GenTestSummaryDataPointValueAtQuantile(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapointvalueatquantileslice.go000066400000000000000000000132401511331344600334050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // SummaryDataPointValueAtQuantileSlice logically represents a slice of SummaryDataPointValueAtQuantile. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewSummaryDataPointValueAtQuantileSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SummaryDataPointValueAtQuantileSlice struct { orig *[]*internal.SummaryDataPointValueAtQuantile state *internal.State } func newSummaryDataPointValueAtQuantileSlice(orig *[]*internal.SummaryDataPointValueAtQuantile, state *internal.State) SummaryDataPointValueAtQuantileSlice { return SummaryDataPointValueAtQuantileSlice{orig: orig, state: state} } // NewSummaryDataPointValueAtQuantileSlice creates a SummaryDataPointValueAtQuantileSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSummaryDataPointValueAtQuantileSlice() SummaryDataPointValueAtQuantileSlice { orig := []*internal.SummaryDataPointValueAtQuantile(nil) return newSummaryDataPointValueAtQuantileSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewSummaryDataPointValueAtQuantileSlice()". func (es SummaryDataPointValueAtQuantileSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es SummaryDataPointValueAtQuantileSlice) At(i int) SummaryDataPointValueAtQuantile { return newSummaryDataPointValueAtQuantile((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es SummaryDataPointValueAtQuantileSlice) All() iter.Seq2[int, SummaryDataPointValueAtQuantile] { return func(yield func(int, SummaryDataPointValueAtQuantile) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new SummaryDataPointValueAtQuantileSlice can be initialized: // // es := NewSummaryDataPointValueAtQuantileSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es SummaryDataPointValueAtQuantileSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.SummaryDataPointValueAtQuantile, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty SummaryDataPointValueAtQuantile. // It returns the newly added SummaryDataPointValueAtQuantile. func (es SummaryDataPointValueAtQuantileSlice) AppendEmpty() SummaryDataPointValueAtQuantile { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewSummaryDataPointValueAtQuantile()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SummaryDataPointValueAtQuantileSlice) MoveAndAppendTo(dest SummaryDataPointValueAtQuantileSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SummaryDataPointValueAtQuantileSlice) RemoveIf(f func(SummaryDataPointValueAtQuantile) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteSummaryDataPointValueAtQuantile((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es SummaryDataPointValueAtQuantileSlice) CopyTo(dest SummaryDataPointValueAtQuantileSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopySummaryDataPointValueAtQuantilePtrSlice(*dest.orig, *es.orig) } // Sort sorts the SummaryDataPointValueAtQuantile elements within SummaryDataPointValueAtQuantileSlice given the // provided less function so that two instances of SummaryDataPointValueAtQuantileSlice // can be compared. func (es SummaryDataPointValueAtQuantileSlice) Sort(less func(a, b SummaryDataPointValueAtQuantile) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pmetric/generated_summarydatapointvalueatquantileslice_test.go000066400000000000000000000133551511331344600344530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetric import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSummaryDataPointValueAtQuantileSlice(t *testing.T) { es := NewSummaryDataPointValueAtQuantileSlice() assert.Equal(t, 0, es.Len()) es = newSummaryDataPointValueAtQuantileSlice(&[]*internal.SummaryDataPointValueAtQuantile{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewSummaryDataPointValueAtQuantile() testVal := generateTestSummaryDataPointValueAtQuantile() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestSummaryDataPointValueAtQuantile() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestSummaryDataPointValueAtQuantileSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newSummaryDataPointValueAtQuantileSlice(&[]*internal.SummaryDataPointValueAtQuantile{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewSummaryDataPointValueAtQuantileSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestSummaryDataPointValueAtQuantileSlice_CopyTo(t *testing.T) { dest := NewSummaryDataPointValueAtQuantileSlice() src := generateTestSummaryDataPointValueAtQuantileSlice() src.CopyTo(dest) assert.Equal(t, generateTestSummaryDataPointValueAtQuantileSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestSummaryDataPointValueAtQuantileSlice(), dest) } func TestSummaryDataPointValueAtQuantileSlice_EnsureCapacity(t *testing.T) { es := generateTestSummaryDataPointValueAtQuantileSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestSummaryDataPointValueAtQuantileSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestSummaryDataPointValueAtQuantileSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestSummaryDataPointValueAtQuantileSlice(), es) } func TestSummaryDataPointValueAtQuantileSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestSummaryDataPointValueAtQuantileSlice() dest := NewSummaryDataPointValueAtQuantileSlice() src := generateTestSummaryDataPointValueAtQuantileSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSummaryDataPointValueAtQuantileSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSummaryDataPointValueAtQuantileSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestSummaryDataPointValueAtQuantileSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestSummaryDataPointValueAtQuantileSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewSummaryDataPointValueAtQuantileSlice() emptySlice.RemoveIf(func(el SummaryDataPointValueAtQuantile) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestSummaryDataPointValueAtQuantileSlice() pos := 0 filtered.RemoveIf(func(el SummaryDataPointValueAtQuantile) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestSummaryDataPointValueAtQuantileSlice_RemoveIfAll(t *testing.T) { got := generateTestSummaryDataPointValueAtQuantileSlice() got.RemoveIf(func(el SummaryDataPointValueAtQuantile) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestSummaryDataPointValueAtQuantileSliceAll(t *testing.T) { ms := generateTestSummaryDataPointValueAtQuantileSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestSummaryDataPointValueAtQuantileSlice_Sort(t *testing.T) { es := generateTestSummaryDataPointValueAtQuantileSlice() es.Sort(func(a, b SummaryDataPointValueAtQuantile) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b SummaryDataPointValueAtQuantile) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestSummaryDataPointValueAtQuantileSlice() SummaryDataPointValueAtQuantileSlice { ms := NewSummaryDataPointValueAtQuantileSlice() *ms.orig = internal.GenTestSummaryDataPointValueAtQuantilePtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pmetric/json.go000066400000000000000000000022731511331344600225760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" ) var _ Marshaler = (*JSONMarshaler)(nil) // JSONMarshaler marshals Metrics to JSON bytes using the OTLP/JSON format. type JSONMarshaler struct{} // MarshalMetrics to the OTLP/JSON format. func (*JSONMarshaler) MarshalMetrics(md Metrics) ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) md.getOrig().MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } // JSONUnmarshaler unmarshals OTLP/JSON formatted-bytes to Metrics. type JSONUnmarshaler struct{} // UnmarshalMetrics from OTLP/JSON format into Metrics. func (*JSONUnmarshaler) UnmarshalMetrics(buf []byte) (Metrics, error) { iter := json.BorrowIterator(buf) defer json.ReturnIterator(iter) md := NewMetrics() md.getOrig().UnmarshalJSON(iter) if iter.Error() != nil { return Metrics{}, iter.Error() } otlp.MigrateMetrics(md.getOrig().ResourceMetrics) return md, nil } opentelemetry-collector-0.141.0/pdata/pmetric/metric_data_point_flags.go000066400000000000000000000016341511331344600264660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" const noRecordValueMask = uint32(1) var DefaultDataPointFlags = DataPointFlags(0) // DataPointFlags defines how a metric aggregator reports aggregated values. // It describes how those values relate to the time interval over which they are aggregated. type DataPointFlags uint32 // NoRecordedValue returns true if the DataPointFlags contains the NoRecordedValue flag. func (ms DataPointFlags) NoRecordedValue() bool { return uint32(ms)&noRecordValueMask != 0 } // WithNoRecordedValue returns a new DataPointFlags, with the NoRecordedValue flag set to the given value. func (ms DataPointFlags) WithNoRecordedValue(b bool) DataPointFlags { orig := uint32(ms) if b { orig |= noRecordValueMask } else { orig &^= noRecordValueMask } return DataPointFlags(orig) } opentelemetry-collector-0.141.0/pdata/pmetric/metric_data_point_flags_test.go000066400000000000000000000013251511331344600275220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric import ( "testing" "github.com/stretchr/testify/assert" ) func TestLogRecordFlags(t *testing.T) { flags := DataPointFlags(1) assert.True(t, flags.NoRecordedValue()) assert.EqualValues(t, uint32(1), flags) flags = flags.WithNoRecordedValue(false) assert.False(t, flags.NoRecordedValue()) assert.EqualValues(t, uint32(0), flags) flags = flags.WithNoRecordedValue(true) assert.True(t, flags.NoRecordedValue()) assert.EqualValues(t, uint32(1), flags) } func TestDefaultLogRecordFlags(t *testing.T) { flags := DefaultDataPointFlags assert.False(t, flags.NoRecordedValue()) assert.EqualValues(t, uint32(0), flags) } opentelemetry-collector-0.141.0/pdata/pmetric/metric_type.go000066400000000000000000000015131511331344600241450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" // MetricType specifies the type of data in a Metric. type MetricType int32 const ( // MetricTypeEmpty means that metric type is unset. MetricTypeEmpty MetricType = iota MetricTypeGauge MetricTypeSum MetricTypeHistogram MetricTypeExponentialHistogram MetricTypeSummary ) // String returns the string representation of the MetricType. func (mdt MetricType) String() string { switch mdt { case MetricTypeEmpty: return "Empty" case MetricTypeGauge: return "Gauge" case MetricTypeSum: return "Sum" case MetricTypeHistogram: return "Histogram" case MetricTypeExponentialHistogram: return "ExponentialHistogram" case MetricTypeSummary: return "Summary" } return "" } opentelemetry-collector-0.141.0/pdata/pmetric/metric_type_test.go000066400000000000000000000012231511331344600252020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" import ( "testing" "github.com/stretchr/testify/assert" ) func TestMetricTypeString(t *testing.T) { assert.Equal(t, "Empty", MetricTypeEmpty.String()) assert.Equal(t, "Gauge", MetricTypeGauge.String()) assert.Equal(t, "Sum", MetricTypeSum.String()) assert.Equal(t, "Histogram", MetricTypeHistogram.String()) assert.Equal(t, "ExponentialHistogram", MetricTypeExponentialHistogram.String()) assert.Equal(t, "Summary", MetricTypeSummary.String()) assert.Empty(t, (MetricTypeSummary + 1).String()) } opentelemetry-collector-0.141.0/pdata/pmetric/metrics.go000066400000000000000000000031721511331344600232720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" // MarkReadOnly marks the Metrics as shared so that no further modifications can be done on it. func (ms Metrics) MarkReadOnly() { ms.getState().MarkReadOnly() } // IsReadOnly returns true if this Metrics instance is read-only. func (ms Metrics) IsReadOnly() bool { return ms.getState().IsReadOnly() } // MetricCount calculates the total number of metrics. func (ms Metrics) MetricCount() int { metricCount := 0 rms := ms.ResourceMetrics() for i := 0; i < rms.Len(); i++ { rm := rms.At(i) ilms := rm.ScopeMetrics() for j := 0; j < ilms.Len(); j++ { ilm := ilms.At(j) metricCount += ilm.Metrics().Len() } } return metricCount } // DataPointCount calculates the total number of data points. func (ms Metrics) DataPointCount() (dataPointCount int) { rms := ms.ResourceMetrics() for i := 0; i < rms.Len(); i++ { rm := rms.At(i) ilms := rm.ScopeMetrics() for j := 0; j < ilms.Len(); j++ { ilm := ilms.At(j) ms := ilm.Metrics() for k := 0; k < ms.Len(); k++ { m := ms.At(k) switch m.Type() { case MetricTypeGauge: dataPointCount += m.Gauge().DataPoints().Len() case MetricTypeSum: dataPointCount += m.Sum().DataPoints().Len() case MetricTypeHistogram: dataPointCount += m.Histogram().DataPoints().Len() case MetricTypeExponentialHistogram: dataPointCount += m.ExponentialHistogram().DataPoints().Len() case MetricTypeSummary: dataPointCount += m.Summary().DataPoints().Len() } } } } return dataPointCount } opentelemetry-collector-0.141.0/pdata/pmetric/metrics_test.go000066400000000000000000000757361511331344600243500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) const ( startTime = uint64(12578940000000012345) endTime = uint64(12578940000000054321) ) func TestMetricCount(t *testing.T) { md := NewMetrics() assert.Equal(t, 0, md.MetricCount()) rms := md.ResourceMetrics() rms.EnsureCapacity(3) rm := rms.AppendEmpty() assert.Equal(t, 0, md.MetricCount()) ilm := rm.ScopeMetrics().AppendEmpty() assert.Equal(t, 0, md.MetricCount()) ilm.Metrics().AppendEmpty() assert.Equal(t, 1, md.MetricCount()) rms.AppendEmpty().ScopeMetrics().AppendEmpty() ilmm := rms.AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() ilmm.EnsureCapacity(5) for range 5 { ilmm.AppendEmpty() } // 5 + 1 (from rms.At(0) initialized first) assert.Equal(t, 6, md.MetricCount()) } func TestMetricCountWithEmpty(t *testing.T) { assert.Equal(t, 0, generateMetricsEmptyResource().MetricCount()) assert.Equal(t, 0, generateMetricsEmptyInstrumentation().MetricCount()) assert.Equal(t, 1, generateMetricsEmptyMetrics().MetricCount()) } func TestMetricAndDataPointCount(t *testing.T) { md := NewMetrics() dps := md.DataPointCount() assert.Equal(t, 0, dps) rms := md.ResourceMetrics() rms.AppendEmpty() dps = md.DataPointCount() assert.Equal(t, 0, dps) ilms := md.ResourceMetrics().At(0).ScopeMetrics() ilms.AppendEmpty() dps = md.DataPointCount() assert.Equal(t, 0, dps) ilms.At(0).Metrics().AppendEmpty() dps = md.DataPointCount() assert.Equal(t, 0, dps) intSum := ilms.At(0).Metrics().At(0).SetEmptySum() intSum.DataPoints().AppendEmpty() intSum.DataPoints().AppendEmpty() intSum.DataPoints().AppendEmpty() assert.Equal(t, 3, md.DataPointCount()) md = NewMetrics() rms = md.ResourceMetrics() rms.EnsureCapacity(3) rms.AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() rms.AppendEmpty().ScopeMetrics().AppendEmpty() rms.AppendEmpty().ScopeMetrics().AppendEmpty() ilms = rms.At(2).ScopeMetrics() ilm := ilms.At(0).Metrics() for range 5 { ilm.AppendEmpty() } assert.Equal(t, 0, md.DataPointCount()) ilm.At(0).SetEmptyGauge().DataPoints().AppendEmpty() assert.Equal(t, 1, md.DataPointCount()) ilm.At(1).SetEmptySum().DataPoints().AppendEmpty() assert.Equal(t, 2, md.DataPointCount()) ilm.At(2).SetEmptyHistogram().DataPoints().AppendEmpty() assert.Equal(t, 3, md.DataPointCount()) ilm.At(3).SetEmptyExponentialHistogram().DataPoints().AppendEmpty() assert.Equal(t, 4, md.DataPointCount()) ilm.At(4).SetEmptySummary().DataPoints().AppendEmpty() assert.Equal(t, 5, md.DataPointCount()) } func TestDataPointCountWithEmpty(t *testing.T) { assert.Equal(t, 0, generateMetricsEmptyResource().DataPointCount()) assert.Equal(t, 0, generateMetricsEmptyInstrumentation().DataPointCount()) assert.Equal(t, 0, generateMetricsEmptyMetrics().DataPointCount()) assert.Equal(t, 1, generateMetricsEmptyDataPoints().DataPointCount()) } func TestDataPointCountWithNilDataPoints(t *testing.T) { md := NewMetrics() ilm := md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty() ilm.Metrics().AppendEmpty().SetEmptyGauge() ilm.Metrics().AppendEmpty().SetEmptySum() ilm.Metrics().AppendEmpty().SetEmptyHistogram() ilm.Metrics().AppendEmpty().SetEmptyExponentialHistogram() ilm.Metrics().AppendEmpty().SetEmptySummary() assert.Equal(t, 0, md.DataPointCount()) } func TestHistogramWithNilSum(t *testing.T) { md := NewMetrics() ilm := md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty() histo := ilm.Metrics().AppendEmpty() histogramDataPoints := histo.SetEmptyHistogram().DataPoints() histogramDataPoints.AppendEmpty() dest := ilm.Metrics().AppendEmpty() histo.CopyTo(dest) assert.Equal(t, histo, dest) } func TestHistogramWithValidSum(t *testing.T) { md := NewMetrics() ilm := md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty() histo := ilm.Metrics().AppendEmpty() histogramDataPoints := histo.SetEmptyHistogram().DataPoints() histogramDataPoints.AppendEmpty() histogramDataPoints.At(0).SetSum(10) dest := ilm.Metrics().AppendEmpty() histo.CopyTo(dest) assert.Equal(t, histo, dest) } func TestOtlpToInternalReadOnly(t *testing.T) { md := newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoGaugeMetric(), generateTestProtoSumMetric(), generateTestProtoHistogramMetric()}, }, }, }, }, }, new(internal.State)) resourceMetrics := md.ResourceMetrics() assert.Equal(t, 1, resourceMetrics.Len()) resourceMetric := resourceMetrics.At(0) assert.Equal(t, map[string]any{ "string": "string-resource", }, resourceMetric.Resource().Attributes().AsRaw()) metrics := resourceMetric.ScopeMetrics().At(0).Metrics() assert.Equal(t, 3, metrics.Len()) // Check int64 metric metricInt := metrics.At(0) assert.Equal(t, "my_metric_int", metricInt.Name()) assert.Equal(t, "My metric", metricInt.Description()) assert.Equal(t, "ms", metricInt.Unit()) assert.Equal(t, MetricTypeGauge, metricInt.Type()) gaugeDataPoints := metricInt.Gauge().DataPoints() assert.Equal(t, 2, gaugeDataPoints.Len()) // First point assert.EqualValues(t, startTime, gaugeDataPoints.At(0).StartTimestamp()) assert.EqualValues(t, endTime, gaugeDataPoints.At(0).Timestamp()) assert.InDelta(t, 123.1, gaugeDataPoints.At(0).DoubleValue(), 0.01) assert.Equal(t, map[string]any{"key0": "value0"}, gaugeDataPoints.At(0).Attributes().AsRaw()) // Second point assert.EqualValues(t, startTime, gaugeDataPoints.At(1).StartTimestamp()) assert.EqualValues(t, endTime, gaugeDataPoints.At(1).Timestamp()) assert.InDelta(t, 456.1, gaugeDataPoints.At(1).DoubleValue(), 0.01) assert.Equal(t, map[string]any{"key1": "value1"}, gaugeDataPoints.At(1).Attributes().AsRaw()) // Check double metric metricDouble := metrics.At(1) assert.Equal(t, "my_metric_double", metricDouble.Name()) assert.Equal(t, "My metric", metricDouble.Description()) assert.Equal(t, "ms", metricDouble.Unit()) assert.Equal(t, MetricTypeSum, metricDouble.Type()) dsd := metricDouble.Sum() assert.Equal(t, AggregationTemporalityCumulative, dsd.AggregationTemporality()) sumDataPoints := dsd.DataPoints() assert.Equal(t, 2, sumDataPoints.Len()) // First point assert.EqualValues(t, startTime, sumDataPoints.At(0).StartTimestamp()) assert.EqualValues(t, endTime, sumDataPoints.At(0).Timestamp()) assert.InDelta(t, 123.1, sumDataPoints.At(0).DoubleValue(), 0.01) assert.Equal(t, map[string]any{"key0": "value0"}, sumDataPoints.At(0).Attributes().AsRaw()) // Second point assert.EqualValues(t, startTime, sumDataPoints.At(1).StartTimestamp()) assert.EqualValues(t, endTime, sumDataPoints.At(1).Timestamp()) assert.InDelta(t, 456.1, sumDataPoints.At(1).DoubleValue(), 0.01) assert.Equal(t, map[string]any{"key1": "value1"}, sumDataPoints.At(1).Attributes().AsRaw()) // Check histogram metric metricHistogram := metrics.At(2) assert.Equal(t, "my_metric_histogram", metricHistogram.Name()) assert.Equal(t, "My metric", metricHistogram.Description()) assert.Equal(t, "ms", metricHistogram.Unit()) assert.Equal(t, MetricTypeHistogram, metricHistogram.Type()) dhd := metricHistogram.Histogram() assert.Equal(t, AggregationTemporalityDelta, dhd.AggregationTemporality()) histogramDataPoints := dhd.DataPoints() assert.Equal(t, 2, histogramDataPoints.Len()) // First point assert.EqualValues(t, startTime, histogramDataPoints.At(0).StartTimestamp()) assert.EqualValues(t, endTime, histogramDataPoints.At(0).Timestamp()) assert.Equal(t, []float64{1, 2}, histogramDataPoints.At(0).ExplicitBounds().AsRaw()) assert.Equal(t, map[string]any{"key0": "value0"}, histogramDataPoints.At(0).Attributes().AsRaw()) assert.Equal(t, []uint64{10, 15, 1}, histogramDataPoints.At(0).BucketCounts().AsRaw()) // Second point assert.EqualValues(t, startTime, histogramDataPoints.At(1).StartTimestamp()) assert.EqualValues(t, endTime, histogramDataPoints.At(1).Timestamp()) assert.Equal(t, []float64{1}, histogramDataPoints.At(1).ExplicitBounds().AsRaw()) assert.Equal(t, map[string]any{"key1": "value1"}, histogramDataPoints.At(1).Attributes().AsRaw()) assert.Equal(t, []uint64{10, 1}, histogramDataPoints.At(1).BucketCounts().AsRaw()) } func TestOtlpToFromInternalReadOnly(t *testing.T) { md := newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoGaugeMetric(), generateTestProtoSumMetric(), generateTestProtoHistogramMetric()}, }, }, }, }, }, new(internal.State)) // Test that nothing changed assert.EqualValues(t, &internal.MetricsData{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoGaugeMetric(), generateTestProtoSumMetric(), generateTestProtoHistogramMetric()}, }, }, }, }, }, md.getOrig()) } func TestOtlpToFromInternalGaugeMutating(t *testing.T) { newAttributes := map[string]any{"k": "v"} md := newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoGaugeMetric()}, }, }, }, }, }, new(internal.State)) resourceMetrics := md.ResourceMetrics() metric := resourceMetrics.At(0).ScopeMetrics().At(0).Metrics().At(0) // Mutate MetricDescriptor metric.SetName("new_my_metric_int") assert.Equal(t, "new_my_metric_int", metric.Name()) metric.SetDescription("My new metric") assert.Equal(t, "My new metric", metric.Description()) metric.SetUnit("1") assert.Equal(t, "1", metric.Unit()) // Mutate DataPoints igd := metric.Gauge() assert.Equal(t, 2, igd.DataPoints().Len()) gaugeDataPoints := metric.SetEmptyGauge().DataPoints() gaugeDataPoints.AppendEmpty() assert.Equal(t, 1, gaugeDataPoints.Len()) gaugeDataPoints.At(0).SetStartTimestamp(pcommon.Timestamp(startTime + 1)) assert.EqualValues(t, startTime+1, gaugeDataPoints.At(0).StartTimestamp()) gaugeDataPoints.At(0).SetTimestamp(pcommon.Timestamp(endTime + 1)) assert.EqualValues(t, endTime+1, gaugeDataPoints.At(0).Timestamp()) gaugeDataPoints.At(0).SetDoubleValue(124.1) assert.InDelta(t, 124.1, gaugeDataPoints.At(0).DoubleValue(), 0.01) gaugeDataPoints.At(0).Attributes().Remove("key0") gaugeDataPoints.At(0).Attributes().PutStr("k", "v") assert.Equal(t, newAttributes, gaugeDataPoints.At(0).Attributes().AsRaw()) // Test that everything is updated. assert.EqualValues(t, &internal.MetricsData{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{ { Name: "new_my_metric_int", Description: "My new metric", Unit: "1", Data: &internal.Metric_Gauge{ Gauge: &internal.Gauge{ DataPoints: []*internal.NumberDataPoint{ { Attributes: []internal.KeyValue{ { Key: "k", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "v"}}, }, }, StartTimeUnixNano: startTime + 1, TimeUnixNano: endTime + 1, Value: &internal.NumberDataPoint_AsDouble{ AsDouble: 124.1, }, }, }, }, }, }, }, }, }, }, }, }, md.getOrig()) } func TestOtlpToFromInternalSumMutating(t *testing.T) { newAttributes := map[string]any{"k": "v"} md := newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoSumMetric()}, }, }, }, }, }, new(internal.State)) resourceMetrics := md.ResourceMetrics() metric := resourceMetrics.At(0).ScopeMetrics().At(0).Metrics().At(0) // Mutate MetricDescriptor metric.SetName("new_my_metric_double") assert.Equal(t, "new_my_metric_double", metric.Name()) metric.SetDescription("My new metric") assert.Equal(t, "My new metric", metric.Description()) metric.SetUnit("1") assert.Equal(t, "1", metric.Unit()) // Mutate DataPoints dsd := metric.Sum() assert.Equal(t, 2, dsd.DataPoints().Len()) metric.SetEmptySum().SetAggregationTemporality(AggregationTemporalityCumulative) doubleDataPoints := metric.Sum().DataPoints() doubleDataPoints.AppendEmpty() assert.Equal(t, 1, doubleDataPoints.Len()) doubleDataPoints.At(0).SetStartTimestamp(pcommon.Timestamp(startTime + 1)) assert.EqualValues(t, startTime+1, doubleDataPoints.At(0).StartTimestamp()) doubleDataPoints.At(0).SetTimestamp(pcommon.Timestamp(endTime + 1)) assert.EqualValues(t, endTime+1, doubleDataPoints.At(0).Timestamp()) doubleDataPoints.At(0).SetDoubleValue(124.1) assert.InDelta(t, 124.1, doubleDataPoints.At(0).DoubleValue(), 0.01) doubleDataPoints.At(0).Attributes().Remove("key0") doubleDataPoints.At(0).Attributes().PutStr("k", "v") assert.Equal(t, newAttributes, doubleDataPoints.At(0).Attributes().AsRaw()) // Test that everything is updated. assert.EqualValues(t, &internal.MetricsData{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{ { Name: "new_my_metric_double", Description: "My new metric", Unit: "1", Data: &internal.Metric_Sum{ Sum: &internal.Sum{ AggregationTemporality: internal.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE, DataPoints: []*internal.NumberDataPoint{ { Attributes: []internal.KeyValue{ { Key: "k", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "v"}}, }, }, StartTimeUnixNano: startTime + 1, TimeUnixNano: endTime + 1, Value: &internal.NumberDataPoint_AsDouble{ AsDouble: 124.1, }, }, }, }, }, }, }, }, }, }, }, }, md.getOrig()) } func TestOtlpToFromInternalHistogramMutating(t *testing.T) { newAttributes := map[string]any{"k": "v"} md := newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoHistogramMetric()}, }, }, }, }, }, new(internal.State)) resourceMetrics := md.ResourceMetrics() metric := resourceMetrics.At(0).ScopeMetrics().At(0).Metrics().At(0) // Mutate MetricDescriptor metric.SetName("new_my_metric_histogram") assert.Equal(t, "new_my_metric_histogram", metric.Name()) metric.SetDescription("My new metric") assert.Equal(t, "My new metric", metric.Description()) metric.SetUnit("1") assert.Equal(t, "1", metric.Unit()) // Mutate DataPoints dhd := metric.Histogram() assert.Equal(t, 2, dhd.DataPoints().Len()) metric.SetEmptyHistogram().SetAggregationTemporality(AggregationTemporalityDelta) histogramDataPoints := metric.Histogram().DataPoints() histogramDataPoints.AppendEmpty() assert.Equal(t, 1, histogramDataPoints.Len()) histogramDataPoints.At(0).SetStartTimestamp(pcommon.Timestamp(startTime + 1)) assert.EqualValues(t, startTime+1, histogramDataPoints.At(0).StartTimestamp()) histogramDataPoints.At(0).SetTimestamp(pcommon.Timestamp(endTime + 1)) assert.EqualValues(t, endTime+1, histogramDataPoints.At(0).Timestamp()) histogramDataPoints.At(0).Attributes().Remove("key0") histogramDataPoints.At(0).Attributes().PutStr("k", "v") assert.Equal(t, newAttributes, histogramDataPoints.At(0).Attributes().AsRaw()) histogramDataPoints.At(0).ExplicitBounds().FromRaw([]float64{1}) assert.Equal(t, []float64{1}, histogramDataPoints.At(0).ExplicitBounds().AsRaw()) histogramDataPoints.At(0).BucketCounts().FromRaw([]uint64{21, 32}) // Test that everything is updated. assert.EqualValues(t, &internal.MetricsData{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{ { Name: "new_my_metric_histogram", Description: "My new metric", Unit: "1", Data: &internal.Metric_Histogram{ Histogram: &internal.Histogram{ AggregationTemporality: internal.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA, DataPoints: []*internal.HistogramDataPoint{ { Attributes: []internal.KeyValue{ { Key: "k", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "v"}}, }, }, StartTimeUnixNano: startTime + 1, TimeUnixNano: endTime + 1, BucketCounts: []uint64{21, 32}, ExplicitBounds: []float64{1}, }, }, }, }, }, }, }, }, }, }, }, md.getOrig()) } func TestOtlpToFromInternalExponentialHistogramMutating(t *testing.T) { newAttributes := map[string]any{"k": "v"} md := newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoHistogramMetric()}, }, }, }, }, }, new(internal.State)) resourceMetrics := md.ResourceMetrics() metric := resourceMetrics.At(0).ScopeMetrics().At(0).Metrics().At(0) // Mutate MetricDescriptor metric.SetName("new_my_metric_exponential_histogram") assert.Equal(t, "new_my_metric_exponential_histogram", metric.Name()) metric.SetDescription("My new metric") assert.Equal(t, "My new metric", metric.Description()) metric.SetUnit("1") assert.Equal(t, "1", metric.Unit()) // Mutate DataPoints dhd := metric.Histogram() assert.Equal(t, 2, dhd.DataPoints().Len()) metric.SetEmptyExponentialHistogram().SetAggregationTemporality(AggregationTemporalityDelta) histogramDataPoints := metric.ExponentialHistogram().DataPoints() histogramDataPoints.AppendEmpty() assert.Equal(t, 1, histogramDataPoints.Len()) histogramDataPoints.At(0).SetStartTimestamp(pcommon.Timestamp(startTime + 1)) assert.EqualValues(t, startTime+1, histogramDataPoints.At(0).StartTimestamp()) histogramDataPoints.At(0).SetTimestamp(pcommon.Timestamp(endTime + 1)) assert.EqualValues(t, endTime+1, histogramDataPoints.At(0).Timestamp()) histogramDataPoints.At(0).Attributes().Remove("key0") histogramDataPoints.At(0).Attributes().PutStr("k", "v") assert.Equal(t, newAttributes, histogramDataPoints.At(0).Attributes().AsRaw()) // Test that everything is updated. assert.EqualValues(t, &internal.MetricsData{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{ { Name: "new_my_metric_exponential_histogram", Description: "My new metric", Unit: "1", Data: &internal.Metric_ExponentialHistogram{ ExponentialHistogram: &internal.ExponentialHistogram{ AggregationTemporality: internal.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA, DataPoints: []*internal.ExponentialHistogramDataPoint{ { Attributes: []internal.KeyValue{ { Key: "k", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "v"}}, }, }, StartTimeUnixNano: startTime + 1, TimeUnixNano: endTime + 1, }, }, }, }, }, }, }, }, }, }, }, md.getOrig()) } func TestMetricsCopyTo(t *testing.T) { md := generateTestMetrics() metricsCopy := NewMetrics() md.CopyTo(metricsCopy) assert.Equal(t, md, metricsCopy) } func TestReadOnlyMetricsInvalidUsage(t *testing.T) { metrics := NewMetrics() assert.False(t, metrics.IsReadOnly()) res := metrics.ResourceMetrics().AppendEmpty().Resource() res.Attributes().PutStr("k1", "v1") metrics.MarkReadOnly() assert.True(t, metrics.IsReadOnly()) assert.Panics(t, func() { res.Attributes().PutStr("k2", "v2") }) } func BenchmarkOtlpToFromInternal_PassThrough(b *testing.B) { testutil.SkipMemoryBench(b) req := &internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoGaugeMetric(), generateTestProtoSumMetric(), generateTestProtoHistogramMetric()}, }, }, }, }, } var state internal.State for b.Loop() { md := newMetrics(req, &state) newReq := md.getOrig() if len(req.ResourceMetrics) != len(newReq.ResourceMetrics) { b.Fail() } } } func BenchmarkOtlpToFromInternal_Gauge_MutateOneLabel(b *testing.B) { testutil.SkipMemoryBench(b) req := &internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoGaugeMetric()}, }, }, }, }, } var state internal.State for b.Loop() { md := newMetrics(req, &state) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Gauge().DataPoints().At(0).Attributes(). PutStr("key0", "value2") newReq := md.getOrig() if len(req.ResourceMetrics) != len(newReq.ResourceMetrics) { b.Fail() } } } func BenchmarkOtlpToFromInternal_Sum_MutateOneLabel(b *testing.B) { testutil.SkipMemoryBench(b) req := &internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoSumMetric()}, }, }, }, }, } var state internal.State for b.Loop() { md := newMetrics(req, &state) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Sum().DataPoints().At(0).Attributes(). PutStr("key0", "value2") newReq := md.getOrig() if len(req.ResourceMetrics) != len(newReq.ResourceMetrics) { b.Fail() } } } func BenchmarkOtlpToFromInternal_HistogramPoints_MutateOneLabel(b *testing.B) { testutil.SkipMemoryBench(b) req := &internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { Resource: generateTestProtoResource(), ScopeMetrics: []*internal.ScopeMetrics{ { Scope: generateTestProtoInstrumentationScope(), Metrics: []*internal.Metric{generateTestProtoHistogramMetric()}, }, }, }, }, } var state internal.State for b.Loop() { md := newMetrics(req, &state) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Histogram().DataPoints().At(0).Attributes(). PutStr("key0", "value2") newReq := md.getOrig() if len(req.ResourceMetrics) != len(newReq.ResourceMetrics) { b.Fail() } } } func generateTestProtoResource() internal.Resource { return internal.Resource{ Attributes: []internal.KeyValue{ { Key: "string", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "string-resource"}}, }, }, } } func generateTestProtoInstrumentationScope() internal.InstrumentationScope { return internal.InstrumentationScope{ Name: "test", Version: "", } } func generateTestProtoGaugeMetric() *internal.Metric { return &internal.Metric{ Name: "my_metric_int", Description: "My metric", Unit: "ms", Data: &internal.Metric_Gauge{ Gauge: &internal.Gauge{ DataPoints: []*internal.NumberDataPoint{ { Attributes: []internal.KeyValue{ { Key: "key0", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "value0"}}, }, }, StartTimeUnixNano: startTime, TimeUnixNano: endTime, Value: &internal.NumberDataPoint_AsDouble{ AsDouble: 123.1, }, }, { Attributes: []internal.KeyValue{ { Key: "key1", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "value1"}}, }, }, StartTimeUnixNano: startTime, TimeUnixNano: endTime, Value: &internal.NumberDataPoint_AsDouble{ AsDouble: 456.1, }, }, }, }, }, } } func generateTestProtoSumMetric() *internal.Metric { return &internal.Metric{ Name: "my_metric_double", Description: "My metric", Unit: "ms", Data: &internal.Metric_Sum{ Sum: &internal.Sum{ AggregationTemporality: internal.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE, DataPoints: []*internal.NumberDataPoint{ { Attributes: []internal.KeyValue{ { Key: "key0", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "value0"}}, }, }, StartTimeUnixNano: startTime, TimeUnixNano: endTime, Value: &internal.NumberDataPoint_AsDouble{ AsDouble: 123.1, }, }, { Attributes: []internal.KeyValue{ { Key: "key1", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "value1"}}, }, }, StartTimeUnixNano: startTime, TimeUnixNano: endTime, Value: &internal.NumberDataPoint_AsDouble{ AsDouble: 456.1, }, }, }, }, }, } } func generateTestProtoHistogramMetric() *internal.Metric { return &internal.Metric{ Name: "my_metric_histogram", Description: "My metric", Unit: "ms", Data: &internal.Metric_Histogram{ Histogram: &internal.Histogram{ AggregationTemporality: internal.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA, DataPoints: []*internal.HistogramDataPoint{ { Attributes: []internal.KeyValue{ { Key: "key0", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "value0"}}, }, }, StartTimeUnixNano: startTime, TimeUnixNano: endTime, BucketCounts: []uint64{10, 15, 1}, ExplicitBounds: []float64{1, 2}, }, { Attributes: []internal.KeyValue{ { Key: "key1", Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: "value1"}}, }, }, StartTimeUnixNano: startTime, TimeUnixNano: endTime, BucketCounts: []uint64{10, 1}, ExplicitBounds: []float64{1}, }, }, }, }, } } func generateMetricsEmptyResource() Metrics { return newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{{}}, }, new(internal.State)) } func generateMetricsEmptyInstrumentation() Metrics { return newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { ScopeMetrics: []*internal.ScopeMetrics{{}}, }, }, }, new(internal.State)) } func generateMetricsEmptyMetrics() Metrics { return newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { ScopeMetrics: []*internal.ScopeMetrics{ { Metrics: []*internal.Metric{{}}, }, }, }, }, }, new(internal.State)) } func generateMetricsEmptyDataPoints() Metrics { return newMetrics(&internal.ExportMetricsServiceRequest{ ResourceMetrics: []*internal.ResourceMetrics{ { ScopeMetrics: []*internal.ScopeMetrics{ { Metrics: []*internal.Metric{ { Data: &internal.Metric_Gauge{ Gauge: &internal.Gauge{ DataPoints: []*internal.NumberDataPoint{ {}, }, }, }, }, }, }, }, }, }, }, new(internal.State)) } func BenchmarkMetricsUsage(b *testing.B) { md := generateTestMetrics() ts := pcommon.NewTimestampFromTime(time.Now()) b.ReportAllocs() for b.Loop() { for i := 0; i < md.ResourceMetrics().Len(); i++ { rm := md.ResourceMetrics().At(i) res := rm.Resource() res.Attributes().PutStr("foo", "bar") v, ok := res.Attributes().Get("foo") assert.True(b, ok) assert.Equal(b, "bar", v.Str()) v.SetStr("new-bar") assert.Equal(b, "new-bar", v.Str()) res.Attributes().Remove("foo") for j := 0; j < rm.ScopeMetrics().Len(); j++ { sm := rm.ScopeMetrics().At(j) for k := 0; k < sm.Metrics().Len(); k++ { m := sm.Metrics().At(k) m.SetName("new_metric_name") assert.Equal(b, "new_metric_name", m.Name()) // Only process Sum metrics to avoid nil pointer dereference if m.Type() == MetricTypeSum { assert.Equal(b, MetricTypeSum, m.Type()) m.Sum().SetAggregationTemporality(AggregationTemporalityCumulative) assert.Equal(b, AggregationTemporalityCumulative, m.Sum().AggregationTemporality()) m.Sum().SetIsMonotonic(true) assert.True(b, m.Sum().IsMonotonic()) for l := 0; l < m.Sum().DataPoints().Len(); l++ { dp := m.Sum().DataPoints().At(l) dp.SetIntValue(123) assert.Equal(b, int64(123), dp.IntValue()) assert.Equal(b, NumberDataPointValueTypeInt, dp.ValueType()) dp.SetStartTimestamp(ts) assert.Equal(b, ts, dp.StartTimestamp()) } dp := m.Sum().DataPoints().AppendEmpty() dp.Attributes().PutStr("foo", "bar") dp.SetDoubleValue(123) dp.SetStartTimestamp(ts) dp.SetTimestamp(ts) m.Sum().DataPoints().RemoveIf(func(dp NumberDataPoint) bool { _, ok := dp.Attributes().Get("foo") return ok }) } } } } } } func BenchmarkMetricsMarshalJSON(b *testing.B) { md := generateTestMetrics() encoder := &JSONMarshaler{} b.ReportAllocs() for b.Loop() { jsonBuf, err := encoder.MarshalMetrics(md) require.NoError(b, err) require.NotNil(b, jsonBuf) } } opentelemetry-collector-0.141.0/pdata/pmetric/number_data_point_value_type.go000066400000000000000000000014241511331344600275510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" // NumberDataPointValueType specifies the type of NumberDataPoint value. type NumberDataPointValueType int32 const ( // NumberDataPointValueTypeEmpty means that data point value is unset. NumberDataPointValueTypeEmpty NumberDataPointValueType = iota NumberDataPointValueTypeInt NumberDataPointValueTypeDouble ) // String returns the string representation of the NumberDataPointValueType. func (nt NumberDataPointValueType) String() string { switch nt { case NumberDataPointValueTypeEmpty: return "Empty" case NumberDataPointValueTypeInt: return "Int" case NumberDataPointValueTypeDouble: return "Double" } return "" } opentelemetry-collector-0.141.0/pdata/pmetric/number_data_point_value_type_test.go000066400000000000000000000010241511331344600306040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" import ( "testing" "github.com/stretchr/testify/assert" ) func TestNumberDataPointValueTypeString(t *testing.T) { assert.Equal(t, "Empty", NumberDataPointValueTypeEmpty.String()) assert.Equal(t, "Int", NumberDataPointValueTypeInt.String()) assert.Equal(t, "Double", NumberDataPointValueTypeDouble.String()) assert.Empty(t, (NumberDataPointValueTypeDouble + 1).String()) } opentelemetry-collector-0.141.0/pdata/pmetric/package_test.go000066400000000000000000000003101511331344600242450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/pmetric/pb.go000066400000000000000000000026651511331344600222330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric // import "go.opentelemetry.io/collector/pdata/pmetric" var _ MarshalSizer = (*ProtoMarshaler)(nil) type ProtoMarshaler struct{} func (e *ProtoMarshaler) MarshalMetrics(md Metrics) ([]byte, error) { size := md.getOrig().SizeProto() buf := make([]byte, size) _ = md.getOrig().MarshalProto(buf) return buf, nil } func (e *ProtoMarshaler) MetricsSize(md Metrics) int { return md.getOrig().SizeProto() } func (e *ProtoMarshaler) ResourceMetricsSize(md ResourceMetrics) int { return md.orig.SizeProto() } func (e *ProtoMarshaler) ScopeMetricsSize(md ScopeMetrics) int { return md.orig.SizeProto() } func (e *ProtoMarshaler) MetricSize(md Metric) int { return md.orig.SizeProto() } func (e *ProtoMarshaler) NumberDataPointSize(md NumberDataPoint) int { return md.orig.SizeProto() } func (e *ProtoMarshaler) SummaryDataPointSize(md SummaryDataPoint) int { return md.orig.SizeProto() } func (e *ProtoMarshaler) HistogramDataPointSize(md HistogramDataPoint) int { return md.orig.SizeProto() } func (e *ProtoMarshaler) ExponentialHistogramDataPointSize(md ExponentialHistogramDataPoint) int { return md.orig.SizeProto() } type ProtoUnmarshaler struct{} func (d *ProtoUnmarshaler) UnmarshalMetrics(buf []byte) (Metrics, error) { md := NewMetrics() err := md.getOrig().UnmarshalProto(buf) if err != nil { return Metrics{}, err } return md, nil } opentelemetry-collector-0.141.0/pdata/pmetric/pb_test.go000066400000000000000000000066101511331344600232640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetric import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpmetrics "go.opentelemetry.io/proto/slim/otlp/metrics/v1" goproto "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestMetricsProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Metrics as pdata struct. td := generateTestMetrics() // Marshal its underlying ProtoBuf to wire. marshaler := &ProtoMarshaler{} wire1, err := marshaler.MarshalMetrics(td) require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlpmetrics.MetricsData err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. var td2 Metrics unmarshaler := &ProtoUnmarshaler{} td2, err = unmarshaler.UnmarshalMetrics(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. assert.Equal(t, td, td2) } func TestProtoMetricsUnmarshalerError(t *testing.T) { p := &ProtoUnmarshaler{} _, err := p.UnmarshalMetrics([]byte("+$%")) assert.Error(t, err) } func TestProtoSizer(t *testing.T) { marshaler := &ProtoMarshaler{} md := NewMetrics() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetName("foo") size := marshaler.MetricsSize(md) bytes, err := marshaler.MarshalMetrics(md) require.NoError(t, err) assert.Equal(t, len(bytes), size) } func TestProtoSizerEmptyMetrics(t *testing.T) { sizer := &ProtoMarshaler{} assert.Equal(t, 0, sizer.MetricsSize(NewMetrics())) } func BenchmarkMetricsToProto(b *testing.B) { marshaler := &ProtoMarshaler{} metrics := generateBenchmarkMetrics(128) for b.Loop() { buf, err := marshaler.MarshalMetrics(metrics) require.NoError(b, err) assert.NotEmpty(b, buf) } } func BenchmarkMetricsFromProto(b *testing.B) { marshaler := &ProtoMarshaler{} unmarshaler := &ProtoUnmarshaler{} baseMetrics := generateBenchmarkMetrics(128) buf, err := marshaler.MarshalMetrics(baseMetrics) require.NoError(b, err) assert.NotEmpty(b, buf) b.ReportAllocs() for b.Loop() { metrics, err := unmarshaler.UnmarshalMetrics(buf) require.NoError(b, err) assert.Equal(b, baseMetrics.ResourceMetrics().Len(), metrics.ResourceMetrics().Len()) } } func generateBenchmarkMetrics(metricsCount int) Metrics { now := time.Now() startTime := pcommon.NewTimestampFromTime(now.Add(-10 * time.Second)) endTime := pcommon.NewTimestampFromTime(now) md := NewMetrics() ilm := md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty() ilm.Metrics().EnsureCapacity(metricsCount) for range metricsCount { im := ilm.Metrics().AppendEmpty() im.SetName("test_name") idp := im.SetEmptySum().DataPoints().AppendEmpty() idp.SetStartTimestamp(startTime) idp.SetTimestamp(endTime) idp.SetIntValue(123) } return md } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/000077500000000000000000000000001511331344600236345ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/fuzz_test.go000066400000000000000000000014401511331344600262170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp // import "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" import ( "testing" ) func FuzzRequestUnmarshalJSON(f *testing.F) { f.Fuzz(func(_ *testing.T, data []byte) { er := NewExportRequest() _ = er.UnmarshalJSON(data) }) } func FuzzResponseUnmarshalJSON(f *testing.F) { f.Fuzz(func(_ *testing.T, data []byte) { er := NewExportResponse() _ = er.UnmarshalJSON(data) }) } func FuzzRequestUnmarshalProto(f *testing.F) { f.Fuzz(func(_ *testing.T, data []byte) { er := NewExportRequest() _ = er.UnmarshalJSON(data) }) } func FuzzResponseUnmarshalProto(f *testing.F) { f.Fuzz(func(_ *testing.T, data []byte) { er := NewExportResponse() _ = er.UnmarshalJSON(data) }) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess.go000066400000000000000000000053641511331344600325000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetricotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportPartialSuccess represents the details of a partially successful export request. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportPartialSuccess function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportPartialSuccess struct { orig *internal.ExportMetricsPartialSuccess state *internal.State } func newExportPartialSuccess(orig *internal.ExportMetricsPartialSuccess, state *internal.State) ExportPartialSuccess { return ExportPartialSuccess{orig: orig, state: state} } // NewExportPartialSuccess creates a new empty ExportPartialSuccess. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.NewExportMetricsPartialSuccess(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportPartialSuccess) MoveTo(dest ExportPartialSuccess) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportMetricsPartialSuccess(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // RejectedDataPoints returns the rejecteddatapoints associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) RejectedDataPoints() int64 { return ms.orig.RejectedDataPoints } // SetRejectedDataPoints replaces the rejecteddatapoints associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetRejectedDataPoints(v int64) { ms.state.AssertMutable() ms.orig.RejectedDataPoints = v } // ErrorMessage returns the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) ErrorMessage() string { return ms.orig.ErrorMessage } // SetErrorMessage replaces the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetErrorMessage(v string) { ms.state.AssertMutable() ms.orig.ErrorMessage = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportPartialSuccess) CopyTo(dest ExportPartialSuccess) { dest.state.AssertMutable() internal.CopyExportMetricsPartialSuccess(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/generated_exportpartialsuccess_test.go000066400000000000000000000046471511331344600335420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetricotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportPartialSuccess_MoveTo(t *testing.T) { ms := generateTestExportPartialSuccess() dest := NewExportPartialSuccess() ms.MoveTo(dest) assert.Equal(t, NewExportPartialSuccess(), ms) assert.Equal(t, generateTestExportPartialSuccess(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportPartialSuccess(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportPartialSuccess(internal.NewExportMetricsPartialSuccess(), sharedState)) }) assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportMetricsPartialSuccess(), sharedState).MoveTo(dest) }) } func TestExportPartialSuccess_CopyTo(t *testing.T) { ms := NewExportPartialSuccess() orig := NewExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportPartialSuccess(internal.NewExportMetricsPartialSuccess(), sharedState)) }) } func TestExportPartialSuccess_RejectedDataPoints(t *testing.T) { ms := NewExportPartialSuccess() assert.Equal(t, int64(0), ms.RejectedDataPoints()) ms.SetRejectedDataPoints(int64(13)) assert.Equal(t, int64(13), ms.RejectedDataPoints()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportMetricsPartialSuccess(), sharedState).SetRejectedDataPoints(int64(13)) }) } func TestExportPartialSuccess_ErrorMessage(t *testing.T) { ms := NewExportPartialSuccess() assert.Empty(t, ms.ErrorMessage()) ms.SetErrorMessage("test_errormessage") assert.Equal(t, "test_errormessage", ms.ErrorMessage()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportMetricsPartialSuccess(), sharedState).SetErrorMessage("test_errormessage") }) } func generateTestExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.GenTestExportMetricsPartialSuccess(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/generated_exportresponse.go000066400000000000000000000041241511331344600313020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetricotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportResponse represents the response for gRPC/HTTP client/server. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportResponse function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportResponse struct { orig *internal.ExportMetricsServiceResponse state *internal.State } func newExportResponse(orig *internal.ExportMetricsServiceResponse, state *internal.State) ExportResponse { return ExportResponse{orig: orig, state: state} } // NewExportResponse creates a new empty ExportResponse. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportResponse() ExportResponse { return newExportResponse(internal.NewExportMetricsServiceResponse(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportResponse) MoveTo(dest ExportResponse) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportMetricsServiceResponse(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // PartialSuccess returns the partialsuccess associated with this ExportResponse. func (ms ExportResponse) PartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(&ms.orig.PartialSuccess, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportResponse) CopyTo(dest ExportResponse) { dest.state.AssertMutable() internal.CopyExportMetricsServiceResponse(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/generated_exportresponse_test.go000066400000000000000000000033641511331344600323460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pmetricotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportResponse_MoveTo(t *testing.T) { ms := generateTestExportResponse() dest := NewExportResponse() ms.MoveTo(dest) assert.Equal(t, NewExportResponse(), ms) assert.Equal(t, generateTestExportResponse(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportResponse(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportResponse(internal.NewExportMetricsServiceResponse(), sharedState)) }) assert.Panics(t, func() { newExportResponse(internal.NewExportMetricsServiceResponse(), sharedState).MoveTo(dest) }) } func TestExportResponse_CopyTo(t *testing.T) { ms := NewExportResponse() orig := NewExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportResponse(internal.NewExportMetricsServiceResponse(), sharedState)) }) } func TestExportResponse_PartialSuccess(t *testing.T) { ms := NewExportResponse() assert.Equal(t, NewExportPartialSuccess(), ms.PartialSuccess()) ms.orig.PartialSuccess = *internal.GenTestExportMetricsPartialSuccess() assert.Equal(t, generateTestExportPartialSuccess(), ms.PartialSuccess()) } func generateTestExportResponse() ExportResponse { return newExportResponse(internal.GenTestExportMetricsServiceResponse(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/grpc.go000066400000000000000000000060161511331344600251210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp // import "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otelgrpc" "go.opentelemetry.io/collector/pdata/internal/otlp" ) // GRPCClient is the client API for OTLP-GRPC Metrics service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type GRPCClient interface { // Export pmetric.Metrics to the server. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) // unexported disallow implementation of the GRPCClient. unexported() } // NewGRPCClient returns a new GRPCClient connected using the given connection. func NewGRPCClient(cc *grpc.ClientConn) GRPCClient { return &grpcClient{rawClient: otelgrpc.NewMetricsServiceClient(cc)} } type grpcClient struct { rawClient otelgrpc.MetricsServiceClient } func (c *grpcClient) Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) { rsp, err := c.rawClient.Export(ctx, request.orig, opts...) if err != nil { return ExportResponse{}, err } return ExportResponse{orig: rsp, state: internal.NewState()}, err } func (c *grpcClient) unexported() {} // GRPCServer is the server API for OTLP gRPC MetricsService service. // Implementations MUST embed UnimplementedGRPCServer. type GRPCServer interface { // Export is called every time a new request is received. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(context.Context, ExportRequest) (ExportResponse, error) // unexported disallow implementation of the GRPCServer. unexported() } var _ GRPCServer = (*UnimplementedGRPCServer)(nil) // UnimplementedGRPCServer MUST be embedded to have forward compatible implementations. type UnimplementedGRPCServer struct{} func (*UnimplementedGRPCServer) Export(context.Context, ExportRequest) (ExportResponse, error) { return ExportResponse{}, status.Errorf(codes.Unimplemented, "method Export not implemented") } func (*UnimplementedGRPCServer) unexported() {} // RegisterGRPCServer registers the GRPCServer to the grpc.Server. func RegisterGRPCServer(s *grpc.Server, srv GRPCServer) { otelgrpc.RegisterMetricsServiceServer(s, &rawMetricsServer{srv: srv}) } type rawMetricsServer struct { srv GRPCServer } func (s rawMetricsServer) Export(ctx context.Context, request *internal.ExportMetricsServiceRequest) (*internal.ExportMetricsServiceResponse, error) { otlp.MigrateMetrics(request.ResourceMetrics) rsp, err := s.srv.Export(ctx, ExportRequest{orig: request, state: internal.NewState()}) return rsp.orig, err } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/grpc_test.go000066400000000000000000000053421511331344600261610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp import ( "context" "errors" "net" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" "go.opentelemetry.io/collector/pdata/pmetric" ) func TestGrpc(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeMetricsServer{t: t}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) resolver.SetDefaultScheme("passthrough") cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateMetricsRequest()) require.NoError(t, err) assert.Equal(t, NewExportResponse(), resp) } func TestGrpcError(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeMetricsServer{t: t, err: errors.New("my error")}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateMetricsRequest()) require.Error(t, err) st, okSt := status.FromError(err) require.True(t, okSt) assert.Equal(t, "my error", st.Message()) assert.Equal(t, codes.Unknown, st.Code()) assert.Equal(t, ExportResponse{}, resp) } type fakeMetricsServer struct { UnimplementedGRPCServer t *testing.T err error } func (f fakeMetricsServer) Export(_ context.Context, request ExportRequest) (ExportResponse, error) { assert.Equal(f.t, generateMetricsRequest(), request) return NewExportResponse(), f.err } func generateMetricsRequest() ExportRequest { md := pmetric.NewMetrics() m := md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") m.SetEmptyGauge().DataPoints().AppendEmpty() return NewExportRequestFromMetrics(md) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/package_test.go000066400000000000000000000003141511331344600266130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/request.go000066400000000000000000000045471511331344600256650ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp // import "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/pmetric" ) // ExportRequest represents the request for gRPC/HTTP client/server. // It's a wrapper for pmetric.Metrics data. type ExportRequest struct { orig *internal.ExportMetricsServiceRequest state *internal.State } // NewExportRequest returns an empty ExportRequest. func NewExportRequest() ExportRequest { return ExportRequest{ orig: &internal.ExportMetricsServiceRequest{}, state: internal.NewState(), } } // NewExportRequestFromMetrics returns a ExportRequest from pmetric.Metrics. // Because ExportRequest is a wrapper for pmetric.Metrics, // any changes to the provided Metrics struct will be reflected in the ExportRequest and vice versa. func NewExportRequestFromMetrics(md pmetric.Metrics) ExportRequest { return ExportRequest{ orig: internal.GetMetricsOrig(internal.MetricsWrapper(md)), state: internal.GetMetricsState(internal.MetricsWrapper(md)), } } // MarshalProto marshals ExportRequest into proto bytes. func (ms ExportRequest) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportRequest from proto bytes. func (ms ExportRequest) UnmarshalProto(data []byte) error { err := ms.orig.UnmarshalProto(data) if err != nil { return err } otlp.MigrateMetrics(ms.orig.ResourceMetrics) return nil } // MarshalJSON marshals ExportRequest into JSON bytes. func (ms ExportRequest) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } // UnmarshalJSON unmarshalls ExportRequest from JSON bytes. func (ms ExportRequest) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } func (ms ExportRequest) Metrics() pmetric.Metrics { return pmetric.Metrics(internal.NewMetricsWrapper(ms.orig, ms.state)) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/request_test.go000066400000000000000000000053501511331344600267150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp import ( "encoding/json" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectormetrics "go.opentelemetry.io/proto/slim/otlp/collector/metrics/v1" goproto "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/pmetric" ) var ( _ json.Unmarshaler = ExportRequest{} _ json.Marshaler = ExportRequest{} ) var metricsRequestJSON = []byte(` { "resourceMetrics": [ { "resource": {}, "scopeMetrics": [ { "scope": {}, "metrics": [ { "name": "test_metric" } ] } ] } ] }`) func TestRequestToPData(t *testing.T) { tr := NewExportRequest() assert.Equal(t, 0, tr.Metrics().MetricCount()) tr.Metrics().ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() assert.Equal(t, 1, tr.Metrics().MetricCount()) } func TestRequestJSON(t *testing.T) { mr := NewExportRequest() require.NoError(t, mr.UnmarshalJSON(metricsRequestJSON)) assert.Equal(t, "test_metric", mr.Metrics().ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) got, err := mr.MarshalJSON() require.NoError(t, err) assert.Equal(t, strings.Join(strings.Fields(string(metricsRequestJSON)), ""), string(got)) } func TestMetricsProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Metrics as pdata struct. md := NewExportRequestFromMetrics(pmetric.Metrics(internal.GenTestMetricsWrapper())) // Marshal its underlying ProtoBuf to wire. wire1, err := md.MarshalProto() require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlpcollectormetrics.ExportMetricsServiceRequest err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. md2 := NewExportRequest() err = md2.UnmarshalProto(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. // Migration logic will run, so run it on the original message as well. otlp.MigrateMetrics(md.orig.ResourceMetrics) assert.Equal(t, md, md2) } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/response.go000066400000000000000000000021501511331344600260170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp // import "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" ) // MarshalProto marshals ExportResponse into proto bytes. func (ms ExportResponse) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportResponse from proto bytes. func (ms ExportResponse) UnmarshalProto(data []byte) error { return ms.orig.UnmarshalProto(data) } // MarshalJSON marshals ExportResponse into JSON bytes. func (ms ExportResponse) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) return slices.Clone(dest.Buffer()), dest.Error() } // UnmarshalJSON unmarshalls ExportResponse from JSON bytes. func (ms ExportResponse) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } opentelemetry-collector-0.141.0/pdata/pmetric/pmetricotlp/response_test.go000066400000000000000000000020251511331344600270570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pmetricotlp import ( stdjson "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( _ stdjson.Unmarshaler = ExportResponse{} _ stdjson.Marshaler = ExportResponse{} ) func TestExportResponseJSON(t *testing.T) { jsonStr := `{"partialSuccess": {"rejectedDataPoints":"1", "errorMessage":"nothing"}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) expected := NewExportResponse() expected.PartialSuccess().SetRejectedDataPoints(1) expected.PartialSuccess().SetErrorMessage("nothing") assert.Equal(t, expected, val) buf, err := val.MarshalJSON() require.NoError(t, err) assert.JSONEq(t, jsonStr, string(buf)) } func TestUnmarshalJSONExportResponse(t *testing.T) { jsonStr := `{"extra":"", "partialSuccess": {"extra":""}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) assert.Equal(t, NewExportResponse(), val) } opentelemetry-collector-0.141.0/pdata/pprofile/000077500000000000000000000000001511331344600214475ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/pprofile/Makefile000066400000000000000000000000361511331344600231060ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/pdata/pprofile/aggregation_temporality.go000066400000000000000000000027361511331344600267260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "go.opentelemetry.io/collector/pdata/internal" ) // AggregationTemporality specifies the method of aggregating metric values, // either DELTA (change since last report) or CUMULATIVE (total since a fixed // start time). type AggregationTemporality int32 const ( // AggregationTemporalityUnspecified is the default AggregationTemporality, it MUST NOT be used. AggregationTemporalityUnspecified = AggregationTemporality(internal.AggregationTemporality_AGGREGATION_TEMPORALITY_UNSPECIFIED) // AggregationTemporalityDelta is a AggregationTemporality for a metric aggregator which reports changes since last report time. AggregationTemporalityDelta = AggregationTemporality(internal.AggregationTemporality_AGGREGATION_TEMPORALITY_DELTA) // AggregationTemporalityCumulative is a AggregationTemporality for a metric aggregator which reports changes since a fixed start time. AggregationTemporalityCumulative = AggregationTemporality(internal.AggregationTemporality_AGGREGATION_TEMPORALITY_CUMULATIVE) ) // String returns the string representation of the AggregationTemporality. func (at AggregationTemporality) String() string { switch at { case AggregationTemporalityUnspecified: return "Unspecified" case AggregationTemporalityDelta: return "Delta" case AggregationTemporalityCumulative: return "Cumulative" } return "" } opentelemetry-collector-0.141.0/pdata/pprofile/aggregation_temporality_test.go000066400000000000000000000007571511331344600277660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" ) func TestAggregationTemporalityString(t *testing.T) { assert.Equal(t, "Unspecified", AggregationTemporalityUnspecified.String()) assert.Equal(t, "Delta", AggregationTemporalityDelta.String()) assert.Equal(t, "Cumulative", AggregationTemporalityCumulative.String()) assert.Empty(t, (AggregationTemporalityCumulative + 1).String()) } opentelemetry-collector-0.141.0/pdata/pprofile/attributes.go000066400000000000000000000030031511331344600241600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "errors" "math" "go.opentelemetry.io/collector/pdata/pcommon" ) type attributable interface { AttributeIndices() pcommon.Int32Slice } // FromAttributeIndices builds a [pcommon.Map] containing the attributes of a // record. // The record can be any struct that implements an `AttributeIndices` method. // Updates made to the return map will not be applied back to the record. func FromAttributeIndices(table KeyValueAndUnitSlice, record attributable, dic ProfilesDictionary) pcommon.Map { m := pcommon.NewMap() m.EnsureCapacity(record.AttributeIndices().Len()) for i := 0; i < record.AttributeIndices().Len(); i++ { kv := table.At(int(record.AttributeIndices().At(i))) key := dic.StringTable().At(int(kv.KeyStrindex())) kv.Value().CopyTo(m.PutEmpty(key)) } return m } var errTooManyAttributeTableEntries = errors.New("too many entries in AttributeTable") // SetAttribute updates an AttributeTable, adding or providing a value and // returns its index. func SetAttribute(table KeyValueAndUnitSlice, attr KeyValueAndUnit) (int32, error) { for j, a := range table.All() { if a.Equal(attr) { if j > math.MaxInt32 { return 0, errTooManyAttributeTableEntries } return int32(j), nil } } if table.Len() >= math.MaxInt32 { return 0, errTooManyAttributeTableEntries } attr.CopyTo(table.AppendEmpty()) return int32(table.Len() - 1), nil } opentelemetry-collector-0.141.0/pdata/pprofile/attributes_test.go000066400000000000000000000103211511331344600252200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestFromAttributeIndices(t *testing.T) { dic := NewProfilesDictionary() dic.StringTable().Append("") dic.StringTable().Append("hello") dic.StringTable().Append("bonjour") table := NewKeyValueAndUnitSlice() att := table.AppendEmpty() att.SetKeyStrindex(1) att.Value().SetStr("world") att2 := table.AppendEmpty() att2.SetKeyStrindex(2) att2.Value().SetStr("monde") attrs := FromAttributeIndices(table, NewProfile(), dic) assert.Equal(t, attrs, pcommon.NewMap()) // A Location with a single attribute loc := NewLocation() loc.AttributeIndices().Append(0) attrs = FromAttributeIndices(table, loc, dic) m := map[string]any{"hello": "world"} assert.Equal(t, attrs.AsRaw(), m) // A Mapping with two attributes mapp := NewLocation() mapp.AttributeIndices().Append(0, 1) attrs = FromAttributeIndices(table, mapp, dic) m = map[string]any{"hello": "world", "bonjour": "monde"} assert.Equal(t, attrs.AsRaw(), m) } func BenchmarkFromAttributeIndices(b *testing.B) { dic := NewProfilesDictionary() table := NewKeyValueAndUnitSlice() for i := range 10 { dic.StringTable().Append(fmt.Sprintf("key_%d", i)) att := table.AppendEmpty() att.SetKeyStrindex(int32(dic.StringTable().Len())) att.Value().SetStr(fmt.Sprintf("value_%d", i)) } obj := NewLocation() obj.AttributeIndices().Append(1, 3, 7) b.ReportAllocs() for b.Loop() { _ = FromAttributeIndices(table, obj, dic) } } func TestSetAttribute(t *testing.T) { table := NewKeyValueAndUnitSlice() attr := NewKeyValueAndUnit() attr.SetKeyStrindex(1) attr.SetUnitStrindex(2) require.NoError(t, attr.Value().FromRaw("test")) attr2 := NewKeyValueAndUnit() attr2.SetKeyStrindex(3) attr2.SetUnitStrindex(4) require.NoError(t, attr.Value().FromRaw("test2")) // Put a first value idx, err := SetAttribute(table, attr) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Put the same attribute // This should be a no-op. idx, err = SetAttribute(table, attr) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Set a new value // This sets the index and adds to the table. idx, err = SetAttribute(table, attr2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) // Set an existing value idx, err = SetAttribute(table, attr) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(0), idx) // Set another existing value idx, err = SetAttribute(table, attr2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) } func BenchmarkSetAttribute(b *testing.B) { testutil.SkipMemoryBench(b) for _, bb := range []struct { name string attr KeyValueAndUnit runBefore func(*testing.B, KeyValueAndUnitSlice) }{ { name: "with a new attribute", attr: NewKeyValueAndUnit(), }, { name: "with an existing attribute", attr: func() KeyValueAndUnit { a := NewKeyValueAndUnit() a.SetKeyStrindex(1) return a }(), runBefore: func(_ *testing.B, table KeyValueAndUnitSlice) { a := table.AppendEmpty() a.SetKeyStrindex(1) }, }, { name: "with a duplicate attribute", attr: NewKeyValueAndUnit(), runBefore: func(_ *testing.B, table KeyValueAndUnitSlice) { _, err := SetAttribute(table, NewKeyValueAndUnit()) require.NoError(b, err) }, }, { name: "with a hundred locations to loop through", attr: func() KeyValueAndUnit { a := NewKeyValueAndUnit() a.SetKeyStrindex(1) return a }(), runBefore: func(_ *testing.B, table KeyValueAndUnitSlice) { for i := range 100 { l := table.AppendEmpty() l.SetKeyStrindex(int32(i)) } }, }, } { b.Run(bb.name, func(b *testing.B) { table := NewKeyValueAndUnitSlice() if bb.runBefore != nil { bb.runBefore(b, table) } b.ResetTimer() b.ReportAllocs() for b.Loop() { _, _ = SetAttribute(table, bb.attr) } }) } } opentelemetry-collector-0.141.0/pdata/pprofile/encoding.go000066400000000000000000000020441511331344600235640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" // MarshalSizer is the interface that groups the basic Marshal and Size methods type MarshalSizer interface { Marshaler Sizer } // Marshaler marshals pprofile.Profiles into bytes. type Marshaler interface { // MarshalProfiles the given pprofile.Profiles into bytes. // If the error is not nil, the returned bytes slice cannot be used. MarshalProfiles(td Profiles) ([]byte, error) } // Unmarshaler unmarshalls bytes into pprofile.Profiles. type Unmarshaler interface { // UnmarshalProfiles the given bytes into pprofile.Profiles. // If the error is not nil, the returned pprofile.Profiles cannot be used. UnmarshalProfiles(buf []byte) (Profiles, error) } // Sizer is an optional interface implemented by the Marshaler, // that calculates the size of a marshaled Profiles. type Sizer interface { // ProfilesSize returns the size in bytes of a marshaled Profiles. ProfilesSize(td Profiles) int } opentelemetry-collector-0.141.0/pdata/pprofile/function.go000066400000000000000000000033351511331344600236270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // Equal checks equality with another Function func (fn Function) Equal(val Function) bool { return fn.NameStrindex() == val.NameStrindex() && fn.SystemNameStrindex() == val.SystemNameStrindex() && fn.FilenameStrindex() == val.FilenameStrindex() && fn.StartLine() == val.StartLine() } // switchDictionary updates the Function, switching its indices from one // dictionary to another. func (fn Function) switchDictionary(src, dst ProfilesDictionary) error { if fn.NameStrindex() > 0 { if src.StringTable().Len() < int(fn.NameStrindex()) { return fmt.Errorf("invalid name index %d", fn.NameStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(fn.NameStrindex()))) if err != nil { return fmt.Errorf("couldn't set name: %w", err) } fn.SetNameStrindex(idx) } if fn.SystemNameStrindex() > 0 { if src.StringTable().Len() < int(fn.SystemNameStrindex()) { return fmt.Errorf("invalid system name index %d", fn.SystemNameStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(fn.SystemNameStrindex()))) if err != nil { return fmt.Errorf("couldn't set system name: %w", err) } fn.SetSystemNameStrindex(idx) } if fn.FilenameStrindex() > 0 { if src.StringTable().Len() < int(fn.FilenameStrindex()) { return fmt.Errorf("invalid filename index %d", fn.FilenameStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(fn.FilenameStrindex()))) if err != nil { return fmt.Errorf("couldn't set filename: %w", err) } fn.SetFilenameStrindex(idx) } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/function_test.go000066400000000000000000000140541511331344600246660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestFunctionEqual(t *testing.T) { for _, tt := range []struct { name string orig Function dest Function want bool }{ { name: "empty functions", orig: NewFunction(), dest: NewFunction(), want: true, }, { name: "non-empty identical functions", orig: buildFunction(1, 2, 3, 4), dest: buildFunction(1, 2, 3, 4), want: true, }, { name: "with different name", orig: buildFunction(1, 2, 3, 4), dest: buildFunction(2, 2, 3, 4), want: false, }, { name: "with different system name", orig: buildFunction(1, 2, 3, 4), dest: buildFunction(1, 3, 3, 4), want: false, }, { name: "with different file name", orig: buildFunction(1, 2, 3, 4), dest: buildFunction(1, 2, 4, 4), want: false, }, { name: "with different start line", orig: buildFunction(1, 2, 3, 4), dest: buildFunction(1, 2, 3, 5), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func TestFunctionSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string function Function src ProfilesDictionary dst ProfilesDictionary wantFunction Function wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty key value and unit", function: NewFunction(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantFunction: NewFunction(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing name", function: func() Function { fn := NewFunction() fn.SetNameStrindex(1) return fn }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantFunction: func() Function { fn := NewFunction() fn.SetNameStrindex(2) return fn }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a name index that does not match anything", function: func() Function { fn := NewFunction() fn.SetNameStrindex(1) return fn }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantFunction: func() Function { fn := NewFunction() fn.SetNameStrindex(1) return fn }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid name index 1"), }, { name: "with an existing system name", function: func() Function { fn := NewFunction() fn.SetSystemNameStrindex(1) return fn }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantFunction: func() Function { fn := NewFunction() fn.SetSystemNameStrindex(2) return fn }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a system name index that does not match anything", function: func() Function { fn := NewFunction() fn.SetSystemNameStrindex(1) return fn }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantFunction: func() Function { fn := NewFunction() fn.SetSystemNameStrindex(1) return fn }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid system name index 1"), }, { name: "with an existing filename", function: func() Function { fn := NewFunction() fn.SetFilenameStrindex(1) return fn }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantFunction: func() Function { fn := NewFunction() fn.SetFilenameStrindex(2) return fn }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a filename index that does not match anything", function: func() Function { fn := NewFunction() fn.SetFilenameStrindex(1) return fn }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantFunction: func() Function { fn := NewFunction() fn.SetFilenameStrindex(1) return fn }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid filename index 1"), }, } { t.Run(tt.name, func(t *testing.T) { fn := tt.function dst := tt.dst err := fn.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantFunction, fn) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkFunctionSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) fn := NewFunction() fn.SetNameStrindex(1) fn.SetSystemNameStrindex(2) src := NewProfilesDictionary() src.StringTable().Append("", "test", "foo") b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() dst.StringTable().Append("", "foo") b.StartTimer() _ = fn.switchDictionary(src, dst) } } func buildFunction(name, sName, fileName int32, startLine int64) Function { f := NewFunction() f.SetNameStrindex(name) f.SetSystemNameStrindex(sName) f.SetFilenameStrindex(fileName) f.SetStartLine(startLine) return f } opentelemetry-collector-0.141.0/pdata/pprofile/functions.go000066400000000000000000000013501511331344600240050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "errors" "math" ) var errTooManyFunctionTableEntries = errors.New("too many entries in FunctionTable") // SetFunction updates a FunctionTable, adding or providing a value and returns // its index. func SetFunction(table FunctionSlice, fn Function) (int32, error) { for j, m := range table.All() { if m.Equal(fn) { if j > math.MaxInt32 { return 0, errTooManyFunctionTableEntries } return int32(j), nil } } if table.Len() >= math.MaxInt32 { return 0, errTooManyFunctionTableEntries } fn.CopyTo(table.AppendEmpty()) return int32(table.Len() - 1), nil } opentelemetry-collector-0.141.0/pdata/pprofile/functions_test.go000066400000000000000000000047541511331344600250570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestSetFunction(t *testing.T) { table := NewFunctionSlice() f := NewFunction() f.SetNameStrindex(1) f2 := NewFunction() f2.SetNameStrindex(2) // Put a first function idx, err := SetFunction(table, f) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Put the same function // This should be a no-op. idx, err = SetFunction(table, f) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Set a new function // This sets the index and adds to the table. idx, err = SetFunction(table, f2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) // Set an existing function idx, err = SetFunction(table, f) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(0), idx) // Set another existing function idx, err = SetFunction(table, f2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) } func BenchmarkSetFunction(b *testing.B) { testutil.SkipMemoryBench(b) for _, bb := range []struct { name string fn Function runBefore func(*testing.B, FunctionSlice) }{ { name: "with a new function", fn: NewFunction(), }, { name: "with an existing function", fn: func() Function { f := NewFunction() f.SetNameStrindex(1) return f }(), runBefore: func(_ *testing.B, table FunctionSlice) { f := table.AppendEmpty() f.SetNameStrindex(1) }, }, { name: "with a duplicate function", fn: NewFunction(), runBefore: func(b *testing.B, table FunctionSlice) { _, err := SetFunction(table, NewFunction()) require.NoError(b, err) }, }, { name: "with a hundred functions to loop through", fn: func() Function { f := NewFunction() f.SetNameStrindex(1) return f }(), runBefore: func(_ *testing.B, table FunctionSlice) { for i := range 100 { f := table.AppendEmpty() f.SetNameStrindex(int32(i)) } }, }, } { b.Run(bb.name, func(b *testing.B) { table := NewFunctionSlice() if bb.runBefore != nil { bb.runBefore(b, table) } b.ResetTimer() b.ReportAllocs() for b.Loop() { _, _ = SetFunction(table, bb.fn) } }) } } opentelemetry-collector-0.141.0/pdata/pprofile/fuzz_test.go000066400000000000000000000017131511331344600240350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "bytes" "testing" "github.com/stretchr/testify/require" ) var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." func FuzzUnmarshalProfiles(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { u1 := &JSONUnmarshaler{} ld1, err := u1.UnmarshalProfiles(data) if err != nil { return } m1 := &JSONMarshaler{} b1, err := m1.MarshalProfiles(ld1) require.NoError(t, err, "failed to marshal valid struct") u2 := &JSONUnmarshaler{} ld2, err := u2.UnmarshalProfiles(b1) require.NoError(t, err, "failed to unmarshal valid bytes") m2 := &JSONMarshaler{} b2, err := m2.MarshalProfiles(ld2) require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_function.go000066400000000000000000000061041511331344600256420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" ) // Function describes a function, including its human-readable name, system name, source file, and starting line number in the source. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewFunction function to create new instances. // Important: zero-initialized instance is not valid for use. type Function struct { orig *internal.Function state *internal.State } func newFunction(orig *internal.Function, state *internal.State) Function { return Function{orig: orig, state: state} } // NewFunction creates a new empty Function. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewFunction() Function { return newFunction(internal.NewFunction(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Function) MoveTo(dest Function) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteFunction(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // NameStrindex returns the namestrindex associated with this Function. func (ms Function) NameStrindex() int32 { return ms.orig.NameStrindex } // SetNameStrindex replaces the namestrindex associated with this Function. func (ms Function) SetNameStrindex(v int32) { ms.state.AssertMutable() ms.orig.NameStrindex = v } // SystemNameStrindex returns the systemnamestrindex associated with this Function. func (ms Function) SystemNameStrindex() int32 { return ms.orig.SystemNameStrindex } // SetSystemNameStrindex replaces the systemnamestrindex associated with this Function. func (ms Function) SetSystemNameStrindex(v int32) { ms.state.AssertMutable() ms.orig.SystemNameStrindex = v } // FilenameStrindex returns the filenamestrindex associated with this Function. func (ms Function) FilenameStrindex() int32 { return ms.orig.FilenameStrindex } // SetFilenameStrindex replaces the filenamestrindex associated with this Function. func (ms Function) SetFilenameStrindex(v int32) { ms.state.AssertMutable() ms.orig.FilenameStrindex = v } // StartLine returns the startline associated with this Function. func (ms Function) StartLine() int64 { return ms.orig.StartLine } // SetStartLine replaces the startline associated with this Function. func (ms Function) SetStartLine(v int64) { ms.state.AssertMutable() ms.orig.StartLine = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms Function) CopyTo(dest Function) { dest.state.AssertMutable() internal.CopyFunction(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_function_test.go000066400000000000000000000053571511331344600267120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestFunction_MoveTo(t *testing.T) { ms := generateTestFunction() dest := NewFunction() ms.MoveTo(dest) assert.Equal(t, NewFunction(), ms) assert.Equal(t, generateTestFunction(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestFunction(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newFunction(internal.NewFunction(), sharedState)) }) assert.Panics(t, func() { newFunction(internal.NewFunction(), sharedState).MoveTo(dest) }) } func TestFunction_CopyTo(t *testing.T) { ms := NewFunction() orig := NewFunction() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestFunction() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newFunction(internal.NewFunction(), sharedState)) }) } func TestFunction_NameStrindex(t *testing.T) { ms := NewFunction() assert.Equal(t, int32(0), ms.NameStrindex()) ms.SetNameStrindex(int32(13)) assert.Equal(t, int32(13), ms.NameStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newFunction(internal.NewFunction(), sharedState).SetNameStrindex(int32(13)) }) } func TestFunction_SystemNameStrindex(t *testing.T) { ms := NewFunction() assert.Equal(t, int32(0), ms.SystemNameStrindex()) ms.SetSystemNameStrindex(int32(13)) assert.Equal(t, int32(13), ms.SystemNameStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newFunction(internal.NewFunction(), sharedState).SetSystemNameStrindex(int32(13)) }) } func TestFunction_FilenameStrindex(t *testing.T) { ms := NewFunction() assert.Equal(t, int32(0), ms.FilenameStrindex()) ms.SetFilenameStrindex(int32(13)) assert.Equal(t, int32(13), ms.FilenameStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newFunction(internal.NewFunction(), sharedState).SetFilenameStrindex(int32(13)) }) } func TestFunction_StartLine(t *testing.T) { ms := NewFunction() assert.Equal(t, int64(0), ms.StartLine()) ms.SetStartLine(int64(13)) assert.Equal(t, int64(13), ms.StartLine()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newFunction(internal.NewFunction(), sharedState).SetStartLine(int64(13)) }) } func generateTestFunction() Function { return newFunction(internal.GenTestFunction(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_functionslice.go000066400000000000000000000112261511331344600266630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // FunctionSlice logically represents a slice of Function. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewFunctionSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type FunctionSlice struct { orig *[]*internal.Function state *internal.State } func newFunctionSlice(orig *[]*internal.Function, state *internal.State) FunctionSlice { return FunctionSlice{orig: orig, state: state} } // NewFunctionSlice creates a FunctionSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewFunctionSlice() FunctionSlice { orig := []*internal.Function(nil) return newFunctionSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewFunctionSlice()". func (es FunctionSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es FunctionSlice) At(i int) Function { return newFunction((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es FunctionSlice) All() iter.Seq2[int, Function] { return func(yield func(int, Function) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new FunctionSlice can be initialized: // // es := NewFunctionSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es FunctionSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Function, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Function. // It returns the newly added Function. func (es FunctionSlice) AppendEmpty() Function { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewFunction()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es FunctionSlice) MoveAndAppendTo(dest FunctionSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es FunctionSlice) RemoveIf(f func(Function) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteFunction((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es FunctionSlice) CopyTo(dest FunctionSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyFunctionPtrSlice(*dest.orig, *es.orig) } // Sort sorts the Function elements within FunctionSlice given the // provided less function so that two instances of FunctionSlice // can be compared. func (es FunctionSlice) Sort(less func(a, b Function) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_functionslice_test.go000066400000000000000000000113141511331344600277200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestFunctionSlice(t *testing.T) { es := NewFunctionSlice() assert.Equal(t, 0, es.Len()) es = newFunctionSlice(&[]*internal.Function{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewFunction() testVal := generateTestFunction() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestFunction() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestFunctionSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newFunctionSlice(&[]*internal.Function{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewFunctionSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestFunctionSlice_CopyTo(t *testing.T) { dest := NewFunctionSlice() src := generateTestFunctionSlice() src.CopyTo(dest) assert.Equal(t, generateTestFunctionSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestFunctionSlice(), dest) } func TestFunctionSlice_EnsureCapacity(t *testing.T) { es := generateTestFunctionSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestFunctionSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestFunctionSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestFunctionSlice(), es) } func TestFunctionSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestFunctionSlice() dest := NewFunctionSlice() src := generateTestFunctionSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestFunctionSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestFunctionSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestFunctionSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestFunctionSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewFunctionSlice() emptySlice.RemoveIf(func(el Function) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestFunctionSlice() pos := 0 filtered.RemoveIf(func(el Function) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestFunctionSlice_RemoveIfAll(t *testing.T) { got := generateTestFunctionSlice() got.RemoveIf(func(el Function) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestFunctionSliceAll(t *testing.T) { ms := generateTestFunctionSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestFunctionSlice_Sort(t *testing.T) { es := generateTestFunctionSlice() es.Sort(func(a, b Function) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Function) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestFunctionSlice() FunctionSlice { ms := NewFunctionSlice() *ms.orig = internal.GenTestFunctionPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_keyvalueandunit.go000066400000000000000000000055241511331344600272320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // KeyValueAndUnit represents a custom 'dictionary native' // style of encoding attributes which is more convenient // for profiles than opentelemetry.proto.common.v1.KeyValue. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewKeyValueAndUnit function to create new instances. // Important: zero-initialized instance is not valid for use. type KeyValueAndUnit struct { orig *internal.KeyValueAndUnit state *internal.State } func newKeyValueAndUnit(orig *internal.KeyValueAndUnit, state *internal.State) KeyValueAndUnit { return KeyValueAndUnit{orig: orig, state: state} } // NewKeyValueAndUnit creates a new empty KeyValueAndUnit. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewKeyValueAndUnit() KeyValueAndUnit { return newKeyValueAndUnit(internal.NewKeyValueAndUnit(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms KeyValueAndUnit) MoveTo(dest KeyValueAndUnit) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteKeyValueAndUnit(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // KeyStrindex returns the keystrindex associated with this KeyValueAndUnit. func (ms KeyValueAndUnit) KeyStrindex() int32 { return ms.orig.KeyStrindex } // SetKeyStrindex replaces the keystrindex associated with this KeyValueAndUnit. func (ms KeyValueAndUnit) SetKeyStrindex(v int32) { ms.state.AssertMutable() ms.orig.KeyStrindex = v } // Value returns the value associated with this KeyValueAndUnit. func (ms KeyValueAndUnit) Value() pcommon.Value { return pcommon.Value(internal.NewValueWrapper(&ms.orig.Value, ms.state)) } // UnitStrindex returns the unitstrindex associated with this KeyValueAndUnit. func (ms KeyValueAndUnit) UnitStrindex() int32 { return ms.orig.UnitStrindex } // SetUnitStrindex replaces the unitstrindex associated with this KeyValueAndUnit. func (ms KeyValueAndUnit) SetUnitStrindex(v int32) { ms.state.AssertMutable() ms.orig.UnitStrindex = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms KeyValueAndUnit) CopyTo(dest KeyValueAndUnit) { dest.state.AssertMutable() internal.CopyKeyValueAndUnit(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_keyvalueandunit_test.go000066400000000000000000000047351511331344600302740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestKeyValueAndUnit_MoveTo(t *testing.T) { ms := generateTestKeyValueAndUnit() dest := NewKeyValueAndUnit() ms.MoveTo(dest) assert.Equal(t, NewKeyValueAndUnit(), ms) assert.Equal(t, generateTestKeyValueAndUnit(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestKeyValueAndUnit(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newKeyValueAndUnit(internal.NewKeyValueAndUnit(), sharedState)) }) assert.Panics(t, func() { newKeyValueAndUnit(internal.NewKeyValueAndUnit(), sharedState).MoveTo(dest) }) } func TestKeyValueAndUnit_CopyTo(t *testing.T) { ms := NewKeyValueAndUnit() orig := NewKeyValueAndUnit() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestKeyValueAndUnit() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newKeyValueAndUnit(internal.NewKeyValueAndUnit(), sharedState)) }) } func TestKeyValueAndUnit_KeyStrindex(t *testing.T) { ms := NewKeyValueAndUnit() assert.Equal(t, int32(0), ms.KeyStrindex()) ms.SetKeyStrindex(int32(13)) assert.Equal(t, int32(13), ms.KeyStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newKeyValueAndUnit(internal.NewKeyValueAndUnit(), sharedState).SetKeyStrindex(int32(13)) }) } func TestKeyValueAndUnit_Value(t *testing.T) { ms := NewKeyValueAndUnit() assert.Equal(t, pcommon.NewValueEmpty(), ms.Value()) ms.orig.Value = *internal.GenTestAnyValue() assert.Equal(t, pcommon.Value(internal.GenTestValueWrapper()), ms.Value()) } func TestKeyValueAndUnit_UnitStrindex(t *testing.T) { ms := NewKeyValueAndUnit() assert.Equal(t, int32(0), ms.UnitStrindex()) ms.SetUnitStrindex(int32(13)) assert.Equal(t, int32(13), ms.UnitStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newKeyValueAndUnit(internal.NewKeyValueAndUnit(), sharedState).SetUnitStrindex(int32(13)) }) } func generateTestKeyValueAndUnit() KeyValueAndUnit { return newKeyValueAndUnit(internal.GenTestKeyValueAndUnit(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_keyvalueandunitslice.go000066400000000000000000000117211511331344600302460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // KeyValueAndUnitSlice logically represents a slice of KeyValueAndUnit. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewKeyValueAndUnitSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type KeyValueAndUnitSlice struct { orig *[]*internal.KeyValueAndUnit state *internal.State } func newKeyValueAndUnitSlice(orig *[]*internal.KeyValueAndUnit, state *internal.State) KeyValueAndUnitSlice { return KeyValueAndUnitSlice{orig: orig, state: state} } // NewKeyValueAndUnitSlice creates a KeyValueAndUnitSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewKeyValueAndUnitSlice() KeyValueAndUnitSlice { orig := []*internal.KeyValueAndUnit(nil) return newKeyValueAndUnitSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewKeyValueAndUnitSlice()". func (es KeyValueAndUnitSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es KeyValueAndUnitSlice) At(i int) KeyValueAndUnit { return newKeyValueAndUnit((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es KeyValueAndUnitSlice) All() iter.Seq2[int, KeyValueAndUnit] { return func(yield func(int, KeyValueAndUnit) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new KeyValueAndUnitSlice can be initialized: // // es := NewKeyValueAndUnitSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es KeyValueAndUnitSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.KeyValueAndUnit, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty KeyValueAndUnit. // It returns the newly added KeyValueAndUnit. func (es KeyValueAndUnitSlice) AppendEmpty() KeyValueAndUnit { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewKeyValueAndUnit()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es KeyValueAndUnitSlice) MoveAndAppendTo(dest KeyValueAndUnitSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es KeyValueAndUnitSlice) RemoveIf(f func(KeyValueAndUnit) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteKeyValueAndUnit((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es KeyValueAndUnitSlice) CopyTo(dest KeyValueAndUnitSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyKeyValueAndUnitPtrSlice(*dest.orig, *es.orig) } // Sort sorts the KeyValueAndUnit elements within KeyValueAndUnitSlice given the // provided less function so that two instances of KeyValueAndUnitSlice // can be compared. func (es KeyValueAndUnitSlice) Sort(less func(a, b KeyValueAndUnit) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_keyvalueandunitslice_test.go000066400000000000000000000120161511331344600313030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestKeyValueAndUnitSlice(t *testing.T) { es := NewKeyValueAndUnitSlice() assert.Equal(t, 0, es.Len()) es = newKeyValueAndUnitSlice(&[]*internal.KeyValueAndUnit{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewKeyValueAndUnit() testVal := generateTestKeyValueAndUnit() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestKeyValueAndUnit() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestKeyValueAndUnitSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newKeyValueAndUnitSlice(&[]*internal.KeyValueAndUnit{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewKeyValueAndUnitSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestKeyValueAndUnitSlice_CopyTo(t *testing.T) { dest := NewKeyValueAndUnitSlice() src := generateTestKeyValueAndUnitSlice() src.CopyTo(dest) assert.Equal(t, generateTestKeyValueAndUnitSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestKeyValueAndUnitSlice(), dest) } func TestKeyValueAndUnitSlice_EnsureCapacity(t *testing.T) { es := generateTestKeyValueAndUnitSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestKeyValueAndUnitSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestKeyValueAndUnitSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestKeyValueAndUnitSlice(), es) } func TestKeyValueAndUnitSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestKeyValueAndUnitSlice() dest := NewKeyValueAndUnitSlice() src := generateTestKeyValueAndUnitSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestKeyValueAndUnitSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestKeyValueAndUnitSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestKeyValueAndUnitSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestKeyValueAndUnitSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewKeyValueAndUnitSlice() emptySlice.RemoveIf(func(el KeyValueAndUnit) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestKeyValueAndUnitSlice() pos := 0 filtered.RemoveIf(func(el KeyValueAndUnit) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestKeyValueAndUnitSlice_RemoveIfAll(t *testing.T) { got := generateTestKeyValueAndUnitSlice() got.RemoveIf(func(el KeyValueAndUnit) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestKeyValueAndUnitSliceAll(t *testing.T) { ms := generateTestKeyValueAndUnitSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestKeyValueAndUnitSlice_Sort(t *testing.T) { es := generateTestKeyValueAndUnitSlice() es.Sort(func(a, b KeyValueAndUnit) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b KeyValueAndUnit) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestKeyValueAndUnitSlice() KeyValueAndUnitSlice { ms := NewKeyValueAndUnitSlice() *ms.orig = internal.GenTestKeyValueAndUnitPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_line.go000066400000000000000000000046461511331344600247550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" ) // Line details a specific line in a source code, linked to a function. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewLine function to create new instances. // Important: zero-initialized instance is not valid for use. type Line struct { orig *internal.Line state *internal.State } func newLine(orig *internal.Line, state *internal.State) Line { return Line{orig: orig, state: state} } // NewLine creates a new empty Line. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewLine() Line { return newLine(internal.NewLine(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Line) MoveTo(dest Line) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteLine(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // FunctionIndex returns the functionindex associated with this Line. func (ms Line) FunctionIndex() int32 { return ms.orig.FunctionIndex } // SetFunctionIndex replaces the functionindex associated with this Line. func (ms Line) SetFunctionIndex(v int32) { ms.state.AssertMutable() ms.orig.FunctionIndex = v } // Line returns the line associated with this Line. func (ms Line) Line() int64 { return ms.orig.Line } // SetLine replaces the line associated with this Line. func (ms Line) SetLine(v int64) { ms.state.AssertMutable() ms.orig.Line = v } // Column returns the column associated with this Line. func (ms Line) Column() int64 { return ms.orig.Column } // SetColumn replaces the column associated with this Line. func (ms Line) SetColumn(v int64) { ms.state.AssertMutable() ms.orig.Column = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms Line) CopyTo(dest Line) { dest.state.AssertMutable() internal.CopyLine(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_line_test.go000066400000000000000000000042361511331344600260070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestLine_MoveTo(t *testing.T) { ms := generateTestLine() dest := NewLine() ms.MoveTo(dest) assert.Equal(t, NewLine(), ms) assert.Equal(t, generateTestLine(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestLine(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newLine(internal.NewLine(), sharedState)) }) assert.Panics(t, func() { newLine(internal.NewLine(), sharedState).MoveTo(dest) }) } func TestLine_CopyTo(t *testing.T) { ms := NewLine() orig := NewLine() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestLine() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newLine(internal.NewLine(), sharedState)) }) } func TestLine_FunctionIndex(t *testing.T) { ms := NewLine() assert.Equal(t, int32(0), ms.FunctionIndex()) ms.SetFunctionIndex(int32(13)) assert.Equal(t, int32(13), ms.FunctionIndex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLine(internal.NewLine(), sharedState).SetFunctionIndex(int32(13)) }) } func TestLine_Line(t *testing.T) { ms := NewLine() assert.Equal(t, int64(0), ms.Line()) ms.SetLine(int64(13)) assert.Equal(t, int64(13), ms.Line()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLine(internal.NewLine(), sharedState).SetLine(int64(13)) }) } func TestLine_Column(t *testing.T) { ms := NewLine() assert.Equal(t, int64(0), ms.Column()) ms.SetColumn(int64(13)) assert.Equal(t, int64(13), ms.Column()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLine(internal.NewLine(), sharedState).SetColumn(int64(13)) }) } func generateTestLine() Line { return newLine(internal.GenTestLine(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_lineslice.go000066400000000000000000000107421511331344600257670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // LineSlice logically represents a slice of Line. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewLineSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type LineSlice struct { orig *[]*internal.Line state *internal.State } func newLineSlice(orig *[]*internal.Line, state *internal.State) LineSlice { return LineSlice{orig: orig, state: state} } // NewLineSlice creates a LineSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewLineSlice() LineSlice { orig := []*internal.Line(nil) return newLineSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewLineSlice()". func (es LineSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es LineSlice) At(i int) Line { return newLine((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es LineSlice) All() iter.Seq2[int, Line] { return func(yield func(int, Line) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new LineSlice can be initialized: // // es := NewLineSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es LineSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Line, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Line. // It returns the newly added Line. func (es LineSlice) AppendEmpty() Line { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewLine()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es LineSlice) MoveAndAppendTo(dest LineSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es LineSlice) RemoveIf(f func(Line) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteLine((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es LineSlice) CopyTo(dest LineSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyLinePtrSlice(*dest.orig, *es.orig) } // Sort sorts the Line elements within LineSlice given the // provided less function so that two instances of LineSlice // can be compared. func (es LineSlice) Sort(less func(a, b Line) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_lineslice_test.go000066400000000000000000000110241511331344600270200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestLineSlice(t *testing.T) { es := NewLineSlice() assert.Equal(t, 0, es.Len()) es = newLineSlice(&[]*internal.Line{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewLine() testVal := generateTestLine() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestLine() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestLineSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newLineSlice(&[]*internal.Line{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewLineSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestLineSlice_CopyTo(t *testing.T) { dest := NewLineSlice() src := generateTestLineSlice() src.CopyTo(dest) assert.Equal(t, generateTestLineSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestLineSlice(), dest) } func TestLineSlice_EnsureCapacity(t *testing.T) { es := generateTestLineSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestLineSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestLineSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestLineSlice(), es) } func TestLineSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestLineSlice() dest := NewLineSlice() src := generateTestLineSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLineSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLineSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestLineSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestLineSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewLineSlice() emptySlice.RemoveIf(func(el Line) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestLineSlice() pos := 0 filtered.RemoveIf(func(el Line) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestLineSlice_RemoveIfAll(t *testing.T) { got := generateTestLineSlice() got.RemoveIf(func(el Line) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestLineSliceAll(t *testing.T) { ms := generateTestLineSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestLineSlice_Sort(t *testing.T) { es := generateTestLineSlice() es.Sort(func(a, b Line) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Line) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestLineSlice() LineSlice { ms := NewLineSlice() *ms.orig = internal.GenTestLinePtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_link.go000066400000000000000000000044301511331344600247520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Link represents a pointer from a profile Sample to a trace Span. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewLink function to create new instances. // Important: zero-initialized instance is not valid for use. type Link struct { orig *internal.Link state *internal.State } func newLink(orig *internal.Link, state *internal.State) Link { return Link{orig: orig, state: state} } // NewLink creates a new empty Link. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewLink() Link { return newLink(internal.NewLink(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Link) MoveTo(dest Link) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteLink(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // TraceID returns the traceid associated with this Link. func (ms Link) TraceID() pcommon.TraceID { return pcommon.TraceID(ms.orig.TraceId) } // SetTraceID replaces the traceid associated with this Link. func (ms Link) SetTraceID(v pcommon.TraceID) { ms.state.AssertMutable() ms.orig.TraceId = internal.TraceID(v) } // SpanID returns the spanid associated with this Link. func (ms Link) SpanID() pcommon.SpanID { return pcommon.SpanID(ms.orig.SpanId) } // SetSpanID replaces the spanid associated with this Link. func (ms Link) SetSpanID(v pcommon.SpanID) { ms.state.AssertMutable() ms.orig.SpanId = internal.SpanID(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Link) CopyTo(dest Link) { dest.state.AssertMutable() internal.CopyLink(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_link_test.go000066400000000000000000000035341511331344600260150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestLink_MoveTo(t *testing.T) { ms := generateTestLink() dest := NewLink() ms.MoveTo(dest) assert.Equal(t, NewLink(), ms) assert.Equal(t, generateTestLink(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestLink(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newLink(internal.NewLink(), sharedState)) }) assert.Panics(t, func() { newLink(internal.NewLink(), sharedState).MoveTo(dest) }) } func TestLink_CopyTo(t *testing.T) { ms := NewLink() orig := NewLink() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestLink() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newLink(internal.NewLink(), sharedState)) }) } func TestLink_TraceID(t *testing.T) { ms := NewLink() assert.Equal(t, pcommon.TraceID(internal.TraceID([16]byte{})), ms.TraceID()) testValTraceID := pcommon.TraceID(internal.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})) ms.SetTraceID(testValTraceID) assert.Equal(t, testValTraceID, ms.TraceID()) } func TestLink_SpanID(t *testing.T) { ms := NewLink() assert.Equal(t, pcommon.SpanID(internal.SpanID([8]byte{})), ms.SpanID()) testValSpanID := pcommon.SpanID(internal.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})) ms.SetSpanID(testValSpanID) assert.Equal(t, testValSpanID, ms.SpanID()) } func generateTestLink() Link { return newLink(internal.GenTestLink(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_linkslice.go000066400000000000000000000107421511331344600257750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // LinkSlice logically represents a slice of Link. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewLinkSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type LinkSlice struct { orig *[]*internal.Link state *internal.State } func newLinkSlice(orig *[]*internal.Link, state *internal.State) LinkSlice { return LinkSlice{orig: orig, state: state} } // NewLinkSlice creates a LinkSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewLinkSlice() LinkSlice { orig := []*internal.Link(nil) return newLinkSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewLinkSlice()". func (es LinkSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es LinkSlice) At(i int) Link { return newLink((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es LinkSlice) All() iter.Seq2[int, Link] { return func(yield func(int, Link) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new LinkSlice can be initialized: // // es := NewLinkSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es LinkSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Link, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Link. // It returns the newly added Link. func (es LinkSlice) AppendEmpty() Link { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewLink()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es LinkSlice) MoveAndAppendTo(dest LinkSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es LinkSlice) RemoveIf(f func(Link) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteLink((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es LinkSlice) CopyTo(dest LinkSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyLinkPtrSlice(*dest.orig, *es.orig) } // Sort sorts the Link elements within LinkSlice given the // provided less function so that two instances of LinkSlice // can be compared. func (es LinkSlice) Sort(less func(a, b Link) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_linkslice_test.go000066400000000000000000000110241511331344600270260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestLinkSlice(t *testing.T) { es := NewLinkSlice() assert.Equal(t, 0, es.Len()) es = newLinkSlice(&[]*internal.Link{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewLink() testVal := generateTestLink() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestLink() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestLinkSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newLinkSlice(&[]*internal.Link{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewLinkSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestLinkSlice_CopyTo(t *testing.T) { dest := NewLinkSlice() src := generateTestLinkSlice() src.CopyTo(dest) assert.Equal(t, generateTestLinkSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestLinkSlice(), dest) } func TestLinkSlice_EnsureCapacity(t *testing.T) { es := generateTestLinkSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestLinkSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestLinkSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestLinkSlice(), es) } func TestLinkSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestLinkSlice() dest := NewLinkSlice() src := generateTestLinkSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLinkSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLinkSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestLinkSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestLinkSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewLinkSlice() emptySlice.RemoveIf(func(el Link) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestLinkSlice() pos := 0 filtered.RemoveIf(func(el Link) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestLinkSlice_RemoveIfAll(t *testing.T) { got := generateTestLinkSlice() got.RemoveIf(func(el Link) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestLinkSliceAll(t *testing.T) { ms := generateTestLinkSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestLinkSlice_Sort(t *testing.T) { es := generateTestLinkSlice() es.Sort(func(a, b Link) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Link) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestLinkSlice() LinkSlice { ms := NewLinkSlice() *ms.orig = internal.GenTestLinkPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_location.go000066400000000000000000000053111511331344600256240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Location describes function and line table debug information. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewLocation function to create new instances. // Important: zero-initialized instance is not valid for use. type Location struct { orig *internal.Location state *internal.State } func newLocation(orig *internal.Location, state *internal.State) Location { return Location{orig: orig, state: state} } // NewLocation creates a new empty Location. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewLocation() Location { return newLocation(internal.NewLocation(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Location) MoveTo(dest Location) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteLocation(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // MappingIndex returns the mappingindex associated with this Location. func (ms Location) MappingIndex() int32 { return ms.orig.MappingIndex } // SetMappingIndex replaces the mappingindex associated with this Location. func (ms Location) SetMappingIndex(v int32) { ms.state.AssertMutable() ms.orig.MappingIndex = v } // Address returns the address associated with this Location. func (ms Location) Address() uint64 { return ms.orig.Address } // SetAddress replaces the address associated with this Location. func (ms Location) SetAddress(v uint64) { ms.state.AssertMutable() ms.orig.Address = v } // Lines returns the Lines associated with this Location. func (ms Location) Lines() LineSlice { return newLineSlice(&ms.orig.Lines, ms.state) } // AttributeIndices returns the AttributeIndices associated with this Location. func (ms Location) AttributeIndices() pcommon.Int32Slice { return pcommon.Int32Slice(internal.NewInt32SliceWrapper(&ms.orig.AttributeIndices, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Location) CopyTo(dest Location) { dest.state.AssertMutable() internal.CopyLocation(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_location_test.go000066400000000000000000000050051511331344600266630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestLocation_MoveTo(t *testing.T) { ms := generateTestLocation() dest := NewLocation() ms.MoveTo(dest) assert.Equal(t, NewLocation(), ms) assert.Equal(t, generateTestLocation(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestLocation(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newLocation(internal.NewLocation(), sharedState)) }) assert.Panics(t, func() { newLocation(internal.NewLocation(), sharedState).MoveTo(dest) }) } func TestLocation_CopyTo(t *testing.T) { ms := NewLocation() orig := NewLocation() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestLocation() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newLocation(internal.NewLocation(), sharedState)) }) } func TestLocation_MappingIndex(t *testing.T) { ms := NewLocation() assert.Equal(t, int32(0), ms.MappingIndex()) ms.SetMappingIndex(int32(13)) assert.Equal(t, int32(13), ms.MappingIndex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLocation(internal.NewLocation(), sharedState).SetMappingIndex(int32(13)) }) } func TestLocation_Address(t *testing.T) { ms := NewLocation() assert.Equal(t, uint64(0), ms.Address()) ms.SetAddress(uint64(13)) assert.Equal(t, uint64(13), ms.Address()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newLocation(internal.NewLocation(), sharedState).SetAddress(uint64(13)) }) } func TestLocation_Lines(t *testing.T) { ms := NewLocation() assert.Equal(t, NewLineSlice(), ms.Lines()) ms.orig.Lines = internal.GenTestLinePtrSlice() assert.Equal(t, generateTestLineSlice(), ms.Lines()) } func TestLocation_AttributeIndices(t *testing.T) { ms := NewLocation() assert.Equal(t, pcommon.NewInt32Slice(), ms.AttributeIndices()) ms.orig.AttributeIndices = internal.GenTestInt32Slice() assert.Equal(t, pcommon.Int32Slice(internal.GenTestInt32SliceWrapper()), ms.AttributeIndices()) } func generateTestLocation() Location { return newLocation(internal.GenTestLocation(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_locationslice.go000066400000000000000000000112261511331344600266460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // LocationSlice logically represents a slice of Location. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewLocationSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type LocationSlice struct { orig *[]*internal.Location state *internal.State } func newLocationSlice(orig *[]*internal.Location, state *internal.State) LocationSlice { return LocationSlice{orig: orig, state: state} } // NewLocationSlice creates a LocationSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewLocationSlice() LocationSlice { orig := []*internal.Location(nil) return newLocationSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewLocationSlice()". func (es LocationSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es LocationSlice) At(i int) Location { return newLocation((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es LocationSlice) All() iter.Seq2[int, Location] { return func(yield func(int, Location) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new LocationSlice can be initialized: // // es := NewLocationSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es LocationSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Location, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Location. // It returns the newly added Location. func (es LocationSlice) AppendEmpty() Location { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewLocation()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es LocationSlice) MoveAndAppendTo(dest LocationSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es LocationSlice) RemoveIf(f func(Location) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteLocation((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es LocationSlice) CopyTo(dest LocationSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyLocationPtrSlice(*dest.orig, *es.orig) } // Sort sorts the Location elements within LocationSlice given the // provided less function so that two instances of LocationSlice // can be compared. func (es LocationSlice) Sort(less func(a, b Location) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_locationslice_test.go000066400000000000000000000113141511331344600277030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestLocationSlice(t *testing.T) { es := NewLocationSlice() assert.Equal(t, 0, es.Len()) es = newLocationSlice(&[]*internal.Location{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewLocation() testVal := generateTestLocation() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestLocation() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestLocationSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newLocationSlice(&[]*internal.Location{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewLocationSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestLocationSlice_CopyTo(t *testing.T) { dest := NewLocationSlice() src := generateTestLocationSlice() src.CopyTo(dest) assert.Equal(t, generateTestLocationSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestLocationSlice(), dest) } func TestLocationSlice_EnsureCapacity(t *testing.T) { es := generateTestLocationSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestLocationSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestLocationSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestLocationSlice(), es) } func TestLocationSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestLocationSlice() dest := NewLocationSlice() src := generateTestLocationSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLocationSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestLocationSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestLocationSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestLocationSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewLocationSlice() emptySlice.RemoveIf(func(el Location) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestLocationSlice() pos := 0 filtered.RemoveIf(func(el Location) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestLocationSlice_RemoveIfAll(t *testing.T) { got := generateTestLocationSlice() got.RemoveIf(func(el Location) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestLocationSliceAll(t *testing.T) { ms := generateTestLocationSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestLocationSlice_Sort(t *testing.T) { es := generateTestLocationSlice() es.Sort(func(a, b Location) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Location) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestLocationSlice() LocationSlice { ms := NewLocationSlice() *ms.orig = internal.GenTestLocationPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_mapping.go000066400000000000000000000063771511331344600254640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Mapping describes the mapping of a binary in memory, including its address range, file offset, and metadata like build ID // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewMapping function to create new instances. // Important: zero-initialized instance is not valid for use. type Mapping struct { orig *internal.Mapping state *internal.State } func newMapping(orig *internal.Mapping, state *internal.State) Mapping { return Mapping{orig: orig, state: state} } // NewMapping creates a new empty Mapping. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewMapping() Mapping { return newMapping(internal.NewMapping(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Mapping) MoveTo(dest Mapping) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteMapping(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // MemoryStart returns the memorystart associated with this Mapping. func (ms Mapping) MemoryStart() uint64 { return ms.orig.MemoryStart } // SetMemoryStart replaces the memorystart associated with this Mapping. func (ms Mapping) SetMemoryStart(v uint64) { ms.state.AssertMutable() ms.orig.MemoryStart = v } // MemoryLimit returns the memorylimit associated with this Mapping. func (ms Mapping) MemoryLimit() uint64 { return ms.orig.MemoryLimit } // SetMemoryLimit replaces the memorylimit associated with this Mapping. func (ms Mapping) SetMemoryLimit(v uint64) { ms.state.AssertMutable() ms.orig.MemoryLimit = v } // FileOffset returns the fileoffset associated with this Mapping. func (ms Mapping) FileOffset() uint64 { return ms.orig.FileOffset } // SetFileOffset replaces the fileoffset associated with this Mapping. func (ms Mapping) SetFileOffset(v uint64) { ms.state.AssertMutable() ms.orig.FileOffset = v } // FilenameStrindex returns the filenamestrindex associated with this Mapping. func (ms Mapping) FilenameStrindex() int32 { return ms.orig.FilenameStrindex } // SetFilenameStrindex replaces the filenamestrindex associated with this Mapping. func (ms Mapping) SetFilenameStrindex(v int32) { ms.state.AssertMutable() ms.orig.FilenameStrindex = v } // AttributeIndices returns the AttributeIndices associated with this Mapping. func (ms Mapping) AttributeIndices() pcommon.Int32Slice { return pcommon.Int32Slice(internal.NewInt32SliceWrapper(&ms.orig.AttributeIndices, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Mapping) CopyTo(dest Mapping) { dest.state.AssertMutable() internal.CopyMapping(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_mapping_test.go000066400000000000000000000060071511331344600265110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestMapping_MoveTo(t *testing.T) { ms := generateTestMapping() dest := NewMapping() ms.MoveTo(dest) assert.Equal(t, NewMapping(), ms) assert.Equal(t, generateTestMapping(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestMapping(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newMapping(internal.NewMapping(), sharedState)) }) assert.Panics(t, func() { newMapping(internal.NewMapping(), sharedState).MoveTo(dest) }) } func TestMapping_CopyTo(t *testing.T) { ms := NewMapping() orig := NewMapping() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestMapping() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newMapping(internal.NewMapping(), sharedState)) }) } func TestMapping_MemoryStart(t *testing.T) { ms := NewMapping() assert.Equal(t, uint64(0), ms.MemoryStart()) ms.SetMemoryStart(uint64(13)) assert.Equal(t, uint64(13), ms.MemoryStart()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMapping(internal.NewMapping(), sharedState).SetMemoryStart(uint64(13)) }) } func TestMapping_MemoryLimit(t *testing.T) { ms := NewMapping() assert.Equal(t, uint64(0), ms.MemoryLimit()) ms.SetMemoryLimit(uint64(13)) assert.Equal(t, uint64(13), ms.MemoryLimit()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMapping(internal.NewMapping(), sharedState).SetMemoryLimit(uint64(13)) }) } func TestMapping_FileOffset(t *testing.T) { ms := NewMapping() assert.Equal(t, uint64(0), ms.FileOffset()) ms.SetFileOffset(uint64(13)) assert.Equal(t, uint64(13), ms.FileOffset()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMapping(internal.NewMapping(), sharedState).SetFileOffset(uint64(13)) }) } func TestMapping_FilenameStrindex(t *testing.T) { ms := NewMapping() assert.Equal(t, int32(0), ms.FilenameStrindex()) ms.SetFilenameStrindex(int32(13)) assert.Equal(t, int32(13), ms.FilenameStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newMapping(internal.NewMapping(), sharedState).SetFilenameStrindex(int32(13)) }) } func TestMapping_AttributeIndices(t *testing.T) { ms := NewMapping() assert.Equal(t, pcommon.NewInt32Slice(), ms.AttributeIndices()) ms.orig.AttributeIndices = internal.GenTestInt32Slice() assert.Equal(t, pcommon.Int32Slice(internal.GenTestInt32SliceWrapper()), ms.AttributeIndices()) } func generateTestMapping() Mapping { return newMapping(internal.GenTestMapping(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_mappingslice.go000066400000000000000000000111511511331344600264660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // MappingSlice logically represents a slice of Mapping. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewMappingSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type MappingSlice struct { orig *[]*internal.Mapping state *internal.State } func newMappingSlice(orig *[]*internal.Mapping, state *internal.State) MappingSlice { return MappingSlice{orig: orig, state: state} } // NewMappingSlice creates a MappingSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewMappingSlice() MappingSlice { orig := []*internal.Mapping(nil) return newMappingSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewMappingSlice()". func (es MappingSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es MappingSlice) At(i int) Mapping { return newMapping((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es MappingSlice) All() iter.Seq2[int, Mapping] { return func(yield func(int, Mapping) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new MappingSlice can be initialized: // // es := NewMappingSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es MappingSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Mapping, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Mapping. // It returns the newly added Mapping. func (es MappingSlice) AppendEmpty() Mapping { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewMapping()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es MappingSlice) MoveAndAppendTo(dest MappingSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es MappingSlice) RemoveIf(f func(Mapping) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteMapping((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es MappingSlice) CopyTo(dest MappingSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyMappingPtrSlice(*dest.orig, *es.orig) } // Sort sorts the Mapping elements within MappingSlice given the // provided less function so that two instances of MappingSlice // can be compared. func (es MappingSlice) Sort(less func(a, b Mapping) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_mappingslice_test.go000066400000000000000000000112361511331344600275310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestMappingSlice(t *testing.T) { es := NewMappingSlice() assert.Equal(t, 0, es.Len()) es = newMappingSlice(&[]*internal.Mapping{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewMapping() testVal := generateTestMapping() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestMapping() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestMappingSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newMappingSlice(&[]*internal.Mapping{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewMappingSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestMappingSlice_CopyTo(t *testing.T) { dest := NewMappingSlice() src := generateTestMappingSlice() src.CopyTo(dest) assert.Equal(t, generateTestMappingSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestMappingSlice(), dest) } func TestMappingSlice_EnsureCapacity(t *testing.T) { es := generateTestMappingSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestMappingSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestMappingSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestMappingSlice(), es) } func TestMappingSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestMappingSlice() dest := NewMappingSlice() src := generateTestMappingSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestMappingSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestMappingSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestMappingSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestMappingSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewMappingSlice() emptySlice.RemoveIf(func(el Mapping) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestMappingSlice() pos := 0 filtered.RemoveIf(func(el Mapping) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestMappingSlice_RemoveIfAll(t *testing.T) { got := generateTestMappingSlice() got.RemoveIf(func(el Mapping) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestMappingSliceAll(t *testing.T) { ms := generateTestMappingSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestMappingSlice_Sort(t *testing.T) { es := generateTestMappingSlice() es.Sort(func(a, b Mapping) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Mapping) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestMappingSlice() MappingSlice { ms := NewMappingSlice() *ms.orig = internal.GenTestMappingPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profile.go000066400000000000000000000112051511331344600254530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Profile are an implementation of the pprofextended data model. // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewProfile function to create new instances. // Important: zero-initialized instance is not valid for use. type Profile struct { orig *internal.Profile state *internal.State } func newProfile(orig *internal.Profile, state *internal.State) Profile { return Profile{orig: orig, state: state} } // NewProfile creates a new empty Profile. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewProfile() Profile { return newProfile(internal.NewProfile(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Profile) MoveTo(dest Profile) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteProfile(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // SampleType returns the sampletype associated with this Profile. func (ms Profile) SampleType() ValueType { return newValueType(&ms.orig.SampleType, ms.state) } // Samples returns the Samples associated with this Profile. func (ms Profile) Samples() SampleSlice { return newSampleSlice(&ms.orig.Samples, ms.state) } // Time returns the time associated with this Profile. func (ms Profile) Time() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTime replaces the time associated with this Profile. func (ms Profile) SetTime(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // DurationNano returns the durationnano associated with this Profile. func (ms Profile) DurationNano() uint64 { return ms.orig.DurationNano } // SetDurationNano replaces the durationnano associated with this Profile. func (ms Profile) SetDurationNano(v uint64) { ms.state.AssertMutable() ms.orig.DurationNano = v } // PeriodType returns the periodtype associated with this Profile. func (ms Profile) PeriodType() ValueType { return newValueType(&ms.orig.PeriodType, ms.state) } // Period returns the period associated with this Profile. func (ms Profile) Period() int64 { return ms.orig.Period } // SetPeriod replaces the period associated with this Profile. func (ms Profile) SetPeriod(v int64) { ms.state.AssertMutable() ms.orig.Period = v } // ProfileID returns the profileid associated with this Profile. func (ms Profile) ProfileID() ProfileID { return ProfileID(ms.orig.ProfileId) } // SetProfileID replaces the profileid associated with this Profile. func (ms Profile) SetProfileID(v ProfileID) { ms.state.AssertMutable() ms.orig.ProfileId = internal.ProfileID(v) } // DroppedAttributesCount returns the droppedattributescount associated with this Profile. func (ms Profile) DroppedAttributesCount() uint32 { return ms.orig.DroppedAttributesCount } // SetDroppedAttributesCount replaces the droppedattributescount associated with this Profile. func (ms Profile) SetDroppedAttributesCount(v uint32) { ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // OriginalPayloadFormat returns the originalpayloadformat associated with this Profile. func (ms Profile) OriginalPayloadFormat() string { return ms.orig.OriginalPayloadFormat } // SetOriginalPayloadFormat replaces the originalpayloadformat associated with this Profile. func (ms Profile) SetOriginalPayloadFormat(v string) { ms.state.AssertMutable() ms.orig.OriginalPayloadFormat = v } // OriginalPayload returns the OriginalPayload associated with this Profile. func (ms Profile) OriginalPayload() pcommon.ByteSlice { return pcommon.ByteSlice(internal.NewByteSliceWrapper(&ms.orig.OriginalPayload, ms.state)) } // AttributeIndices returns the AttributeIndices associated with this Profile. func (ms Profile) AttributeIndices() pcommon.Int32Slice { return pcommon.Int32Slice(internal.NewInt32SliceWrapper(&ms.orig.AttributeIndices, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Profile) CopyTo(dest Profile) { dest.state.AssertMutable() internal.CopyProfile(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profile_test.go000066400000000000000000000111471511331344600265170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestProfile_MoveTo(t *testing.T) { ms := generateTestProfile() dest := NewProfile() ms.MoveTo(dest) assert.Equal(t, NewProfile(), ms) assert.Equal(t, generateTestProfile(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestProfile(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newProfile(internal.NewProfile(), sharedState)) }) assert.Panics(t, func() { newProfile(internal.NewProfile(), sharedState).MoveTo(dest) }) } func TestProfile_CopyTo(t *testing.T) { ms := NewProfile() orig := NewProfile() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestProfile() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newProfile(internal.NewProfile(), sharedState)) }) } func TestProfile_SampleType(t *testing.T) { ms := NewProfile() assert.Equal(t, NewValueType(), ms.SampleType()) ms.orig.SampleType = *internal.GenTestValueType() assert.Equal(t, generateTestValueType(), ms.SampleType()) } func TestProfile_Samples(t *testing.T) { ms := NewProfile() assert.Equal(t, NewSampleSlice(), ms.Samples()) ms.orig.Samples = internal.GenTestSamplePtrSlice() assert.Equal(t, generateTestSampleSlice(), ms.Samples()) } func TestProfile_Time(t *testing.T) { ms := NewProfile() assert.Equal(t, pcommon.Timestamp(0), ms.Time()) testValTime := pcommon.Timestamp(1234567890) ms.SetTime(testValTime) assert.Equal(t, testValTime, ms.Time()) } func TestProfile_DurationNano(t *testing.T) { ms := NewProfile() assert.Equal(t, uint64(0), ms.DurationNano()) ms.SetDurationNano(uint64(13)) assert.Equal(t, uint64(13), ms.DurationNano()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newProfile(internal.NewProfile(), sharedState).SetDurationNano(uint64(13)) }) } func TestProfile_PeriodType(t *testing.T) { ms := NewProfile() assert.Equal(t, NewValueType(), ms.PeriodType()) ms.orig.PeriodType = *internal.GenTestValueType() assert.Equal(t, generateTestValueType(), ms.PeriodType()) } func TestProfile_Period(t *testing.T) { ms := NewProfile() assert.Equal(t, int64(0), ms.Period()) ms.SetPeriod(int64(13)) assert.Equal(t, int64(13), ms.Period()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newProfile(internal.NewProfile(), sharedState).SetPeriod(int64(13)) }) } func TestProfile_ProfileID(t *testing.T) { ms := NewProfile() assert.Equal(t, ProfileID(internal.ProfileID([16]byte{})), ms.ProfileID()) testValProfileID := ProfileID(internal.ProfileID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})) ms.SetProfileID(testValProfileID) assert.Equal(t, testValProfileID, ms.ProfileID()) } func TestProfile_DroppedAttributesCount(t *testing.T) { ms := NewProfile() assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedAttributesCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newProfile(internal.NewProfile(), sharedState).SetDroppedAttributesCount(uint32(13)) }) } func TestProfile_OriginalPayloadFormat(t *testing.T) { ms := NewProfile() assert.Empty(t, ms.OriginalPayloadFormat()) ms.SetOriginalPayloadFormat("test_originalpayloadformat") assert.Equal(t, "test_originalpayloadformat", ms.OriginalPayloadFormat()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newProfile(internal.NewProfile(), sharedState).SetOriginalPayloadFormat("test_originalpayloadformat") }) } func TestProfile_OriginalPayload(t *testing.T) { ms := NewProfile() assert.Equal(t, pcommon.NewByteSlice(), ms.OriginalPayload()) ms.orig.OriginalPayload = internal.GenTestByteSlice() assert.Equal(t, pcommon.ByteSlice(internal.GenTestByteSliceWrapper()), ms.OriginalPayload()) } func TestProfile_AttributeIndices(t *testing.T) { ms := NewProfile() assert.Equal(t, pcommon.NewInt32Slice(), ms.AttributeIndices()) ms.orig.AttributeIndices = internal.GenTestInt32Slice() assert.Equal(t, pcommon.Int32Slice(internal.GenTestInt32SliceWrapper()), ms.AttributeIndices()) } func generateTestProfile() Profile { return newProfile(internal.GenTestProfile(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profiles.go000066400000000000000000000051021511331344600256350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" ) // Profiles is the top-level struct that is propagated through the profiles pipeline. // Use NewProfiles to create new instance, zero-initialized instance is not valid for use. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewProfiles function to create new instances. // Important: zero-initialized instance is not valid for use. type Profiles internal.ProfilesWrapper func newProfiles(orig *internal.ExportProfilesServiceRequest, state *internal.State) Profiles { return Profiles(internal.NewProfilesWrapper(orig, state)) } // NewProfiles creates a new empty Profiles. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewProfiles() Profiles { return newProfiles(internal.NewExportProfilesServiceRequest(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Profiles) MoveTo(dest Profiles) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteExportProfilesServiceRequest(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // ResourceProfiles returns the ResourceProfiles associated with this Profiles. func (ms Profiles) ResourceProfiles() ResourceProfilesSlice { return newResourceProfilesSlice(&ms.getOrig().ResourceProfiles, ms.getState()) } // Dictionary returns the dictionary associated with this Profiles. func (ms Profiles) Dictionary() ProfilesDictionary { return newProfilesDictionary(&ms.getOrig().Dictionary, ms.getState()) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Profiles) CopyTo(dest Profiles) { dest.getState().AssertMutable() internal.CopyExportProfilesServiceRequest(dest.getOrig(), ms.getOrig()) } func (ms Profiles) getOrig() *internal.ExportProfilesServiceRequest { return internal.GetProfilesOrig(internal.ProfilesWrapper(ms)) } func (ms Profiles) getState() *internal.State { return internal.GetProfilesState(internal.ProfilesWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profiles_test.go000066400000000000000000000036251511331344600267040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestProfiles_MoveTo(t *testing.T) { ms := generateTestProfiles() dest := NewProfiles() ms.MoveTo(dest) assert.Equal(t, NewProfiles(), ms) assert.Equal(t, generateTestProfiles(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestProfiles(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newProfiles(internal.NewExportProfilesServiceRequest(), sharedState)) }) assert.Panics(t, func() { newProfiles(internal.NewExportProfilesServiceRequest(), sharedState).MoveTo(dest) }) } func TestProfiles_CopyTo(t *testing.T) { ms := NewProfiles() orig := NewProfiles() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestProfiles() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newProfiles(internal.NewExportProfilesServiceRequest(), sharedState)) }) } func TestProfiles_ResourceProfiles(t *testing.T) { ms := NewProfiles() assert.Equal(t, NewResourceProfilesSlice(), ms.ResourceProfiles()) ms.getOrig().ResourceProfiles = internal.GenTestResourceProfilesPtrSlice() assert.Equal(t, generateTestResourceProfilesSlice(), ms.ResourceProfiles()) } func TestProfiles_Dictionary(t *testing.T) { ms := NewProfiles() assert.Equal(t, NewProfilesDictionary(), ms.Dictionary()) ms.getOrig().Dictionary = *internal.GenTestProfilesDictionary() assert.Equal(t, generateTestProfilesDictionary(), ms.Dictionary()) } func generateTestProfiles() Profiles { return newProfiles(internal.GenTestExportProfilesServiceRequest(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profilesdata.go000066400000000000000000000051651511331344600265000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" ) // ProfilesData represents the profiles data that can be stored in persistent storage, // OR can be embedded by other protocols that transfer OTLP profiles data but do not // implement the OTLP protocol. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewProfilesData function to create new instances. // Important: zero-initialized instance is not valid for use. type ProfilesData internal.ProfilesDataWrapper func newProfilesData(orig *internal.ProfilesData, state *internal.State) ProfilesData { return ProfilesData(internal.NewProfilesDataWrapper(orig, state)) } // NewProfilesData creates a new empty ProfilesData. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewProfilesData() ProfilesData { return newProfilesData(internal.NewProfilesData(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ProfilesData) MoveTo(dest ProfilesData) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteProfilesData(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // ResourceProfiles returns the ResourceProfiles associated with this ProfilesData. func (ms ProfilesData) ResourceProfiles() ResourceProfilesSlice { return newResourceProfilesSlice(&ms.getOrig().ResourceProfiles, ms.getState()) } // Dictionary returns the dictionary associated with this ProfilesData. func (ms ProfilesData) Dictionary() ProfilesDictionary { return newProfilesDictionary(&ms.getOrig().Dictionary, ms.getState()) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ProfilesData) CopyTo(dest ProfilesData) { dest.getState().AssertMutable() internal.CopyProfilesData(dest.getOrig(), ms.getOrig()) } func (ms ProfilesData) getOrig() *internal.ProfilesData { return internal.GetProfilesDataOrig(internal.ProfilesDataWrapper(ms)) } func (ms ProfilesData) getState() *internal.State { return internal.GetProfilesDataState(internal.ProfilesDataWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profilesdata_test.go000066400000000000000000000036451511331344600275400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestProfilesData_MoveTo(t *testing.T) { ms := generateTestProfilesData() dest := NewProfilesData() ms.MoveTo(dest) assert.Equal(t, NewProfilesData(), ms) assert.Equal(t, generateTestProfilesData(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestProfilesData(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newProfilesData(internal.NewProfilesData(), sharedState)) }) assert.Panics(t, func() { newProfilesData(internal.NewProfilesData(), sharedState).MoveTo(dest) }) } func TestProfilesData_CopyTo(t *testing.T) { ms := NewProfilesData() orig := NewProfilesData() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestProfilesData() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newProfilesData(internal.NewProfilesData(), sharedState)) }) } func TestProfilesData_ResourceProfiles(t *testing.T) { ms := NewProfilesData() assert.Equal(t, NewResourceProfilesSlice(), ms.ResourceProfiles()) ms.getOrig().ResourceProfiles = internal.GenTestResourceProfilesPtrSlice() assert.Equal(t, generateTestResourceProfilesSlice(), ms.ResourceProfiles()) } func TestProfilesData_Dictionary(t *testing.T) { ms := NewProfilesData() assert.Equal(t, NewProfilesDictionary(), ms.Dictionary()) ms.getOrig().Dictionary = *internal.GenTestProfilesDictionary() assert.Equal(t, generateTestProfilesDictionary(), ms.Dictionary()) } func generateTestProfilesData() ProfilesData { return newProfilesData(internal.GenTestProfilesData(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profilesdictionary.go000066400000000000000000000066051511331344600277340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ProfilesDictionary is the reference table containing all data shared by profiles across the message being sent. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewProfilesDictionary function to create new instances. // Important: zero-initialized instance is not valid for use. type ProfilesDictionary struct { orig *internal.ProfilesDictionary state *internal.State } func newProfilesDictionary(orig *internal.ProfilesDictionary, state *internal.State) ProfilesDictionary { return ProfilesDictionary{orig: orig, state: state} } // NewProfilesDictionary creates a new empty ProfilesDictionary. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewProfilesDictionary() ProfilesDictionary { return newProfilesDictionary(internal.NewProfilesDictionary(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ProfilesDictionary) MoveTo(dest ProfilesDictionary) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteProfilesDictionary(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // MappingTable returns the MappingTable associated with this ProfilesDictionary. func (ms ProfilesDictionary) MappingTable() MappingSlice { return newMappingSlice(&ms.orig.MappingTable, ms.state) } // LocationTable returns the LocationTable associated with this ProfilesDictionary. func (ms ProfilesDictionary) LocationTable() LocationSlice { return newLocationSlice(&ms.orig.LocationTable, ms.state) } // FunctionTable returns the FunctionTable associated with this ProfilesDictionary. func (ms ProfilesDictionary) FunctionTable() FunctionSlice { return newFunctionSlice(&ms.orig.FunctionTable, ms.state) } // LinkTable returns the LinkTable associated with this ProfilesDictionary. func (ms ProfilesDictionary) LinkTable() LinkSlice { return newLinkSlice(&ms.orig.LinkTable, ms.state) } // StringTable returns the StringTable associated with this ProfilesDictionary. func (ms ProfilesDictionary) StringTable() pcommon.StringSlice { return pcommon.StringSlice(internal.NewStringSliceWrapper(&ms.orig.StringTable, ms.state)) } // AttributeTable returns the AttributeTable associated with this ProfilesDictionary. func (ms ProfilesDictionary) AttributeTable() KeyValueAndUnitSlice { return newKeyValueAndUnitSlice(&ms.orig.AttributeTable, ms.state) } // StackTable returns the StackTable associated with this ProfilesDictionary. func (ms ProfilesDictionary) StackTable() StackSlice { return newStackSlice(&ms.orig.StackTable, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ProfilesDictionary) CopyTo(dest ProfilesDictionary) { dest.state.AssertMutable() internal.CopyProfilesDictionary(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profilesdictionary_test.go000066400000000000000000000066141511331344600307730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestProfilesDictionary_MoveTo(t *testing.T) { ms := generateTestProfilesDictionary() dest := NewProfilesDictionary() ms.MoveTo(dest) assert.Equal(t, NewProfilesDictionary(), ms) assert.Equal(t, generateTestProfilesDictionary(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestProfilesDictionary(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newProfilesDictionary(internal.NewProfilesDictionary(), sharedState)) }) assert.Panics(t, func() { newProfilesDictionary(internal.NewProfilesDictionary(), sharedState).MoveTo(dest) }) } func TestProfilesDictionary_CopyTo(t *testing.T) { ms := NewProfilesDictionary() orig := NewProfilesDictionary() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestProfilesDictionary() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newProfilesDictionary(internal.NewProfilesDictionary(), sharedState)) }) } func TestProfilesDictionary_MappingTable(t *testing.T) { ms := NewProfilesDictionary() assert.Equal(t, NewMappingSlice(), ms.MappingTable()) ms.orig.MappingTable = internal.GenTestMappingPtrSlice() assert.Equal(t, generateTestMappingSlice(), ms.MappingTable()) } func TestProfilesDictionary_LocationTable(t *testing.T) { ms := NewProfilesDictionary() assert.Equal(t, NewLocationSlice(), ms.LocationTable()) ms.orig.LocationTable = internal.GenTestLocationPtrSlice() assert.Equal(t, generateTestLocationSlice(), ms.LocationTable()) } func TestProfilesDictionary_FunctionTable(t *testing.T) { ms := NewProfilesDictionary() assert.Equal(t, NewFunctionSlice(), ms.FunctionTable()) ms.orig.FunctionTable = internal.GenTestFunctionPtrSlice() assert.Equal(t, generateTestFunctionSlice(), ms.FunctionTable()) } func TestProfilesDictionary_LinkTable(t *testing.T) { ms := NewProfilesDictionary() assert.Equal(t, NewLinkSlice(), ms.LinkTable()) ms.orig.LinkTable = internal.GenTestLinkPtrSlice() assert.Equal(t, generateTestLinkSlice(), ms.LinkTable()) } func TestProfilesDictionary_StringTable(t *testing.T) { ms := NewProfilesDictionary() assert.Equal(t, pcommon.NewStringSlice(), ms.StringTable()) ms.orig.StringTable = internal.GenTestStringSlice() assert.Equal(t, pcommon.StringSlice(internal.GenTestStringSliceWrapper()), ms.StringTable()) } func TestProfilesDictionary_AttributeTable(t *testing.T) { ms := NewProfilesDictionary() assert.Equal(t, NewKeyValueAndUnitSlice(), ms.AttributeTable()) ms.orig.AttributeTable = internal.GenTestKeyValueAndUnitPtrSlice() assert.Equal(t, generateTestKeyValueAndUnitSlice(), ms.AttributeTable()) } func TestProfilesDictionary_StackTable(t *testing.T) { ms := NewProfilesDictionary() assert.Equal(t, NewStackSlice(), ms.StackTable()) ms.orig.StackTable = internal.GenTestStackPtrSlice() assert.Equal(t, generateTestStackSlice(), ms.StackTable()) } func generateTestProfilesDictionary() ProfilesDictionary { return newProfilesDictionary(internal.GenTestProfilesDictionary(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profilesslice.go000066400000000000000000000112041511331344600266550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ProfilesSlice logically represents a slice of Profile. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewProfilesSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ProfilesSlice struct { orig *[]*internal.Profile state *internal.State } func newProfilesSlice(orig *[]*internal.Profile, state *internal.State) ProfilesSlice { return ProfilesSlice{orig: orig, state: state} } // NewProfilesSlice creates a ProfilesSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewProfilesSlice() ProfilesSlice { orig := []*internal.Profile(nil) return newProfilesSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewProfilesSlice()". func (es ProfilesSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ProfilesSlice) At(i int) Profile { return newProfile((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ProfilesSlice) All() iter.Seq2[int, Profile] { return func(yield func(int, Profile) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ProfilesSlice can be initialized: // // es := NewProfilesSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ProfilesSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Profile, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Profile. // It returns the newly added Profile. func (es ProfilesSlice) AppendEmpty() Profile { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewProfile()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ProfilesSlice) MoveAndAppendTo(dest ProfilesSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ProfilesSlice) RemoveIf(f func(Profile) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteProfile((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ProfilesSlice) CopyTo(dest ProfilesSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyProfilePtrSlice(*dest.orig, *es.orig) } // Sort sorts the Profile elements within ProfilesSlice given the // provided less function so that two instances of ProfilesSlice // can be compared. func (es ProfilesSlice) Sort(less func(a, b Profile) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_profilesslice_test.go000066400000000000000000000113011511331344600277120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestProfilesSlice(t *testing.T) { es := NewProfilesSlice() assert.Equal(t, 0, es.Len()) es = newProfilesSlice(&[]*internal.Profile{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewProfile() testVal := generateTestProfile() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestProfile() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestProfilesSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newProfilesSlice(&[]*internal.Profile{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewProfilesSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestProfilesSlice_CopyTo(t *testing.T) { dest := NewProfilesSlice() src := generateTestProfilesSlice() src.CopyTo(dest) assert.Equal(t, generateTestProfilesSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestProfilesSlice(), dest) } func TestProfilesSlice_EnsureCapacity(t *testing.T) { es := generateTestProfilesSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestProfilesSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestProfilesSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestProfilesSlice(), es) } func TestProfilesSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestProfilesSlice() dest := NewProfilesSlice() src := generateTestProfilesSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestProfilesSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestProfilesSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestProfilesSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestProfilesSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewProfilesSlice() emptySlice.RemoveIf(func(el Profile) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestProfilesSlice() pos := 0 filtered.RemoveIf(func(el Profile) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestProfilesSlice_RemoveIfAll(t *testing.T) { got := generateTestProfilesSlice() got.RemoveIf(func(el Profile) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestProfilesSliceAll(t *testing.T) { ms := generateTestProfilesSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestProfilesSlice_Sort(t *testing.T) { es := generateTestProfilesSlice() es.Sort(func(a, b Profile) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Profile) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestProfilesSlice() ProfilesSlice { ms := NewProfilesSlice() *ms.orig = internal.GenTestProfilePtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_resourceprofiles.go000066400000000000000000000051721511331344600274140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceProfiles is a collection of profiles from a Resource. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewResourceProfiles function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceProfiles struct { orig *internal.ResourceProfiles state *internal.State } func newResourceProfiles(orig *internal.ResourceProfiles, state *internal.State) ResourceProfiles { return ResourceProfiles{orig: orig, state: state} } // NewResourceProfiles creates a new empty ResourceProfiles. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResourceProfiles() ResourceProfiles { return newResourceProfiles(internal.NewResourceProfiles(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ResourceProfiles) MoveTo(dest ResourceProfiles) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteResourceProfiles(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Resource returns the resource associated with this ResourceProfiles. func (ms ResourceProfiles) Resource() pcommon.Resource { return pcommon.Resource(internal.NewResourceWrapper(&ms.orig.Resource, ms.state)) } // ScopeProfiles returns the ScopeProfiles associated with this ResourceProfiles. func (ms ResourceProfiles) ScopeProfiles() ScopeProfilesSlice { return newScopeProfilesSlice(&ms.orig.ScopeProfiles, ms.state) } // SchemaUrl returns the schemaurl associated with this ResourceProfiles. func (ms ResourceProfiles) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ResourceProfiles. func (ms ResourceProfiles) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ResourceProfiles) CopyTo(dest ResourceProfiles) { dest.state.AssertMutable() internal.CopyResourceProfiles(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_resourceprofiles_test.go000066400000000000000000000046401511331344600304520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestResourceProfiles_MoveTo(t *testing.T) { ms := generateTestResourceProfiles() dest := NewResourceProfiles() ms.MoveTo(dest) assert.Equal(t, NewResourceProfiles(), ms) assert.Equal(t, generateTestResourceProfiles(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestResourceProfiles(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newResourceProfiles(internal.NewResourceProfiles(), sharedState)) }) assert.Panics(t, func() { newResourceProfiles(internal.NewResourceProfiles(), sharedState).MoveTo(dest) }) } func TestResourceProfiles_CopyTo(t *testing.T) { ms := NewResourceProfiles() orig := NewResourceProfiles() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestResourceProfiles() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newResourceProfiles(internal.NewResourceProfiles(), sharedState)) }) } func TestResourceProfiles_Resource(t *testing.T) { ms := NewResourceProfiles() assert.Equal(t, pcommon.NewResource(), ms.Resource()) ms.orig.Resource = *internal.GenTestResource() assert.Equal(t, pcommon.Resource(internal.GenTestResourceWrapper()), ms.Resource()) } func TestResourceProfiles_ScopeProfiles(t *testing.T) { ms := NewResourceProfiles() assert.Equal(t, NewScopeProfilesSlice(), ms.ScopeProfiles()) ms.orig.ScopeProfiles = internal.GenTestScopeProfilesPtrSlice() assert.Equal(t, generateTestScopeProfilesSlice(), ms.ScopeProfiles()) } func TestResourceProfiles_SchemaUrl(t *testing.T) { ms := NewResourceProfiles() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newResourceProfiles(internal.NewResourceProfiles(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestResourceProfiles() ResourceProfiles { return newResourceProfiles(internal.GenTestResourceProfiles(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_resourceprofilesslice.go000066400000000000000000000117761511331344600304430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ResourceProfilesSlice logically represents a slice of ResourceProfiles. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewResourceProfilesSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceProfilesSlice struct { orig *[]*internal.ResourceProfiles state *internal.State } func newResourceProfilesSlice(orig *[]*internal.ResourceProfiles, state *internal.State) ResourceProfilesSlice { return ResourceProfilesSlice{orig: orig, state: state} } // NewResourceProfilesSlice creates a ResourceProfilesSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewResourceProfilesSlice() ResourceProfilesSlice { orig := []*internal.ResourceProfiles(nil) return newResourceProfilesSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewResourceProfilesSlice()". func (es ResourceProfilesSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ResourceProfilesSlice) At(i int) ResourceProfiles { return newResourceProfiles((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ResourceProfilesSlice) All() iter.Seq2[int, ResourceProfiles] { return func(yield func(int, ResourceProfiles) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ResourceProfilesSlice can be initialized: // // es := NewResourceProfilesSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ResourceProfilesSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ResourceProfiles, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ResourceProfiles. // It returns the newly added ResourceProfiles. func (es ResourceProfilesSlice) AppendEmpty() ResourceProfiles { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewResourceProfiles()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceProfilesSlice) MoveAndAppendTo(dest ResourceProfilesSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ResourceProfilesSlice) RemoveIf(f func(ResourceProfiles) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteResourceProfiles((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ResourceProfilesSlice) CopyTo(dest ResourceProfilesSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyResourceProfilesPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ResourceProfiles elements within ResourceProfilesSlice given the // provided less function so that two instances of ResourceProfilesSlice // can be compared. func (es ResourceProfilesSlice) Sort(less func(a, b ResourceProfiles) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_resourceprofilesslice_test.go000066400000000000000000000120741511331344600314720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestResourceProfilesSlice(t *testing.T) { es := NewResourceProfilesSlice() assert.Equal(t, 0, es.Len()) es = newResourceProfilesSlice(&[]*internal.ResourceProfiles{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewResourceProfiles() testVal := generateTestResourceProfiles() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestResourceProfiles() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestResourceProfilesSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newResourceProfilesSlice(&[]*internal.ResourceProfiles{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewResourceProfilesSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestResourceProfilesSlice_CopyTo(t *testing.T) { dest := NewResourceProfilesSlice() src := generateTestResourceProfilesSlice() src.CopyTo(dest) assert.Equal(t, generateTestResourceProfilesSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestResourceProfilesSlice(), dest) } func TestResourceProfilesSlice_EnsureCapacity(t *testing.T) { es := generateTestResourceProfilesSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestResourceProfilesSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestResourceProfilesSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestResourceProfilesSlice(), es) } func TestResourceProfilesSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestResourceProfilesSlice() dest := NewResourceProfilesSlice() src := generateTestResourceProfilesSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceProfilesSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceProfilesSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestResourceProfilesSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestResourceProfilesSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewResourceProfilesSlice() emptySlice.RemoveIf(func(el ResourceProfiles) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestResourceProfilesSlice() pos := 0 filtered.RemoveIf(func(el ResourceProfiles) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestResourceProfilesSlice_RemoveIfAll(t *testing.T) { got := generateTestResourceProfilesSlice() got.RemoveIf(func(el ResourceProfiles) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestResourceProfilesSliceAll(t *testing.T) { ms := generateTestResourceProfilesSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestResourceProfilesSlice_Sort(t *testing.T) { es := generateTestResourceProfilesSlice() es.Sort(func(a, b ResourceProfiles) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ResourceProfiles) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestResourceProfilesSlice() ResourceProfilesSlice { ms := NewResourceProfilesSlice() *ms.orig = internal.GenTestResourceProfilesPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_sample.go000066400000000000000000000056741511331344600253110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Sample represents each record value encountered within a profiled program. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSample function to create new instances. // Important: zero-initialized instance is not valid for use. type Sample struct { orig *internal.Sample state *internal.State } func newSample(orig *internal.Sample, state *internal.State) Sample { return Sample{orig: orig, state: state} } // NewSample creates a new empty Sample. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSample() Sample { return newSample(internal.NewSample(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Sample) MoveTo(dest Sample) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSample(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // StackIndex returns the stackindex associated with this Sample. func (ms Sample) StackIndex() int32 { return ms.orig.StackIndex } // SetStackIndex replaces the stackindex associated with this Sample. func (ms Sample) SetStackIndex(v int32) { ms.state.AssertMutable() ms.orig.StackIndex = v } // Values returns the Values associated with this Sample. func (ms Sample) Values() pcommon.Int64Slice { return pcommon.Int64Slice(internal.NewInt64SliceWrapper(&ms.orig.Values, ms.state)) } // AttributeIndices returns the AttributeIndices associated with this Sample. func (ms Sample) AttributeIndices() pcommon.Int32Slice { return pcommon.Int32Slice(internal.NewInt32SliceWrapper(&ms.orig.AttributeIndices, ms.state)) } // LinkIndex returns the linkindex associated with this Sample. func (ms Sample) LinkIndex() int32 { return ms.orig.LinkIndex } // SetLinkIndex replaces the linkindex associated with this Sample. func (ms Sample) SetLinkIndex(v int32) { ms.state.AssertMutable() ms.orig.LinkIndex = v } // TimestampsUnixNano returns the TimestampsUnixNano associated with this Sample. func (ms Sample) TimestampsUnixNano() pcommon.UInt64Slice { return pcommon.UInt64Slice(internal.NewUInt64SliceWrapper(&ms.orig.TimestampsUnixNano, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Sample) CopyTo(dest Sample) { dest.state.AssertMutable() internal.CopySample(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_sample_test.go000066400000000000000000000054321511331344600263400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSample_MoveTo(t *testing.T) { ms := generateTestSample() dest := NewSample() ms.MoveTo(dest) assert.Equal(t, NewSample(), ms) assert.Equal(t, generateTestSample(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSample(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSample(internal.NewSample(), sharedState)) }) assert.Panics(t, func() { newSample(internal.NewSample(), sharedState).MoveTo(dest) }) } func TestSample_CopyTo(t *testing.T) { ms := NewSample() orig := NewSample() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSample() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSample(internal.NewSample(), sharedState)) }) } func TestSample_StackIndex(t *testing.T) { ms := NewSample() assert.Equal(t, int32(0), ms.StackIndex()) ms.SetStackIndex(int32(13)) assert.Equal(t, int32(13), ms.StackIndex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSample(internal.NewSample(), sharedState).SetStackIndex(int32(13)) }) } func TestSample_Values(t *testing.T) { ms := NewSample() assert.Equal(t, pcommon.NewInt64Slice(), ms.Values()) ms.orig.Values = internal.GenTestInt64Slice() assert.Equal(t, pcommon.Int64Slice(internal.GenTestInt64SliceWrapper()), ms.Values()) } func TestSample_AttributeIndices(t *testing.T) { ms := NewSample() assert.Equal(t, pcommon.NewInt32Slice(), ms.AttributeIndices()) ms.orig.AttributeIndices = internal.GenTestInt32Slice() assert.Equal(t, pcommon.Int32Slice(internal.GenTestInt32SliceWrapper()), ms.AttributeIndices()) } func TestSample_LinkIndex(t *testing.T) { ms := NewSample() assert.Equal(t, int32(0), ms.LinkIndex()) ms.SetLinkIndex(int32(13)) assert.Equal(t, int32(13), ms.LinkIndex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSample(internal.NewSample(), sharedState).SetLinkIndex(int32(13)) }) } func TestSample_TimestampsUnixNano(t *testing.T) { ms := NewSample() assert.Equal(t, pcommon.NewUInt64Slice(), ms.TimestampsUnixNano()) ms.orig.TimestampsUnixNano = internal.GenTestUint64Slice() assert.Equal(t, pcommon.UInt64Slice(internal.GenTestUInt64SliceWrapper()), ms.TimestampsUnixNano()) } func generateTestSample() Sample { return newSample(internal.GenTestSample(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_sampleslice.go000066400000000000000000000110741511331344600263200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // SampleSlice logically represents a slice of Sample. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewSampleSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SampleSlice struct { orig *[]*internal.Sample state *internal.State } func newSampleSlice(orig *[]*internal.Sample, state *internal.State) SampleSlice { return SampleSlice{orig: orig, state: state} } // NewSampleSlice creates a SampleSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSampleSlice() SampleSlice { orig := []*internal.Sample(nil) return newSampleSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewSampleSlice()". func (es SampleSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es SampleSlice) At(i int) Sample { return newSample((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es SampleSlice) All() iter.Seq2[int, Sample] { return func(yield func(int, Sample) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new SampleSlice can be initialized: // // es := NewSampleSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es SampleSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Sample, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Sample. // It returns the newly added Sample. func (es SampleSlice) AppendEmpty() Sample { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewSample()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SampleSlice) MoveAndAppendTo(dest SampleSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SampleSlice) RemoveIf(f func(Sample) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteSample((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es SampleSlice) CopyTo(dest SampleSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopySamplePtrSlice(*dest.orig, *es.orig) } // Sort sorts the Sample elements within SampleSlice given the // provided less function so that two instances of SampleSlice // can be compared. func (es SampleSlice) Sort(less func(a, b Sample) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_sampleslice_test.go000066400000000000000000000111601511331344600273530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSampleSlice(t *testing.T) { es := NewSampleSlice() assert.Equal(t, 0, es.Len()) es = newSampleSlice(&[]*internal.Sample{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewSample() testVal := generateTestSample() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestSample() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestSampleSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newSampleSlice(&[]*internal.Sample{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewSampleSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestSampleSlice_CopyTo(t *testing.T) { dest := NewSampleSlice() src := generateTestSampleSlice() src.CopyTo(dest) assert.Equal(t, generateTestSampleSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestSampleSlice(), dest) } func TestSampleSlice_EnsureCapacity(t *testing.T) { es := generateTestSampleSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestSampleSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestSampleSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestSampleSlice(), es) } func TestSampleSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestSampleSlice() dest := NewSampleSlice() src := generateTestSampleSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSampleSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSampleSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestSampleSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestSampleSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewSampleSlice() emptySlice.RemoveIf(func(el Sample) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestSampleSlice() pos := 0 filtered.RemoveIf(func(el Sample) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestSampleSlice_RemoveIfAll(t *testing.T) { got := generateTestSampleSlice() got.RemoveIf(func(el Sample) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestSampleSliceAll(t *testing.T) { ms := generateTestSampleSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestSampleSlice_Sort(t *testing.T) { es := generateTestSampleSlice() es.Sort(func(a, b Sample) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Sample) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestSampleSlice() SampleSlice { ms := NewSampleSlice() *ms.orig = internal.GenTestSamplePtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_scopeprofiles.go000066400000000000000000000050561511331344600266770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ScopeProfiles is a collection of profiles from a LibraryInstrumentation. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewScopeProfiles function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeProfiles struct { orig *internal.ScopeProfiles state *internal.State } func newScopeProfiles(orig *internal.ScopeProfiles, state *internal.State) ScopeProfiles { return ScopeProfiles{orig: orig, state: state} } // NewScopeProfiles creates a new empty ScopeProfiles. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewScopeProfiles() ScopeProfiles { return newScopeProfiles(internal.NewScopeProfiles(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ScopeProfiles) MoveTo(dest ScopeProfiles) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteScopeProfiles(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Scope returns the scope associated with this ScopeProfiles. func (ms ScopeProfiles) Scope() pcommon.InstrumentationScope { return pcommon.InstrumentationScope(internal.NewInstrumentationScopeWrapper(&ms.orig.Scope, ms.state)) } // Profiles returns the Profiles associated with this ScopeProfiles. func (ms ScopeProfiles) Profiles() ProfilesSlice { return newProfilesSlice(&ms.orig.Profiles, ms.state) } // SchemaUrl returns the schemaurl associated with this ScopeProfiles. func (ms ScopeProfiles) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ScopeProfiles. func (ms ScopeProfiles) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ScopeProfiles) CopyTo(dest ScopeProfiles) { dest.state.AssertMutable() internal.CopyScopeProfiles(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_scopeprofiles_test.go000066400000000000000000000045111511331344600277310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestScopeProfiles_MoveTo(t *testing.T) { ms := generateTestScopeProfiles() dest := NewScopeProfiles() ms.MoveTo(dest) assert.Equal(t, NewScopeProfiles(), ms) assert.Equal(t, generateTestScopeProfiles(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestScopeProfiles(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newScopeProfiles(internal.NewScopeProfiles(), sharedState)) }) assert.Panics(t, func() { newScopeProfiles(internal.NewScopeProfiles(), sharedState).MoveTo(dest) }) } func TestScopeProfiles_CopyTo(t *testing.T) { ms := NewScopeProfiles() orig := NewScopeProfiles() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestScopeProfiles() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newScopeProfiles(internal.NewScopeProfiles(), sharedState)) }) } func TestScopeProfiles_Scope(t *testing.T) { ms := NewScopeProfiles() assert.Equal(t, pcommon.NewInstrumentationScope(), ms.Scope()) ms.orig.Scope = *internal.GenTestInstrumentationScope() assert.Equal(t, pcommon.InstrumentationScope(internal.GenTestInstrumentationScopeWrapper()), ms.Scope()) } func TestScopeProfiles_Profiles(t *testing.T) { ms := NewScopeProfiles() assert.Equal(t, NewProfilesSlice(), ms.Profiles()) ms.orig.Profiles = internal.GenTestProfilePtrSlice() assert.Equal(t, generateTestProfilesSlice(), ms.Profiles()) } func TestScopeProfiles_SchemaUrl(t *testing.T) { ms := NewScopeProfiles() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newScopeProfiles(internal.NewScopeProfiles(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestScopeProfiles() ScopeProfiles { return newScopeProfiles(internal.GenTestScopeProfiles(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_scopeprofilesslice.go000066400000000000000000000115671511331344600277230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ScopeProfilesSlice logically represents a slice of ScopeProfiles. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewScopeProfilesSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeProfilesSlice struct { orig *[]*internal.ScopeProfiles state *internal.State } func newScopeProfilesSlice(orig *[]*internal.ScopeProfiles, state *internal.State) ScopeProfilesSlice { return ScopeProfilesSlice{orig: orig, state: state} } // NewScopeProfilesSlice creates a ScopeProfilesSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewScopeProfilesSlice() ScopeProfilesSlice { orig := []*internal.ScopeProfiles(nil) return newScopeProfilesSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewScopeProfilesSlice()". func (es ScopeProfilesSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ScopeProfilesSlice) At(i int) ScopeProfiles { return newScopeProfiles((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ScopeProfilesSlice) All() iter.Seq2[int, ScopeProfiles] { return func(yield func(int, ScopeProfiles) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ScopeProfilesSlice can be initialized: // // es := NewScopeProfilesSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ScopeProfilesSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ScopeProfiles, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ScopeProfiles. // It returns the newly added ScopeProfiles. func (es ScopeProfilesSlice) AppendEmpty() ScopeProfiles { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewScopeProfiles()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ScopeProfilesSlice) MoveAndAppendTo(dest ScopeProfilesSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ScopeProfilesSlice) RemoveIf(f func(ScopeProfiles) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteScopeProfiles((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ScopeProfilesSlice) CopyTo(dest ScopeProfilesSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyScopeProfilesPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ScopeProfiles elements within ScopeProfilesSlice given the // provided less function so that two instances of ScopeProfilesSlice // can be compared. func (es ScopeProfilesSlice) Sort(less func(a, b ScopeProfiles) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_scopeprofilesslice_test.go000066400000000000000000000116621511331344600307560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestScopeProfilesSlice(t *testing.T) { es := NewScopeProfilesSlice() assert.Equal(t, 0, es.Len()) es = newScopeProfilesSlice(&[]*internal.ScopeProfiles{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewScopeProfiles() testVal := generateTestScopeProfiles() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestScopeProfiles() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestScopeProfilesSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newScopeProfilesSlice(&[]*internal.ScopeProfiles{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewScopeProfilesSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestScopeProfilesSlice_CopyTo(t *testing.T) { dest := NewScopeProfilesSlice() src := generateTestScopeProfilesSlice() src.CopyTo(dest) assert.Equal(t, generateTestScopeProfilesSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestScopeProfilesSlice(), dest) } func TestScopeProfilesSlice_EnsureCapacity(t *testing.T) { es := generateTestScopeProfilesSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestScopeProfilesSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestScopeProfilesSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestScopeProfilesSlice(), es) } func TestScopeProfilesSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestScopeProfilesSlice() dest := NewScopeProfilesSlice() src := generateTestScopeProfilesSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeProfilesSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeProfilesSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestScopeProfilesSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestScopeProfilesSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewScopeProfilesSlice() emptySlice.RemoveIf(func(el ScopeProfiles) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestScopeProfilesSlice() pos := 0 filtered.RemoveIf(func(el ScopeProfiles) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestScopeProfilesSlice_RemoveIfAll(t *testing.T) { got := generateTestScopeProfilesSlice() got.RemoveIf(func(el ScopeProfiles) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestScopeProfilesSliceAll(t *testing.T) { ms := generateTestScopeProfilesSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestScopeProfilesSlice_Sort(t *testing.T) { es := generateTestScopeProfilesSlice() es.Sort(func(a, b ScopeProfiles) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ScopeProfiles) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestScopeProfilesSlice() ScopeProfilesSlice { ms := NewScopeProfilesSlice() *ms.orig = internal.GenTestScopeProfilesPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_stack.go000066400000000000000000000036121511331344600251230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Stack represents a stack trace as a list of locations. // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewStack function to create new instances. // Important: zero-initialized instance is not valid for use. type Stack struct { orig *internal.Stack state *internal.State } func newStack(orig *internal.Stack, state *internal.State) Stack { return Stack{orig: orig, state: state} } // NewStack creates a new empty Stack. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewStack() Stack { return newStack(internal.NewStack(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Stack) MoveTo(dest Stack) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteStack(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // LocationIndices returns the LocationIndices associated with this Stack. func (ms Stack) LocationIndices() pcommon.Int32Slice { return pcommon.Int32Slice(internal.NewInt32SliceWrapper(&ms.orig.LocationIndices, ms.state)) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Stack) CopyTo(dest Stack) { dest.state.AssertMutable() internal.CopyStack(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_stack_test.go000066400000000000000000000030471511331344600261640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestStack_MoveTo(t *testing.T) { ms := generateTestStack() dest := NewStack() ms.MoveTo(dest) assert.Equal(t, NewStack(), ms) assert.Equal(t, generateTestStack(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestStack(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newStack(internal.NewStack(), sharedState)) }) assert.Panics(t, func() { newStack(internal.NewStack(), sharedState).MoveTo(dest) }) } func TestStack_CopyTo(t *testing.T) { ms := NewStack() orig := NewStack() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestStack() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newStack(internal.NewStack(), sharedState)) }) } func TestStack_LocationIndices(t *testing.T) { ms := NewStack() assert.Equal(t, pcommon.NewInt32Slice(), ms.LocationIndices()) ms.orig.LocationIndices = internal.GenTestInt32Slice() assert.Equal(t, pcommon.Int32Slice(internal.GenTestInt32SliceWrapper()), ms.LocationIndices()) } func generateTestStack() Stack { return newStack(internal.GenTestStack(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_stackslice.go000066400000000000000000000110171511331344600261410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // StackSlice logically represents a slice of Stack. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewStackSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type StackSlice struct { orig *[]*internal.Stack state *internal.State } func newStackSlice(orig *[]*internal.Stack, state *internal.State) StackSlice { return StackSlice{orig: orig, state: state} } // NewStackSlice creates a StackSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewStackSlice() StackSlice { orig := []*internal.Stack(nil) return newStackSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewStackSlice()". func (es StackSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es StackSlice) At(i int) Stack { return newStack((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es StackSlice) All() iter.Seq2[int, Stack] { return func(yield func(int, Stack) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new StackSlice can be initialized: // // es := NewStackSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es StackSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Stack, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Stack. // It returns the newly added Stack. func (es StackSlice) AppendEmpty() Stack { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewStack()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es StackSlice) MoveAndAppendTo(dest StackSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es StackSlice) RemoveIf(f func(Stack) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteStack((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es StackSlice) CopyTo(dest StackSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyStackPtrSlice(*dest.orig, *es.orig) } // Sort sorts the Stack elements within StackSlice given the // provided less function so that two instances of StackSlice // can be compared. func (es StackSlice) Sort(less func(a, b Stack) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_stackslice_test.go000066400000000000000000000111021511331344600271730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestStackSlice(t *testing.T) { es := NewStackSlice() assert.Equal(t, 0, es.Len()) es = newStackSlice(&[]*internal.Stack{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewStack() testVal := generateTestStack() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestStack() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestStackSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newStackSlice(&[]*internal.Stack{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewStackSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestStackSlice_CopyTo(t *testing.T) { dest := NewStackSlice() src := generateTestStackSlice() src.CopyTo(dest) assert.Equal(t, generateTestStackSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestStackSlice(), dest) } func TestStackSlice_EnsureCapacity(t *testing.T) { es := generateTestStackSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestStackSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestStackSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestStackSlice(), es) } func TestStackSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestStackSlice() dest := NewStackSlice() src := generateTestStackSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestStackSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestStackSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestStackSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestStackSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewStackSlice() emptySlice.RemoveIf(func(el Stack) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestStackSlice() pos := 0 filtered.RemoveIf(func(el Stack) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestStackSlice_RemoveIfAll(t *testing.T) { got := generateTestStackSlice() got.RemoveIf(func(el Stack) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestStackSliceAll(t *testing.T) { ms := generateTestStackSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestStackSlice_Sort(t *testing.T) { es := generateTestStackSlice() es.Sort(func(a, b Stack) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Stack) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestStackSlice() StackSlice { ms := NewStackSlice() *ms.orig = internal.GenTestStackPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/generated_valuetype.go000066400000000000000000000045201511331344600260330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "go.opentelemetry.io/collector/pdata/internal" ) // ValueType describes the type and units of a value. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewValueType function to create new instances. // Important: zero-initialized instance is not valid for use. type ValueType struct { orig *internal.ValueType state *internal.State } func newValueType(orig *internal.ValueType, state *internal.State) ValueType { return ValueType{orig: orig, state: state} } // NewValueType creates a new empty ValueType. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewValueType() ValueType { return newValueType(internal.NewValueType(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ValueType) MoveTo(dest ValueType) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteValueType(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // TypeStrindex returns the typestrindex associated with this ValueType. func (ms ValueType) TypeStrindex() int32 { return ms.orig.TypeStrindex } // SetTypeStrindex replaces the typestrindex associated with this ValueType. func (ms ValueType) SetTypeStrindex(v int32) { ms.state.AssertMutable() ms.orig.TypeStrindex = v } // UnitStrindex returns the unitstrindex associated with this ValueType. func (ms ValueType) UnitStrindex() int32 { return ms.orig.UnitStrindex } // SetUnitStrindex replaces the unitstrindex associated with this ValueType. func (ms ValueType) SetUnitStrindex(v int32) { ms.state.AssertMutable() ms.orig.UnitStrindex = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ValueType) CopyTo(dest ValueType) { dest.state.AssertMutable() internal.CopyValueType(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_valuetype_test.go000066400000000000000000000040161511331344600270720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestValueType_MoveTo(t *testing.T) { ms := generateTestValueType() dest := NewValueType() ms.MoveTo(dest) assert.Equal(t, NewValueType(), ms) assert.Equal(t, generateTestValueType(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestValueType(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newValueType(internal.NewValueType(), sharedState)) }) assert.Panics(t, func() { newValueType(internal.NewValueType(), sharedState).MoveTo(dest) }) } func TestValueType_CopyTo(t *testing.T) { ms := NewValueType() orig := NewValueType() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestValueType() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newValueType(internal.NewValueType(), sharedState)) }) } func TestValueType_TypeStrindex(t *testing.T) { ms := NewValueType() assert.Equal(t, int32(0), ms.TypeStrindex()) ms.SetTypeStrindex(int32(13)) assert.Equal(t, int32(13), ms.TypeStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newValueType(internal.NewValueType(), sharedState).SetTypeStrindex(int32(13)) }) } func TestValueType_UnitStrindex(t *testing.T) { ms := NewValueType() assert.Equal(t, int32(0), ms.UnitStrindex()) ms.SetUnitStrindex(int32(13)) assert.Equal(t, int32(13), ms.UnitStrindex()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newValueType(internal.NewValueType(), sharedState).SetUnitStrindex(int32(13)) }) } func generateTestValueType() ValueType { return newValueType(internal.GenTestValueType(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_valuetypeslice.go000066400000000000000000000113031511331344600270500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ValueTypeSlice logically represents a slice of ValueType. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewValueTypeSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ValueTypeSlice struct { orig *[]*internal.ValueType state *internal.State } func newValueTypeSlice(orig *[]*internal.ValueType, state *internal.State) ValueTypeSlice { return ValueTypeSlice{orig: orig, state: state} } // NewValueTypeSlice creates a ValueTypeSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewValueTypeSlice() ValueTypeSlice { orig := []*internal.ValueType(nil) return newValueTypeSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewValueTypeSlice()". func (es ValueTypeSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ValueTypeSlice) At(i int) ValueType { return newValueType((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ValueTypeSlice) All() iter.Seq2[int, ValueType] { return func(yield func(int, ValueType) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ValueTypeSlice can be initialized: // // es := NewValueTypeSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ValueTypeSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ValueType, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ValueType. // It returns the newly added ValueType. func (es ValueTypeSlice) AppendEmpty() ValueType { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewValueType()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ValueTypeSlice) MoveAndAppendTo(dest ValueTypeSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ValueTypeSlice) RemoveIf(f func(ValueType) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteValueType((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ValueTypeSlice) CopyTo(dest ValueTypeSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyValueTypePtrSlice(*dest.orig, *es.orig) } // Sort sorts the ValueType elements within ValueTypeSlice given the // provided less function so that two instances of ValueTypeSlice // can be compared. func (es ValueTypeSlice) Sort(less func(a, b ValueType) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/pprofile/generated_valuetypeslice_test.go000066400000000000000000000113721511331344600301150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofile import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestValueTypeSlice(t *testing.T) { es := NewValueTypeSlice() assert.Equal(t, 0, es.Len()) es = newValueTypeSlice(&[]*internal.ValueType{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewValueType() testVal := generateTestValueType() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestValueType() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestValueTypeSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newValueTypeSlice(&[]*internal.ValueType{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewValueTypeSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestValueTypeSlice_CopyTo(t *testing.T) { dest := NewValueTypeSlice() src := generateTestValueTypeSlice() src.CopyTo(dest) assert.Equal(t, generateTestValueTypeSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestValueTypeSlice(), dest) } func TestValueTypeSlice_EnsureCapacity(t *testing.T) { es := generateTestValueTypeSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestValueTypeSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestValueTypeSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestValueTypeSlice(), es) } func TestValueTypeSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestValueTypeSlice() dest := NewValueTypeSlice() src := generateTestValueTypeSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestValueTypeSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestValueTypeSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestValueTypeSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestValueTypeSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewValueTypeSlice() emptySlice.RemoveIf(func(el ValueType) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestValueTypeSlice() pos := 0 filtered.RemoveIf(func(el ValueType) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestValueTypeSlice_RemoveIfAll(t *testing.T) { got := generateTestValueTypeSlice() got.RemoveIf(func(el ValueType) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestValueTypeSliceAll(t *testing.T) { ms := generateTestValueTypeSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestValueTypeSlice_Sort(t *testing.T) { es := generateTestValueTypeSlice() es.Sort(func(a, b ValueType) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ValueType) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestValueTypeSlice() ValueTypeSlice { ms := NewValueTypeSlice() *ms.orig = internal.GenTestValueTypePtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/pprofile/go.mod000066400000000000000000000026741511331344600225660ustar00rootroot00000000000000module go.opentelemetry.io/collector/pdata/pprofile go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development v0.2.0 go.opentelemetry.io/proto/slim/otlp/profiles/v1development v0.2.0 go.uber.org/goleak v1.3.0 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.10 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/proto/slim/otlp v1.9.0 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect golang.org/x/sys v0.37.0 // indirect golang.org/x/text v0.30.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../ replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/pdata/pprofile/go.sum000066400000000000000000000156261511331344600226140ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/pdata/pprofile/json.go000066400000000000000000000022741511331344600227540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" ) // JSONMarshaler marshals pprofile.Profiles to JSON bytes using the OTLP/JSON format. type JSONMarshaler struct{} // MarshalProfiles to the OTLP/JSON format. func (*JSONMarshaler) MarshalProfiles(pd Profiles) ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) pd.getOrig().MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } // JSONUnmarshaler unmarshals OTLP/JSON formatted-bytes to pprofile.Profiles. type JSONUnmarshaler struct{} // UnmarshalProfiles from OTLP/JSON format into pprofile.Profiles. func (*JSONUnmarshaler) UnmarshalProfiles(buf []byte) (Profiles, error) { iter := json.BorrowIterator(buf) defer json.ReturnIterator(iter) pd := NewProfiles() pd.getOrig().UnmarshalJSON(iter) if iter.Error() != nil { return Profiles{}, iter.Error() } otlp.MigrateProfiles(pd.getOrig().ResourceProfiles) return pd, nil } opentelemetry-collector-0.141.0/pdata/pprofile/keyvalueandunit.go000066400000000000000000000025111511331344600252050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // Equal checks equality with another KeyValueAndUnit // It assumes both structs refer to the same dictionary. func (ms KeyValueAndUnit) Equal(val KeyValueAndUnit) bool { return ms.KeyStrindex() == val.KeyStrindex() && ms.UnitStrindex() == val.UnitStrindex() && ms.Value().Equal(val.Value()) } // switchDictionary updates the KeyValueAndUnit, switching its indices from one // dictionary to another. func (ms KeyValueAndUnit) switchDictionary(src, dst ProfilesDictionary) error { if ms.KeyStrindex() > 0 { if src.StringTable().Len() < int(ms.KeyStrindex()) { return fmt.Errorf("invalid key index %d", ms.KeyStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(ms.KeyStrindex()))) if err != nil { return fmt.Errorf("couldn't set key: %w", err) } ms.SetKeyStrindex(idx) } if ms.UnitStrindex() > 0 { if src.StringTable().Len() < int(ms.UnitStrindex()) { return fmt.Errorf("invalid unit index %d", ms.UnitStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(ms.UnitStrindex()))) if err != nil { return fmt.Errorf("couldn't set unit: %w", err) } ms.SetUnitStrindex(idx) } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/keyvalueandunit_test.go000066400000000000000000000124661511331344600262560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestKeyValueAndUnitEqual(t *testing.T) { for _, tt := range []struct { name string orig KeyValueAndUnit dest KeyValueAndUnit want bool }{ { name: "empty keyvalueandunit", orig: NewKeyValueAndUnit(), dest: NewKeyValueAndUnit(), want: true, }, { name: "non-empty identical keyvalueandunit", orig: buildKeyValueAndUnit(1, 2, pcommon.NewValueStr("test")), dest: buildKeyValueAndUnit(1, 2, pcommon.NewValueStr("test")), want: true, }, { name: "with different key index", orig: buildKeyValueAndUnit(1, 2, pcommon.NewValueStr("test")), dest: buildKeyValueAndUnit(2, 2, pcommon.NewValueStr("test")), want: false, }, { name: "with different unit index", orig: buildKeyValueAndUnit(1, 2, pcommon.NewValueStr("test")), dest: buildKeyValueAndUnit(1, 3, pcommon.NewValueStr("test")), want: false, }, { name: "with different value", orig: buildKeyValueAndUnit(1, 2, pcommon.NewValueStr("test")), dest: buildKeyValueAndUnit(1, 2, pcommon.NewValueStr("hello")), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func TestKeyValueAndUnitSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string keyValueAndUnit KeyValueAndUnit src ProfilesDictionary dst ProfilesDictionary wantKeyValueAndUnit KeyValueAndUnit wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty key value and unit", keyValueAndUnit: NewKeyValueAndUnit(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantKeyValueAndUnit: NewKeyValueAndUnit(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing key", keyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetKeyStrindex(1) return kvu }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantKeyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetKeyStrindex(2) return kvu }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a key index that does not match anything", keyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetKeyStrindex(1) return kvu }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantKeyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetKeyStrindex(1) return kvu }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid key index 1"), }, { name: "with an existing unit", keyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetUnitStrindex(1) return kvu }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantKeyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetUnitStrindex(2) return kvu }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a unit index that does not match anything", keyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetUnitStrindex(1) return kvu }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantKeyValueAndUnit: func() KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetUnitStrindex(1) return kvu }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid unit index 1"), }, } { t.Run(tt.name, func(t *testing.T) { kvu := tt.keyValueAndUnit dst := tt.dst err := kvu.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantKeyValueAndUnit, kvu) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkKeyValueAndUnitSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) kvu := NewKeyValueAndUnit() kvu.SetKeyStrindex(1) src := NewProfilesDictionary() src.StringTable().Append("", "test") b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() b.StartTimer() _ = kvu.switchDictionary(src, dst) } } func buildKeyValueAndUnit(keyIdx, unitIdx int32, val pcommon.Value) KeyValueAndUnit { kvu := NewKeyValueAndUnit() kvu.SetKeyStrindex(keyIdx) kvu.SetUnitStrindex(unitIdx) val.CopyTo(kvu.Value()) return kvu } opentelemetry-collector-0.141.0/pdata/pprofile/line.go000066400000000000000000000024011511331344600227220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // Equal checks equality with another LineSlice func (l LineSlice) Equal(val LineSlice) bool { if l.Len() != val.Len() { return false } for i := range l.Len() { if !l.At(i).Equal(val.At(i)) { return false } } return true } // Equal checks equality with another Line func (l Line) Equal(val Line) bool { return l.Column() == val.Column() && l.FunctionIndex() == val.FunctionIndex() && l.Line() == val.Line() } // switchDictionary updates the Line, switching its indices from one // dictionary to another. func (l Line) switchDictionary(src, dst ProfilesDictionary) error { if l.FunctionIndex() > 0 { if src.FunctionTable().Len() < int(l.FunctionIndex()) { return fmt.Errorf("invalid function index %d", l.FunctionIndex()) } fn := src.FunctionTable().At(int(l.FunctionIndex())) err := fn.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch function dictionary: %w", err) } idx, err := SetFunction(dst.FunctionTable(), fn) if err != nil { return fmt.Errorf("couldn't set function: %w", err) } l.SetFunctionIndex(idx) } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/line_test.go000066400000000000000000000115721511331344600237720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestLineSliceEqual(t *testing.T) { for _, tt := range []struct { name string orig LineSlice dest LineSlice want bool }{ { name: "with empty slices", orig: NewLineSlice(), dest: NewLineSlice(), want: true, }, { name: "with non-empty equal slices", orig: func() LineSlice { ls := NewLineSlice() ls.AppendEmpty().SetLine(1) return ls }(), dest: func() LineSlice { ls := NewLineSlice() ls.AppendEmpty().SetLine(1) return ls }(), want: true, }, { name: "with different lengths", orig: func() LineSlice { ls := NewLineSlice() ls.AppendEmpty() return ls }(), dest: NewLineSlice(), want: false, }, { name: "with non-equal slices", orig: func() LineSlice { ls := NewLineSlice() ls.AppendEmpty().SetLine(2) return ls }(), dest: func() LineSlice { ls := NewLineSlice() ls.AppendEmpty().SetLine(1) return ls }(), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func TestLineEqual(t *testing.T) { for _, tt := range []struct { name string orig Line dest Line want bool }{ { name: "with empty lines", orig: NewLine(), dest: NewLine(), want: true, }, { name: "with non-empty lines", orig: buildLine(1, 2, 3), dest: buildLine(1, 2, 3), want: true, }, { name: "with non-equal column", orig: buildLine(1, 2, 3), dest: buildLine(2, 2, 3), want: false, }, { name: "with non-equal function index", orig: buildLine(1, 2, 3), dest: buildLine(1, 3, 3), want: false, }, { name: "with non-equal line", orig: buildLine(1, 2, 3), dest: buildLine(1, 2, 4), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func TestLineSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string line Line src ProfilesDictionary dst ProfilesDictionary wantLine Line wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty line", line: NewLine(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantLine: NewLine(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing function", line: func() Line { l := NewLine() l.SetFunctionIndex(1) return l }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") d.FunctionTable().AppendEmpty() f := d.FunctionTable().AppendEmpty() f.SetNameStrindex(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") d.FunctionTable().AppendEmpty() d.FunctionTable().AppendEmpty() return d }(), wantLine: func() Line { l := NewLine() l.SetFunctionIndex(2) return l }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") d.FunctionTable().AppendEmpty() d.FunctionTable().AppendEmpty() f := d.FunctionTable().AppendEmpty() f.SetNameStrindex(2) return d }(), }, { name: "with a function index that does not match anything", line: func() Line { l := NewLine() l.SetFunctionIndex(1) return l }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantLine: func() Line { l := NewLine() l.SetFunctionIndex(1) return l }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid function index 1"), }, } { t.Run(tt.name, func(t *testing.T) { line := tt.line dst := tt.dst err := line.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantLine, line) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkLineSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) l := NewLine() l.SetFunctionIndex(1) src := NewProfilesDictionary() src.StringTable().Append("", "test") src.FunctionTable().AppendEmpty() src.FunctionTable().AppendEmpty().SetNameStrindex(1) b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() b.StartTimer() _ = l.switchDictionary(src, dst) } } func buildLine(col int64, funcIdx int32, line int64) Line { l := NewLine() l.SetColumn(col) l.SetFunctionIndex(funcIdx) l.SetLine(line) return l } opentelemetry-collector-0.141.0/pdata/pprofile/link.go000066400000000000000000000004641511331344600227370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" // Equal checks equality with another Link func (ms Link) Equal(val Link) bool { return ms.TraceID() == val.TraceID() && ms.SpanID() == val.SpanID() } opentelemetry-collector-0.141.0/pdata/pprofile/link_test.go000066400000000000000000000035101511331344600237710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestLinkEqual(t *testing.T) { for _, tt := range []struct { name string orig Link dest Link want bool }{ { name: "empty links", orig: NewLink(), dest: NewLink(), want: true, }, { name: "non-empty identical links", orig: buildLink( pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}), pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}), ), dest: buildLink( pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}), pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}), ), want: true, }, { name: "with different trace IDs", orig: buildLink( pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}), pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}), ), dest: buildLink( pcommon.TraceID([16]byte{8, 7, 6, 5, 4, 3, 2, 1, 1, 2, 3, 4, 5, 6, 7, 8}), pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}), ), want: false, }, { name: "with different span IDs", orig: buildLink( pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}), pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}), ), dest: buildLink( pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}), pcommon.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1}), ), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func buildLink(traceID pcommon.TraceID, spanID pcommon.SpanID) Link { l := NewLink() l.SetTraceID(traceID) l.SetSpanID(spanID) return l } opentelemetry-collector-0.141.0/pdata/pprofile/links.go000066400000000000000000000013041511331344600231140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "errors" "math" ) var errTooManyLinkTableEntries = errors.New("too many entries in LinkTable") // SetLink updates a LinkTable, adding or providing a value and returns its // index. func SetLink(table LinkSlice, li Link) (int32, error) { for j, l := range table.All() { if l.Equal(li) { if j > math.MaxInt32 { return 0, errTooManyLinkTableEntries } return int32(j), nil } } if table.Len() >= math.MaxInt32 { return 0, errTooManyLinkTableEntries } li.CopyTo(table.AppendEmpty()) return int32(table.Len() - 1), nil } opentelemetry-collector-0.141.0/pdata/pprofile/links_test.go000066400000000000000000000050541511331344600241610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSetLink(t *testing.T) { table := NewLinkSlice() l := NewLink() l.SetTraceID(pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})) l2 := NewLink() l.SetTraceID(pcommon.TraceID([16]byte{2, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 2})) // Put a first link idx, err := SetLink(table, l) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Put the same link // This should be a no-op. idx, err = SetLink(table, l) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Set a new link // This sets the index and adds to the table. idx, err = SetLink(table, l2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) // Set an existing link idx, err = SetLink(table, l) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(0), idx) // Set another existing link idx, err = SetLink(table, l2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) } func BenchmarkSetLink(b *testing.B) { testutil.SkipMemoryBench(b) for _, bb := range []struct { name string link Link runBefore func(*testing.B, LinkSlice) }{ { name: "with a new link", link: NewLink(), }, { name: "with an existing link", link: func() Link { l := NewLink() l.SetTraceID(pcommon.NewTraceIDEmpty()) return l }(), runBefore: func(_ *testing.B, table LinkSlice) { l := table.AppendEmpty() l.SetTraceID(pcommon.NewTraceIDEmpty()) }, }, { name: "with a duplicate link", link: NewLink(), runBefore: func(b *testing.B, table LinkSlice) { _, err := SetLink(table, NewLink()) require.NoError(b, err) }, }, { name: "with a hundred links to loop through", link: func() Link { l := NewLink() l.SetTraceID(pcommon.NewTraceIDEmpty()) return l }(), runBefore: func(_ *testing.B, table LinkSlice) { for range 100 { table.AppendEmpty() } }, }, } { b.Run(bb.name, func(b *testing.B) { table := NewLinkSlice() if bb.runBefore != nil { bb.runBefore(b, table) } b.ResetTimer() b.ReportAllocs() for b.Loop() { _, _ = SetLink(table, bb.link) } }) } } opentelemetry-collector-0.141.0/pdata/pprofile/location.go000066400000000000000000000034521511331344600236120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // Equal checks equality with another Location func (ms Location) Equal(val Location) bool { return ms.MappingIndex() == val.MappingIndex() && ms.Address() == val.Address() && ms.AttributeIndices().Equal(val.AttributeIndices()) && ms.Lines().Equal(val.Lines()) } // switchDictionary updates the Location, switching its indices from one // dictionary to another. func (ms Location) switchDictionary(src, dst ProfilesDictionary) error { if ms.MappingIndex() > 0 { if src.MappingTable().Len() < int(ms.MappingIndex()) { return fmt.Errorf("invalid mapping index %d", ms.MappingIndex()) } mapping := src.MappingTable().At(int(ms.MappingIndex())) err := mapping.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch dictionary for mapping: %w", err) } idx, err := SetMapping(dst.MappingTable(), mapping) if err != nil { return fmt.Errorf("couldn't set mapping: %w", err) } ms.SetMappingIndex(idx) } for i, v := range ms.AttributeIndices().All() { if src.AttributeTable().Len() < int(v) { return fmt.Errorf("invalid attribute index %d", v) } attr := src.AttributeTable().At(int(v)) err := attr.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch dictionary for attribute %d: %w", i, err) } idx, err := SetAttribute(dst.AttributeTable(), attr) if err != nil { return fmt.Errorf("couldn't set attribute %d: %w", i, err) } ms.AttributeIndices().SetAt(i, idx) } for i, v := range ms.Lines().All() { err := v.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch dictionary for line %d: %w", i, err) } } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/location_test.go000066400000000000000000000157731511331344600246620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestLocationEqual(t *testing.T) { for _, tt := range []struct { name string orig Location dest Location want bool }{ { name: "empty locations", orig: NewLocation(), dest: NewLocation(), want: true, }, { name: "non-empty locations", orig: buildLocation(1, 2, []int32{3}, buildLine(1, 2, 3)), dest: buildLocation(1, 2, []int32{3}, buildLine(1, 2, 3)), want: true, }, { name: "with non-equal mapping index", orig: buildLocation(1, 2, []int32{3}, buildLine(1, 2, 3)), dest: buildLocation(2, 2, []int32{3}, buildLine(1, 2, 3)), want: false, }, { name: "with non-equal address", orig: buildLocation(1, 2, []int32{3}, buildLine(1, 2, 3)), dest: buildLocation(1, 3, []int32{3}, buildLine(1, 2, 3)), want: false, }, { name: "with non-equal attribute indices", orig: buildLocation(1, 2, []int32{3}, buildLine(1, 2, 3)), dest: buildLocation(1, 2, []int32{5}, buildLine(1, 2, 3)), want: false, }, { name: "with non-equal lines", orig: buildLocation(1, 2, []int32{3}, buildLine(4, 5, 6)), dest: buildLocation(1, 2, []int32{3}, buildLine(1, 2, 3)), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func TestLocationSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string location Location src ProfilesDictionary dst ProfilesDictionary wantLocation Location wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty location", location: NewLocation(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantLocation: NewLocation(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing mapping", location: func() Location { l := NewLocation() l.SetMappingIndex(1) return l }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") d.MappingTable().AppendEmpty() m := d.MappingTable().AppendEmpty() m.SetFilenameStrindex(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") d.MappingTable().AppendEmpty() d.MappingTable().AppendEmpty() return d }(), wantLocation: func() Location { l := NewLocation() l.SetMappingIndex(2) return l }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") d.MappingTable().AppendEmpty() d.MappingTable().AppendEmpty() m := d.MappingTable().AppendEmpty() m.SetFilenameStrindex(2) return d }(), }, { name: "with a mapping that cannot be found", location: func() Location { l := NewLocation() l.SetMappingIndex(1) return l }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantLocation: func() Location { l := NewLocation() l.SetMappingIndex(1) return l }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid mapping index 1"), }, { name: "with an existing attribute", location: func() Location { l := NewLocation() l.AttributeIndices().Append(1) return l }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() return d }(), wantLocation: func() Location { l := NewLocation() l.AttributeIndices().Append(2) return l }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(2) return d }(), }, { name: "with an attribute index that does not match anything", location: func() Location { l := NewLocation() l.AttributeIndices().Append(1) return l }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantLocation: func() Location { l := NewLocation() l.AttributeIndices().Append(1) return l }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid attribute index 1"), }, { name: "with an existing line", location: func() Location { l := NewLocation() l.Lines().AppendEmpty().SetFunctionIndex(1) return l }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") d.FunctionTable().AppendEmpty() f := d.FunctionTable().AppendEmpty() f.SetNameStrindex(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") d.FunctionTable().AppendEmpty() d.FunctionTable().AppendEmpty() return d }(), wantLocation: func() Location { l := NewLocation() l.Lines().AppendEmpty().SetFunctionIndex(2) return l }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") d.FunctionTable().AppendEmpty() d.FunctionTable().AppendEmpty() f := d.FunctionTable().AppendEmpty() f.SetNameStrindex(2) return d }(), }, } { t.Run(tt.name, func(t *testing.T) { l := tt.location dst := tt.dst err := l.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantLocation, l) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkLocationSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) l := NewLocation() l.AttributeIndices().Append(1, 2) src := NewProfilesDictionary() src.StringTable().Append("", "test") src.AttributeTable().AppendEmpty() src.AttributeTable().AppendEmpty().SetKeyStrindex(1) src.AttributeTable().AppendEmpty().SetKeyStrindex(2) b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() dst.StringTable().Append("", "foo") dst.AttributeTable().AppendEmpty() dst.AttributeTable().AppendEmpty().SetKeyStrindex(1) b.StartTimer() _ = l.switchDictionary(src, dst) } } func buildLocation(mapIdx int32, addr uint64, attrIdxs []int32, line Line) Location { l := NewLocation() l.SetMappingIndex(mapIdx) l.SetAddress(addr) l.AttributeIndices().FromRaw(attrIdxs) line.MoveTo(l.Lines().AppendEmpty()) return l } opentelemetry-collector-0.141.0/pdata/pprofile/locations.go000066400000000000000000000022321511331344600237700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "errors" "math" ) // FromLocationIndices builds a slice containing all the locations of a Stack. // Updates made to the returned map will not be applied back to the Stack. func FromLocationIndices(table LocationSlice, record Stack) LocationSlice { m := NewLocationSlice() m.EnsureCapacity(record.LocationIndices().Len()) for _, idx := range record.LocationIndices().All() { l := table.At(int(idx)) l.CopyTo(m.AppendEmpty()) } return m } var errTooManyLocationTableEntries = errors.New("too many entries in LocationTable") // SetLocation updates a LocationTable, adding or providing a value and returns // its index. func SetLocation(table LocationSlice, loc Location) (int32, error) { for j, a := range table.All() { if a.Equal(loc) { if j > math.MaxInt32 { return 0, errTooManyLocationTableEntries } return int32(j), nil } } if table.Len() >= math.MaxInt32 { return 0, errTooManyLocationTableEntries } loc.CopyTo(table.AppendEmpty()) return int32(table.Len() - 1), nil } opentelemetry-collector-0.141.0/pdata/pprofile/locations_test.go000066400000000000000000000066511511331344600250400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestFromLocationIndices(t *testing.T) { table := NewLocationSlice() table.AppendEmpty().SetAddress(1) table.AppendEmpty().SetAddress(2) stack := NewStack() locs := FromLocationIndices(table, stack) assert.Equal(t, locs, NewLocationSlice()) // Add a location stack.LocationIndices().Append(0) locs = FromLocationIndices(table, stack) tLoc := NewLocationSlice() tLoc.AppendEmpty().SetAddress(1) assert.Equal(t, tLoc, locs) // Add another location stack.LocationIndices().Append(1) locs = FromLocationIndices(table, stack) assert.Equal(t, table, locs) } func TestSetLocation(t *testing.T) { table := NewLocationSlice() l := NewLocation() l.SetAddress(1) l2 := NewLocation() l2.SetAddress(2) // Put a first value idx, err := SetLocation(table, l) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Put the same string // This should be a no-op. idx, err = SetLocation(table, l) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Set a new value // This sets the index and adds to the table. idx, err = SetLocation(table, l2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) // Set an existing value idx, err = SetLocation(table, l) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(0), idx) // Set another existing value idx, err = SetLocation(table, l2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) } func BenchmarkFromLocationIndices(b *testing.B) { table := NewLocationSlice() for i := range 100 { table.AppendEmpty().SetAddress(uint64(i)) } obj := NewStack() for i := range int32(50) { obj.LocationIndices().Append(2*i + 1) } b.ReportAllocs() for b.Loop() { _ = FromLocationIndices(table, obj) } } func BenchmarkSetLocation(b *testing.B) { testutil.SkipMemoryBench(b) for _, bb := range []struct { name string location Location runBefore func(*testing.B, LocationSlice) }{ { name: "with a new location", location: NewLocation(), }, { name: "with an existing location", location: func() Location { l := NewLocation() l.SetAddress(1) return l }(), runBefore: func(_ *testing.B, table LocationSlice) { l := table.AppendEmpty() l.SetAddress(1) }, }, { name: "with a duplicate location", location: NewLocation(), runBefore: func(_ *testing.B, table LocationSlice) { _, err := SetLocation(table, NewLocation()) require.NoError(b, err) }, }, { name: "with a hundred locations to loop through", location: func() Location { l := NewLocation() l.SetMappingIndex(1) return l }(), runBefore: func(_ *testing.B, table LocationSlice) { for i := range 100 { l := table.AppendEmpty() l.SetAddress(uint64(i)) } l := table.AppendEmpty() l.SetMappingIndex(1) }, }, } { b.Run(bb.name, func(b *testing.B) { table := NewLocationSlice() if bb.runBefore != nil { bb.runBefore(b, table) } b.ResetTimer() b.ReportAllocs() for b.Loop() { _, _ = SetLocation(table, bb.location) } }) } } opentelemetry-collector-0.141.0/pdata/pprofile/mapping.go000066400000000000000000000030501511331344600234270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // Equal checks equality with another Mapping func (ms Mapping) Equal(val Mapping) bool { return ms.MemoryStart() == val.MemoryStart() && ms.MemoryLimit() == val.MemoryLimit() && ms.FileOffset() == val.FileOffset() && ms.FilenameStrindex() == val.FilenameStrindex() && ms.AttributeIndices().Equal(val.AttributeIndices()) } // switchDictionary updates the Mapping, switching its indices from one // dictionary to another. func (ms Mapping) switchDictionary(src, dst ProfilesDictionary) error { if ms.FilenameStrindex() > 0 { if src.StringTable().Len() < int(ms.FilenameStrindex()) { return fmt.Errorf("invalid filename index %d", ms.FilenameStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(ms.FilenameStrindex()))) if err != nil { return fmt.Errorf("couldn't set filename: %w", err) } ms.SetFilenameStrindex(idx) } for i, v := range ms.AttributeIndices().All() { if src.AttributeTable().Len() < int(v) { return fmt.Errorf("invalid attribute index %d", v) } attr := src.AttributeTable().At(int(v)) err := attr.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch dictionary for attribute %d: %w", i, err) } idx, err := SetAttribute(dst.AttributeTable(), attr) if err != nil { return fmt.Errorf("couldn't set attribute %d: %w", i, err) } ms.AttributeIndices().SetAt(i, idx) } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/mapping_test.go000066400000000000000000000134711511331344600244760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestMappingEqual(t *testing.T) { for _, tt := range []struct { name string orig Mapping dest Mapping want bool }{ { name: "empty mappings", orig: NewMapping(), dest: NewMapping(), want: true, }, { name: "non-empty identical mappings", orig: buildMapping(1, 2, 3, 4, []int32{1, 2}), dest: buildMapping(1, 2, 3, 4, []int32{1, 2}), want: true, }, { name: "with different MemoryStart", orig: buildMapping(1, 2, 3, 4, []int32{1, 2}), dest: buildMapping(2, 2, 3, 4, []int32{1, 2}), want: false, }, { name: "with different MemoryLimit", orig: buildMapping(1, 2, 3, 4, []int32{1, 2}), dest: buildMapping(1, 3, 3, 4, []int32{1, 2}), want: false, }, { name: "with different FileOffset", orig: buildMapping(1, 2, 3, 4, []int32{1, 2}), dest: buildMapping(1, 2, 4, 4, []int32{1, 2}), want: false, }, { name: "with different FilenameStrindex", orig: buildMapping(1, 2, 3, 4, []int32{1, 2}), dest: buildMapping(1, 2, 3, 5, []int32{1, 2}), want: false, }, { name: "with different AttributeIndices", orig: buildMapping(1, 2, 3, 4, []int32{1, 2}), dest: buildMapping(1, 2, 3, 4, []int32{1, 3}), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func TestMappingSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string mapping Mapping src ProfilesDictionary dst ProfilesDictionary wantMapping Mapping wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty mapping", mapping: NewMapping(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantMapping: NewMapping(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing filename", mapping: func() Mapping { m := NewMapping() m.SetFilenameStrindex(1) return m }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantMapping: func() Mapping { m := NewMapping() m.SetFilenameStrindex(2) return m }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a filename index that does not match anything", mapping: func() Mapping { m := NewMapping() m.SetFilenameStrindex(1) return m }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantMapping: func() Mapping { m := NewMapping() m.SetFilenameStrindex(1) return m }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid filename index 1"), }, { name: "with an existing attribute", mapping: func() Mapping { m := NewMapping() m.AttributeIndices().Append(1) return m }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() return d }(), wantMapping: func() Mapping { m := NewMapping() m.AttributeIndices().Append(2) return m }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(2) return d }(), }, { name: "with an attribute index that does not match anything", mapping: func() Mapping { m := NewMapping() m.AttributeIndices().Append(1) return m }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantMapping: func() Mapping { m := NewMapping() m.AttributeIndices().Append(1) return m }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid attribute index 1"), }, } { t.Run(tt.name, func(t *testing.T) { m := tt.mapping dst := tt.dst err := m.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantMapping, m) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkMappingSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) m := NewMapping() m.AttributeIndices().Append(1, 2) src := NewProfilesDictionary() src.StringTable().Append("", "test", "foo") src.AttributeTable().AppendEmpty() src.AttributeTable().AppendEmpty().SetKeyStrindex(1) src.AttributeTable().AppendEmpty().SetKeyStrindex(2) b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() dst.StringTable().Append("", "foo") dst.AttributeTable().AppendEmpty() dst.AttributeTable().AppendEmpty().SetKeyStrindex(1) b.StartTimer() _ = m.switchDictionary(src, dst) } } func buildMapping(memStart, memLimit, fileOffset uint64, filenameIdx int32, attrIdxs []int32) Mapping { m := NewMapping() m.SetMemoryStart(memStart) m.SetMemoryLimit(memLimit) m.SetFileOffset(fileOffset) m.SetFilenameStrindex(filenameIdx) m.AttributeIndices().FromRaw(attrIdxs) return m } opentelemetry-collector-0.141.0/pdata/pprofile/mappings.go000066400000000000000000000013371511331344600236200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "errors" "math" ) var errTooManyMappingTableEntries = errors.New("too many entries in MappingTable") // SetMapping updates a MappingTable, adding or providing a value and returns // its index. func SetMapping(table MappingSlice, ma Mapping) (int32, error) { for j, m := range table.All() { if m.Equal(ma) { if j > math.MaxInt32 { return 0, errTooManyMappingTableEntries } return int32(j), nil } } if table.Len() >= math.MaxInt32 { return 0, errTooManyMappingTableEntries } ma.CopyTo(table.AppendEmpty()) return int32(table.Len() - 1), nil } opentelemetry-collector-0.141.0/pdata/pprofile/mappings_test.go000066400000000000000000000047461511331344600246660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestSetMapping(t *testing.T) { table := NewMappingSlice() m := NewMapping() m.SetMemoryLimit(1) m2 := NewMapping() m2.SetMemoryLimit(2) // Put a first mapping idx, err := SetMapping(table, m) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Put the same mapping // This should be a no-op. idx, err = SetMapping(table, m) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Set a new mapping // This sets the index and adds to the table. idx, err = SetMapping(table, m2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) // Set an existing mapping idx, err = SetMapping(table, m) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(0), idx) // Set another existing mapping idx, err = SetMapping(table, m2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) } func BenchmarkSetMapping(b *testing.B) { testutil.SkipMemoryBench(b) for _, bb := range []struct { name string mapping Mapping runBefore func(*testing.B, MappingSlice) }{ { name: "with a new mapping", mapping: NewMapping(), }, { name: "with an existing mapping", mapping: func() Mapping { m := NewMapping() m.SetMemoryLimit(1) return m }(), runBefore: func(_ *testing.B, table MappingSlice) { m := table.AppendEmpty() m.SetMemoryLimit(1) }, }, { name: "with a duplicate mapping", mapping: NewMapping(), runBefore: func(_ *testing.B, table MappingSlice) { _, err := SetMapping(table, NewMapping()) require.NoError(b, err) }, }, { name: "with a hundred mappings to loop through", mapping: func() Mapping { m := NewMapping() m.SetMemoryLimit(1) return m }(), runBefore: func(_ *testing.B, table MappingSlice) { for i := range 100 { m := table.AppendEmpty() m.SetMemoryLimit(uint64(i)) } }, }, } { b.Run(bb.name, func(b *testing.B) { table := NewMappingSlice() if bb.runBefore != nil { bb.runBefore(b, table) } b.ResetTimer() b.ReportAllocs() for b.Loop() { _, _ = SetMapping(table, bb.mapping) } }) } } opentelemetry-collector-0.141.0/pdata/pprofile/metadata.yaml000066400000000000000000000003371511331344600241160ustar00rootroot00000000000000type: pprofile github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pdata codeowners: active: - mx-psi - dmathieu stability: development: [profiles] opentelemetry-collector-0.141.0/pdata/pprofile/pb.go000066400000000000000000000020111511331344600223710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" var _ MarshalSizer = (*ProtoMarshaler)(nil) type ProtoMarshaler struct{} func (e *ProtoMarshaler) MarshalProfiles(pd Profiles) ([]byte, error) { size := pd.getOrig().SizeProto() buf := make([]byte, size) _ = pd.getOrig().MarshalProto(buf) return buf, nil } func (e *ProtoMarshaler) ProfilesSize(pd Profiles) int { return pd.getOrig().SizeProto() } func (e *ProtoMarshaler) ResourceProfilesSize(pd ResourceProfiles) int { return pd.orig.SizeProto() } func (e *ProtoMarshaler) ScopeProfilesSize(pd ScopeProfiles) int { return pd.orig.SizeProto() } func (e *ProtoMarshaler) ProfileSize(pd Profile) int { return pd.orig.SizeProto() } type ProtoUnmarshaler struct{} func (d *ProtoUnmarshaler) UnmarshalProfiles(buf []byte) (Profiles, error) { pd := NewProfiles() err := pd.getOrig().UnmarshalProto(buf) if err != nil { return Profiles{}, err } return pd, nil } opentelemetry-collector-0.141.0/pdata/pprofile/pb_test.go000066400000000000000000000062501511331344600234410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpprofiles "go.opentelemetry.io/proto/slim/otlp/profiles/v1development" goproto "google.golang.org/protobuf/proto" ) func TestProfilesProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Profiles as pdata struct. td := generateTestProfiles() // Marshal its underlying ProtoBuf to wire. marshaler := &ProtoMarshaler{} wire1, err := marshaler.MarshalProfiles(td) require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlpprofiles.ProfilesData err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. var td2 Profiles unmarshaler := &ProtoUnmarshaler{} td2, err = unmarshaler.UnmarshalProfiles(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. assert.Equal(t, td, td2) } func TestProtoProfilesUnmarshalerError(t *testing.T) { p := &ProtoUnmarshaler{} _, err := p.UnmarshalProfiles([]byte("+$%")) assert.Error(t, err) } func TestProtoSizer(t *testing.T) { marshaler := &ProtoMarshaler{} td := NewProfiles() td.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() td.Dictionary().StringTable().Append("foobar") size := marshaler.ProfilesSize(td) bytes, err := marshaler.MarshalProfiles(td) require.NoError(t, err) assert.Equal(t, len(bytes), size) } func TestProtoSizerEmptyProfiles(t *testing.T) { sizer := &ProtoMarshaler{} assert.Equal(t, 2, sizer.ProfilesSize(NewProfiles())) } func BenchmarkProfilesToProto(b *testing.B) { marshaler := &ProtoMarshaler{} profiles := generateBenchmarkProfiles(128) for b.Loop() { buf, err := marshaler.MarshalProfiles(profiles) require.NoError(b, err) assert.NotEmpty(b, buf) } } func BenchmarkProfilesFromProto(b *testing.B) { marshaler := &ProtoMarshaler{} unmarshaler := &ProtoUnmarshaler{} baseProfiles := generateBenchmarkProfiles(128) buf, err := marshaler.MarshalProfiles(baseProfiles) require.NoError(b, err) assert.NotEmpty(b, buf) b.ReportAllocs() for b.Loop() { profiles, err := unmarshaler.UnmarshalProfiles(buf) require.NoError(b, err) assert.Equal(b, baseProfiles.ResourceProfiles().Len(), profiles.ResourceProfiles().Len()) } } func generateBenchmarkProfiles(samplesCount int) Profiles { md := NewProfiles() ilm := md.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() ilm.Samples().EnsureCapacity(samplesCount) for range samplesCount { im := ilm.Samples().AppendEmpty() im.SetStackIndex(0) } return md } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/000077500000000000000000000000001511331344600241665ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/fuzz_test.go000066400000000000000000000050751511331344600265610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp // import "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" import ( "bytes" "testing" "github.com/stretchr/testify/require" ) var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." func FuzzRequestUnmarshalJSON(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportRequest() err := er.UnmarshalJSON(data) if err != nil { return } b1, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") er = NewExportRequest() require.NoError(t, er.UnmarshalJSON(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzResponseUnmarshalJSON(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportResponse() err := er.UnmarshalJSON(data) if err != nil { return } b1, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") er = NewExportResponse() require.NoError(t, er.UnmarshalJSON(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzRequestUnmarshalProto(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportRequest() err := er.UnmarshalProto(data) if err != nil { return } b1, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") er = NewExportRequest() require.NoError(t, er.UnmarshalProto(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzResponseUnmarshalProto(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportResponse() err := er.UnmarshalProto(data) if err != nil { return } b1, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") er = NewExportResponse() require.NoError(t, er.UnmarshalProto(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/generated_exportpartialsuccess.go000066400000000000000000000053521511331344600330270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofileotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportPartialSuccess represents the details of a partially successful export request. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportPartialSuccess function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportPartialSuccess struct { orig *internal.ExportProfilesPartialSuccess state *internal.State } func newExportPartialSuccess(orig *internal.ExportProfilesPartialSuccess, state *internal.State) ExportPartialSuccess { return ExportPartialSuccess{orig: orig, state: state} } // NewExportPartialSuccess creates a new empty ExportPartialSuccess. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.NewExportProfilesPartialSuccess(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportPartialSuccess) MoveTo(dest ExportPartialSuccess) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportProfilesPartialSuccess(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // RejectedProfiles returns the rejectedprofiles associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) RejectedProfiles() int64 { return ms.orig.RejectedProfiles } // SetRejectedProfiles replaces the rejectedprofiles associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetRejectedProfiles(v int64) { ms.state.AssertMutable() ms.orig.RejectedProfiles = v } // ErrorMessage returns the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) ErrorMessage() string { return ms.orig.ErrorMessage } // SetErrorMessage replaces the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetErrorMessage(v string) { ms.state.AssertMutable() ms.orig.ErrorMessage = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportPartialSuccess) CopyTo(dest ExportPartialSuccess) { dest.state.AssertMutable() internal.CopyExportProfilesPartialSuccess(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/generated_exportpartialsuccess_test.go000066400000000000000000000046441511331344600340710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofileotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportPartialSuccess_MoveTo(t *testing.T) { ms := generateTestExportPartialSuccess() dest := NewExportPartialSuccess() ms.MoveTo(dest) assert.Equal(t, NewExportPartialSuccess(), ms) assert.Equal(t, generateTestExportPartialSuccess(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportPartialSuccess(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportPartialSuccess(internal.NewExportProfilesPartialSuccess(), sharedState)) }) assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportProfilesPartialSuccess(), sharedState).MoveTo(dest) }) } func TestExportPartialSuccess_CopyTo(t *testing.T) { ms := NewExportPartialSuccess() orig := NewExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportPartialSuccess(internal.NewExportProfilesPartialSuccess(), sharedState)) }) } func TestExportPartialSuccess_RejectedProfiles(t *testing.T) { ms := NewExportPartialSuccess() assert.Equal(t, int64(0), ms.RejectedProfiles()) ms.SetRejectedProfiles(int64(13)) assert.Equal(t, int64(13), ms.RejectedProfiles()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportProfilesPartialSuccess(), sharedState).SetRejectedProfiles(int64(13)) }) } func TestExportPartialSuccess_ErrorMessage(t *testing.T) { ms := NewExportPartialSuccess() assert.Empty(t, ms.ErrorMessage()) ms.SetErrorMessage("test_errormessage") assert.Equal(t, "test_errormessage", ms.ErrorMessage()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportProfilesPartialSuccess(), sharedState).SetErrorMessage("test_errormessage") }) } func generateTestExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.GenTestExportProfilesPartialSuccess(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/generated_exportresponse.go000066400000000000000000000041321511331344600316330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofileotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportResponse represents the response for gRPC/HTTP client/server. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportResponse function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportResponse struct { orig *internal.ExportProfilesServiceResponse state *internal.State } func newExportResponse(orig *internal.ExportProfilesServiceResponse, state *internal.State) ExportResponse { return ExportResponse{orig: orig, state: state} } // NewExportResponse creates a new empty ExportResponse. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportResponse() ExportResponse { return newExportResponse(internal.NewExportProfilesServiceResponse(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportResponse) MoveTo(dest ExportResponse) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportProfilesServiceResponse(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // PartialSuccess returns the partialsuccess associated with this ExportResponse. func (ms ExportResponse) PartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(&ms.orig.PartialSuccess, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportResponse) CopyTo(dest ExportResponse) { dest.state.AssertMutable() internal.CopyExportProfilesServiceResponse(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/generated_exportresponse_test.go000066400000000000000000000033721511331344600326770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package pprofileotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportResponse_MoveTo(t *testing.T) { ms := generateTestExportResponse() dest := NewExportResponse() ms.MoveTo(dest) assert.Equal(t, NewExportResponse(), ms) assert.Equal(t, generateTestExportResponse(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportResponse(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportResponse(internal.NewExportProfilesServiceResponse(), sharedState)) }) assert.Panics(t, func() { newExportResponse(internal.NewExportProfilesServiceResponse(), sharedState).MoveTo(dest) }) } func TestExportResponse_CopyTo(t *testing.T) { ms := NewExportResponse() orig := NewExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportResponse(internal.NewExportProfilesServiceResponse(), sharedState)) }) } func TestExportResponse_PartialSuccess(t *testing.T) { ms := NewExportResponse() assert.Equal(t, NewExportPartialSuccess(), ms.PartialSuccess()) ms.orig.PartialSuccess = *internal.GenTestExportProfilesPartialSuccess() assert.Equal(t, generateTestExportPartialSuccess(), ms.PartialSuccess()) } func generateTestExportResponse() ExportResponse { return newExportResponse(internal.GenTestExportProfilesServiceResponse(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/grpc.go000066400000000000000000000061121511331344600254500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp // import "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otelgrpc" "go.opentelemetry.io/collector/pdata/internal/otlp" ) // GRPCClient is the client API for OTLP-GRPC Profiles service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type GRPCClient interface { // Export pprofile.Profiles to the server. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) // unexported disallow implementation of the GRPCClient. unexported() } // NewGRPCClient returns a new GRPCClient connected using the given connection. func NewGRPCClient(cc *grpc.ClientConn) GRPCClient { return &grpcClient{rawClient: otelgrpc.NewProfilesServiceClient(cc)} } type grpcClient struct { rawClient otelgrpc.ProfilesServiceClient } // Export implements the Client interface. func (c *grpcClient) Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) { rsp, err := c.rawClient.Export(ctx, request.orig, opts...) if err != nil { return ExportResponse{}, err } return ExportResponse{orig: rsp, state: internal.NewState()}, err } func (c *grpcClient) unexported() {} // GRPCServer is the server API for OTLP gRPC ProfilesService service. // Implementations MUST embed UnimplementedGRPCServer. type GRPCServer interface { // Export is called every time a new request is received. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(context.Context, ExportRequest) (ExportResponse, error) // unexported disallow implementation of the GRPCServer. unexported() } var _ GRPCServer = (*UnimplementedGRPCServer)(nil) // UnimplementedGRPCServer MUST be embedded to have forward compatible implementations. type UnimplementedGRPCServer struct{} func (*UnimplementedGRPCServer) Export(context.Context, ExportRequest) (ExportResponse, error) { return ExportResponse{}, status.Errorf(codes.Unimplemented, "method Export not implemented") } func (*UnimplementedGRPCServer) unexported() {} // RegisterGRPCServer registers the GRPCServer to the grpc.Server. func RegisterGRPCServer(s *grpc.Server, srv GRPCServer) { otelgrpc.RegisterProfilesServiceServer(s, &rawProfilesServer{srv: srv}) } type rawProfilesServer struct { srv GRPCServer } func (s rawProfilesServer) Export(ctx context.Context, request *internal.ExportProfilesServiceRequest) (*internal.ExportProfilesServiceResponse, error) { otlp.MigrateProfiles(request.ResourceProfiles) rsp, err := s.srv.Export(ctx, ExportRequest{orig: request, state: internal.NewState()}) return rsp.orig, err } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/grpc_test.go000066400000000000000000000052451511331344600265150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp import ( "context" "errors" "net" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" "go.opentelemetry.io/collector/pdata/pprofile" ) func TestGrpc(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeProfilesServer{t: t}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) resolver.SetDefaultScheme("passthrough") cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateProfilesRequest()) require.NoError(t, err) assert.Equal(t, NewExportResponse(), resp) } func TestGrpcError(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeProfilesServer{t: t, err: errors.New("my error")}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateProfilesRequest()) require.Error(t, err) st, okSt := status.FromError(err) require.True(t, okSt) assert.Equal(t, "my error", st.Message()) assert.Equal(t, codes.Unknown, st.Code()) assert.Equal(t, ExportResponse{}, resp) } type fakeProfilesServer struct { UnimplementedGRPCServer t *testing.T err error } func (f fakeProfilesServer) Export(_ context.Context, request ExportRequest) (ExportResponse, error) { assert.Equal(f.t, generateProfilesRequest(), request) return NewExportResponse(), f.err } func generateProfilesRequest() ExportRequest { td := pprofile.NewProfiles() td.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() return NewExportRequestFromProfiles(td) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/package_test.go000066400000000000000000000003151511331344600271460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/request.go000066400000000000000000000046041511331344600262110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp // import "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/pprofile" ) // ExportRequest represents the request for gRPC/HTTP client/server. // It's a wrapper for pprofile.Profiles data. type ExportRequest struct { orig *internal.ExportProfilesServiceRequest state *internal.State } // NewExportRequest returns an empty ExportRequest. func NewExportRequest() ExportRequest { return ExportRequest{ orig: &internal.ExportProfilesServiceRequest{}, state: internal.NewState(), } } // NewExportRequestFromProfiles returns a ExportRequest from pprofile.Profiles. // Because ExportRequest is a wrapper for pprofile.Profiles, // any changes to the provided Profiles struct will be reflected in the ExportRequest and vice versa. func NewExportRequestFromProfiles(td pprofile.Profiles) ExportRequest { return ExportRequest{ orig: internal.GetProfilesOrig(internal.ProfilesWrapper(td)), state: internal.GetProfilesState(internal.ProfilesWrapper(td)), } } // MarshalProto marshals ExportRequest into proto bytes. func (ms ExportRequest) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportRequest from proto bytes. func (ms ExportRequest) UnmarshalProto(data []byte) error { err := ms.orig.UnmarshalProto(data) if err != nil { return err } otlp.MigrateProfiles(ms.orig.ResourceProfiles) return nil } // MarshalJSON marshals ExportRequest into JSON bytes. func (ms ExportRequest) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } // UnmarshalJSON unmarshalls ExportRequest from JSON bytes. func (ms ExportRequest) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } func (ms ExportRequest) Profiles() pprofile.Profiles { return pprofile.Profiles(internal.NewProfilesWrapper(ms.orig, ms.state)) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/request_test.go000066400000000000000000000056651511331344600272600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp import ( "encoding/json" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectorprofiles "go.opentelemetry.io/proto/slim/otlp/collector/profiles/v1development" goproto "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/pprofile" ) var ( _ json.Unmarshaler = ExportRequest{} _ json.Marshaler = ExportRequest{} ) var profilesRequestJSON = []byte(` { "resourceProfiles": [ { "resource": {}, "scopeProfiles": [ { "scope": {}, "profiles": [ { "sampleType": {}, "samples": [ { "stackIndex": 42 } ], "periodType": {} } ] } ] } ], "dictionary": {} }`) func TestRequestToPData(t *testing.T) { tr := NewExportRequest() assert.Equal(t, 0, tr.Profiles().SampleCount()) tr.Profiles().ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty().Samples().AppendEmpty() assert.Equal(t, 1, tr.Profiles().SampleCount()) } func TestRequestJSON(t *testing.T) { tr := NewExportRequest() require.NoError(t, tr.UnmarshalJSON(profilesRequestJSON)) assert.Equal(t, int32(42), tr.Profiles().ResourceProfiles().At(0).ScopeProfiles().At(0).Profiles().At(0).Samples().At(0).StackIndex()) got, err := tr.MarshalJSON() require.NoError(t, err) assert.Equal(t, strings.Join(strings.Fields(string(profilesRequestJSON)), ""), string(got)) } func TestProfilesProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Profiles as pdata struct. pd := NewExportRequestFromProfiles(pprofile.Profiles(internal.GenTestProfilesWrapper())) // Marshal its underlying ProtoBuf to wire. wire1, err := pd.MarshalProto() require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlpcollectorprofiles.ExportProfilesServiceRequest err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. pd2 := NewExportRequest() err = pd2.UnmarshalProto(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. // Migration logic will run, so run it on the original message as well. otlp.MigrateProfiles(pd.orig.ResourceProfiles) assert.Equal(t, pd, pd2) } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/response.go000066400000000000000000000021531511331344600263540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp // import "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" ) // MarshalProto marshals ExportResponse into proto bytes. func (ms ExportResponse) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportResponse from proto bytes. func (ms ExportResponse) UnmarshalProto(data []byte) error { return ms.orig.UnmarshalProto(data) } // MarshalJSON marshals ExportResponse into JSON bytes. func (ms ExportResponse) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) return slices.Clone(dest.Buffer()), dest.Error() } // UnmarshalJSON unmarshalls ExportResponse from JSON bytes. func (ms ExportResponse) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } opentelemetry-collector-0.141.0/pdata/pprofile/pprofileotlp/response_test.go000066400000000000000000000020221511331344600274060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofileotlp import ( stdjson "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( _ stdjson.Unmarshaler = ExportResponse{} _ stdjson.Marshaler = ExportResponse{} ) func TestExportResponseJSON(t *testing.T) { jsonStr := `{"partialSuccess": {"rejectedProfiles":"1", "errorMessage":"nothing"}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) expected := NewExportResponse() expected.PartialSuccess().SetRejectedProfiles(1) expected.PartialSuccess().SetErrorMessage("nothing") assert.Equal(t, expected, val) buf, err := val.MarshalJSON() require.NoError(t, err) assert.JSONEq(t, jsonStr, string(buf)) } func TestUnmarshalJSONExportResponse(t *testing.T) { jsonStr := `{"extra":"", "partialSuccess": {"extra":""}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) assert.Equal(t, NewExportResponse(), val) } opentelemetry-collector-0.141.0/pdata/pprofile/profile.go000066400000000000000000000033511511331344600234400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "fmt" "go.opentelemetry.io/collector/pdata/pcommon" ) // switchDictionary updates the Profile, switching its indices from one // dictionary to another. func (ms Profile) switchDictionary(src, dst ProfilesDictionary) error { for i, v := range ms.AttributeIndices().All() { if src.AttributeTable().Len() < int(v) { return fmt.Errorf("invalid attribute index %d", v) } attr := src.AttributeTable().At(int(v)) err := attr.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch dictionary for attribute %d: %w", i, err) } idx, err := SetAttribute(dst.AttributeTable(), attr) if err != nil { return fmt.Errorf("couldn't set attribute %d: %w", i, err) } ms.AttributeIndices().SetAt(i, idx) } for i, v := range ms.Samples().All() { err := v.switchDictionary(src, dst) if err != nil { return fmt.Errorf("error switching dictionary for sample %d: %w", i, err) } } err := ms.PeriodType().switchDictionary(src, dst) if err != nil { return fmt.Errorf("error switching dictionary for period type: %w", err) } err = ms.SampleType().switchDictionary(src, dst) if err != nil { return fmt.Errorf("error switching dictionary for sample type: %w", err) } return nil } // Duration returns the duration associated with this Profile. // // Deprecated: Use Profile.DurationNano instead. func (ms Profile) Duration() pcommon.Timestamp { return pcommon.Timestamp(0) } // SetDuration replaces the duration associated with this Profile. // // Deprecated: Use Profile.SetDurationNano instead. func (ms Profile) SetDuration(_ pcommon.Timestamp) { } opentelemetry-collector-0.141.0/pdata/pprofile/profile_test.go000066400000000000000000000130141511331344600244740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestProfileSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string profile Profile src ProfilesDictionary dst ProfilesDictionary wantProfile Profile wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty profile", profile: NewProfile(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantProfile: NewProfile(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing attribute", profile: func() Profile { p := NewProfile() p.AttributeIndices().Append(1) return p }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() return d }(), wantProfile: func() Profile { p := NewProfile() p.AttributeIndices().Append(2) return p }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(2) return d }(), }, { name: "with an attribute index that does not match anything", profile: func() Profile { p := NewProfile() p.AttributeIndices().Append(1) return p }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantProfile: func() Profile { p := NewProfile() p.AttributeIndices().Append(1) return p }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid attribute index 1"), }, { name: "with a profile that has a sample", profile: func() Profile { p := NewProfile() p.Samples().AppendEmpty().SetLinkIndex(1) return p }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() return d }(), wantProfile: func() Profile { p := NewProfile() p.Samples().AppendEmpty().SetLinkIndex(2) return p }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), }, { name: "with a profile that has a period type", profile: func() Profile { p := NewProfile() p.PeriodType().SetTypeStrindex(1) return p }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantProfile: func() Profile { p := NewProfile() p.PeriodType().SetTypeStrindex(2) return p }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a profile that has a sample type", profile: func() Profile { p := NewProfile() p.SampleType().SetTypeStrindex(1) return p }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantProfile: func() Profile { p := NewProfile() p.SampleType().SetTypeStrindex(2) return p }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, } { t.Run(tt.name, func(t *testing.T) { profile := tt.profile dst := tt.dst err := profile.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantProfile, profile) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkProfileSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) p := NewProfile() p.AttributeIndices().Append(1, 2) src := NewProfilesDictionary() src.StringTable().Append("", "test", "foo") src.AttributeTable().AppendEmpty() src.AttributeTable().AppendEmpty().SetKeyStrindex(1) src.AttributeTable().AppendEmpty().SetKeyStrindex(2) b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() dst.StringTable().Append("", "foo") dst.AttributeTable().AppendEmpty() dst.AttributeTable().AppendEmpty().SetKeyStrindex(1) b.StartTimer() _ = p.switchDictionary(src, dst) } } func TestProfile_Duration(_ *testing.T) { ms := NewProfile() ms.SetDuration(0) ts := ms.Duration() _ = ts } opentelemetry-collector-0.141.0/pdata/pprofile/profileid.go000066400000000000000000000017541511331344600237620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "encoding/hex" "go.opentelemetry.io/collector/pdata/internal" ) var emptyProfileID = ProfileID([16]byte{}) // ProfileID is a profile identifier. type ProfileID [16]byte // NewProfileIDEmpty returns a new empty (all zero bytes) ProfileID. func NewProfileIDEmpty() ProfileID { return emptyProfileID } // String returns string representation of the ProfileID. // // Important: Don't rely on this method to get a string identifier of ProfileID. // Use hex.EncodeToString explicitly instead. // This method is meant to implement Stringer interface for display purposes only. func (ms ProfileID) String() string { if ms.IsEmpty() { return "" } return hex.EncodeToString(ms[:]) } // IsEmpty returns true if id doesn't contain at least one non-zero byte. func (ms ProfileID) IsEmpty() bool { return internal.ProfileID(ms).IsEmpty() } opentelemetry-collector-0.141.0/pdata/pprofile/profileid_test.go000066400000000000000000000023171511331344600250150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" ) func TestProfileID(t *testing.T) { pid := ProfileID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) assert.Equal(t, [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}, [16]byte(pid)) assert.False(t, pid.IsEmpty()) } func TestNewProfileIDEmpty(t *testing.T) { pid := NewProfileIDEmpty() assert.Equal(t, [16]byte{}, [16]byte(pid)) assert.True(t, pid.IsEmpty()) } func TestProfileIDString(t *testing.T) { pid := ProfileID([16]byte{}) assert.Empty(t, pid.String()) pid = [16]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} assert.Equal(t, "12345678123456781234567812345678", pid.String()) } func TestProfileIDImmutable(t *testing.T) { initialBytes := [16]byte{0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78} pid := ProfileID(initialBytes) assert.Equal(t, ProfileID(initialBytes), pid) // Get the bytes and try to mutate. pid[4] = 0x23 // Does not change the already created ProfileID. assert.NotEqual(t, ProfileID(initialBytes), pid) } opentelemetry-collector-0.141.0/pdata/pprofile/profiles.go000066400000000000000000000024041511331344600236210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // MarkReadOnly marks the ResourceProfiles as shared so that no further modifications can be done on it. func (ms Profiles) MarkReadOnly() { ms.getState().MarkReadOnly() } // IsReadOnly returns true if this ResourceProfiles instance is read-only. func (ms Profiles) IsReadOnly() bool { return ms.getState().IsReadOnly() } // SampleCount calculates the total number of samples. func (ms Profiles) SampleCount() int { sampleCount := 0 rps := ms.ResourceProfiles() for i := 0; i < rps.Len(); i++ { rp := rps.At(i) sps := rp.ScopeProfiles() for j := 0; j < sps.Len(); j++ { pcs := sps.At(j).Profiles() for k := 0; k < pcs.Len(); k++ { sampleCount += pcs.At(k).Samples().Len() } } } return sampleCount } // switchDictionary updates the Profiles, switching its indices from one // dictionary to another. func (ms Profiles) switchDictionary(src, dst ProfilesDictionary) error { for i, v := range ms.ResourceProfiles().All() { err := v.switchDictionary(src, dst) if err != nil { return fmt.Errorf("error switching dictionary for resource profile %d: %w", i, err) } } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/profiles_merge.go000066400000000000000000000013341511331344600250010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" // MergeTo merges the current Profiles into dest, updating the destination // dictionary as needed and appending the resource profiles. // The source Profiles is consumed and marked read-only after this operation. func (ms Profiles) MergeTo(dest Profiles) error { ms.getState().AssertMutable() dest.getState().AssertMutable() if ms.getOrig() == dest.getOrig() { return nil } if err := ms.switchDictionary(ms.Dictionary(), dest.Dictionary()); err != nil { return err } ms.ResourceProfiles().MoveAndAppendTo(dest.ResourceProfiles()) ms.MarkReadOnly() return nil } opentelemetry-collector-0.141.0/pdata/pprofile/profiles_merge_test.go000066400000000000000000000030151511331344600260360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestProfilesMergeTo(t *testing.T) { src := NewProfiles() dest := NewProfiles() src.ResourceProfiles().AppendEmpty() src.ResourceProfiles().AppendEmpty() dest.ResourceProfiles().AppendEmpty() require.NoError(t, src.MergeTo(dest)) assert.Equal(t, 3, dest.ResourceProfiles().Len()) assert.Equal(t, 0, src.ResourceProfiles().Len()) assert.True(t, src.IsReadOnly()) } func TestProfilesMergeToSelf(t *testing.T) { profiles := NewProfiles() profiles.Dictionary().StringTable().Append("", "test") profiles.ResourceProfiles().AppendEmpty() require.NoError(t, profiles.MergeTo(profiles)) assert.Equal(t, 2, profiles.Dictionary().StringTable().Len()) assert.Equal(t, 1, profiles.ResourceProfiles().Len()) } func TestProfilesMergeToError(t *testing.T) { src := NewProfiles() dest := NewProfiles() stackTable := src.Dictionary().StackTable() stackTable.AppendEmpty() stack := stackTable.AppendEmpty() stack.LocationIndices().Append(1) locationTable := src.Dictionary().LocationTable() locationTable.AppendEmpty() locationTable.AppendEmpty().SetMappingIndex(1) sample := src.ResourceProfiles().AppendEmpty(). ScopeProfiles().AppendEmpty(). Profiles().AppendEmpty(). Samples().AppendEmpty() sample.SetStackIndex(1) err := src.MergeTo(dest) require.Error(t, err) assert.Equal(t, 0, dest.ResourceProfiles().Len()) } opentelemetry-collector-0.141.0/pdata/pprofile/profiles_test.go000066400000000000000000000151121511331344600246600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestReadOnlyProfilesInvalidUsage(t *testing.T) { pd := NewProfiles() assert.False(t, pd.IsReadOnly()) res := pd.ResourceProfiles().AppendEmpty().Resource() res.Attributes().PutStr("k1", "v1") pd.MarkReadOnly() assert.True(t, pd.IsReadOnly()) assert.Panics(t, func() { res.Attributes().PutStr("k2", "v2") }) } func TestSampleCount(t *testing.T) { pd := NewProfiles() assert.Equal(t, 0, pd.SampleCount()) rs := pd.ResourceProfiles().AppendEmpty() assert.Equal(t, 0, pd.SampleCount()) ils := rs.ScopeProfiles().AppendEmpty() assert.Equal(t, 0, pd.SampleCount()) ps := ils.Profiles().AppendEmpty() assert.Equal(t, 0, pd.SampleCount()) ps.Samples().AppendEmpty() assert.Equal(t, 1, pd.SampleCount()) ils2 := rs.ScopeProfiles().AppendEmpty() assert.Equal(t, 1, pd.SampleCount()) ps2 := ils2.Profiles().AppendEmpty() assert.Equal(t, 1, pd.SampleCount()) ps2.Samples().AppendEmpty() assert.Equal(t, 2, pd.SampleCount()) rms := pd.ResourceProfiles() rms.EnsureCapacity(3) rms.AppendEmpty().ScopeProfiles().AppendEmpty() ilss := rms.AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty().Samples() for range 5 { ilss.AppendEmpty() } // 5 + 2 (from rms.At(0) and rms.At(1) initialized first) assert.Equal(t, 7, pd.SampleCount()) } func TestSampleCountWithEmpty(t *testing.T) { assert.Equal(t, 0, newProfiles(&internal.ExportProfilesServiceRequest{ ResourceProfiles: []*internal.ResourceProfiles{{}}, }, new(internal.State)).SampleCount()) assert.Equal(t, 0, newProfiles(&internal.ExportProfilesServiceRequest{ ResourceProfiles: []*internal.ResourceProfiles{ { ScopeProfiles: []*internal.ScopeProfiles{{}}, }, }, }, new(internal.State)).SampleCount()) assert.Equal(t, 1, newProfiles(&internal.ExportProfilesServiceRequest{ ResourceProfiles: []*internal.ResourceProfiles{ { ScopeProfiles: []*internal.ScopeProfiles{ { Profiles: []*internal.Profile{ { Samples: []*internal.Sample{ {}, }, }, }, }, }, }, }, }, new(internal.State)).SampleCount()) } func TestProfilesSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string profiles Profiles src ProfilesDictionary dst ProfilesDictionary wantProfiles Profiles wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty profiles", profiles: NewProfiles(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantProfiles: NewProfiles(), wantDictionary: NewProfilesDictionary(), }, { name: "with a profiles that has a profile", profiles: func() Profiles { p := NewProfiles() profile := p.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(1) return p }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() return d }(), wantProfiles: func() Profiles { p := NewProfiles() profile := p.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(2) return p }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), }, } { t.Run(tt.name, func(t *testing.T) { p := tt.profiles dst := tt.dst err := p.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantProfiles, p) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkProfilesSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) p := NewProfiles() profile := p.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(1) src := NewProfilesDictionary() src.LinkTable().AppendEmpty() src.LinkTable().AppendEmpty().SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() b.StartTimer() _ = p.switchDictionary(src, dst) } } func BenchmarkProfilesUsage(b *testing.B) { pd := generateTestProfiles() ts := pcommon.NewTimestampFromTime(time.Now()) dur := uint64(1_000_000_000) testValProfileID := ProfileID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) testSecondValProfileID := ProfileID([16]byte{2, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}) b.ReportAllocs() for b.Loop() { for i := 0; i < pd.ResourceProfiles().Len(); i++ { rs := pd.ResourceProfiles().At(i) res := rs.Resource() res.Attributes().PutStr("foo", "bar") v, ok := res.Attributes().Get("foo") assert.True(b, ok) assert.Equal(b, "bar", v.Str()) v.SetStr("new-bar") assert.Equal(b, "new-bar", v.Str()) res.Attributes().Remove("foo") for j := 0; j < rs.ScopeProfiles().Len(); j++ { iss := rs.ScopeProfiles().At(j) iss.Scope().SetName("new_test_name") assert.Equal(b, "new_test_name", iss.Scope().Name()) for k := 0; k < iss.Profiles().Len(); k++ { s := iss.Profiles().At(k) s.SetProfileID(testValProfileID) assert.Equal(b, testValProfileID, s.ProfileID()) s.SetTime(ts) assert.Equal(b, ts, s.Time()) s.SetDurationNano(dur) assert.Equal(b, dur, s.DurationNano()) } s := iss.Profiles().AppendEmpty() s.SetProfileID(testSecondValProfileID) s.SetTime(ts) s.SetDurationNano(dur) s.AttributeIndices().Append(1) iss.Profiles().RemoveIf(func(lr Profile) bool { return lr.ProfileID() == testSecondValProfileID }) } } } } func BenchmarkProfilesMarshalJSON(b *testing.B) { pd := generateTestProfiles() encoder := &JSONMarshaler{} b.ReportAllocs() for b.Loop() { jsonBuf, err := encoder.MarshalProfiles(pd) require.NoError(b, err) require.NotNil(b, jsonBuf) } } opentelemetry-collector-0.141.0/pdata/pprofile/resourceprofiles.go000066400000000000000000000010641511331344600253720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // switchDictionary updates the ResourceProfiles, switching its indices from one // dictionary to another. func (ms ResourceProfiles) switchDictionary(src, dst ProfilesDictionary) error { for i, v := range ms.ScopeProfiles().All() { err := v.switchDictionary(src, dst) if err != nil { return fmt.Errorf("error switching dictionary for scope profile %d: %w", i, err) } } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/resourceprofiles_test.go000066400000000000000000000055641511331344600264420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestResourceProfilesSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string resourceProfiles ResourceProfiles src ProfilesDictionary dst ProfilesDictionary wantResourceProfiles ResourceProfiles wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty resource profile", resourceProfiles: NewResourceProfiles(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantResourceProfiles: NewResourceProfiles(), wantDictionary: NewProfilesDictionary(), }, { name: "with a resource profiles that has a profile", resourceProfiles: func() ResourceProfiles { r := NewResourceProfiles() profile := r.ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(1) return r }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() return d }(), wantResourceProfiles: func() ResourceProfiles { r := NewResourceProfiles() profile := r.ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(2) return r }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), }, } { t.Run(tt.name, func(t *testing.T) { rp := tt.resourceProfiles dst := tt.dst err := rp.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantResourceProfiles, rp) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkResourceProfilesSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) r := NewResourceProfiles() profile := r.ScopeProfiles().AppendEmpty().Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(1) src := NewProfilesDictionary() src.LinkTable().AppendEmpty() src.LinkTable().AppendEmpty().SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() b.StartTimer() _ = r.switchDictionary(src, dst) } } opentelemetry-collector-0.141.0/pdata/pprofile/sample.go000066400000000000000000000032101511331344600232530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // switchDictionary updates the Sample, switching its indices from one // dictionary to another. func (ms Sample) switchDictionary(src, dst ProfilesDictionary) error { for i, v := range ms.AttributeIndices().All() { if src.AttributeTable().Len() < int(v) { return fmt.Errorf("invalid attribute index %d", v) } attr := src.AttributeTable().At(int(v)) err := attr.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch dictionary for attribute %d: %w", i, err) } idx, err := SetAttribute(dst.AttributeTable(), attr) if err != nil { return fmt.Errorf("couldn't set attribute %d: %w", i, err) } ms.AttributeIndices().SetAt(i, idx) } if ms.LinkIndex() > 0 { if src.LinkTable().Len() < int(ms.LinkIndex()) { return fmt.Errorf("invalid link index %d", ms.LinkIndex()) } idx, err := SetLink(dst.LinkTable(), src.LinkTable().At(int(ms.LinkIndex()))) if err != nil { return fmt.Errorf("couldn't set link: %w", err) } ms.SetLinkIndex(idx) } if ms.StackIndex() > 0 { if src.StackTable().Len() < int(ms.StackIndex()) { return fmt.Errorf("invalid stack index %d", ms.StackIndex()) } stack := src.StackTable().At(int(ms.StackIndex())) err := stack.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch stack dictionary: %w", err) } idx, err := SetStack(dst.StackTable(), stack) if err != nil { return fmt.Errorf("couldn't set stack: %w", err) } ms.SetStackIndex(idx) } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/sample_test.go000066400000000000000000000134751511331344600243300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSampleSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string sample Sample src ProfilesDictionary dst ProfilesDictionary wantSample Sample wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty sample", sample: NewSample(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantSample: NewSample(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing attribute", sample: func() Sample { s := NewSample() s.AttributeIndices().Append(1) return s }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() return d }(), wantSample: func() Sample { s := NewSample() s.AttributeIndices().Append(2) return s }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") d.AttributeTable().AppendEmpty() d.AttributeTable().AppendEmpty() a := d.AttributeTable().AppendEmpty() a.SetKeyStrindex(2) return d }(), }, { name: "with an attribute index that does not match anything", sample: func() Sample { s := NewSample() s.AttributeIndices().Append(1) return s }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantSample: func() Sample { s := NewSample() s.AttributeIndices().Append(1) return s }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid attribute index 1"), }, { name: "with an existing link", sample: func() Sample { s := NewSample() s.SetLinkIndex(1) return s }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() return d }(), wantSample: func() Sample { s := NewSample() s.SetLinkIndex(2) return s }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), }, { name: "with a link index that does not match anything", sample: func() Sample { s := NewSample() s.SetLinkIndex(1) return s }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantSample: func() Sample { s := NewSample() s.SetLinkIndex(1) return s }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid link index 1"), }, { name: "with an existing stack", sample: func() Sample { s := NewSample() s.SetStackIndex(1) return s }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.LocationTable().AppendEmpty().SetAddress(1) d.LocationTable().AppendEmpty().SetAddress(2) d.StackTable().AppendEmpty() s := d.StackTable().AppendEmpty() s.LocationIndices().Append(1) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StackTable().AppendEmpty() d.StackTable().AppendEmpty() return d }(), wantSample: func() Sample { s := NewSample() s.SetStackIndex(2) return s }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.LocationTable().AppendEmpty().SetAddress(2) d.StackTable().AppendEmpty() d.StackTable().AppendEmpty() s := d.StackTable().AppendEmpty() s.LocationIndices().Append(0) return d }(), }, { name: "with a stack index that does not match anything", sample: func() Sample { s := NewSample() s.SetStackIndex(1) return s }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantSample: func() Sample { s := NewSample() s.SetStackIndex(1) return s }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid stack index 1"), }, } { t.Run(tt.name, func(t *testing.T) { sample := tt.sample dst := tt.dst err := sample.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantSample, sample) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkSampleSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) s := NewSample() s.SetLinkIndex(1) s.SetStackIndex(1) src := NewProfilesDictionary() src.LocationTable().AppendEmpty() src.LocationTable().AppendEmpty().SetAddress(2) src.LinkTable().AppendEmpty() src.LinkTable().AppendEmpty().SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) src.StackTable().AppendEmpty() src.StackTable().AppendEmpty().LocationIndices().Append(1) dst := NewProfilesDictionary() src.LinkTable().AppendEmpty() src.LinkTable().AppendEmpty().SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) b.ReportAllocs() for b.Loop() { _ = s.switchDictionary(src, dst) } } opentelemetry-collector-0.141.0/pdata/pprofile/scopeprofiles.go000066400000000000000000000010431511331344600246510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // switchDictionary updates the ScopeProfiles, switching its indices from one // dictionary to another. func (ms ScopeProfiles) switchDictionary(src, dst ProfilesDictionary) error { for i, v := range ms.Profiles().All() { err := v.switchDictionary(src, dst) if err != nil { return fmt.Errorf("error switching dictionary for profile %d: %w", i, err) } } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/scopeprofiles_test.go000066400000000000000000000052521511331344600257160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestScopeProfilesSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string scopeProfiles ScopeProfiles src ProfilesDictionary dst ProfilesDictionary wantScopeProfiles ScopeProfiles wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty scope profile", scopeProfiles: NewScopeProfiles(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantScopeProfiles: NewScopeProfiles(), wantDictionary: NewProfilesDictionary(), }, { name: "with a scope profiles that has a profile", scopeProfiles: func() ScopeProfiles { s := NewScopeProfiles() profile := s.Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(1) return s }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() return d }(), wantScopeProfiles: func() ScopeProfiles { s := NewScopeProfiles() profile := s.Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(2) return s }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.LinkTable().AppendEmpty() d.LinkTable().AppendEmpty() l := d.LinkTable().AppendEmpty() l.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) return d }(), }, } { t.Run(tt.name, func(t *testing.T) { sp := tt.scopeProfiles dst := tt.dst err := sp.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantScopeProfiles, sp) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkScopeProfilesSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) s := NewScopeProfiles() profile := s.Profiles().AppendEmpty() profile.Samples().AppendEmpty().SetLinkIndex(1) src := NewProfilesDictionary() src.LinkTable().AppendEmpty() src.LinkTable().AppendEmpty().SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) dst := NewProfilesDictionary() b.ReportAllocs() for b.Loop() { _ = s.switchDictionary(src, dst) } } opentelemetry-collector-0.141.0/pdata/pprofile/stack.go000066400000000000000000000022211511331344600231000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "fmt" ) // Equal checks equality with another Stack func (ms Stack) Equal(val Stack) bool { if ms.LocationIndices().Len() != val.LocationIndices().Len() { return false } for i := range ms.LocationIndices().Len() { if ms.LocationIndices().At(i) != val.LocationIndices().At(i) { return false } } return true } // switchDictionary updates the Stack, switching its indices from one // dictionary to another. func (ms Stack) switchDictionary(src, dst ProfilesDictionary) error { for i, v := range ms.LocationIndices().All() { if src.LocationTable().Len() < int(v) { return fmt.Errorf("invalid location index %d", v) } loc := src.LocationTable().At(int(v)) err := loc.switchDictionary(src, dst) if err != nil { return fmt.Errorf("couldn't switch dictionary for location: %w", err) } idx, err := SetLocation(dst.LocationTable(), loc) if err != nil { return fmt.Errorf("couldn't set location %d: %w", i, err) } ms.LocationIndices().SetAt(i, idx) } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/stack_test.go000066400000000000000000000107231511331344600241450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestStackEqual(t *testing.T) { for _, tt := range []struct { name string orig Stack dest Stack want bool }{ { name: "with empty stacks", orig: NewStack(), dest: NewStack(), want: true, }, { name: "with non-empty equal stacks", orig: func() Stack { s := NewStack() s.LocationIndices().Append(1) return s }(), dest: func() Stack { s := NewStack() s.LocationIndices().Append(1) return s }(), want: true, }, { name: "with different location indices lengths", orig: func() Stack { s := NewStack() s.LocationIndices().Append(1) return s }(), dest: NewStack(), want: false, }, { name: "with non-equal location indices", orig: func() Stack { s := NewStack() s.LocationIndices().Append(2) return s }(), dest: func() Stack { s := NewStack() s.LocationIndices().Append(1) return s }(), want: false, }, } { t.Run(tt.name, func(t *testing.T) { if tt.want { assert.True(t, tt.orig.Equal(tt.dest)) } else { assert.False(t, tt.orig.Equal(tt.dest)) } }) } } func TestStackSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string stack Stack src ProfilesDictionary dst ProfilesDictionary wantStack Stack wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty stack", stack: NewStack(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantStack: NewStack(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing location", stack: func() Stack { s := NewStack() s.LocationIndices().Append(0) return s }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() loc := d.LocationTable().AppendEmpty() loc.SetAddress(42) return d }(), dst: NewProfilesDictionary(), wantStack: func() Stack { s := NewStack() s.LocationIndices().Append(0) return s }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() loc := d.LocationTable().AppendEmpty() loc.SetAddress(42) return d }(), }, { name: "with an existing location that needs a new indice", stack: func() Stack { s := NewStack() s.LocationIndices().Append(0) return s }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() loc := d.LocationTable().AppendEmpty() loc.SetAddress(42) return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() loc := d.LocationTable().AppendEmpty() loc.SetAddress(2) return d }(), wantStack: func() Stack { s := NewStack() s.LocationIndices().Append(1) return s }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() loc := d.LocationTable().AppendEmpty() loc.SetAddress(2) loc = d.LocationTable().AppendEmpty() loc.SetAddress(42) return d }(), }, { name: "with a location index that does not match anything", stack: func() Stack { s := NewStack() s.LocationIndices().Append(2) return s }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantStack: func() Stack { s := NewStack() s.LocationIndices().Append(2) return s }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid location index 2"), }, } { t.Run(tt.name, func(t *testing.T) { stack := tt.stack dst := tt.dst err := stack.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantStack, stack) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkStackSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) s := NewStack() s.LocationIndices().Append(1, 2) src := NewProfilesDictionary() src.LocationTable().AppendEmpty() src.LocationTable().AppendEmpty().SetAddress(42) src.LocationTable().AppendEmpty().SetAddress(43) b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() dst.LocationTable().AppendEmpty() dst.LocationTable().AppendEmpty().SetAddress(43) b.StartTimer() _ = s.switchDictionary(src, dst) } } opentelemetry-collector-0.141.0/pdata/pprofile/stacks.go000066400000000000000000000013151511331344600232660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "errors" "math" ) var errTooManyStackTableEntries = errors.New("too many entries in StackTable") // SetStack updates a StackSlice, adding or providing a stack and returns its // index. func SetStack(table StackSlice, st Stack) (int32, error) { for j, l := range table.All() { if l.Equal(st) { if j > math.MaxInt32 { return 0, errTooManyStackTableEntries } return int32(j), nil } } if table.Len() >= math.MaxInt32 { return 0, errTooManyStackTableEntries } st.CopyTo(table.AppendEmpty()) return int32(table.Len() - 1), nil } opentelemetry-collector-0.141.0/pdata/pprofile/stacks_test.go000066400000000000000000000046261511331344600243350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestSetStack(t *testing.T) { table := NewStackSlice() s := NewStack() s.LocationIndices().Append(1) s2 := NewStack() s.LocationIndices().Append(2) // Put a first stack idx, err := SetStack(table, s) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Put the same stack // This should be a no-op. idx, err = SetStack(table, s) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Set a new stack // This sets the index and adds to the table. idx, err = SetStack(table, s2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) // Set an existing stack idx, err = SetStack(table, s) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(0), idx) // Set another existing stack idx, err = SetStack(table, s2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) } func BenchmarkSetStack(b *testing.B) { testutil.SkipMemoryBench(b) for _, bb := range []struct { name string stack Stack runBefore func(*testing.B, StackSlice) }{ { name: "with a new stack", stack: NewStack(), }, { name: "with an existing stack", stack: func() Stack { s := NewStack() s.LocationIndices().Append(1) return s }(), runBefore: func(_ *testing.B, table StackSlice) { s := table.AppendEmpty() s.LocationIndices().Append(1) }, }, { name: "with a duplicate stack", stack: NewStack(), runBefore: func(_ *testing.B, table StackSlice) { _, err := SetStack(table, NewStack()) require.NoError(b, err) }, }, { name: "with a hundred stacks to loop through", stack: func() Stack { s := NewStack() s.LocationIndices().Append(1) return s }(), runBefore: func(_ *testing.B, table StackSlice) { for range 100 { table.AppendEmpty() } }, }, } { b.Run(bb.name, func(b *testing.B) { table := NewStackSlice() if bb.runBefore != nil { bb.runBefore(b, table) } b.ResetTimer() b.ReportAllocs() for b.Loop() { _, _ = SetStack(table, bb.stack) } }) } } opentelemetry-collector-0.141.0/pdata/pprofile/string_table.go000066400000000000000000000014531511331344600244560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import ( "errors" "math" "go.opentelemetry.io/collector/pdata/pcommon" ) var errTooManyStringTableEntries = errors.New("too many entries in StringTable") // SetString updates a StringTable, adding or providing a value and returns its index. func SetString(table pcommon.StringSlice, val string) (int32, error) { for j, v := range table.All() { if v == val { if j > math.MaxInt32 { return 0, errTooManyStringTableEntries } // Return the index of the existing value. return int32(j), nil } } if table.Len() >= math.MaxInt32 { return 0, errTooManyMappingTableEntries } table.Append(val) return int32(table.Len() - 1), nil } opentelemetry-collector-0.141.0/pdata/pprofile/string_table_test.go000066400000000000000000000042531511331344600255160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSetString(t *testing.T) { table := pcommon.NewStringSlice() v := "test" v2 := "test2" // Put a first value idx, err := SetString(table, v) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Put the same string // This should be a no-op. idx, err = SetString(table, v) require.NoError(t, err) assert.Equal(t, 1, table.Len()) assert.Equal(t, int32(0), idx) // Set a new value // This sets the index and adds to the table. idx, err = SetString(table, v2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) // Set an existing value idx, err = SetString(table, v) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(0), idx) // Set another existing value idx, err = SetString(table, v2) require.NoError(t, err) assert.Equal(t, 2, table.Len()) assert.Equal(t, int32(table.Len()-1), idx) } func BenchmarkSetString(b *testing.B) { for _, bb := range []struct { name string val string runBefore func(*testing.B, pcommon.StringSlice) }{ { name: "with a new value", val: "test", }, { name: "with an existing value", val: "test", runBefore: func(_ *testing.B, table pcommon.StringSlice) { table.Append("test") }, }, { name: "with a duplicate value", val: "test", runBefore: func(_ *testing.B, table pcommon.StringSlice) { _, err := SetString(table, "test") require.NoError(b, err) }, }, { name: "with a hundred values to loop through", val: "test", runBefore: func(_ *testing.B, table pcommon.StringSlice) { for i := range 100 { table.Append(strconv.Itoa(i)) } }, }, } { b.Run(bb.name, func(b *testing.B) { table := pcommon.NewStringSlice() if bb.runBefore != nil { bb.runBefore(b, table) } b.ResetTimer() b.ReportAllocs() for b.Loop() { _, _ = SetString(table, bb.val) } }) } } opentelemetry-collector-0.141.0/pdata/pprofile/valuetype.go000066400000000000000000000020301511331344600240070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile // import "go.opentelemetry.io/collector/pdata/pprofile" import "fmt" // switchDictionary updates the ValueType, switching its indices from one // dictionary to another. func (ms ValueType) switchDictionary(src, dst ProfilesDictionary) error { if ms.TypeStrindex() > 0 { if src.StringTable().Len() < int(ms.TypeStrindex()) { return fmt.Errorf("invalid type index %d", ms.TypeStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(ms.TypeStrindex()))) if err != nil { return fmt.Errorf("couldn't set type: %w", err) } ms.SetTypeStrindex(idx) } if ms.UnitStrindex() > 0 { if src.StringTable().Len() < int(ms.UnitStrindex()) { return fmt.Errorf("invalid unit index %d", ms.UnitStrindex()) } idx, err := SetString(dst.StringTable(), src.StringTable().At(int(ms.UnitStrindex()))) if err != nil { return fmt.Errorf("couldn't set unit: %w", err) } ms.SetUnitStrindex(idx) } return nil } opentelemetry-collector-0.141.0/pdata/pprofile/valuetype_test.go000066400000000000000000000072221511331344600250560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pprofile import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/internal/testutil" ) func TestValueTypeSwitchDictionary(t *testing.T) { for _, tt := range []struct { name string valueType ValueType src ProfilesDictionary dst ProfilesDictionary wantValueType ValueType wantDictionary ProfilesDictionary wantErr error }{ { name: "with an empty value type", valueType: NewValueType(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantValueType: NewValueType(), wantDictionary: NewProfilesDictionary(), }, { name: "with an existing type", valueType: func() ValueType { vt := NewValueType() vt.SetTypeStrindex(1) return vt }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantValueType: func() ValueType { vt := NewValueType() vt.SetTypeStrindex(2) return vt }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a type index that does not match anything", valueType: func() ValueType { vt := NewValueType() vt.SetTypeStrindex(1) return vt }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantValueType: func() ValueType { vt := NewValueType() vt.SetTypeStrindex(1) return vt }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid type index 1"), }, { name: "with an existing unit", valueType: func() ValueType { vt := NewValueType() vt.SetUnitStrindex(1) return vt }(), src: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "test") return d }(), dst: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo") return d }(), wantValueType: func() ValueType { vt := NewValueType() vt.SetUnitStrindex(2) return vt }(), wantDictionary: func() ProfilesDictionary { d := NewProfilesDictionary() d.StringTable().Append("", "foo", "test") return d }(), }, { name: "with a unit index that does not match anything", valueType: func() ValueType { vt := NewValueType() vt.SetUnitStrindex(1) return vt }(), src: NewProfilesDictionary(), dst: NewProfilesDictionary(), wantValueType: func() ValueType { vt := NewValueType() vt.SetUnitStrindex(1) return vt }(), wantDictionary: NewProfilesDictionary(), wantErr: errors.New("invalid unit index 1"), }, } { t.Run(tt.name, func(t *testing.T) { vt := tt.valueType dst := tt.dst err := vt.switchDictionary(tt.src, dst) if tt.wantErr == nil { require.NoError(t, err) } else { require.Equal(t, tt.wantErr, err) } assert.Equal(t, tt.wantValueType, vt) assert.Equal(t, tt.wantDictionary, dst) }) } } func BenchmarkValueTypeSwitchDictionary(b *testing.B) { testutil.SkipMemoryBench(b) vt := NewValueType() vt.SetTypeStrindex(1) vt.SetUnitStrindex(2) src := NewProfilesDictionary() src.StringTable().Append("", "test", "foo") b.ReportAllocs() for b.Loop() { b.StopTimer() dst := NewProfilesDictionary() dst.StringTable().Append("", "foo") b.StartTimer() _ = vt.switchDictionary(src, dst) } } opentelemetry-collector-0.141.0/pdata/ptrace/000077500000000000000000000000001511331344600211055ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/ptrace/doc_test.go000066400000000000000000000217241511331344600232460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace_test import ( "fmt" "strconv" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" ) func ExampleNewTraces() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() resourceSpans.Resource().Attributes().PutStr("service.name", "my-service") resourceSpans.Resource().Attributes().PutStr("service.version", "1.0.0") scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() scopeSpans.Scope().SetName("my-instrumentation-library") scopeSpans.Scope().SetVersion("1.0.0") span := scopeSpans.Spans().AppendEmpty() span.SetName("my-operation") span.SetKind(ptrace.SpanKindServer) span.SetStartTimestamp(pcommon.Timestamp(1640995200000000000)) // 2022-01-01 00:00:00 UTC span.SetEndTimestamp(pcommon.Timestamp(1640995200100000000)) // 2022-01-01 00:00:00.1 UTC span.Attributes().PutStr("http.method", "GET") span.Attributes().PutStr("http.url", "/api/v1/users") span.Attributes().PutInt("http.status_code", 200) fmt.Printf("Resource spans count: %d\n", traces.ResourceSpans().Len()) fmt.Printf("Spans count: %d\n", scopeSpans.Spans().Len()) fmt.Printf("Span name: %s\n", span.Name()) // Output: // Resource spans count: 1 // Spans count: 1 // Span name: my-operation } func ExampleSpan_SetTraceID() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() span := scopeSpans.Spans().AppendEmpty() traceID := pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) spanID := pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) parentSpanID := pcommon.SpanID([8]byte{9, 10, 11, 12, 13, 14, 15, 16}) span.SetTraceID(traceID) span.SetSpanID(spanID) span.SetParentSpanID(parentSpanID) span.SetName("child-operation") fmt.Printf("TraceID: %s\n", span.TraceID()) fmt.Printf("SpanID: %s\n", span.SpanID()) fmt.Printf("ParentSpanID: %s\n", span.ParentSpanID()) // Output: // TraceID: 0102030405060708090a0b0c0d0e0f10 // SpanID: 0102030405060708 // ParentSpanID: 090a0b0c0d0e0f10 } func ExampleSpan_Events() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() span := scopeSpans.Spans().AppendEmpty() span.SetName("database-query") event1 := span.Events().AppendEmpty() event1.SetName("query.start") event1.SetTimestamp(pcommon.Timestamp(1640995200000000000)) event1.Attributes().PutStr("query", "SELECT * FROM users") event2 := span.Events().AppendEmpty() event2.SetName("query.end") event2.SetTimestamp(pcommon.Timestamp(1640995200050000000)) event2.Attributes().PutInt("rows_returned", 42) fmt.Printf("Events count: %d\n", span.Events().Len()) fmt.Printf("First event name: %s\n", span.Events().At(0).Name()) fmt.Printf("Second event name: %s\n", span.Events().At(1).Name()) // Output: // Events count: 2 // First event name: query.start // Second event name: query.end } func ExampleSpan_Status() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() span := scopeSpans.Spans().AppendEmpty() span.SetName("failed-operation") status := span.Status() status.SetCode(ptrace.StatusCodeError) status.SetMessage("Connection timeout") fmt.Printf("Status code: %s\n", status.Code()) fmt.Printf("Status message: %s\n", status.Message()) // Output: // Status code: Error // Status message: Connection timeout } func ExampleSpanKind() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() // Different span kinds kinds := []ptrace.SpanKind{ ptrace.SpanKindUnspecified, ptrace.SpanKindInternal, ptrace.SpanKindServer, ptrace.SpanKindClient, ptrace.SpanKindProducer, ptrace.SpanKindConsumer, } for i, kind := range kinds { span := scopeSpans.Spans().AppendEmpty() span.SetName("operation-" + strconv.Itoa(i)) span.SetKind(kind) span.SetStartTimestamp(pcommon.Timestamp(1640995200000000000)) span.SetEndTimestamp(pcommon.Timestamp(1640995200100000000)) } fmt.Printf("Total spans: %d\n", scopeSpans.Spans().Len()) fmt.Printf("First span kind: %s\n", scopeSpans.Spans().At(0).Kind()) fmt.Printf("Server span kind: %s\n", scopeSpans.Spans().At(2).Kind()) fmt.Printf("Client span kind: %s\n", scopeSpans.Spans().At(3).Kind()) // Output: // Total spans: 6 // First span kind: Unspecified // Server span kind: Server // Client span kind: Client } func ExampleSpan_Links() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() span := scopeSpans.Spans().AppendEmpty() span.SetName("memlimit-processor") span.SetKind(ptrace.SpanKindInternal) // Add links to other spans link1 := span.Links().AppendEmpty() link1.SetTraceID(pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16})) link1.SetSpanID(pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8})) link1.TraceState().FromRaw("rojo=00f067aa0ba902b7,congo=t61rcWkgMzE") link1.Attributes().PutStr("link.type", "follows_from") link1.SetFlags(0x01) link2 := span.Links().AppendEmpty() link2.SetTraceID(pcommon.TraceID([16]byte{16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1})) link2.SetSpanID(pcommon.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})) link2.Attributes().PutStr("link.type", "child_of") link2.SetDroppedAttributesCount(2) span.SetDroppedLinksCount(1) fmt.Printf("Links count: %d\n", span.Links().Len()) fmt.Printf("First link trace state: %s\n", link1.TraceState().AsRaw()) fmt.Printf("First link flags: %d\n", link1.Flags()) fmt.Printf("Dropped links count: %d\n", span.DroppedLinksCount()) // Output: // Links count: 2 // First link trace state: rojo=00f067aa0ba902b7,congo=t61rcWkgMzE // First link flags: 1 // Dropped links count: 1 } func ExampleSpan_TraceState() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() span := scopeSpans.Spans().AppendEmpty() span.SetName("traced-operation") // Set trace state (W3C Trace Context) span.TraceState().FromRaw("rojo=00f067aa0ba902b7,congo=t61rcWkgMzE") fmt.Printf("Trace state: %s\n", span.TraceState().AsRaw()) // Output: // Trace state: rojo=00f067aa0ba902b7,congo=t61rcWkgMzE } func ExampleSpan_Flags() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() span := scopeSpans.Spans().AppendEmpty() span.SetName("sampled-span") // Set trace flags (W3C Trace Context) span.SetFlags(0x01) // Sampled flag fmt.Printf("Span flags: %d\n", span.Flags()) // Output: // Span flags: 1 } func ExampleStatusCode() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() // Different status codes statuses := []struct { code ptrace.StatusCode msg string name string }{ {ptrace.StatusCodeUnset, "", "unset"}, {ptrace.StatusCodeOk, "Success", "ok"}, {ptrace.StatusCodeError, "Internal server error", "error"}, } for _, s := range statuses { span := scopeSpans.Spans().AppendEmpty() span.SetName("operation-" + s.name) status := span.Status() status.SetCode(s.code) status.SetMessage(s.msg) } fmt.Printf("Total spans: %d\n", scopeSpans.Spans().Len()) fmt.Printf("Unset status: %s\n", scopeSpans.Spans().At(0).Status().Code()) fmt.Printf("Ok status: %s\n", scopeSpans.Spans().At(1).Status().Code()) fmt.Printf("Error status: %s\n", scopeSpans.Spans().At(2).Status().Code()) fmt.Printf("Error message: %s\n", scopeSpans.Spans().At(2).Status().Message()) // Output: // Total spans: 3 // Unset status: Unset // Ok status: Ok // Error status: Error // Error message: Internal server error } func ExampleSpan_DroppedAttributesCount() { traces := ptrace.NewTraces() resourceSpans := traces.ResourceSpans().AppendEmpty() scopeSpans := resourceSpans.ScopeSpans().AppendEmpty() span := scopeSpans.Spans().AppendEmpty() span.SetName("span-with-dropped-data") // Add some attributes and events span.Attributes().PutStr("key1", "value1") span.Attributes().PutStr("key2", "value2") event := span.Events().AppendEmpty() event.SetName("event1") event.SetTimestamp(pcommon.Timestamp(1640995200000000000)) // Set dropped counts span.SetDroppedAttributesCount(5) span.SetDroppedEventsCount(3) span.SetDroppedLinksCount(2) fmt.Printf("Current attributes: %d\n", span.Attributes().Len()) fmt.Printf("Dropped attributes: %d\n", span.DroppedAttributesCount()) fmt.Printf("Current events: %d\n", span.Events().Len()) fmt.Printf("Dropped events: %d\n", span.DroppedEventsCount()) fmt.Printf("Dropped links: %d\n", span.DroppedLinksCount()) // Output: // Current attributes: 2 // Dropped attributes: 5 // Current events: 1 // Dropped events: 3 // Dropped links: 2 } opentelemetry-collector-0.141.0/pdata/ptrace/encoding.go000066400000000000000000000017231511331344600232250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" // MarshalSizer is the interface that groups the basic Marshal and Size methods type MarshalSizer interface { Marshaler Sizer } // Marshaler marshals Traces into bytes. type Marshaler interface { // MarshalTraces the given Traces into bytes. // If the error is not nil, the returned bytes slice cannot be used. MarshalTraces(td Traces) ([]byte, error) } // Unmarshaler unmarshalls bytes into Traces. type Unmarshaler interface { // UnmarshalTraces the given bytes into Traces. // If the error is not nil, the returned Traces cannot be used. UnmarshalTraces(buf []byte) (Traces, error) } // Sizer is an optional interface implemented by the Marshaler, // that calculates the size of a marshaled Traces. type Sizer interface { // TracesSize returns the size in bytes of a marshaled Traces. TracesSize(td Traces) int } opentelemetry-collector-0.141.0/pdata/ptrace/fuzz_test.go000066400000000000000000000031241511331344600234710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" import ( "bytes" "testing" "github.com/stretchr/testify/require" ) var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." func FuzzUnmarshalJSONTraces(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { u1 := &JSONUnmarshaler{} ld1, err := u1.UnmarshalTraces(data) if err != nil { return } m1 := &JSONMarshaler{} b1, err := m1.MarshalTraces(ld1) require.NoError(t, err, "failed to marshal valid struct") u2 := &JSONUnmarshaler{} ld2, err := u2.UnmarshalTraces(b1) require.NoError(t, err, "failed to unmarshal valid bytes") m2 := &JSONMarshaler{} b2, err := m2.MarshalTraces(ld2) require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzUnmarshalPBTraces(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { u1 := &ProtoUnmarshaler{} ld1, err := u1.UnmarshalTraces(data) if err != nil { return } m1 := &ProtoMarshaler{} b1, err := m1.MarshalTraces(ld1) require.NoError(t, err, "failed to marshal valid struct") u2 := &ProtoUnmarshaler{} ld2, err := u2.UnmarshalTraces(b1) require.NoError(t, err, "failed to unmarshal valid bytes") m2 := &ProtoMarshaler{} b2, err := m2.MarshalTraces(ld2) require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_resourcespans.go000066400000000000000000000050171511331344600263510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceSpans is a collection of spans from a Resource. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewResourceSpans function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceSpans struct { orig *internal.ResourceSpans state *internal.State } func newResourceSpans(orig *internal.ResourceSpans, state *internal.State) ResourceSpans { return ResourceSpans{orig: orig, state: state} } // NewResourceSpans creates a new empty ResourceSpans. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewResourceSpans() ResourceSpans { return newResourceSpans(internal.NewResourceSpans(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ResourceSpans) MoveTo(dest ResourceSpans) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteResourceSpans(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Resource returns the resource associated with this ResourceSpans. func (ms ResourceSpans) Resource() pcommon.Resource { return pcommon.Resource(internal.NewResourceWrapper(&ms.orig.Resource, ms.state)) } // ScopeSpans returns the ScopeSpans associated with this ResourceSpans. func (ms ResourceSpans) ScopeSpans() ScopeSpansSlice { return newScopeSpansSlice(&ms.orig.ScopeSpans, ms.state) } // SchemaUrl returns the schemaurl associated with this ResourceSpans. func (ms ResourceSpans) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ResourceSpans. func (ms ResourceSpans) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ResourceSpans) CopyTo(dest ResourceSpans) { dest.state.AssertMutable() internal.CopyResourceSpans(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_resourcespans_test.go000066400000000000000000000044621511331344600274130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestResourceSpans_MoveTo(t *testing.T) { ms := generateTestResourceSpans() dest := NewResourceSpans() ms.MoveTo(dest) assert.Equal(t, NewResourceSpans(), ms) assert.Equal(t, generateTestResourceSpans(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestResourceSpans(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newResourceSpans(internal.NewResourceSpans(), sharedState)) }) assert.Panics(t, func() { newResourceSpans(internal.NewResourceSpans(), sharedState).MoveTo(dest) }) } func TestResourceSpans_CopyTo(t *testing.T) { ms := NewResourceSpans() orig := NewResourceSpans() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestResourceSpans() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newResourceSpans(internal.NewResourceSpans(), sharedState)) }) } func TestResourceSpans_Resource(t *testing.T) { ms := NewResourceSpans() assert.Equal(t, pcommon.NewResource(), ms.Resource()) ms.orig.Resource = *internal.GenTestResource() assert.Equal(t, pcommon.Resource(internal.GenTestResourceWrapper()), ms.Resource()) } func TestResourceSpans_ScopeSpans(t *testing.T) { ms := NewResourceSpans() assert.Equal(t, NewScopeSpansSlice(), ms.ScopeSpans()) ms.orig.ScopeSpans = internal.GenTestScopeSpansPtrSlice() assert.Equal(t, generateTestScopeSpansSlice(), ms.ScopeSpans()) } func TestResourceSpans_SchemaUrl(t *testing.T) { ms := NewResourceSpans() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newResourceSpans(internal.NewResourceSpans(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestResourceSpans() ResourceSpans { return newResourceSpans(internal.GenTestResourceSpans(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_resourcespansslice.go000066400000000000000000000115651511331344600273760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ResourceSpansSlice logically represents a slice of ResourceSpans. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewResourceSpansSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ResourceSpansSlice struct { orig *[]*internal.ResourceSpans state *internal.State } func newResourceSpansSlice(orig *[]*internal.ResourceSpans, state *internal.State) ResourceSpansSlice { return ResourceSpansSlice{orig: orig, state: state} } // NewResourceSpansSlice creates a ResourceSpansSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewResourceSpansSlice() ResourceSpansSlice { orig := []*internal.ResourceSpans(nil) return newResourceSpansSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewResourceSpansSlice()". func (es ResourceSpansSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ResourceSpansSlice) At(i int) ResourceSpans { return newResourceSpans((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ResourceSpansSlice) All() iter.Seq2[int, ResourceSpans] { return func(yield func(int, ResourceSpans) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ResourceSpansSlice can be initialized: // // es := NewResourceSpansSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ResourceSpansSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ResourceSpans, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ResourceSpans. // It returns the newly added ResourceSpans. func (es ResourceSpansSlice) AppendEmpty() ResourceSpans { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewResourceSpans()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ResourceSpansSlice) MoveAndAppendTo(dest ResourceSpansSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ResourceSpansSlice) RemoveIf(f func(ResourceSpans) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteResourceSpans((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ResourceSpansSlice) CopyTo(dest ResourceSpansSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyResourceSpansPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ResourceSpans elements within ResourceSpansSlice given the // provided less function so that two instances of ResourceSpansSlice // can be compared. func (es ResourceSpansSlice) Sort(less func(a, b ResourceSpans) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_resourcespansslice_test.go000066400000000000000000000116601511331344600304310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestResourceSpansSlice(t *testing.T) { es := NewResourceSpansSlice() assert.Equal(t, 0, es.Len()) es = newResourceSpansSlice(&[]*internal.ResourceSpans{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewResourceSpans() testVal := generateTestResourceSpans() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestResourceSpans() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestResourceSpansSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newResourceSpansSlice(&[]*internal.ResourceSpans{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewResourceSpansSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestResourceSpansSlice_CopyTo(t *testing.T) { dest := NewResourceSpansSlice() src := generateTestResourceSpansSlice() src.CopyTo(dest) assert.Equal(t, generateTestResourceSpansSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestResourceSpansSlice(), dest) } func TestResourceSpansSlice_EnsureCapacity(t *testing.T) { es := generateTestResourceSpansSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestResourceSpansSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestResourceSpansSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestResourceSpansSlice(), es) } func TestResourceSpansSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestResourceSpansSlice() dest := NewResourceSpansSlice() src := generateTestResourceSpansSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceSpansSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestResourceSpansSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestResourceSpansSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestResourceSpansSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewResourceSpansSlice() emptySlice.RemoveIf(func(el ResourceSpans) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestResourceSpansSlice() pos := 0 filtered.RemoveIf(func(el ResourceSpans) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestResourceSpansSlice_RemoveIfAll(t *testing.T) { got := generateTestResourceSpansSlice() got.RemoveIf(func(el ResourceSpans) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestResourceSpansSliceAll(t *testing.T) { ms := generateTestResourceSpansSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestResourceSpansSlice_Sort(t *testing.T) { es := generateTestResourceSpansSlice() es.Sort(func(a, b ResourceSpans) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ResourceSpans) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestResourceSpansSlice() ResourceSpansSlice { ms := NewResourceSpansSlice() *ms.orig = internal.GenTestResourceSpansPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/ptrace/generated_scopespans.go000066400000000000000000000047011511331344600256320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ScopeSpans is a collection of spans from a LibraryInstrumentation. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewScopeSpans function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeSpans struct { orig *internal.ScopeSpans state *internal.State } func newScopeSpans(orig *internal.ScopeSpans, state *internal.State) ScopeSpans { return ScopeSpans{orig: orig, state: state} } // NewScopeSpans creates a new empty ScopeSpans. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewScopeSpans() ScopeSpans { return newScopeSpans(internal.NewScopeSpans(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ScopeSpans) MoveTo(dest ScopeSpans) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteScopeSpans(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Scope returns the scope associated with this ScopeSpans. func (ms ScopeSpans) Scope() pcommon.InstrumentationScope { return pcommon.InstrumentationScope(internal.NewInstrumentationScopeWrapper(&ms.orig.Scope, ms.state)) } // Spans returns the Spans associated with this ScopeSpans. func (ms ScopeSpans) Spans() SpanSlice { return newSpanSlice(&ms.orig.Spans, ms.state) } // SchemaUrl returns the schemaurl associated with this ScopeSpans. func (ms ScopeSpans) SchemaUrl() string { return ms.orig.SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this ScopeSpans. func (ms ScopeSpans) SetSchemaUrl(v string) { ms.state.AssertMutable() ms.orig.SchemaUrl = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ScopeSpans) CopyTo(dest ScopeSpans) { dest.state.AssertMutable() internal.CopyScopeSpans(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_scopespans_test.go000066400000000000000000000043341511331344600266730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestScopeSpans_MoveTo(t *testing.T) { ms := generateTestScopeSpans() dest := NewScopeSpans() ms.MoveTo(dest) assert.Equal(t, NewScopeSpans(), ms) assert.Equal(t, generateTestScopeSpans(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestScopeSpans(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newScopeSpans(internal.NewScopeSpans(), sharedState)) }) assert.Panics(t, func() { newScopeSpans(internal.NewScopeSpans(), sharedState).MoveTo(dest) }) } func TestScopeSpans_CopyTo(t *testing.T) { ms := NewScopeSpans() orig := NewScopeSpans() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestScopeSpans() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newScopeSpans(internal.NewScopeSpans(), sharedState)) }) } func TestScopeSpans_Scope(t *testing.T) { ms := NewScopeSpans() assert.Equal(t, pcommon.NewInstrumentationScope(), ms.Scope()) ms.orig.Scope = *internal.GenTestInstrumentationScope() assert.Equal(t, pcommon.InstrumentationScope(internal.GenTestInstrumentationScopeWrapper()), ms.Scope()) } func TestScopeSpans_Spans(t *testing.T) { ms := NewScopeSpans() assert.Equal(t, NewSpanSlice(), ms.Spans()) ms.orig.Spans = internal.GenTestSpanPtrSlice() assert.Equal(t, generateTestSpanSlice(), ms.Spans()) } func TestScopeSpans_SchemaUrl(t *testing.T) { ms := NewScopeSpans() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newScopeSpans(internal.NewScopeSpans(), sharedState).SetSchemaUrl("test_schemaurl") }) } func generateTestScopeSpans() ScopeSpans { return newScopeSpans(internal.GenTestScopeSpans(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_scopespansslice.go000066400000000000000000000113561511331344600266560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // ScopeSpansSlice logically represents a slice of ScopeSpans. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewScopeSpansSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type ScopeSpansSlice struct { orig *[]*internal.ScopeSpans state *internal.State } func newScopeSpansSlice(orig *[]*internal.ScopeSpans, state *internal.State) ScopeSpansSlice { return ScopeSpansSlice{orig: orig, state: state} } // NewScopeSpansSlice creates a ScopeSpansSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewScopeSpansSlice() ScopeSpansSlice { orig := []*internal.ScopeSpans(nil) return newScopeSpansSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewScopeSpansSlice()". func (es ScopeSpansSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es ScopeSpansSlice) At(i int) ScopeSpans { return newScopeSpans((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es ScopeSpansSlice) All() iter.Seq2[int, ScopeSpans] { return func(yield func(int, ScopeSpans) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new ScopeSpansSlice can be initialized: // // es := NewScopeSpansSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es ScopeSpansSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.ScopeSpans, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty ScopeSpans. // It returns the newly added ScopeSpans. func (es ScopeSpansSlice) AppendEmpty() ScopeSpans { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewScopeSpans()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es ScopeSpansSlice) MoveAndAppendTo(dest ScopeSpansSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es ScopeSpansSlice) RemoveIf(f func(ScopeSpans) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteScopeSpans((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es ScopeSpansSlice) CopyTo(dest ScopeSpansSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopyScopeSpansPtrSlice(*dest.orig, *es.orig) } // Sort sorts the ScopeSpans elements within ScopeSpansSlice given the // provided less function so that two instances of ScopeSpansSlice // can be compared. func (es ScopeSpansSlice) Sort(less func(a, b ScopeSpans) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_scopespansslice_test.go000066400000000000000000000114461511331344600277150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestScopeSpansSlice(t *testing.T) { es := NewScopeSpansSlice() assert.Equal(t, 0, es.Len()) es = newScopeSpansSlice(&[]*internal.ScopeSpans{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewScopeSpans() testVal := generateTestScopeSpans() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestScopeSpans() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestScopeSpansSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newScopeSpansSlice(&[]*internal.ScopeSpans{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewScopeSpansSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestScopeSpansSlice_CopyTo(t *testing.T) { dest := NewScopeSpansSlice() src := generateTestScopeSpansSlice() src.CopyTo(dest) assert.Equal(t, generateTestScopeSpansSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestScopeSpansSlice(), dest) } func TestScopeSpansSlice_EnsureCapacity(t *testing.T) { es := generateTestScopeSpansSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestScopeSpansSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestScopeSpansSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestScopeSpansSlice(), es) } func TestScopeSpansSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestScopeSpansSlice() dest := NewScopeSpansSlice() src := generateTestScopeSpansSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeSpansSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestScopeSpansSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestScopeSpansSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestScopeSpansSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewScopeSpansSlice() emptySlice.RemoveIf(func(el ScopeSpans) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestScopeSpansSlice() pos := 0 filtered.RemoveIf(func(el ScopeSpans) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestScopeSpansSlice_RemoveIfAll(t *testing.T) { got := generateTestScopeSpansSlice() got.RemoveIf(func(el ScopeSpans) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestScopeSpansSliceAll(t *testing.T) { ms := generateTestScopeSpansSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestScopeSpansSlice_Sort(t *testing.T) { es := generateTestScopeSpansSlice() es.Sort(func(a, b ScopeSpans) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b ScopeSpans) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestScopeSpansSlice() ScopeSpansSlice { ms := NewScopeSpansSlice() *ms.orig = internal.GenTestScopeSpansPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/ptrace/generated_span.go000066400000000000000000000141501511331344600244140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // Span represents a single operation within a trace. // See Span definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSpan function to create new instances. // Important: zero-initialized instance is not valid for use. type Span struct { orig *internal.Span state *internal.State } func newSpan(orig *internal.Span, state *internal.State) Span { return Span{orig: orig, state: state} } // NewSpan creates a new empty Span. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSpan() Span { return newSpan(internal.NewSpan(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Span) MoveTo(dest Span) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSpan(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // TraceID returns the traceid associated with this Span. func (ms Span) TraceID() pcommon.TraceID { return pcommon.TraceID(ms.orig.TraceId) } // SetTraceID replaces the traceid associated with this Span. func (ms Span) SetTraceID(v pcommon.TraceID) { ms.state.AssertMutable() ms.orig.TraceId = internal.TraceID(v) } // SpanID returns the spanid associated with this Span. func (ms Span) SpanID() pcommon.SpanID { return pcommon.SpanID(ms.orig.SpanId) } // SetSpanID replaces the spanid associated with this Span. func (ms Span) SetSpanID(v pcommon.SpanID) { ms.state.AssertMutable() ms.orig.SpanId = internal.SpanID(v) } // TraceState returns the tracestate associated with this Span. func (ms Span) TraceState() pcommon.TraceState { return pcommon.TraceState(internal.NewTraceStateWrapper(&ms.orig.TraceState, ms.state)) } // ParentSpanID returns the parentspanid associated with this Span. func (ms Span) ParentSpanID() pcommon.SpanID { return pcommon.SpanID(ms.orig.ParentSpanId) } // SetParentSpanID replaces the parentspanid associated with this Span. func (ms Span) SetParentSpanID(v pcommon.SpanID) { ms.state.AssertMutable() ms.orig.ParentSpanId = internal.SpanID(v) } // Flags returns the flags associated with this Span. func (ms Span) Flags() uint32 { return ms.orig.Flags } // SetFlags replaces the flags associated with this Span. func (ms Span) SetFlags(v uint32) { ms.state.AssertMutable() ms.orig.Flags = v } // Name returns the name associated with this Span. func (ms Span) Name() string { return ms.orig.Name } // SetName replaces the name associated with this Span. func (ms Span) SetName(v string) { ms.state.AssertMutable() ms.orig.Name = v } // Kind returns the kind associated with this Span. func (ms Span) Kind() SpanKind { return SpanKind(ms.orig.Kind) } // SetKind replaces the kind associated with this Span. func (ms Span) SetKind(v SpanKind) { ms.state.AssertMutable() ms.orig.Kind = internal.SpanKind(v) } // StartTimestamp returns the starttimestamp associated with this Span. func (ms Span) StartTimestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.StartTimeUnixNano) } // SetStartTimestamp replaces the starttimestamp associated with this Span. func (ms Span) SetStartTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.StartTimeUnixNano = uint64(v) } // EndTimestamp returns the endtimestamp associated with this Span. func (ms Span) EndTimestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.EndTimeUnixNano) } // SetEndTimestamp replaces the endtimestamp associated with this Span. func (ms Span) SetEndTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.EndTimeUnixNano = uint64(v) } // Attributes returns the Attributes associated with this Span. func (ms Span) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this Span. func (ms Span) DroppedAttributesCount() uint32 { return ms.orig.DroppedAttributesCount } // SetDroppedAttributesCount replaces the droppedattributescount associated with this Span. func (ms Span) SetDroppedAttributesCount(v uint32) { ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // Events returns the Events associated with this Span. func (ms Span) Events() SpanEventSlice { return newSpanEventSlice(&ms.orig.Events, ms.state) } // DroppedEventsCount returns the droppedeventscount associated with this Span. func (ms Span) DroppedEventsCount() uint32 { return ms.orig.DroppedEventsCount } // SetDroppedEventsCount replaces the droppedeventscount associated with this Span. func (ms Span) SetDroppedEventsCount(v uint32) { ms.state.AssertMutable() ms.orig.DroppedEventsCount = v } // Links returns the Links associated with this Span. func (ms Span) Links() SpanLinkSlice { return newSpanLinkSlice(&ms.orig.Links, ms.state) } // DroppedLinksCount returns the droppedlinkscount associated with this Span. func (ms Span) DroppedLinksCount() uint32 { return ms.orig.DroppedLinksCount } // SetDroppedLinksCount replaces the droppedlinkscount associated with this Span. func (ms Span) SetDroppedLinksCount(v uint32) { ms.state.AssertMutable() ms.orig.DroppedLinksCount = v } // Status returns the status associated with this Span. func (ms Span) Status() Status { return newStatus(&ms.orig.Status, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Span) CopyTo(dest Span) { dest.state.AssertMutable() internal.CopySpan(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_span_test.go000066400000000000000000000135101511331344600254520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSpan_MoveTo(t *testing.T) { ms := generateTestSpan() dest := NewSpan() ms.MoveTo(dest) assert.Equal(t, NewSpan(), ms) assert.Equal(t, generateTestSpan(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSpan(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSpan(internal.NewSpan(), sharedState)) }) assert.Panics(t, func() { newSpan(internal.NewSpan(), sharedState).MoveTo(dest) }) } func TestSpan_CopyTo(t *testing.T) { ms := NewSpan() orig := NewSpan() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSpan() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSpan(internal.NewSpan(), sharedState)) }) } func TestSpan_TraceID(t *testing.T) { ms := NewSpan() assert.Equal(t, pcommon.TraceID(internal.TraceID([16]byte{})), ms.TraceID()) testValTraceID := pcommon.TraceID(internal.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})) ms.SetTraceID(testValTraceID) assert.Equal(t, testValTraceID, ms.TraceID()) } func TestSpan_SpanID(t *testing.T) { ms := NewSpan() assert.Equal(t, pcommon.SpanID(internal.SpanID([8]byte{})), ms.SpanID()) testValSpanID := pcommon.SpanID(internal.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})) ms.SetSpanID(testValSpanID) assert.Equal(t, testValSpanID, ms.SpanID()) } func TestSpan_TraceState(t *testing.T) { ms := NewSpan() assert.Equal(t, pcommon.NewTraceState(), ms.TraceState()) ms.orig.TraceState = *internal.GenTestTraceState() assert.Equal(t, pcommon.TraceState(internal.GenTestTraceStateWrapper()), ms.TraceState()) } func TestSpan_ParentSpanID(t *testing.T) { ms := NewSpan() assert.Equal(t, pcommon.SpanID(internal.SpanID([8]byte{})), ms.ParentSpanID()) testValParentSpanID := pcommon.SpanID(internal.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})) ms.SetParentSpanID(testValParentSpanID) assert.Equal(t, testValParentSpanID, ms.ParentSpanID()) } func TestSpan_Flags(t *testing.T) { ms := NewSpan() assert.Equal(t, uint32(0), ms.Flags()) ms.SetFlags(uint32(13)) assert.Equal(t, uint32(13), ms.Flags()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpan(internal.NewSpan(), sharedState).SetFlags(uint32(13)) }) } func TestSpan_Name(t *testing.T) { ms := NewSpan() assert.Empty(t, ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpan(internal.NewSpan(), sharedState).SetName("test_name") }) } func TestSpan_Kind(t *testing.T) { ms := NewSpan() assert.Equal(t, SpanKind(internal.SpanKind_SPAN_KIND_UNSPECIFIED), ms.Kind()) testValKind := SpanKind(internal.SpanKind_SPAN_KIND_CLIENT) ms.SetKind(testValKind) assert.Equal(t, testValKind, ms.Kind()) } func TestSpan_StartTimestamp(t *testing.T) { ms := NewSpan() assert.Equal(t, pcommon.Timestamp(0), ms.StartTimestamp()) testValStartTimestamp := pcommon.Timestamp(1234567890) ms.SetStartTimestamp(testValStartTimestamp) assert.Equal(t, testValStartTimestamp, ms.StartTimestamp()) } func TestSpan_EndTimestamp(t *testing.T) { ms := NewSpan() assert.Equal(t, pcommon.Timestamp(0), ms.EndTimestamp()) testValEndTimestamp := pcommon.Timestamp(1234567890) ms.SetEndTimestamp(testValEndTimestamp) assert.Equal(t, testValEndTimestamp, ms.EndTimestamp()) } func TestSpan_Attributes(t *testing.T) { ms := NewSpan() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestSpan_DroppedAttributesCount(t *testing.T) { ms := NewSpan() assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedAttributesCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpan(internal.NewSpan(), sharedState).SetDroppedAttributesCount(uint32(13)) }) } func TestSpan_Events(t *testing.T) { ms := NewSpan() assert.Equal(t, NewSpanEventSlice(), ms.Events()) ms.orig.Events = internal.GenTestSpanEventPtrSlice() assert.Equal(t, generateTestSpanEventSlice(), ms.Events()) } func TestSpan_DroppedEventsCount(t *testing.T) { ms := NewSpan() assert.Equal(t, uint32(0), ms.DroppedEventsCount()) ms.SetDroppedEventsCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedEventsCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpan(internal.NewSpan(), sharedState).SetDroppedEventsCount(uint32(13)) }) } func TestSpan_Links(t *testing.T) { ms := NewSpan() assert.Equal(t, NewSpanLinkSlice(), ms.Links()) ms.orig.Links = internal.GenTestSpanLinkPtrSlice() assert.Equal(t, generateTestSpanLinkSlice(), ms.Links()) } func TestSpan_DroppedLinksCount(t *testing.T) { ms := NewSpan() assert.Equal(t, uint32(0), ms.DroppedLinksCount()) ms.SetDroppedLinksCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedLinksCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpan(internal.NewSpan(), sharedState).SetDroppedLinksCount(uint32(13)) }) } func TestSpan_Status(t *testing.T) { ms := NewSpan() assert.Equal(t, NewStatus(), ms.Status()) ms.orig.Status = *internal.GenTestStatus() assert.Equal(t, generateTestStatus(), ms.Status()) } func generateTestSpan() Span { return newSpan(internal.GenTestSpan(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanevent.go000066400000000000000000000060401511331344600254550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // SpanEvent is a time-stamped annotation of the span, consisting of user-supplied // text description and key-value pairs. See OTLP for event definition. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSpanEvent function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanEvent struct { orig *internal.SpanEvent state *internal.State } func newSpanEvent(orig *internal.SpanEvent, state *internal.State) SpanEvent { return SpanEvent{orig: orig, state: state} } // NewSpanEvent creates a new empty SpanEvent. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSpanEvent() SpanEvent { return newSpanEvent(internal.NewSpanEvent(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SpanEvent) MoveTo(dest SpanEvent) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSpanEvent(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Timestamp returns the timestamp associated with this SpanEvent. func (ms SpanEvent) Timestamp() pcommon.Timestamp { return pcommon.Timestamp(ms.orig.TimeUnixNano) } // SetTimestamp replaces the timestamp associated with this SpanEvent. func (ms SpanEvent) SetTimestamp(v pcommon.Timestamp) { ms.state.AssertMutable() ms.orig.TimeUnixNano = uint64(v) } // Name returns the name associated with this SpanEvent. func (ms SpanEvent) Name() string { return ms.orig.Name } // SetName replaces the name associated with this SpanEvent. func (ms SpanEvent) SetName(v string) { ms.state.AssertMutable() ms.orig.Name = v } // Attributes returns the Attributes associated with this SpanEvent. func (ms SpanEvent) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this SpanEvent. func (ms SpanEvent) DroppedAttributesCount() uint32 { return ms.orig.DroppedAttributesCount } // SetDroppedAttributesCount replaces the droppedattributescount associated with this SpanEvent. func (ms SpanEvent) SetDroppedAttributesCount(v uint32) { ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms SpanEvent) CopyTo(dest SpanEvent) { dest.state.AssertMutable() internal.CopySpanEvent(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanevent_test.go000066400000000000000000000051111511331344600265120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSpanEvent_MoveTo(t *testing.T) { ms := generateTestSpanEvent() dest := NewSpanEvent() ms.MoveTo(dest) assert.Equal(t, NewSpanEvent(), ms) assert.Equal(t, generateTestSpanEvent(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSpanEvent(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSpanEvent(internal.NewSpanEvent(), sharedState)) }) assert.Panics(t, func() { newSpanEvent(internal.NewSpanEvent(), sharedState).MoveTo(dest) }) } func TestSpanEvent_CopyTo(t *testing.T) { ms := NewSpanEvent() orig := NewSpanEvent() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSpanEvent() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSpanEvent(internal.NewSpanEvent(), sharedState)) }) } func TestSpanEvent_Timestamp(t *testing.T) { ms := NewSpanEvent() assert.Equal(t, pcommon.Timestamp(0), ms.Timestamp()) testValTimestamp := pcommon.Timestamp(1234567890) ms.SetTimestamp(testValTimestamp) assert.Equal(t, testValTimestamp, ms.Timestamp()) } func TestSpanEvent_Name(t *testing.T) { ms := NewSpanEvent() assert.Empty(t, ms.Name()) ms.SetName("test_name") assert.Equal(t, "test_name", ms.Name()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpanEvent(internal.NewSpanEvent(), sharedState).SetName("test_name") }) } func TestSpanEvent_Attributes(t *testing.T) { ms := NewSpanEvent() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestSpanEvent_DroppedAttributesCount(t *testing.T) { ms := NewSpanEvent() assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedAttributesCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpanEvent(internal.NewSpanEvent(), sharedState).SetDroppedAttributesCount(uint32(13)) }) } func generateTestSpanEvent() SpanEvent { return newSpanEvent(internal.GenTestSpanEvent(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spaneventslice.go000066400000000000000000000113011511331344600264710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // SpanEventSlice logically represents a slice of SpanEvent. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewSpanEventSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanEventSlice struct { orig *[]*internal.SpanEvent state *internal.State } func newSpanEventSlice(orig *[]*internal.SpanEvent, state *internal.State) SpanEventSlice { return SpanEventSlice{orig: orig, state: state} } // NewSpanEventSlice creates a SpanEventSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSpanEventSlice() SpanEventSlice { orig := []*internal.SpanEvent(nil) return newSpanEventSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewSpanEventSlice()". func (es SpanEventSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es SpanEventSlice) At(i int) SpanEvent { return newSpanEvent((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es SpanEventSlice) All() iter.Seq2[int, SpanEvent] { return func(yield func(int, SpanEvent) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new SpanEventSlice can be initialized: // // es := NewSpanEventSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es SpanEventSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.SpanEvent, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty SpanEvent. // It returns the newly added SpanEvent. func (es SpanEventSlice) AppendEmpty() SpanEvent { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewSpanEvent()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanEventSlice) MoveAndAppendTo(dest SpanEventSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SpanEventSlice) RemoveIf(f func(SpanEvent) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteSpanEvent((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es SpanEventSlice) CopyTo(dest SpanEventSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopySpanEventPtrSlice(*dest.orig, *es.orig) } // Sort sorts the SpanEvent elements within SpanEventSlice given the // provided less function so that two instances of SpanEventSlice // can be compared. func (es SpanEventSlice) Sort(less func(a, b SpanEvent) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spaneventslice_test.go000066400000000000000000000113701511331344600275360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSpanEventSlice(t *testing.T) { es := NewSpanEventSlice() assert.Equal(t, 0, es.Len()) es = newSpanEventSlice(&[]*internal.SpanEvent{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewSpanEvent() testVal := generateTestSpanEvent() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestSpanEvent() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestSpanEventSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newSpanEventSlice(&[]*internal.SpanEvent{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewSpanEventSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestSpanEventSlice_CopyTo(t *testing.T) { dest := NewSpanEventSlice() src := generateTestSpanEventSlice() src.CopyTo(dest) assert.Equal(t, generateTestSpanEventSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestSpanEventSlice(), dest) } func TestSpanEventSlice_EnsureCapacity(t *testing.T) { es := generateTestSpanEventSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestSpanEventSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestSpanEventSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestSpanEventSlice(), es) } func TestSpanEventSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestSpanEventSlice() dest := NewSpanEventSlice() src := generateTestSpanEventSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSpanEventSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSpanEventSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestSpanEventSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestSpanEventSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewSpanEventSlice() emptySlice.RemoveIf(func(el SpanEvent) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestSpanEventSlice() pos := 0 filtered.RemoveIf(func(el SpanEvent) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestSpanEventSlice_RemoveIfAll(t *testing.T) { got := generateTestSpanEventSlice() got.RemoveIf(func(el SpanEvent) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestSpanEventSliceAll(t *testing.T) { ms := generateTestSpanEventSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestSpanEventSlice_Sort(t *testing.T) { es := generateTestSpanEventSlice() es.Sort(func(a, b SpanEvent) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b SpanEvent) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestSpanEventSlice() SpanEventSlice { ms := NewSpanEventSlice() *ms.orig = internal.GenTestSpanEventPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanlink.go000066400000000000000000000071531511331344600252770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // SpanLink is a pointer from the current span to another span in the same trace or in a // different trace. // See Link definition in OTLP: https://github.com/open-telemetry/opentelemetry-proto/blob/main/opentelemetry/proto/trace/v1/trace.proto // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewSpanLink function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanLink struct { orig *internal.SpanLink state *internal.State } func newSpanLink(orig *internal.SpanLink, state *internal.State) SpanLink { return SpanLink{orig: orig, state: state} } // NewSpanLink creates a new empty SpanLink. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewSpanLink() SpanLink { return newSpanLink(internal.NewSpanLink(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms SpanLink) MoveTo(dest SpanLink) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteSpanLink(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // TraceID returns the traceid associated with this SpanLink. func (ms SpanLink) TraceID() pcommon.TraceID { return pcommon.TraceID(ms.orig.TraceId) } // SetTraceID replaces the traceid associated with this SpanLink. func (ms SpanLink) SetTraceID(v pcommon.TraceID) { ms.state.AssertMutable() ms.orig.TraceId = internal.TraceID(v) } // SpanID returns the spanid associated with this SpanLink. func (ms SpanLink) SpanID() pcommon.SpanID { return pcommon.SpanID(ms.orig.SpanId) } // SetSpanID replaces the spanid associated with this SpanLink. func (ms SpanLink) SetSpanID(v pcommon.SpanID) { ms.state.AssertMutable() ms.orig.SpanId = internal.SpanID(v) } // TraceState returns the tracestate associated with this SpanLink. func (ms SpanLink) TraceState() pcommon.TraceState { return pcommon.TraceState(internal.NewTraceStateWrapper(&ms.orig.TraceState, ms.state)) } // Attributes returns the Attributes associated with this SpanLink. func (ms SpanLink) Attributes() pcommon.Map { return pcommon.Map(internal.NewMapWrapper(&ms.orig.Attributes, ms.state)) } // DroppedAttributesCount returns the droppedattributescount associated with this SpanLink. func (ms SpanLink) DroppedAttributesCount() uint32 { return ms.orig.DroppedAttributesCount } // SetDroppedAttributesCount replaces the droppedattributescount associated with this SpanLink. func (ms SpanLink) SetDroppedAttributesCount(v uint32) { ms.state.AssertMutable() ms.orig.DroppedAttributesCount = v } // Flags returns the flags associated with this SpanLink. func (ms SpanLink) Flags() uint32 { return ms.orig.Flags } // SetFlags replaces the flags associated with this SpanLink. func (ms SpanLink) SetFlags(v uint32) { ms.state.AssertMutable() ms.orig.Flags = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms SpanLink) CopyTo(dest SpanLink) { dest.state.AssertMutable() internal.CopySpanLink(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanlink_test.go000066400000000000000000000062661511331344600263420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSpanLink_MoveTo(t *testing.T) { ms := generateTestSpanLink() dest := NewSpanLink() ms.MoveTo(dest) assert.Equal(t, NewSpanLink(), ms) assert.Equal(t, generateTestSpanLink(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestSpanLink(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newSpanLink(internal.NewSpanLink(), sharedState)) }) assert.Panics(t, func() { newSpanLink(internal.NewSpanLink(), sharedState).MoveTo(dest) }) } func TestSpanLink_CopyTo(t *testing.T) { ms := NewSpanLink() orig := NewSpanLink() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestSpanLink() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newSpanLink(internal.NewSpanLink(), sharedState)) }) } func TestSpanLink_TraceID(t *testing.T) { ms := NewSpanLink() assert.Equal(t, pcommon.TraceID(internal.TraceID([16]byte{})), ms.TraceID()) testValTraceID := pcommon.TraceID(internal.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1})) ms.SetTraceID(testValTraceID) assert.Equal(t, testValTraceID, ms.TraceID()) } func TestSpanLink_SpanID(t *testing.T) { ms := NewSpanLink() assert.Equal(t, pcommon.SpanID(internal.SpanID([8]byte{})), ms.SpanID()) testValSpanID := pcommon.SpanID(internal.SpanID([8]byte{8, 7, 6, 5, 4, 3, 2, 1})) ms.SetSpanID(testValSpanID) assert.Equal(t, testValSpanID, ms.SpanID()) } func TestSpanLink_TraceState(t *testing.T) { ms := NewSpanLink() assert.Equal(t, pcommon.NewTraceState(), ms.TraceState()) ms.orig.TraceState = *internal.GenTestTraceState() assert.Equal(t, pcommon.TraceState(internal.GenTestTraceStateWrapper()), ms.TraceState()) } func TestSpanLink_Attributes(t *testing.T) { ms := NewSpanLink() assert.Equal(t, pcommon.NewMap(), ms.Attributes()) ms.orig.Attributes = internal.GenTestKeyValueSlice() assert.Equal(t, pcommon.Map(internal.GenTestMapWrapper()), ms.Attributes()) } func TestSpanLink_DroppedAttributesCount(t *testing.T) { ms := NewSpanLink() assert.Equal(t, uint32(0), ms.DroppedAttributesCount()) ms.SetDroppedAttributesCount(uint32(13)) assert.Equal(t, uint32(13), ms.DroppedAttributesCount()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpanLink(internal.NewSpanLink(), sharedState).SetDroppedAttributesCount(uint32(13)) }) } func TestSpanLink_Flags(t *testing.T) { ms := NewSpanLink() assert.Equal(t, uint32(0), ms.Flags()) ms.SetFlags(uint32(13)) assert.Equal(t, uint32(13), ms.Flags()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newSpanLink(internal.NewSpanLink(), sharedState).SetFlags(uint32(13)) }) } func generateTestSpanLink() SpanLink { return newSpanLink(internal.GenTestSpanLink(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanlinkslice.go000066400000000000000000000112241511331344600263110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // SpanLinkSlice logically represents a slice of SpanLink. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewSpanLinkSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanLinkSlice struct { orig *[]*internal.SpanLink state *internal.State } func newSpanLinkSlice(orig *[]*internal.SpanLink, state *internal.State) SpanLinkSlice { return SpanLinkSlice{orig: orig, state: state} } // NewSpanLinkSlice creates a SpanLinkSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSpanLinkSlice() SpanLinkSlice { orig := []*internal.SpanLink(nil) return newSpanLinkSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewSpanLinkSlice()". func (es SpanLinkSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es SpanLinkSlice) At(i int) SpanLink { return newSpanLink((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es SpanLinkSlice) All() iter.Seq2[int, SpanLink] { return func(yield func(int, SpanLink) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new SpanLinkSlice can be initialized: // // es := NewSpanLinkSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es SpanLinkSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.SpanLink, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty SpanLink. // It returns the newly added SpanLink. func (es SpanLinkSlice) AppendEmpty() SpanLink { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewSpanLink()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanLinkSlice) MoveAndAppendTo(dest SpanLinkSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SpanLinkSlice) RemoveIf(f func(SpanLink) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteSpanLink((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es SpanLinkSlice) CopyTo(dest SpanLinkSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopySpanLinkPtrSlice(*dest.orig, *es.orig) } // Sort sorts the SpanLink elements within SpanLinkSlice given the // provided less function so that two instances of SpanLinkSlice // can be compared. func (es SpanLinkSlice) Sort(less func(a, b SpanLink) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanlinkslice_test.go000066400000000000000000000113121511331344600273460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSpanLinkSlice(t *testing.T) { es := NewSpanLinkSlice() assert.Equal(t, 0, es.Len()) es = newSpanLinkSlice(&[]*internal.SpanLink{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewSpanLink() testVal := generateTestSpanLink() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestSpanLink() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestSpanLinkSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newSpanLinkSlice(&[]*internal.SpanLink{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewSpanLinkSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestSpanLinkSlice_CopyTo(t *testing.T) { dest := NewSpanLinkSlice() src := generateTestSpanLinkSlice() src.CopyTo(dest) assert.Equal(t, generateTestSpanLinkSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestSpanLinkSlice(), dest) } func TestSpanLinkSlice_EnsureCapacity(t *testing.T) { es := generateTestSpanLinkSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestSpanLinkSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestSpanLinkSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestSpanLinkSlice(), es) } func TestSpanLinkSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestSpanLinkSlice() dest := NewSpanLinkSlice() src := generateTestSpanLinkSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSpanLinkSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSpanLinkSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestSpanLinkSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestSpanLinkSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewSpanLinkSlice() emptySlice.RemoveIf(func(el SpanLink) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestSpanLinkSlice() pos := 0 filtered.RemoveIf(func(el SpanLink) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestSpanLinkSlice_RemoveIfAll(t *testing.T) { got := generateTestSpanLinkSlice() got.RemoveIf(func(el SpanLink) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestSpanLinkSliceAll(t *testing.T) { ms := generateTestSpanLinkSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestSpanLinkSlice_Sort(t *testing.T) { es := generateTestSpanLinkSlice() es.Sort(func(a, b SpanLink) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b SpanLink) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestSpanLinkSlice() SpanLinkSlice { ms := NewSpanLinkSlice() *ms.orig = internal.GenTestSpanLinkPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanslice.go000066400000000000000000000107401511331344600254350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // SpanSlice logically represents a slice of Span. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewSpanSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type SpanSlice struct { orig *[]*internal.Span state *internal.State } func newSpanSlice(orig *[]*internal.Span, state *internal.State) SpanSlice { return SpanSlice{orig: orig, state: state} } // NewSpanSlice creates a SpanSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewSpanSlice() SpanSlice { orig := []*internal.Span(nil) return newSpanSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewSpanSlice()". func (es SpanSlice) Len() int { return len(*es.orig) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es SpanSlice) At(i int) Span { return newSpan((*es.orig)[i], es.state) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es SpanSlice) All() iter.Seq2[int, Span] { return func(yield func(int, Span) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new SpanSlice can be initialized: // // es := NewSpanSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es SpanSlice) EnsureCapacity(newCap int) { es.state.AssertMutable() oldCap := cap(*es.orig) if newCap <= oldCap { return } newOrig := make([]*internal.Span, len(*es.orig), newCap) copy(newOrig, *es.orig) *es.orig = newOrig } // AppendEmpty will append to the end of the slice an empty Span. // It returns the newly added Span. func (es SpanSlice) AppendEmpty() Span { es.state.AssertMutable() *es.orig = append(*es.orig, internal.NewSpan()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es SpanSlice) MoveAndAppendTo(dest SpanSlice) { es.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.orig == dest.orig { return } if *dest.orig == nil { // We can simply move the entire vector and avoid any allocations. *dest.orig = *es.orig } else { *dest.orig = append(*dest.orig, *es.orig...) } *es.orig = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es SpanSlice) RemoveIf(f func(Span) bool) { es.state.AssertMutable() newLen := 0 for i := 0; i < len(*es.orig); i++ { if f(es.At(i)) { internal.DeleteSpan((*es.orig)[i], true) (*es.orig)[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.orig)[newLen] = (*es.orig)[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.orig)[i] = nil newLen++ } *es.orig = (*es.orig)[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es SpanSlice) CopyTo(dest SpanSlice) { dest.state.AssertMutable() if es.orig == dest.orig { return } *dest.orig = internal.CopySpanPtrSlice(*dest.orig, *es.orig) } // Sort sorts the Span elements within SpanSlice given the // provided less function so that two instances of SpanSlice // can be compared. func (es SpanSlice) Sort(less func(a, b Span) bool) { es.state.AssertMutable() sort.SliceStable(*es.orig, func(i, j int) bool { return less(es.At(i), es.At(j)) }) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_spanslice_test.go000066400000000000000000000110221511331344600264660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestSpanSlice(t *testing.T) { es := NewSpanSlice() assert.Equal(t, 0, es.Len()) es = newSpanSlice(&[]*internal.Span{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewSpan() testVal := generateTestSpan() for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.orig)[i] = internal.GenTestSpan() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestSpanSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newSpanSlice(&[]*internal.Span{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewSpanSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestSpanSlice_CopyTo(t *testing.T) { dest := NewSpanSlice() src := generateTestSpanSlice() src.CopyTo(dest) assert.Equal(t, generateTestSpanSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestSpanSlice(), dest) } func TestSpanSlice_EnsureCapacity(t *testing.T) { es := generateTestSpanSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.orig)) assert.Equal(t, generateTestSpanSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestSpanSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.orig)) assert.Equal(t, generateTestSpanSlice(), es) } func TestSpanSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestSpanSlice() dest := NewSpanSlice() src := generateTestSpanSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSpanSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestSpanSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestSpanSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestSpanSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewSpanSlice() emptySlice.RemoveIf(func(el Span) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestSpanSlice() pos := 0 filtered.RemoveIf(func(el Span) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestSpanSlice_RemoveIfAll(t *testing.T) { got := generateTestSpanSlice() got.RemoveIf(func(el Span) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestSpanSliceAll(t *testing.T) { ms := generateTestSpanSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestSpanSlice_Sort(t *testing.T) { es := generateTestSpanSlice() es.Sort(func(a, b Span) bool { return uintptr(unsafe.Pointer(a.orig)) < uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } es.Sort(func(a, b Span) bool { return uintptr(unsafe.Pointer(a.orig)) > uintptr(unsafe.Pointer(b.orig)) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).orig)), uintptr(unsafe.Pointer(es.At(i).orig))) } } func generateTestSpanSlice() SpanSlice { ms := NewSpanSlice() *ms.orig = internal.GenTestSpanPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/ptrace/generated_status.go000066400000000000000000000044701511331344600250020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "go.opentelemetry.io/collector/pdata/internal" ) // Status is an optional final status for this span. Semantically, when Status was not // set, that means the span ended without errors and to assume Status.Ok (code = 0). // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewStatus function to create new instances. // Important: zero-initialized instance is not valid for use. type Status struct { orig *internal.Status state *internal.State } func newStatus(orig *internal.Status, state *internal.State) Status { return Status{orig: orig, state: state} } // NewStatus creates a new empty Status. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewStatus() Status { return newStatus(internal.NewStatus(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Status) MoveTo(dest Status) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteStatus(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // Message returns the message associated with this Status. func (ms Status) Message() string { return ms.orig.Message } // SetMessage replaces the message associated with this Status. func (ms Status) SetMessage(v string) { ms.state.AssertMutable() ms.orig.Message = v } // Code returns the code associated with this Status. func (ms Status) Code() StatusCode { return StatusCode(ms.orig.Code) } // SetCode replaces the code associated with this Status. func (ms Status) SetCode(v StatusCode) { ms.state.AssertMutable() ms.orig.Code = internal.StatusCode(v) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Status) CopyTo(dest Status) { dest.state.AssertMutable() internal.CopyStatus(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_status_test.go000066400000000000000000000035121511331344600260350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestStatus_MoveTo(t *testing.T) { ms := generateTestStatus() dest := NewStatus() ms.MoveTo(dest) assert.Equal(t, NewStatus(), ms) assert.Equal(t, generateTestStatus(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestStatus(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newStatus(internal.NewStatus(), sharedState)) }) assert.Panics(t, func() { newStatus(internal.NewStatus(), sharedState).MoveTo(dest) }) } func TestStatus_CopyTo(t *testing.T) { ms := NewStatus() orig := NewStatus() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestStatus() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newStatus(internal.NewStatus(), sharedState)) }) } func TestStatus_Message(t *testing.T) { ms := NewStatus() assert.Empty(t, ms.Message()) ms.SetMessage("test_message") assert.Equal(t, "test_message", ms.Message()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newStatus(internal.NewStatus(), sharedState).SetMessage("test_message") }) } func TestStatus_Code(t *testing.T) { ms := NewStatus() assert.Equal(t, StatusCode(internal.StatusCode_STATUS_CODE_UNSET), ms.Code()) testValCode := StatusCode(internal.StatusCode_STATUS_CODE_OK) ms.SetCode(testValCode) assert.Equal(t, testValCode, ms.Code()) } func generateTestStatus() Status { return newStatus(internal.GenTestStatus(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_traces.go000066400000000000000000000044461511331344600247430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "go.opentelemetry.io/collector/pdata/internal" ) // Traces is the top-level struct that is propagated through the traces pipeline. // Use NewTraces to create new instance, zero-initialized instance is not valid for use. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewTraces function to create new instances. // Important: zero-initialized instance is not valid for use. type Traces internal.TracesWrapper func newTraces(orig *internal.ExportTraceServiceRequest, state *internal.State) Traces { return Traces(internal.NewTracesWrapper(orig, state)) } // NewTraces creates a new empty Traces. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewTraces() Traces { return newTraces(internal.NewExportTraceServiceRequest(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms Traces) MoveTo(dest Traces) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteExportTraceServiceRequest(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // ResourceSpans returns the ResourceSpans associated with this Traces. func (ms Traces) ResourceSpans() ResourceSpansSlice { return newResourceSpansSlice(&ms.getOrig().ResourceSpans, ms.getState()) } // CopyTo copies all properties from the current struct overriding the destination. func (ms Traces) CopyTo(dest Traces) { dest.getState().AssertMutable() internal.CopyExportTraceServiceRequest(dest.getOrig(), ms.getOrig()) } func (ms Traces) getOrig() *internal.ExportTraceServiceRequest { return internal.GetTracesOrig(internal.TracesWrapper(ms)) } func (ms Traces) getState() *internal.State { return internal.GetTracesState(internal.TracesWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/ptrace/generated_traces_test.go000066400000000000000000000031111511331344600257660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptrace import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestTraces_MoveTo(t *testing.T) { ms := generateTestTraces() dest := NewTraces() ms.MoveTo(dest) assert.Equal(t, NewTraces(), ms) assert.Equal(t, generateTestTraces(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestTraces(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newTraces(internal.NewExportTraceServiceRequest(), sharedState)) }) assert.Panics(t, func() { newTraces(internal.NewExportTraceServiceRequest(), sharedState).MoveTo(dest) }) } func TestTraces_CopyTo(t *testing.T) { ms := NewTraces() orig := NewTraces() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestTraces() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newTraces(internal.NewExportTraceServiceRequest(), sharedState)) }) } func TestTraces_ResourceSpans(t *testing.T) { ms := NewTraces() assert.Equal(t, NewResourceSpansSlice(), ms.ResourceSpans()) ms.getOrig().ResourceSpans = internal.GenTestResourceSpansPtrSlice() assert.Equal(t, generateTestResourceSpansSlice(), ms.ResourceSpans()) } func generateTestTraces() Traces { return newTraces(internal.GenTestExportTraceServiceRequest(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/json.go000066400000000000000000000022021511331344600224010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" ) // JSONMarshaler marshals Traces to JSON bytes using the OTLP/JSON format. type JSONMarshaler struct{} // MarshalTraces to the OTLP/JSON format. func (*JSONMarshaler) MarshalTraces(td Traces) ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) td.getOrig().MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } // JSONUnmarshaler unmarshals OTLP/JSON formatted-bytes to Traces. type JSONUnmarshaler struct{} // UnmarshalTraces from OTLP/JSON format into Traces. func (*JSONUnmarshaler) UnmarshalTraces(buf []byte) (Traces, error) { iter := json.BorrowIterator(buf) defer json.ReturnIterator(iter) td := NewTraces() td.getOrig().UnmarshalJSON(iter) if iter.Error() != nil { return Traces{}, iter.Error() } otlp.MigrateTraces(td.getOrig().ResourceSpans) return td, nil } opentelemetry-collector-0.141.0/pdata/ptrace/package_test.go000066400000000000000000000003071511331344600240660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/ptrace/pb.go000066400000000000000000000017431511331344600220420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" var _ MarshalSizer = (*ProtoMarshaler)(nil) type ProtoMarshaler struct{} func (e *ProtoMarshaler) MarshalTraces(td Traces) ([]byte, error) { size := td.getOrig().SizeProto() buf := make([]byte, size) _ = td.getOrig().MarshalProto(buf) return buf, nil } func (e *ProtoMarshaler) TracesSize(td Traces) int { return td.getOrig().SizeProto() } func (e *ProtoMarshaler) ResourceSpansSize(td ResourceSpans) int { return td.orig.SizeProto() } func (e *ProtoMarshaler) ScopeSpansSize(td ScopeSpans) int { return td.orig.SizeProto() } func (e *ProtoMarshaler) SpanSize(td Span) int { return td.orig.SizeProto() } type ProtoUnmarshaler struct{} func (d *ProtoUnmarshaler) UnmarshalTraces(buf []byte) (Traces, error) { td := NewTraces() err := td.getOrig().UnmarshalProto(buf) if err != nil { return Traces{}, err } return td, nil } opentelemetry-collector-0.141.0/pdata/ptrace/pb_test.go000066400000000000000000000064201511331344600230760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlptrace "go.opentelemetry.io/proto/slim/otlp/trace/v1" goproto "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestTracesProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Traces as pdata struct. td := generateTestTraces() // Marshal its underlying ProtoBuf to wire. marshaler := &ProtoMarshaler{} wire1, err := marshaler.MarshalTraces(td) require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlptrace.TracesData err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. var td2 Traces unmarshaler := &ProtoUnmarshaler{} td2, err = unmarshaler.UnmarshalTraces(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. assert.Equal(t, td, td2) } func TestProtoTracesUnmarshalerError(t *testing.T) { p := &ProtoUnmarshaler{} _, err := p.UnmarshalTraces([]byte("+$%")) assert.Error(t, err) } func TestProtoSizer(t *testing.T) { marshaler := &ProtoMarshaler{} td := NewTraces() rms := td.ResourceSpans() rms.AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty().SetName("foo") size := marshaler.TracesSize(td) bytes, err := marshaler.MarshalTraces(td) require.NoError(t, err) assert.Equal(t, len(bytes), size) } func TestProtoSizerEmptyTraces(t *testing.T) { sizer := &ProtoMarshaler{} assert.Equal(t, 0, sizer.TracesSize(NewTraces())) } func BenchmarkTracesToProto(b *testing.B) { marshaler := &ProtoMarshaler{} traces := generateBenchmarkTraces(128) for b.Loop() { buf, err := marshaler.MarshalTraces(traces) require.NoError(b, err) assert.NotEmpty(b, buf) } } func BenchmarkTracesFromProto(b *testing.B) { marshaler := &ProtoMarshaler{} unmarshaler := &ProtoUnmarshaler{} baseTraces := generateBenchmarkTraces(128) buf, err := marshaler.MarshalTraces(baseTraces) require.NoError(b, err) assert.NotEmpty(b, buf) b.ReportAllocs() for b.Loop() { traces, err := unmarshaler.UnmarshalTraces(buf) require.NoError(b, err) assert.Equal(b, baseTraces.ResourceSpans().Len(), traces.ResourceSpans().Len()) } } func generateBenchmarkTraces(metricsCount int) Traces { now := time.Now() startTime := pcommon.NewTimestampFromTime(now.Add(-10 * time.Second)) endTime := pcommon.NewTimestampFromTime(now) md := NewTraces() ilm := md.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty() ilm.Spans().EnsureCapacity(metricsCount) for range metricsCount { im := ilm.Spans().AppendEmpty() im.SetName("test_name") im.SetStartTimestamp(startTime) im.SetEndTimestamp(endTime) } return md } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/000077500000000000000000000000001511331344600232625ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/fuzz_test.go000066400000000000000000000050671511331344600256560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp // import "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" import ( "bytes" "testing" "github.com/stretchr/testify/require" ) var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." func FuzzRequestUnmarshalJSON(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportRequest() err := er.UnmarshalJSON(data) if err != nil { return } b1, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") er = NewExportRequest() require.NoError(t, er.UnmarshalJSON(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzResponseUnmarshalJSON(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportResponse() err := er.UnmarshalJSON(data) if err != nil { return } b1, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") er = NewExportResponse() require.NoError(t, er.UnmarshalJSON(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalJSON() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzRequestUnmarshalProto(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportRequest() err := er.UnmarshalProto(data) if err != nil { return } b1, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") er = NewExportRequest() require.NoError(t, er.UnmarshalProto(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } func FuzzResponseUnmarshalProto(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { er := NewExportResponse() err := er.UnmarshalProto(data) if err != nil { return } b1, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") er = NewExportResponse() require.NoError(t, er.UnmarshalProto(b1), "failed to unmarshal valid bytes") b2, err := er.MarshalProto() require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess.go000066400000000000000000000053011511331344600321150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptraceotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportPartialSuccess represents the details of a partially successful export request. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportPartialSuccess function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportPartialSuccess struct { orig *internal.ExportTracePartialSuccess state *internal.State } func newExportPartialSuccess(orig *internal.ExportTracePartialSuccess, state *internal.State) ExportPartialSuccess { return ExportPartialSuccess{orig: orig, state: state} } // NewExportPartialSuccess creates a new empty ExportPartialSuccess. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.NewExportTracePartialSuccess(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportPartialSuccess) MoveTo(dest ExportPartialSuccess) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportTracePartialSuccess(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // RejectedSpans returns the rejectedspans associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) RejectedSpans() int64 { return ms.orig.RejectedSpans } // SetRejectedSpans replaces the rejectedspans associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetRejectedSpans(v int64) { ms.state.AssertMutable() ms.orig.RejectedSpans = v } // ErrorMessage returns the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) ErrorMessage() string { return ms.orig.ErrorMessage } // SetErrorMessage replaces the errormessage associated with this ExportPartialSuccess. func (ms ExportPartialSuccess) SetErrorMessage(v string) { ms.state.AssertMutable() ms.orig.ErrorMessage = v } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportPartialSuccess) CopyTo(dest ExportPartialSuccess) { dest.state.AssertMutable() internal.CopyExportTracePartialSuccess(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/generated_exportpartialsuccess_test.go000066400000000000000000000046011511331344600331560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptraceotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportPartialSuccess_MoveTo(t *testing.T) { ms := generateTestExportPartialSuccess() dest := NewExportPartialSuccess() ms.MoveTo(dest) assert.Equal(t, NewExportPartialSuccess(), ms) assert.Equal(t, generateTestExportPartialSuccess(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportPartialSuccess(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportPartialSuccess(internal.NewExportTracePartialSuccess(), sharedState)) }) assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportTracePartialSuccess(), sharedState).MoveTo(dest) }) } func TestExportPartialSuccess_CopyTo(t *testing.T) { ms := NewExportPartialSuccess() orig := NewExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportPartialSuccess() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportPartialSuccess(internal.NewExportTracePartialSuccess(), sharedState)) }) } func TestExportPartialSuccess_RejectedSpans(t *testing.T) { ms := NewExportPartialSuccess() assert.Equal(t, int64(0), ms.RejectedSpans()) ms.SetRejectedSpans(int64(13)) assert.Equal(t, int64(13), ms.RejectedSpans()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportTracePartialSuccess(), sharedState).SetRejectedSpans(int64(13)) }) } func TestExportPartialSuccess_ErrorMessage(t *testing.T) { ms := NewExportPartialSuccess() assert.Empty(t, ms.ErrorMessage()) ms.SetErrorMessage("test_errormessage") assert.Equal(t, "test_errormessage", ms.ErrorMessage()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newExportPartialSuccess(internal.NewExportTracePartialSuccess(), sharedState).SetErrorMessage("test_errormessage") }) } func generateTestExportPartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(internal.GenTestExportTracePartialSuccess(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/generated_exportresponse.go000066400000000000000000000041111511331344600307240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptraceotlp import ( "go.opentelemetry.io/collector/pdata/internal" ) // ExportResponse represents the response for gRPC/HTTP client/server. // // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewExportResponse function to create new instances. // Important: zero-initialized instance is not valid for use. type ExportResponse struct { orig *internal.ExportTraceServiceResponse state *internal.State } func newExportResponse(orig *internal.ExportTraceServiceResponse, state *internal.State) ExportResponse { return ExportResponse{orig: orig, state: state} } // NewExportResponse creates a new empty ExportResponse. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewExportResponse() ExportResponse { return newExportResponse(internal.NewExportTraceServiceResponse(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms ExportResponse) MoveTo(dest ExportResponse) { ms.state.AssertMutable() dest.state.AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.orig == dest.orig { return } internal.DeleteExportTraceServiceResponse(dest.orig, false) *dest.orig, *ms.orig = *ms.orig, *dest.orig } // PartialSuccess returns the partialsuccess associated with this ExportResponse. func (ms ExportResponse) PartialSuccess() ExportPartialSuccess { return newExportPartialSuccess(&ms.orig.PartialSuccess, ms.state) } // CopyTo copies all properties from the current struct overriding the destination. func (ms ExportResponse) CopyTo(dest ExportResponse) { dest.state.AssertMutable() internal.CopyExportTraceServiceResponse(dest.orig, ms.orig) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/generated_exportresponse_test.go000066400000000000000000000033511511331344600317700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package ptraceotlp import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestExportResponse_MoveTo(t *testing.T) { ms := generateTestExportResponse() dest := NewExportResponse() ms.MoveTo(dest) assert.Equal(t, NewExportResponse(), ms) assert.Equal(t, generateTestExportResponse(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestExportResponse(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newExportResponse(internal.NewExportTraceServiceResponse(), sharedState)) }) assert.Panics(t, func() { newExportResponse(internal.NewExportTraceServiceResponse(), sharedState).MoveTo(dest) }) } func TestExportResponse_CopyTo(t *testing.T) { ms := NewExportResponse() orig := NewExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestExportResponse() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newExportResponse(internal.NewExportTraceServiceResponse(), sharedState)) }) } func TestExportResponse_PartialSuccess(t *testing.T) { ms := NewExportResponse() assert.Equal(t, NewExportPartialSuccess(), ms.PartialSuccess()) ms.orig.PartialSuccess = *internal.GenTestExportTracePartialSuccess() assert.Equal(t, generateTestExportPartialSuccess(), ms.PartialSuccess()) } func generateTestExportResponse() ExportResponse { return newExportResponse(internal.GenTestExportTraceServiceResponse(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/grpc.go000066400000000000000000000060421511331344600245460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp // import "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" import ( "context" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otelgrpc" "go.opentelemetry.io/collector/pdata/internal/otlp" ) // GRPCClient is the client API for OTLP-GRPC Traces service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. type GRPCClient interface { // Export ptrace.Traces to the server. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) // unexported disallow implementation of the GRPCClient. unexported() } // NewGRPCClient returns a new GRPCClient connected using the given connection. func NewGRPCClient(cc *grpc.ClientConn) GRPCClient { return &grpcClient{rawClient: otelgrpc.NewTraceServiceClient(cc)} } type grpcClient struct { rawClient otelgrpc.TraceServiceClient } // Export implements the Client interface. func (c *grpcClient) Export(ctx context.Context, request ExportRequest, opts ...grpc.CallOption) (ExportResponse, error) { rsp, err := c.rawClient.Export(ctx, request.orig, opts...) if err != nil { return ExportResponse{}, err } return ExportResponse{orig: rsp, state: internal.NewState()}, err } func (c *grpcClient) unexported() {} // GRPCServer is the server API for OTLP gRPC TracesService service. // Implementations MUST embed UnimplementedGRPCServer. type GRPCServer interface { // Export is called every time a new request is received. // // For performance reasons, it is recommended to keep this RPC // alive for the entire life of the application. Export(context.Context, ExportRequest) (ExportResponse, error) // unexported disallow implementation of the GRPCServer. unexported() } var _ GRPCServer = (*UnimplementedGRPCServer)(nil) // UnimplementedGRPCServer MUST be embedded to have forward compatible implementations. type UnimplementedGRPCServer struct{} func (*UnimplementedGRPCServer) Export(context.Context, ExportRequest) (ExportResponse, error) { return ExportResponse{}, status.Errorf(codes.Unimplemented, "method Export not implemented") } func (*UnimplementedGRPCServer) unexported() {} // RegisterGRPCServer registers the GRPCServer to the grpc.Server. func RegisterGRPCServer(s *grpc.Server, srv GRPCServer) { otelgrpc.RegisterTraceServiceServer(s, &rawTracesServer{srv: srv}) } type rawTracesServer struct { srv GRPCServer } func (s rawTracesServer) Export(ctx context.Context, request *internal.ExportTraceServiceRequest) (*internal.ExportTraceServiceResponse, error) { otlp.MigrateTraces(request.ResourceSpans) rsp, err := s.srv.Export(ctx, ExportRequest{orig: request, state: internal.NewState()}) return rsp.orig, err } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/grpc_test.go000066400000000000000000000052271511331344600256110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp import ( "context" "errors" "net" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/resolver" "google.golang.org/grpc/status" "google.golang.org/grpc/test/bufconn" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestGrpc(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeTracesServer{t: t}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) resolver.SetDefaultScheme("passthrough") cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateTracesRequest()) require.NoError(t, err) assert.Equal(t, NewExportResponse(), resp) } func TestGrpcError(t *testing.T) { lis := bufconn.Listen(1024 * 1024) s := grpc.NewServer() RegisterGRPCServer(s, &fakeTracesServer{t: t, err: errors.New("my error")}) wg := sync.WaitGroup{} wg.Add(1) go func() { defer wg.Done() assert.NoError(t, s.Serve(lis)) }() t.Cleanup(func() { s.Stop() wg.Wait() }) cc, err := grpc.NewClient("bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { return lis.Dial() }), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, cc.Close()) }) logClient := NewGRPCClient(cc) resp, err := logClient.Export(context.Background(), generateTracesRequest()) require.Error(t, err) st, okSt := status.FromError(err) require.True(t, okSt) assert.Equal(t, "my error", st.Message()) assert.Equal(t, codes.Unknown, st.Code()) assert.Equal(t, ExportResponse{}, resp) } type fakeTracesServer struct { UnimplementedGRPCServer t *testing.T err error } func (f fakeTracesServer) Export(_ context.Context, request ExportRequest) (ExportResponse, error) { assert.Equal(f.t, generateTracesRequest(), request) return NewExportResponse(), f.err } func generateTracesRequest() ExportRequest { td := ptrace.NewTraces() td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty().SetName("test_span") return NewExportRequestFromTraces(td) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/package_test.go000066400000000000000000000003131511331344600262400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/request.go000066400000000000000000000045071511331344600253070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp // import "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/ptrace" ) // ExportRequest represents the request for gRPC/HTTP client/server. // It's a wrapper for ptrace.Traces data. type ExportRequest struct { orig *internal.ExportTraceServiceRequest state *internal.State } // NewExportRequest returns an empty ExportRequest. func NewExportRequest() ExportRequest { return ExportRequest{ orig: &internal.ExportTraceServiceRequest{}, state: internal.NewState(), } } // NewExportRequestFromTraces returns a ExportRequest from ptrace.Traces. // Because ExportRequest is a wrapper for ptrace.Traces, // any changes to the provided Traces struct will be reflected in the ExportRequest and vice versa. func NewExportRequestFromTraces(td ptrace.Traces) ExportRequest { return ExportRequest{ orig: internal.GetTracesOrig(internal.TracesWrapper(td)), state: internal.GetTracesState(internal.TracesWrapper(td)), } } // MarshalProto marshals ExportRequest into proto bytes. func (ms ExportRequest) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportRequest from proto bytes. func (ms ExportRequest) UnmarshalProto(data []byte) error { err := ms.orig.UnmarshalProto(data) if err != nil { return err } otlp.MigrateTraces(ms.orig.ResourceSpans) return nil } // MarshalJSON marshals ExportRequest into JSON bytes. func (ms ExportRequest) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } // UnmarshalJSON unmarshalls ExportRequest from JSON bytes. func (ms ExportRequest) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } func (ms ExportRequest) Traces() ptrace.Traces { return ptrace.Traces(internal.NewTracesWrapper(ms.orig, ms.state)) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/request_test.go000066400000000000000000000053121511331344600263410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp import ( "encoding/json" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" gootlpcollectortrace "go.opentelemetry.io/proto/slim/otlp/collector/trace/v1" goproto "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/otlp" "go.opentelemetry.io/collector/pdata/ptrace" ) var ( _ json.Unmarshaler = ExportRequest{} _ json.Marshaler = ExportRequest{} ) var tracesRequestJSON = []byte(` { "resourceSpans": [ { "resource": {}, "scopeSpans": [ { "scope": {}, "spans": [ { "name": "test_span", "status": {} } ] } ] } ] }`) func TestRequestToPData(t *testing.T) { tr := NewExportRequest() assert.Equal(t, 0, tr.Traces().SpanCount()) tr.Traces().ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() assert.Equal(t, 1, tr.Traces().SpanCount()) } func TestRequestJSON(t *testing.T) { tr := NewExportRequest() require.NoError(t, tr.UnmarshalJSON(tracesRequestJSON)) assert.Equal(t, "test_span", tr.Traces().ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) got, err := tr.MarshalJSON() require.NoError(t, err) assert.Equal(t, strings.Join(strings.Fields(string(tracesRequestJSON)), ""), string(got)) } func TestTracesProtoWireCompatibility(t *testing.T) { // This test verifies that OTLP ProtoBufs generated using goproto lib in // opentelemetry-proto repository OTLP ProtoBufs generated using gogoproto lib in // this repository are wire compatible. // Generate Traces as pdata struct. td := NewExportRequestFromTraces(ptrace.Traces(internal.GenTestTracesWrapper())) // Marshal its underlying ProtoBuf to wire. wire1, err := td.MarshalProto() require.NoError(t, err) assert.NotNil(t, wire1) // Unmarshal from the wire to OTLP Protobuf in goproto's representation. var goprotoMessage gootlpcollectortrace.ExportTraceServiceRequest err = goproto.Unmarshal(wire1, &goprotoMessage) require.NoError(t, err) // Marshal to the wire again. wire2, err := goproto.Marshal(&goprotoMessage) require.NoError(t, err) assert.NotNil(t, wire2) // Unmarshal from the wire into gogoproto's representation. td2 := NewExportRequest() err = td2.UnmarshalProto(wire2) require.NoError(t, err) // Now compare that the original and final ProtoBuf messages are the same. // This proves that goproto and gogoproto marshaling/unmarshaling are wire compatible. // Migration logic will run, so run it on the original message as well. otlp.MigrateTraces(td.orig.ResourceSpans) assert.Equal(t, td, td2) } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/response.go000066400000000000000000000021451511331344600254510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp // import "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" import ( "slices" "go.opentelemetry.io/collector/pdata/internal/json" ) // MarshalProto marshals ExportResponse into proto bytes. func (ms ExportResponse) MarshalProto() ([]byte, error) { size := ms.orig.SizeProto() buf := make([]byte, size) _ = ms.orig.MarshalProto(buf) return buf, nil } // UnmarshalProto unmarshalls ExportResponse from proto bytes. func (ms ExportResponse) UnmarshalProto(data []byte) error { return ms.orig.UnmarshalProto(data) } // MarshalJSON marshals ExportResponse into JSON bytes. func (ms ExportResponse) MarshalJSON() ([]byte, error) { dest := json.BorrowStream(nil) defer json.ReturnStream(dest) ms.orig.MarshalJSON(dest) return slices.Clone(dest.Buffer()), dest.Error() } // UnmarshalJSON unmarshalls ExportResponse from JSON bytes. func (ms ExportResponse) UnmarshalJSON(data []byte) error { iter := json.BorrowIterator(data) defer json.ReturnIterator(iter) ms.orig.UnmarshalJSON(iter) return iter.Error() } opentelemetry-collector-0.141.0/pdata/ptrace/ptraceotlp/response_test.go000066400000000000000000000020121511331344600265010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptraceotlp import ( stdjson "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) var ( _ stdjson.Unmarshaler = ExportResponse{} _ stdjson.Marshaler = ExportResponse{} ) func TestExportResponseJSON(t *testing.T) { jsonStr := `{"partialSuccess": {"rejectedSpans":"1", "errorMessage":"nothing"}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) expected := NewExportResponse() expected.PartialSuccess().SetRejectedSpans(1) expected.PartialSuccess().SetErrorMessage("nothing") assert.Equal(t, expected, val) buf, err := val.MarshalJSON() require.NoError(t, err) assert.JSONEq(t, jsonStr, string(buf)) } func TestUnmarshalJSONExportResponse(t *testing.T) { jsonStr := `{"extra":"", "partialSuccess": {"extra":""}}` val := NewExportResponse() require.NoError(t, val.UnmarshalJSON([]byte(jsonStr))) assert.Equal(t, NewExportResponse(), val) } opentelemetry-collector-0.141.0/pdata/ptrace/span_kind.go000066400000000000000000000043101511331344600234000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" import ( "go.opentelemetry.io/collector/pdata/internal" ) // SpanKind is the type of span. Can be used to specify additional relationships between spans // in addition to a parent/child relationship. type SpanKind int32 const ( // SpanKindUnspecified represents that the SpanKind is unspecified, it MUST NOT be used. SpanKindUnspecified = SpanKind(internal.SpanKind_SPAN_KIND_UNSPECIFIED) // SpanKindInternal indicates that the span represents an internal operation within an application, // as opposed to an operation happening at the boundaries. Default value. SpanKindInternal = SpanKind(internal.SpanKind_SPAN_KIND_INTERNAL) // SpanKindServer indicates that the span covers server-side handling of an RPC or other // remote network request. SpanKindServer = SpanKind(internal.SpanKind_SPAN_KIND_SERVER) // SpanKindClient indicates that the span describes a request to some remote service. SpanKindClient = SpanKind(internal.SpanKind_SPAN_KIND_CLIENT) // SpanKindProducer indicates that the span describes a producer sending a message to a broker. // Unlike CLIENT and SERVER, there is often no direct critical path latency relationship // between producer and consumer spans. // A PRODUCER span ends when the message was accepted by the broker while the logical processing of // the message might span a much longer time. SpanKindProducer = SpanKind(internal.SpanKind_SPAN_KIND_PRODUCER) // SpanKindConsumer indicates that the span describes consumer receiving a message from a broker. // Like the PRODUCER kind, there is often no direct critical path latency relationship between // producer and consumer spans. SpanKindConsumer = SpanKind(internal.SpanKind_SPAN_KIND_CONSUMER) ) // String returns the string representation of the SpanKind. func (sk SpanKind) String() string { switch sk { case SpanKindUnspecified: return "Unspecified" case SpanKindInternal: return "Internal" case SpanKindServer: return "Server" case SpanKindClient: return "Client" case SpanKindProducer: return "Producer" case SpanKindConsumer: return "Consumer" } return "" } opentelemetry-collector-0.141.0/pdata/ptrace/span_kind_test.go000066400000000000000000000011651511331344600244440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" import ( "testing" "github.com/stretchr/testify/assert" ) func TestSpanKindString(t *testing.T) { assert.Equal(t, "Unspecified", SpanKindUnspecified.String()) assert.Equal(t, "Internal", SpanKindInternal.String()) assert.Equal(t, "Server", SpanKindServer.String()) assert.Equal(t, "Client", SpanKindClient.String()) assert.Equal(t, "Producer", SpanKindProducer.String()) assert.Equal(t, "Consumer", SpanKindConsumer.String()) assert.Empty(t, SpanKind(100).String()) } opentelemetry-collector-0.141.0/pdata/ptrace/status_code.go000066400000000000000000000015211511331344600237500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" import ( "go.opentelemetry.io/collector/pdata/internal" ) // StatusCode mirrors the codes defined at // https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/trace/api.md#set-status type StatusCode int32 const ( StatusCodeUnset = StatusCode(internal.StatusCode_STATUS_CODE_UNSET) StatusCodeOk = StatusCode(internal.StatusCode_STATUS_CODE_OK) StatusCodeError = StatusCode(internal.StatusCode_STATUS_CODE_ERROR) ) // String returns the string representation of the StatusCode. func (sc StatusCode) String() string { switch sc { case StatusCodeUnset: return "Unset" case StatusCodeOk: return "Ok" case StatusCodeError: return "Error" } return "" } opentelemetry-collector-0.141.0/pdata/ptrace/status_code_test.go000066400000000000000000000007011511331344600250060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" import ( "testing" "github.com/stretchr/testify/assert" ) func TestStatusCodeString(t *testing.T) { assert.Equal(t, "Unset", StatusCodeUnset.String()) assert.Equal(t, "Ok", StatusCodeOk.String()) assert.Equal(t, "Error", StatusCodeError.String()) assert.Empty(t, StatusCode(100).String()) } opentelemetry-collector-0.141.0/pdata/ptrace/traces.go000066400000000000000000000013731511331344600227210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace // import "go.opentelemetry.io/collector/pdata/ptrace" // MarkReadOnly marks the Traces as shared so that no further modifications can be done on it. func (ms Traces) MarkReadOnly() { ms.getState().MarkReadOnly() } // IsReadOnly returns true if this Traces instance is read-only. func (ms Traces) IsReadOnly() bool { return ms.getState().IsReadOnly() } // SpanCount calculates the total number of spans. func (ms Traces) SpanCount() int { spanCount := 0 rss := ms.ResourceSpans() for i := 0; i < rss.Len(); i++ { rs := rss.At(i) ilss := rs.ScopeSpans() for j := 0; j < ilss.Len(); j++ { spanCount += ilss.At(j).Spans().Len() } } return spanCount } opentelemetry-collector-0.141.0/pdata/ptrace/traces_test.go000066400000000000000000000100031511331344600237460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package ptrace import ( "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestSpanCount(t *testing.T) { traces := NewTraces() assert.Equal(t, 0, traces.SpanCount()) rs := traces.ResourceSpans().AppendEmpty() assert.Equal(t, 0, traces.SpanCount()) ils := rs.ScopeSpans().AppendEmpty() assert.Equal(t, 0, traces.SpanCount()) ils.Spans().AppendEmpty() assert.Equal(t, 1, traces.SpanCount()) rms := traces.ResourceSpans() rms.EnsureCapacity(3) rms.AppendEmpty().ScopeSpans().AppendEmpty() ilss := rms.AppendEmpty().ScopeSpans().AppendEmpty().Spans() for range 5 { ilss.AppendEmpty() } // 5 + 1 (from rms.At(0) initialized first) assert.Equal(t, 6, traces.SpanCount()) } func TestSpanCountWithEmpty(t *testing.T) { assert.Equal(t, 0, newTraces(&internal.ExportTraceServiceRequest{ ResourceSpans: []*internal.ResourceSpans{{}}, }, new(internal.State)).SpanCount()) assert.Equal(t, 0, newTraces(&internal.ExportTraceServiceRequest{ ResourceSpans: []*internal.ResourceSpans{ { ScopeSpans: []*internal.ScopeSpans{{}}, }, }, }, new(internal.State)).SpanCount()) assert.Equal(t, 1, newTraces(&internal.ExportTraceServiceRequest{ ResourceSpans: []*internal.ResourceSpans{ { ScopeSpans: []*internal.ScopeSpans{ { Spans: []*internal.Span{{}}, }, }, }, }, }, new(internal.State)).SpanCount()) } func TestTracesCopyTo(t *testing.T) { td := generateTestTraces() tracesCopy := NewTraces() td.CopyTo(tracesCopy) assert.Equal(t, td, tracesCopy) } func TestReadOnlyTracesInvalidUsage(t *testing.T) { td := NewTraces() assert.False(t, td.IsReadOnly()) res := td.ResourceSpans().AppendEmpty().Resource() res.Attributes().PutStr("k1", "v1") td.MarkReadOnly() assert.True(t, td.IsReadOnly()) assert.Panics(t, func() { res.Attributes().PutStr("k2", "v2") }) } func BenchmarkTracesUsage(b *testing.B) { td := generateTestTraces() ts := pcommon.NewTimestampFromTime(time.Now()) b.ReportAllocs() for b.Loop() { for i := 0; i < td.ResourceSpans().Len(); i++ { rs := td.ResourceSpans().At(i) res := rs.Resource() res.Attributes().PutStr("foo", "bar") v, ok := res.Attributes().Get("foo") assert.True(b, ok) assert.Equal(b, "bar", v.Str()) v.SetStr("new-bar") assert.Equal(b, "new-bar", v.Str()) res.Attributes().Remove("foo") for j := 0; j < rs.ScopeSpans().Len(); j++ { iss := rs.ScopeSpans().At(j) iss.Scope().SetName("new_test_name") assert.Equal(b, "new_test_name", iss.Scope().Name()) for k := 0; k < iss.Spans().Len(); k++ { s := iss.Spans().At(k) s.SetName("new_span") assert.Equal(b, "new_span", s.Name()) s.SetStartTimestamp(ts) assert.Equal(b, ts, s.StartTimestamp()) s.SetEndTimestamp(ts) assert.Equal(b, ts, s.EndTimestamp()) s.SetTraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) assert.Equal(b, pcommon.TraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}), s.TraceID()) s.SetSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) assert.Equal(b, pcommon.SpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}), s.SpanID()) } s := iss.Spans().AppendEmpty() s.SetName("another_span") s.SetStartTimestamp(ts) s.SetEndTimestamp(ts) s.SetTraceID([16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}) s.SetParentSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) s.SetSpanID([8]byte{1, 2, 3, 4, 5, 6, 7, 8}) s.Attributes().PutStr("foo1", "bar1") s.Attributes().PutStr("foo2", "bar2") iss.Spans().RemoveIf(func(lr Span) bool { return lr.Name() == "another_span" }) } } } } func BenchmarkTracesMarshalJSON(b *testing.B) { td := generateTestTraces() encoder := &JSONMarshaler{} b.ReportAllocs() for b.Loop() { jsonBuf, err := encoder.MarshalTraces(td) require.NoError(b, err) require.NotNil(b, jsonBuf) } } opentelemetry-collector-0.141.0/pdata/testdata/000077500000000000000000000000001511331344600214405ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/testdata/Makefile000066400000000000000000000000361511331344600230770ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/pdata/testdata/common.go000066400000000000000000000012611511331344600232570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testdata import ( "go.opentelemetry.io/collector/pdata/pcommon" ) func initMetricExemplarAttributes(dest pcommon.Map) { dest.PutStr("exemplar-attachment", "exemplar-attachment-value") } func initMetricAttributes1(dest pcommon.Map) { dest.PutStr("label-1", "label-value-1") } func initMetricAttributes2(dest pcommon.Map) { dest.PutStr("label-2", "label-value-2") } func initMetricAttributes12(dest pcommon.Map) { initMetricAttributes1(dest) initMetricAttributes2(dest) } func initMetricAttributes13(dest pcommon.Map) { initMetricAttributes1(dest) dest.PutStr("label-3", "label-value-3") } opentelemetry-collector-0.141.0/pdata/testdata/go.mod000066400000000000000000000015001511331344600225420ustar00rootroot00000000000000module go.opentelemetry.io/collector/pdata/testdata go 1.24.0 require ( go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 ) require ( github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.uber.org/multierr v1.11.0 // indirect ) replace go.opentelemetry.io/collector/pdata => ../ replace go.opentelemetry.io/collector/pdata/pprofile => ../pprofile replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/pdata/testdata/go.sum000066400000000000000000000062511511331344600225770ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/pdata/testdata/log.go000066400000000000000000000026061511331344600225540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testdata import ( "time" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" ) var logTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC)) func GenerateLogs(count int) plog.Logs { ld := plog.NewLogs() initResource(ld.ResourceLogs().AppendEmpty().Resource()) logs := ld.ResourceLogs().At(0).ScopeLogs().AppendEmpty().LogRecords() logs.EnsureCapacity(count) for i := range count { switch i % 2 { case 0: fillLogOne(logs.AppendEmpty()) case 1: fillLogTwo(logs.AppendEmpty()) } } return ld } func fillLogOne(log plog.LogRecord) { log.SetTimestamp(logTimestamp) log.SetDroppedAttributesCount(1) log.SetSeverityNumber(plog.SeverityNumberInfo) log.SetSeverityText("Info") log.SetSpanID([8]byte{0x01, 0x02, 0x04, 0x08}) log.SetTraceID([16]byte{0x08, 0x04, 0x02, 0x01}) attrs := log.Attributes() attrs.PutStr("app", "server") attrs.PutInt("instance_num", 1) log.Body().SetStr("This is a log message") } func fillLogTwo(log plog.LogRecord) { log.SetTimestamp(logTimestamp) log.SetDroppedAttributesCount(1) log.SetSeverityNumber(plog.SeverityNumberInfo) log.SetSeverityText("Info") attrs := log.Attributes() attrs.PutStr("customer", "acme") attrs.PutStr("env", "dev") log.Body().SetStr("something happened") } opentelemetry-collector-0.141.0/pdata/testdata/metric.go000066400000000000000000000231371511331344600232600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testdata import ( "time" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pmetric" ) var ( metricStartTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 12, 321, time.UTC)) metricExemplarTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 123, time.UTC)) metricTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC)) ) const ( TestGaugeDoubleMetricName = "gauge-double" TestGaugeIntMetricName = "gauge-int" TestSumDoubleMetricName = "sum-double" TestSumIntMetricName = "sum-int" TestHistogramMetricName = "histogram" TestExponentialHistogramMetricName = "exponential-histogram" TestSummaryMetricName = "summary" ) func generateMetricsOneEmptyInstrumentationScope() pmetric.Metrics { md := pmetric.NewMetrics() initResource(md.ResourceMetrics().AppendEmpty().Resource()) md.ResourceMetrics().At(0).ScopeMetrics().AppendEmpty() return md } func GenerateMetricsAllTypesEmpty() pmetric.Metrics { md := generateMetricsOneEmptyInstrumentationScope() ms := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() doubleGauge := ms.AppendEmpty() initMetric(doubleGauge, TestGaugeDoubleMetricName, pmetric.MetricTypeGauge) doubleGauge.Gauge().DataPoints().AppendEmpty() intGauge := ms.AppendEmpty() initMetric(intGauge, TestGaugeIntMetricName, pmetric.MetricTypeGauge) intGauge.Gauge().DataPoints().AppendEmpty() doubleSum := ms.AppendEmpty() initMetric(doubleSum, TestSumDoubleMetricName, pmetric.MetricTypeSum) doubleSum.Sum().DataPoints().AppendEmpty() intSum := ms.AppendEmpty() initMetric(intSum, TestSumIntMetricName, pmetric.MetricTypeSum) intSum.Sum().DataPoints().AppendEmpty() histogram := ms.AppendEmpty() initMetric(histogram, TestHistogramMetricName, pmetric.MetricTypeHistogram) histogram.Histogram().DataPoints().AppendEmpty() summary := ms.AppendEmpty() initMetric(summary, TestSummaryMetricName, pmetric.MetricTypeSummary) summary.Summary().DataPoints().AppendEmpty() return md } func GenerateMetricsMetricTypeInvalid() pmetric.Metrics { md := generateMetricsOneEmptyInstrumentationScope() initMetric(md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().AppendEmpty(), TestSumIntMetricName, pmetric.MetricTypeEmpty) return md } func GenerateMetricsAllTypes() pmetric.Metrics { md := generateMetricsOneEmptyInstrumentationScope() ms := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() initGaugeIntMetric(ms.AppendEmpty()) initGaugeDoubleMetric(ms.AppendEmpty()) initSumIntMetric(ms.AppendEmpty()) initSumDoubleMetric(ms.AppendEmpty()) initHistogramMetric(ms.AppendEmpty()) initExponentialHistogramMetric(ms.AppendEmpty()) initSummaryMetric(ms.AppendEmpty()) return md } func GenerateMetrics(count int) pmetric.Metrics { md := generateMetricsOneEmptyInstrumentationScope() ms := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() ms.EnsureCapacity(count) for i := range count { switch i % 7 { case 0: initGaugeIntMetric(ms.AppendEmpty()) case 1: initGaugeDoubleMetric(ms.AppendEmpty()) case 2: initSumIntMetric(ms.AppendEmpty()) case 3: initSumDoubleMetric(ms.AppendEmpty()) case 4: initHistogramMetric(ms.AppendEmpty()) case 5: initExponentialHistogramMetric(ms.AppendEmpty()) case 6: initSummaryMetric(ms.AppendEmpty()) } } return md } func initGaugeIntMetric(im pmetric.Metric) { initMetric(im, TestGaugeIntMetricName, pmetric.MetricTypeGauge) idps := im.Gauge().DataPoints() idp0 := idps.AppendEmpty() initMetricAttributes1(idp0.Attributes()) idp0.SetStartTimestamp(metricStartTimestamp) idp0.SetTimestamp(metricTimestamp) idp0.SetIntValue(123) idp1 := idps.AppendEmpty() initMetricAttributes2(idp1.Attributes()) idp1.SetStartTimestamp(metricStartTimestamp) idp1.SetTimestamp(metricTimestamp) idp1.SetIntValue(456) } func initGaugeDoubleMetric(im pmetric.Metric) { initMetric(im, TestGaugeDoubleMetricName, pmetric.MetricTypeGauge) idps := im.Gauge().DataPoints() idp0 := idps.AppendEmpty() initMetricAttributes12(idp0.Attributes()) idp0.SetStartTimestamp(metricStartTimestamp) idp0.SetTimestamp(metricTimestamp) idp0.SetDoubleValue(1.23) idp1 := idps.AppendEmpty() initMetricAttributes13(idp1.Attributes()) idp1.SetStartTimestamp(metricStartTimestamp) idp1.SetTimestamp(metricTimestamp) idp1.SetDoubleValue(4.56) } func initSumIntMetric(im pmetric.Metric) { initMetric(im, TestSumIntMetricName, pmetric.MetricTypeSum) idps := im.Sum().DataPoints() idp0 := idps.AppendEmpty() initMetricAttributes1(idp0.Attributes()) idp0.SetStartTimestamp(metricStartTimestamp) idp0.SetTimestamp(metricTimestamp) idp0.SetIntValue(123) idp1 := idps.AppendEmpty() initMetricAttributes2(idp1.Attributes()) idp1.SetStartTimestamp(metricStartTimestamp) idp1.SetTimestamp(metricTimestamp) idp1.SetIntValue(456) } func initSumDoubleMetric(dm pmetric.Metric) { initMetric(dm, TestSumDoubleMetricName, pmetric.MetricTypeSum) ddps := dm.Sum().DataPoints() ddp0 := ddps.AppendEmpty() initMetricAttributes12(ddp0.Attributes()) ddp0.SetStartTimestamp(metricStartTimestamp) ddp0.SetTimestamp(metricTimestamp) ddp0.SetDoubleValue(1.23) ddp1 := ddps.AppendEmpty() initMetricAttributes13(ddp1.Attributes()) ddp1.SetStartTimestamp(metricStartTimestamp) ddp1.SetTimestamp(metricTimestamp) ddp1.SetDoubleValue(4.56) } func initHistogramMetric(hm pmetric.Metric) { initMetric(hm, TestHistogramMetricName, pmetric.MetricTypeHistogram) hdps := hm.Histogram().DataPoints() hdp0 := hdps.AppendEmpty() initMetricAttributes13(hdp0.Attributes()) hdp0.SetStartTimestamp(metricStartTimestamp) hdp0.SetTimestamp(metricTimestamp) hdp0.SetCount(1) hdp0.SetSum(15) hdp1 := hdps.AppendEmpty() initMetricAttributes2(hdp1.Attributes()) hdp1.SetStartTimestamp(metricStartTimestamp) hdp1.SetTimestamp(metricTimestamp) hdp1.SetCount(1) hdp1.SetSum(15) hdp1.SetMin(15) hdp1.SetMax(15) hdp1.BucketCounts().FromRaw([]uint64{0, 1}) exemplar := hdp1.Exemplars().AppendEmpty() exemplar.SetTraceID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) exemplar.SetSpanID([8]byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) exemplar.SetTimestamp(metricExemplarTimestamp) exemplar.SetDoubleValue(15) initMetricExemplarAttributes(exemplar.FilteredAttributes()) hdp1.ExplicitBounds().FromRaw([]float64{1}) } func initExponentialHistogramMetric(hm pmetric.Metric) { initMetric(hm, TestExponentialHistogramMetricName, pmetric.MetricTypeExponentialHistogram) hdps := hm.ExponentialHistogram().DataPoints() hdp0 := hdps.AppendEmpty() initMetricAttributes13(hdp0.Attributes()) hdp0.SetStartTimestamp(metricStartTimestamp) hdp0.SetTimestamp(metricTimestamp) hdp0.SetCount(5) hdp0.SetSum(0.15) hdp0.SetZeroCount(1) hdp0.SetScale(1) // positive index 1 and 2 are values sqrt(2), 2 at scale 1 hdp0.Positive().SetOffset(1) hdp0.Positive().BucketCounts().FromRaw([]uint64{1, 1}) // negative index -1 and 0 are values -1/sqrt(2), -1 at scale 1 hdp0.Negative().SetOffset(-1) hdp0.Negative().BucketCounts().FromRaw([]uint64{1, 1}) // The above will print: // Bucket (-1.414214, -1.000000], Count: 1 // Bucket (-1.000000, -0.707107], Count: 1 // Bucket [0, 0], Count: 1 // Bucket [0.707107, 1.000000), Count: 1 // Bucket [1.000000, 1.414214), Count: 1 hdp1 := hdps.AppendEmpty() initMetricAttributes2(hdp1.Attributes()) hdp1.SetStartTimestamp(metricStartTimestamp) hdp1.SetTimestamp(metricTimestamp) hdp1.SetCount(3) hdp1.SetSum(1.25) hdp1.SetMin(0) hdp1.SetMax(1) hdp1.SetZeroCount(1) hdp1.SetScale(-1) // index -1 and 0 are values 0.25, 1 at scale -1 hdp1.Positive().SetOffset(-1) hdp1.Positive().BucketCounts().FromRaw([]uint64{1, 1}) // The above will print: // Bucket [0, 0], Count: 1 // Bucket [0.250000, 1.000000), Count: 1 // Bucket [1.000000, 4.000000), Count: 1 exemplar := hdp1.Exemplars().AppendEmpty() exemplar.SetTraceID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) exemplar.SetSpanID([8]byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) exemplar.SetTimestamp(metricExemplarTimestamp) exemplar.SetIntValue(15) initMetricExemplarAttributes(exemplar.FilteredAttributes()) } func initSummaryMetric(sm pmetric.Metric) { initMetric(sm, TestSummaryMetricName, pmetric.MetricTypeSummary) sdps := sm.Summary().DataPoints() sdp0 := sdps.AppendEmpty() initMetricAttributes13(sdp0.Attributes()) sdp0.SetStartTimestamp(metricStartTimestamp) sdp0.SetTimestamp(metricTimestamp) sdp0.SetCount(1) sdp0.SetSum(15) sdp1 := sdps.AppendEmpty() initMetricAttributes2(sdp1.Attributes()) sdp1.SetStartTimestamp(metricStartTimestamp) sdp1.SetTimestamp(metricTimestamp) sdp1.SetCount(1) sdp1.SetSum(15) quantile := sdp1.QuantileValues().AppendEmpty() quantile.SetQuantile(0.01) quantile.SetValue(15) } func initMetric(m pmetric.Metric, name string, ty pmetric.MetricType) { m.SetName(name) m.SetDescription("") m.SetUnit("1") switch ty { case pmetric.MetricTypeGauge: m.SetEmptyGauge() case pmetric.MetricTypeSum: sum := m.SetEmptySum() sum.SetIsMonotonic(true) sum.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) case pmetric.MetricTypeHistogram: histo := m.SetEmptyHistogram() histo.SetAggregationTemporality(pmetric.AggregationTemporalityCumulative) case pmetric.MetricTypeExponentialHistogram: histo := m.SetEmptyExponentialHistogram() histo.SetAggregationTemporality(pmetric.AggregationTemporalityDelta) case pmetric.MetricTypeSummary: m.SetEmptySummary() } } opentelemetry-collector-0.141.0/pdata/testdata/profile.go000066400000000000000000000046351511331344600234370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testdata // import "go.opentelemetry.io/collector/pdata/testdata" import ( "time" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/pprofile" ) var profileStartTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 12, 321, time.UTC)) // GenerateProfiles generates dummy profiling data for tests func GenerateProfiles(profilesCount int) pprofile.Profiles { td := pprofile.NewProfiles() initResource(td.ResourceProfiles().AppendEmpty().Resource()) ss := td.ResourceProfiles().At(0).ScopeProfiles().AppendEmpty().Profiles() dic := td.Dictionary() dic.StringTable().Append("") dic.StringTable().Append("key") attr := dic.AttributeTable().AppendEmpty() attr.SetKeyStrindex(1) attr.Value().SetStr("value") attr2 := dic.AttributeTable().AppendEmpty() attr.SetKeyStrindex(1) attr2.Value().SetStr("value") ss.EnsureCapacity(profilesCount) for i := range profilesCount { switch i % 2 { case 0: fillProfileOne(dic, ss.AppendEmpty()) case 1: fillProfileTwo(dic, ss.AppendEmpty()) } } return td } func fillProfileOne(dic pprofile.ProfilesDictionary, profile pprofile.Profile) { profile.SetProfileID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) profile.SetTime(profileStartTimestamp) profile.SetDurationNano(uint64(time.Second.Nanoseconds())) profile.SetDroppedAttributesCount(1) loc := pprofile.NewLocation() loc.SetAddress(1) id, _ := pprofile.SetLocation(dic.LocationTable(), loc) stack := dic.StackTable().AppendEmpty() stack.LocationIndices().Append(id) sample := profile.Samples().AppendEmpty() sample.SetStackIndex(1) sample.Values().Append(4) sample.AttributeIndices().Append(0) } func fillProfileTwo(dic pprofile.ProfilesDictionary, profile pprofile.Profile) { profile.SetProfileID([16]byte{0x02, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) profile.SetTime(profileStartTimestamp) profile.SetDurationNano(uint64(time.Second.Nanoseconds())) loc := pprofile.NewLocation() loc.SetAddress(2) id, _ := pprofile.SetLocation(dic.LocationTable(), loc) stack := dic.StackTable().AppendEmpty() stack.LocationIndices().Append(id) sample := profile.Samples().AppendEmpty() sample.SetStackIndex(1) sample.Values().Append(9) sample.AttributeIndices().Append(0) } opentelemetry-collector-0.141.0/pdata/testdata/resource.go000066400000000000000000000004001511331344600236100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testdata import "go.opentelemetry.io/collector/pdata/pcommon" func initResource(r pcommon.Resource) { r.Attributes().PutStr("resource-attr", "resource-attr-val-1") } opentelemetry-collector-0.141.0/pdata/testdata/trace.go000066400000000000000000000042511511331344600230670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testdata import ( "time" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" ) var ( spanStartTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 12, 321, time.UTC)) spanEventTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 123, time.UTC)) spanEndTimestamp = pcommon.NewTimestampFromTime(time.Date(2020, 2, 11, 20, 26, 13, 789, time.UTC)) ) func GenerateTraces(spanCount int) ptrace.Traces { td := ptrace.NewTraces() initResource(td.ResourceSpans().AppendEmpty().Resource()) ss := td.ResourceSpans().At(0).ScopeSpans().AppendEmpty().Spans() ss.EnsureCapacity(spanCount) for i := range spanCount { switch i % 2 { case 0: fillSpanOne(ss.AppendEmpty()) case 1: fillSpanTwo(ss.AppendEmpty()) } } return td } func fillSpanOne(span ptrace.Span) { span.SetName("operationA") span.SetStartTimestamp(spanStartTimestamp) span.SetEndTimestamp(spanEndTimestamp) span.SetDroppedAttributesCount(1) span.TraceState().FromRaw("ot=th:0") // 100% sampling span.SetTraceID([16]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10}) span.SetSpanID([8]byte{0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18}) evs := span.Events() ev0 := evs.AppendEmpty() ev0.SetTimestamp(spanEventTimestamp) ev0.SetName("event-with-attr") ev0.Attributes().PutStr("span-event-attr", "span-event-attr-val") ev0.SetDroppedAttributesCount(2) ev1 := evs.AppendEmpty() ev1.SetTimestamp(spanEventTimestamp) ev1.SetName("event") ev1.SetDroppedAttributesCount(2) span.SetDroppedEventsCount(1) status := span.Status() status.SetCode(ptrace.StatusCodeError) status.SetMessage("status-cancelled") } func fillSpanTwo(span ptrace.Span) { span.SetName("operationB") span.SetStartTimestamp(spanStartTimestamp) span.SetEndTimestamp(spanEndTimestamp) link0 := span.Links().AppendEmpty() link0.Attributes().PutStr("span-link-attr", "span-link-attr-val") link0.SetDroppedAttributesCount(4) link1 := span.Links().AppendEmpty() link1.SetDroppedAttributesCount(4) span.SetDroppedLinksCount(3) } opentelemetry-collector-0.141.0/pdata/xpdata/000077500000000000000000000000001511331344600211105ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/xpdata/Makefile000066400000000000000000000000361511331344600225470ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/pdata/xpdata/entity/000077500000000000000000000000001511331344600224245ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/xpdata/entity/entity.go000066400000000000000000000025201511331344600242660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity // import "go.opentelemetry.io/collector/pdata/xpdata/entity" import ( "go.opentelemetry.io/collector/pdata/pcommon" ) // Entity is a helper struct that represents an entity in a more user-friendly way than the underlying // EntityRef protobuf message. After adding an entity to a resource, the entity shares the resource's // attributes map, so modifications to the entity's attributes are immediately reflected in the resource. // To create an Entity, use the EntityMap's PutEmpty method. type Entity struct { ref EntityRef attributes pcommon.Map } func (e Entity) Type() string { return e.ref.Type() } func (e Entity) SchemaURL() string { return e.ref.SchemaUrl() } func (e Entity) SetSchemaURL(schemaURL string) { e.ref.SetSchemaUrl(schemaURL) } // IDAttributes returns an EntityAttributeMap for managing the entity's id attributes. func (e Entity) IDAttributes() EntityAttributeMap { return EntityAttributeMap{ keys: e.ref.IdKeys(), attributes: e.attributes, } } // DescriptionAttributes returns an EntityAttributeMap for managing the entity's description attributes. func (e Entity) DescriptionAttributes() EntityAttributeMap { return EntityAttributeMap{ keys: e.ref.DescriptionKeys(), attributes: e.attributes, } } opentelemetry-collector-0.141.0/pdata/xpdata/entity/entity_attribute_map.go000066400000000000000000000067021511331344600272140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity // import "go.opentelemetry.io/collector/pdata/xpdata/entity" import "go.opentelemetry.io/collector/pdata/pcommon" // EntityAttributeMap is a wrapper around pcommon.Map that restricts operations to only the keys // that belong to a specific set of entity attributes (either ID or Description attributes). type EntityAttributeMap struct { keys pcommon.StringSlice attributes pcommon.Map } // Get returns the Value associated with the key and true. Returned // Value is not a copy, it is a reference to the value stored in this map. It is // allowed to modify the returned value using Value.Set* functions. // // If the key does not exist in the entity's key list or in the underlying map, // returns an invalid instance and false. Calling any functions on the returned // invalid instance will cause a panic. func (m EntityAttributeMap) Get(key string) (pcommon.Value, bool) { if !m.containsKey(key) { return pcommon.Value{}, false } return m.attributes.Get(key) } // CanPut returns true if it's safe to call Put methods on the given key. // Returns true if: // - The key is already owned by this entity (in the entity's key list), OR // - The key doesn't exist in the shared attributes map (available to claim) // // Returns false if the key exists in the shared map but belongs to another entity. // // Use this method before calling Put* methods to avoid conflicts: // // if entity.IDAttributes().CanPut("service.name") { // entity.IDAttributes().PutStr("service.name", "my-service") // } func (m EntityAttributeMap) CanPut(key string) bool { if m.containsKey(key) { return true } _, exists := m.attributes.Get(key) return !exists } // PutEmpty inserts or updates an empty value to the map under given key // and returns the updated/inserted value. // The key is also added to the entity's key list if not already present. // // WARNING: This method is destructive and will overwrite any existing value in the shared // attributes map, even if it belongs to another entity. Use CanPut() to check safety first // if you need to avoid conflicts with other entities. func (m EntityAttributeMap) PutEmpty(k string) pcommon.Value { if !m.containsKey(k) { m.keys.Append(k) } return m.attributes.PutEmpty(k) } // PutStr performs the Insert or Update action. The Value is // inserted to the map that did not originally have the key. The key/value is // updated to the map where the key already existed. // The key is also added to the entity's key list if not already present. // // WARNING: This method is destructive and will overwrite any existing value in the shared // attributes map, even if it belongs to another entity. Use CanPut() to check safety first // if you need to avoid conflicts with other entities. func (m EntityAttributeMap) PutStr(k, v string) { if !m.containsKey(k) { m.keys.Append(k) } m.attributes.PutStr(k, v) } // Remove removes the entry associated with the key and returns true if the key existed. // The key is also removed from the entity's key list. func (m EntityAttributeMap) Remove(key string) bool { var keyFound bool m.keys.RemoveIf(func(k string) bool { if k == key { keyFound = true return true } return false }) if !keyFound { return false } m.attributes.Remove(key) return true } func (m EntityAttributeMap) containsKey(key string) bool { for _, k := range m.keys.All() { if k == key { return true } } return false } opentelemetry-collector-0.141.0/pdata/xpdata/entity/entity_attribute_map_test.go000066400000000000000000000073011511331344600302470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestEntityAttributeMap(t *testing.T) { m := newTestEntityAttributeMap() val, ok := m.Get("non-existent") assert.False(t, ok) assert.Equal(t, pcommon.Value{}, val) m.PutStr("k1", "v1") val, ok = m.Get("k1") assert.True(t, ok) assert.Equal(t, "v1", val.Str()) assert.True(t, m.Remove("k1")) _, ok = m.Get("k1") assert.False(t, ok) assert.False(t, m.Remove("non-existent")) } func TestEntityAttributeMap_Get(t *testing.T) { m := newTestEntityAttributeMap() m.attributes.PutStr("owned", "value1") m.attributes.PutStr("not-owned", "value2") m.keys.Append("owned") val, ok := m.Get("owned") assert.True(t, ok) assert.Equal(t, "value1", val.Str()) _, ok = m.Get("not-owned") assert.False(t, ok) _, ok = m.Get("non-existent") assert.False(t, ok) } func TestEntityAttributeMap_PutStr(t *testing.T) { m := newTestEntityAttributeMap() m.PutStr("k1", "v1") assert.Equal(t, 1, m.keys.Len()) assert.Equal(t, "k1", m.keys.At(0)) val, ok := m.attributes.Get("k1") assert.True(t, ok) assert.Equal(t, "v1", val.Str()) m.PutStr("k1", "v2") assert.Equal(t, 1, m.keys.Len()) val, ok = m.attributes.Get("k1") assert.True(t, ok) assert.Equal(t, "v2", val.Str()) } func TestEntityAttributeMap_PutStr_Overwrites(t *testing.T) { m := newTestEntityAttributeMap() m.attributes.PutStr("existing", "old-value") m.PutStr("existing", "new-value") assert.Equal(t, 1, m.keys.Len()) assert.Equal(t, "existing", m.keys.At(0)) val, ok := m.attributes.Get("existing") assert.True(t, ok) assert.Equal(t, "new-value", val.Str()) } func TestEntityAttributeMap_PutEmpty(t *testing.T) { m := newTestEntityAttributeMap() val := m.PutEmpty("k1") val.SetStr("v1") assert.Equal(t, 1, m.keys.Len()) assert.Equal(t, "k1", m.keys.At(0)) resVal, ok := m.attributes.Get("k1") assert.True(t, ok) assert.Equal(t, "v1", resVal.Str()) } func TestEntityAttributeMap_PutEmpty_Overwrites(t *testing.T) { m := newTestEntityAttributeMap() m.attributes.PutStr("existing", "old-value") val := m.PutEmpty("existing") val.SetStr("new-value") assert.Equal(t, 1, m.keys.Len()) assert.Equal(t, "existing", m.keys.At(0)) resVal, ok := m.attributes.Get("existing") assert.True(t, ok) assert.Equal(t, "new-value", resVal.Str()) } func TestEntityAttributeMap_Remove(t *testing.T) { m := newTestEntityAttributeMap() m.keys.Append("k1") m.keys.Append("k2") m.attributes.PutStr("k1", "v1") m.attributes.PutStr("k2", "v2") assert.True(t, m.Remove("k1")) assert.Equal(t, 1, m.keys.Len()) assert.Equal(t, "k2", m.keys.At(0)) _, ok := m.attributes.Get("k1") assert.False(t, ok) val, ok := m.attributes.Get("k2") assert.True(t, ok) assert.Equal(t, "v2", val.Str()) } func TestEntityAttributeMap_Remove_NotOwned(t *testing.T) { m := newTestEntityAttributeMap() m.attributes.PutStr("not-owned", "value") assert.False(t, m.Remove("not-owned")) val, ok := m.attributes.Get("not-owned") assert.True(t, ok) assert.Equal(t, "value", val.Str()) } func TestEntityAttributeMap_Remove_NonExistent(t *testing.T) { m := newTestEntityAttributeMap() assert.False(t, m.Remove("non-existent")) } func TestEntityAttributeMap_CanPut(t *testing.T) { m := newTestEntityAttributeMap() m.keys.Append("owned") m.attributes.PutStr("owned", "value") m.attributes.PutStr("other", "value") assert.True(t, m.CanPut("owned")) assert.False(t, m.CanPut("other")) assert.True(t, m.CanPut("new-key")) } func newTestEntityAttributeMap() EntityAttributeMap { return EntityAttributeMap{ keys: pcommon.NewStringSlice(), attributes: pcommon.NewMap(), } } opentelemetry-collector-0.141.0/pdata/xpdata/entity/entity_map.go000066400000000000000000000070461511331344600251330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity // import "go.opentelemetry.io/collector/pdata/xpdata/entity" import ( "iter" "go.opentelemetry.io/collector/pdata/pcommon" ) // EntityMap logically represents a map of Entity keyed by entity type. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewEntityMap function to create new instances. // Important: zero-initialized instance is not valid for use. type EntityMap struct { refs EntityRefSlice attributes pcommon.Map } // NewEntityMap creates a EntityMap with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewEntityMap() EntityMap { return EntityMap{ refs: NewEntityRefSlice(), attributes: pcommon.NewMap(), } } // Len returns the number of elements in the map. // // Returns "0" for a newly instance created with "NewEntityMap()". func (em EntityMap) Len() int { return em.refs.Len() } // EnsureCapacity is an operation that ensures the map has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the map capacity will be expanded to equal newCap. func (em EntityMap) EnsureCapacity(newCap int) { em.refs.EnsureCapacity(newCap) } // Get returns the Entity associated with the entityType and true. The returned // Entity is not a copy, it is a reference to the entity stored in this map. // It is allowed to modify the returned entity. // Such modification will be applied to the entity stored in this map. // // If the entityType does not exist, returns a zero-initialized Entity and false. // Calling any functions on the returned invalid instance may cause a panic. func (em EntityMap) Get(entityType string) (Entity, bool) { if entityType == "" { return Entity{}, false } for i := 0; i < em.Len(); i++ { if em.refs.At(i).Type() == entityType { return Entity{ ref: em.refs.At(i), attributes: em.attributes, }, true } } return Entity{}, false } // All returns an iterator over entity type-Entity pairs in the EntityMap. // // for entityType, entity := range em.All() { // ... // Do something with entity type and entity // } func (em EntityMap) All() iter.Seq2[string, Entity] { return func(yield func(string, Entity) bool) { for i := 0; i < em.Len(); i++ { ref := em.refs.At(i) entity := Entity{ ref: ref, attributes: em.attributes, } if !yield(ref.Type(), entity) { return } } } } // Remove removes the entity associated with the entityType and returns true if the entity // was present in the map, otherwise returns false. All attributes associated with the entity // are also removed. func (em EntityMap) Remove(entityType string) bool { for i := 0; i < em.refs.Len(); i++ { ref := em.refs.At(i) if ref.Type() == entityType { for _, k := range ref.IdKeys().All() { em.attributes.Remove(k) } for _, k := range ref.DescriptionKeys().All() { em.attributes.Remove(k) } em.refs.RemoveIf(func(er EntityRef) bool { return er.Type() == entityType }) return true } } return false } // PutEmpty inserts or replaces an empty Entity with the specified type and returns it. // If an entity with the given type already exists, it replaces it and removes all attributes associated with it. func (em EntityMap) PutEmpty(entityType string) Entity { em.Remove(entityType) ref := em.refs.AppendEmpty() ref.SetType(entityType) return Entity{ ref: ref, attributes: em.attributes, } } opentelemetry-collector-0.141.0/pdata/xpdata/entity/entity_map_test.go000066400000000000000000000104151511331344600261640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity import ( "fmt" "testing" "github.com/stretchr/testify/assert" ) func TestEntityMap(t *testing.T) { em := NewEntityMap() assert.Equal(t, 0, em.Len()) e1 := em.PutEmpty("service") assert.Equal(t, 1, em.Len()) assert.Equal(t, "service", e1.Type()) e2 := em.PutEmpty("host") assert.Equal(t, 2, em.Len()) assert.Equal(t, "host", e2.Type()) } func TestEntityMap_PutEmpty(t *testing.T) { em := NewEntityMap() e := em.PutEmpty("service") retrieved, ok := em.Get("service") assert.True(t, ok) assert.Equal(t, "service", retrieved.Type()) assert.Equal(t, "service", e.Type()) } func TestEntityMap_PutEmpty_Override(t *testing.T) { em := NewEntityMap() e1 := em.PutEmpty("service") e1.IDAttributes().PutStr("service.name", "my-service") assert.Equal(t, 1, em.Len()) e2 := em.PutEmpty("service") assert.Equal(t, 1, em.Len()) _, ok := e2.IDAttributes().Get("service.name") assert.False(t, ok) } func TestEntityMap_EnsureCapacity(t *testing.T) { em := NewEntityMap() em.EnsureCapacity(5) for i := range 5 { em.PutEmpty(fmt.Sprintf("type%d", i)) } assert.Equal(t, 5, em.Len()) em.EnsureCapacity(3) assert.Equal(t, 5, em.Len()) } func TestEntityMap_AttributesIsolation(t *testing.T) { em := NewEntityMap() e1 := em.PutEmpty("service") e1.IDAttributes().PutStr("service.name", "my-service") e2 := em.PutEmpty("host") e2.IDAttributes().PutStr("host.name", "my-host") service, ok := em.Get("service") assert.True(t, ok) val, ok := service.IDAttributes().Get("service.name") assert.True(t, ok) assert.Equal(t, "my-service", val.Str()) host, ok := em.Get("host") assert.True(t, ok) val, ok = host.IDAttributes().Get("host.name") assert.True(t, ok) assert.Equal(t, "my-host", val.Str()) _, ok = service.IDAttributes().Get("host.name") assert.False(t, ok) _, ok = host.IDAttributes().Get("service.name") assert.False(t, ok) } func TestEntityMap_Get(t *testing.T) { em := NewEntityMap() e1 := em.PutEmpty("service") e1.IDAttributes().PutStr("service.name", "my-service") e2, ok := em.Get("service") assert.True(t, ok) assert.Equal(t, "service", e2.Type()) val, ok := e2.IDAttributes().Get("service.name") assert.True(t, ok) assert.Equal(t, "my-service", val.Str()) _, ok = em.Get("host") assert.False(t, ok) } func TestEntityMap_Remove(t *testing.T) { em := NewEntityMap() e1 := em.PutEmpty("service") e1.IDAttributes().PutStr("service.name", "my-service") e1.DescriptionAttributes().PutStr("service.version", "1.0.0") assert.Equal(t, 1, em.Len()) assert.Equal(t, 2, em.attributes.Len()) removed := em.Remove("service") assert.True(t, removed) assert.Empty(t, em.Len()) assert.Empty(t, em.attributes.Len()) assert.False(t, em.Remove("service")) } func TestEntityMap_All(t *testing.T) { em := NewEntityMap() e1 := em.PutEmpty("service") e1.IDAttributes().PutStr("service.name", "my-service") e2 := em.PutEmpty("host") e2.IDAttributes().PutStr("host.name", "my-host") e3 := em.PutEmpty("process") e3.IDAttributes().PutStr("process.pid", "1234") types := make(map[string]bool) attributes := make(map[string]string) for entityType, entity := range em.All() { types[entityType] = true switch entityType { case "service": val, ok := entity.IDAttributes().Get("service.name") assert.True(t, ok) attributes[entityType] = val.Str() case "host": val, ok := entity.IDAttributes().Get("host.name") assert.True(t, ok) attributes[entityType] = val.Str() case "process": val, ok := entity.IDAttributes().Get("process.pid") assert.True(t, ok) attributes[entityType] = val.Str() } } assert.Len(t, types, 3) assert.True(t, types["service"]) assert.True(t, types["host"]) assert.True(t, types["process"]) assert.Equal(t, "my-service", attributes["service"]) assert.Equal(t, "my-host", attributes["host"]) assert.Equal(t, "1234", attributes["process"]) } func TestEntityMap_All_Empty(t *testing.T) { em := NewEntityMap() count := 0 for range em.All() { count++ } assert.Equal(t, 0, count) } func TestEntityMap_All_EarlyBreak(t *testing.T) { em := NewEntityMap() em.PutEmpty("service") em.PutEmpty("host") em.PutEmpty("process") count := 0 for range em.All() { count++ if count == 2 { break } } assert.Equal(t, 2, count) } opentelemetry-collector-0.141.0/pdata/xpdata/entity/entity_test.go000066400000000000000000000045471511331344600253400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity import ( "testing" "github.com/stretchr/testify/assert" ) func TestEntity_Type(t *testing.T) { em := NewEntityMap() e := em.PutEmpty("service") assert.Equal(t, "service", e.Type()) } func TestEntity_SchemaURL(t *testing.T) { em := NewEntityMap() e := em.PutEmpty("service") assert.Empty(t, e.SchemaURL()) e.SetSchemaURL("https://opentelemetry.io/schemas/1.0.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.0.0", e.SchemaURL()) e.SetSchemaURL("https://opentelemetry.io/schemas/1.1.0") assert.Equal(t, "https://opentelemetry.io/schemas/1.1.0", e.SchemaURL()) } func TestEntity_IDAttributes(t *testing.T) { em := NewEntityMap() e := em.PutEmpty("service") idAttrs := e.IDAttributes() idAttrs.PutStr("key1", "value1") val, ok := e.IDAttributes().Get("key1") assert.True(t, ok) assert.Equal(t, "value1", val.Str()) } func TestEntity_DescriptionAttributes(t *testing.T) { em := NewEntityMap() e := em.PutEmpty("service") descAttrs := e.DescriptionAttributes() descAttrs.PutStr("key1", "value1") val, ok := e.DescriptionAttributes().Get("key1") assert.True(t, ok) assert.Equal(t, "value1", val.Str()) } func TestEntity_IdAndDescriptionAttributes_Isolated(t *testing.T) { em := NewEntityMap() e := em.PutEmpty("service") e.IDAttributes().PutStr("id.key", "id-value") e.DescriptionAttributes().PutStr("desc.key", "desc-value") val, ok := e.IDAttributes().Get("id.key") assert.True(t, ok) assert.Equal(t, "id-value", val.Str()) _, ok = e.IDAttributes().Get("desc.key") assert.False(t, ok) val, ok = e.DescriptionAttributes().Get("desc.key") assert.True(t, ok) assert.Equal(t, "desc-value", val.Str()) _, ok = e.DescriptionAttributes().Get("id.key") assert.False(t, ok) } func TestEntity_IdAndDescriptionAttributes_CanPut(t *testing.T) { em := NewEntityMap() e := em.PutEmpty("service") e.IDAttributes().PutStr("shared.key", "id-value") assert.True(t, e.IDAttributes().CanPut("shared.key")) assert.False(t, e.DescriptionAttributes().CanPut("shared.key")) e.DescriptionAttributes().PutStr("shared.key", "desc-value") val, ok := e.IDAttributes().Get("shared.key") assert.True(t, ok) assert.Equal(t, "desc-value", val.Str()) val, ok = e.DescriptionAttributes().Get("shared.key") assert.True(t, ok) assert.Equal(t, "desc-value", val.Str()) } opentelemetry-collector-0.141.0/pdata/xpdata/entity/generated_entityref.go000066400000000000000000000057621511331344600270140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package entity import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // This is a reference type, if passed by value and callee modifies it the // caller will see the modification. // // Must use NewEntityRef function to create new instances. // Important: zero-initialized instance is not valid for use. type EntityRef internal.EntityRefWrapper func newEntityRef(orig *internal.EntityRef, state *internal.State) EntityRef { return EntityRef(internal.NewEntityRefWrapper(orig, state)) } // NewEntityRef creates a new empty EntityRef. // // This must be used only in testing code. Users should use "AppendEmpty" when part of a Slice, // OR directly access the member if this is embedded in another struct. func NewEntityRef() EntityRef { return newEntityRef(internal.NewEntityRef(), internal.NewState()) } // MoveTo moves all properties from the current struct overriding the destination and // resetting the current instance to its zero value func (ms EntityRef) MoveTo(dest EntityRef) { ms.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if ms.getOrig() == dest.getOrig() { return } internal.DeleteEntityRef(dest.getOrig(), false) *dest.getOrig(), *ms.getOrig() = *ms.getOrig(), *dest.getOrig() } // SchemaUrl returns the schemaurl associated with this EntityRef. func (ms EntityRef) SchemaUrl() string { return ms.getOrig().SchemaUrl } // SetSchemaUrl replaces the schemaurl associated with this EntityRef. func (ms EntityRef) SetSchemaUrl(v string) { ms.getState().AssertMutable() ms.getOrig().SchemaUrl = v } // Type returns the type associated with this EntityRef. func (ms EntityRef) Type() string { return ms.getOrig().Type } // SetType replaces the type associated with this EntityRef. func (ms EntityRef) SetType(v string) { ms.getState().AssertMutable() ms.getOrig().Type = v } // IdKeys returns the IdKeys associated with this EntityRef. func (ms EntityRef) IdKeys() pcommon.StringSlice { return pcommon.StringSlice(internal.NewStringSliceWrapper(&ms.getOrig().IdKeys, ms.getState())) } // DescriptionKeys returns the DescriptionKeys associated with this EntityRef. func (ms EntityRef) DescriptionKeys() pcommon.StringSlice { return pcommon.StringSlice(internal.NewStringSliceWrapper(&ms.getOrig().DescriptionKeys, ms.getState())) } // CopyTo copies all properties from the current struct overriding the destination. func (ms EntityRef) CopyTo(dest EntityRef) { dest.getState().AssertMutable() internal.CopyEntityRef(dest.getOrig(), ms.getOrig()) } func (ms EntityRef) getOrig() *internal.EntityRef { return internal.GetEntityRefOrig(internal.EntityRefWrapper(ms)) } func (ms EntityRef) getState() *internal.State { return internal.GetEntityRefState(internal.EntityRefWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/xpdata/entity/generated_entityref_test.go000066400000000000000000000051011511331344600300360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package entity import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestEntityRef_MoveTo(t *testing.T) { ms := generateTestEntityRef() dest := NewEntityRef() ms.MoveTo(dest) assert.Equal(t, NewEntityRef(), ms) assert.Equal(t, generateTestEntityRef(), dest) dest.MoveTo(dest) assert.Equal(t, generateTestEntityRef(), dest) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.MoveTo(newEntityRef(internal.NewEntityRef(), sharedState)) }) assert.Panics(t, func() { newEntityRef(internal.NewEntityRef(), sharedState).MoveTo(dest) }) } func TestEntityRef_CopyTo(t *testing.T) { ms := NewEntityRef() orig := NewEntityRef() orig.CopyTo(ms) assert.Equal(t, orig, ms) orig = generateTestEntityRef() orig.CopyTo(ms) assert.Equal(t, orig, ms) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { ms.CopyTo(newEntityRef(internal.NewEntityRef(), sharedState)) }) } func TestEntityRef_SchemaUrl(t *testing.T) { ms := NewEntityRef() assert.Empty(t, ms.SchemaUrl()) ms.SetSchemaUrl("test_schemaurl") assert.Equal(t, "test_schemaurl", ms.SchemaUrl()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newEntityRef(internal.NewEntityRef(), sharedState).SetSchemaUrl("test_schemaurl") }) } func TestEntityRef_Type(t *testing.T) { ms := NewEntityRef() assert.Empty(t, ms.Type()) ms.SetType("test_type") assert.Equal(t, "test_type", ms.Type()) sharedState := internal.NewState() sharedState.MarkReadOnly() assert.Panics(t, func() { newEntityRef(internal.NewEntityRef(), sharedState).SetType("test_type") }) } func TestEntityRef_IdKeys(t *testing.T) { ms := NewEntityRef() assert.Equal(t, pcommon.NewStringSlice(), ms.IdKeys()) ms.getOrig().IdKeys = internal.GenTestStringSlice() assert.Equal(t, pcommon.StringSlice(internal.GenTestStringSliceWrapper()), ms.IdKeys()) } func TestEntityRef_DescriptionKeys(t *testing.T) { ms := NewEntityRef() assert.Equal(t, pcommon.NewStringSlice(), ms.DescriptionKeys()) ms.getOrig().DescriptionKeys = internal.GenTestStringSlice() assert.Equal(t, pcommon.StringSlice(internal.GenTestStringSliceWrapper()), ms.DescriptionKeys()) } func generateTestEntityRef() EntityRef { return newEntityRef(internal.GenTestEntityRef(), internal.NewState()) } opentelemetry-collector-0.141.0/pdata/xpdata/entity/generated_entityrefslice.go000066400000000000000000000122101511331344600300160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package entity import ( "iter" "sort" "go.opentelemetry.io/collector/pdata/internal" ) // EntityRefSlice logically represents a slice of EntityRef. // // This is a reference type. If passed by value and callee modifies it, the // caller will see the modification. // // Must use NewEntityRefSlice function to create new instances. // Important: zero-initialized instance is not valid for use. type EntityRefSlice internal.EntityRefSliceWrapper func newEntityRefSlice(orig *[]*internal.EntityRef, state *internal.State) EntityRefSlice { return EntityRefSlice(internal.NewEntityRefSliceWrapper(orig, state)) } // NewEntityRefSlice creates a EntityRefSliceWrapper with 0 elements. // Can use "EnsureCapacity" to initialize with a given capacity. func NewEntityRefSlice() EntityRefSlice { orig := []*internal.EntityRef(nil) return newEntityRefSlice(&orig, internal.NewState()) } // Len returns the number of elements in the slice. // // Returns "0" for a newly instance created with "NewEntityRefSlice()". func (es EntityRefSlice) Len() int { return len(*es.getOrig()) } // At returns the element at the given index. // // This function is used mostly for iterating over all the values in the slice: // // for i := 0; i < es.Len(); i++ { // e := es.At(i) // ... // Do something with the element // } func (es EntityRefSlice) At(i int) EntityRef { return newEntityRef((*es.getOrig())[i], es.getState()) } // All returns an iterator over index-value pairs in the slice. // // for i, v := range es.All() { // ... // Do something with index-value pair // } func (es EntityRefSlice) All() iter.Seq2[int, EntityRef] { return func(yield func(int, EntityRef) bool) { for i := 0; i < es.Len(); i++ { if !yield(i, es.At(i)) { return } } } } // EnsureCapacity is an operation that ensures the slice has at least the specified capacity. // 1. If the newCap <= cap then no change in capacity. // 2. If the newCap > cap then the slice capacity will be expanded to equal newCap. // // Here is how a new EntityRefSlice can be initialized: // // es := NewEntityRefSlice() // es.EnsureCapacity(4) // for i := 0; i < 4; i++ { // e := es.AppendEmpty() // // Here should set all the values for e. // } func (es EntityRefSlice) EnsureCapacity(newCap int) { es.getState().AssertMutable() oldCap := cap(*es.getOrig()) if newCap <= oldCap { return } newOrig := make([]*internal.EntityRef, len(*es.getOrig()), newCap) copy(newOrig, *es.getOrig()) *es.getOrig() = newOrig } // AppendEmpty will append to the end of the slice an empty EntityRef. // It returns the newly added EntityRef. func (es EntityRefSlice) AppendEmpty() EntityRef { es.getState().AssertMutable() *es.getOrig() = append(*es.getOrig(), internal.NewEntityRef()) return es.At(es.Len() - 1) } // MoveAndAppendTo moves all elements from the current slice and appends them to the dest. // The current slice will be cleared. func (es EntityRefSlice) MoveAndAppendTo(dest EntityRefSlice) { es.getState().AssertMutable() dest.getState().AssertMutable() // If they point to the same data, they are the same, nothing to do. if es.getOrig() == dest.getOrig() { return } if *dest.getOrig() == nil { // We can simply move the entire vector and avoid any allocations. *dest.getOrig() = *es.getOrig() } else { *dest.getOrig() = append(*dest.getOrig(), *es.getOrig()...) } *es.getOrig() = nil } // RemoveIf calls f sequentially for each element present in the slice. // If f returns true, the element is removed from the slice. func (es EntityRefSlice) RemoveIf(f func(EntityRef) bool) { es.getState().AssertMutable() newLen := 0 for i := 0; i < len(*es.getOrig()); i++ { if f(es.At(i)) { internal.DeleteEntityRef((*es.getOrig())[i], true) (*es.getOrig())[i] = nil continue } if newLen == i { // Nothing to move, element is at the right place. newLen++ continue } (*es.getOrig())[newLen] = (*es.getOrig())[i] // Cannot delete here since we just move the data(or pointer to data) to a different position in the slice. (*es.getOrig())[i] = nil newLen++ } *es.getOrig() = (*es.getOrig())[:newLen] } // CopyTo copies all elements from the current slice overriding the destination. func (es EntityRefSlice) CopyTo(dest EntityRefSlice) { dest.getState().AssertMutable() if es.getOrig() == dest.getOrig() { return } *dest.getOrig() = internal.CopyEntityRefPtrSlice(*dest.getOrig(), *es.getOrig()) } // Sort sorts the EntityRef elements within EntityRefSlice given the // provided less function so that two instances of EntityRefSlice // can be compared. func (es EntityRefSlice) Sort(less func(a, b EntityRef) bool) { es.getState().AssertMutable() sort.SliceStable(*es.getOrig(), func(i, j int) bool { return less(es.At(i), es.At(j)) }) } func (ms EntityRefSlice) getOrig() *[]*internal.EntityRef { return internal.GetEntityRefSliceOrig(internal.EntityRefSliceWrapper(ms)) } func (ms EntityRefSlice) getState() *internal.State { return internal.GetEntityRefSliceState(internal.EntityRefSliceWrapper(ms)) } opentelemetry-collector-0.141.0/pdata/xpdata/entity/generated_entityrefslice_test.go000066400000000000000000000115121511331344600310610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Code generated by "internal/cmd/pdatagen/main.go". DO NOT EDIT. // To regenerate this file run "make genpdata". package entity import ( "testing" "unsafe" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/internal" ) func TestEntityRefSlice(t *testing.T) { es := NewEntityRefSlice() assert.Equal(t, 0, es.Len()) es = newEntityRefSlice(&[]*internal.EntityRef{}, internal.NewState()) assert.Equal(t, 0, es.Len()) emptyVal := NewEntityRef() testVal := EntityRef(internal.GenTestEntityRefWrapper()) for i := 0; i < 7; i++ { es.AppendEmpty() assert.Equal(t, emptyVal, es.At(i)) (*es.getOrig())[i] = internal.GenTestEntityRef() assert.Equal(t, testVal, es.At(i)) } assert.Equal(t, 7, es.Len()) } func TestEntityRefSliceReadOnly(t *testing.T) { sharedState := internal.NewState() sharedState.MarkReadOnly() es := newEntityRefSlice(&[]*internal.EntityRef{}, sharedState) assert.Equal(t, 0, es.Len()) assert.Panics(t, func() { es.AppendEmpty() }) assert.Panics(t, func() { es.EnsureCapacity(2) }) es2 := NewEntityRefSlice() es.CopyTo(es2) assert.Panics(t, func() { es2.CopyTo(es) }) assert.Panics(t, func() { es.MoveAndAppendTo(es2) }) assert.Panics(t, func() { es2.MoveAndAppendTo(es) }) } func TestEntityRefSlice_CopyTo(t *testing.T) { dest := NewEntityRefSlice() src := generateTestEntityRefSlice() src.CopyTo(dest) assert.Equal(t, generateTestEntityRefSlice(), dest) dest.CopyTo(dest) assert.Equal(t, generateTestEntityRefSlice(), dest) } func TestEntityRefSlice_EnsureCapacity(t *testing.T) { es := generateTestEntityRefSlice() // Test ensure smaller capacity. const ensureSmallLen = 4 es.EnsureCapacity(ensureSmallLen) assert.Less(t, ensureSmallLen, es.Len()) assert.Equal(t, es.Len(), cap(*es.getOrig())) assert.Equal(t, generateTestEntityRefSlice(), es) // Test ensure larger capacity const ensureLargeLen = 9 es.EnsureCapacity(ensureLargeLen) assert.Less(t, generateTestEntityRefSlice().Len(), ensureLargeLen) assert.Equal(t, ensureLargeLen, cap(*es.getOrig())) assert.Equal(t, generateTestEntityRefSlice(), es) } func TestEntityRefSlice_MoveAndAppendTo(t *testing.T) { // Test MoveAndAppendTo to empty expectedSlice := generateTestEntityRefSlice() dest := NewEntityRefSlice() src := generateTestEntityRefSlice() src.MoveAndAppendTo(dest) assert.Equal(t, generateTestEntityRefSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo empty slice src.MoveAndAppendTo(dest) assert.Equal(t, generateTestEntityRefSlice(), dest) assert.Equal(t, 0, src.Len()) assert.Equal(t, expectedSlice.Len(), dest.Len()) // Test MoveAndAppendTo not empty slice generateTestEntityRefSlice().MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } dest.MoveAndAppendTo(dest) assert.Equal(t, 2*expectedSlice.Len(), dest.Len()) for i := 0; i < expectedSlice.Len(); i++ { assert.Equal(t, expectedSlice.At(i), dest.At(i)) assert.Equal(t, expectedSlice.At(i), dest.At(i+expectedSlice.Len())) } } func TestEntityRefSlice_RemoveIf(t *testing.T) { // Test RemoveIf on empty slice emptySlice := NewEntityRefSlice() emptySlice.RemoveIf(func(el EntityRef) bool { t.Fail() return false }) // Test RemoveIf filtered := generateTestEntityRefSlice() pos := 0 filtered.RemoveIf(func(el EntityRef) bool { pos++ return pos%2 == 1 }) assert.Equal(t, 2, filtered.Len()) } func TestEntityRefSlice_RemoveIfAll(t *testing.T) { got := generateTestEntityRefSlice() got.RemoveIf(func(el EntityRef) bool { return true }) assert.Equal(t, 0, got.Len()) } func TestEntityRefSliceAll(t *testing.T) { ms := generateTestEntityRefSlice() assert.NotEmpty(t, ms.Len()) var c int for i, v := range ms.All() { assert.Equal(t, ms.At(i), v, "element should match") c++ } assert.Equal(t, ms.Len(), c, "All elements should have been visited") } func TestEntityRefSlice_Sort(t *testing.T) { es := generateTestEntityRefSlice() es.Sort(func(a, b EntityRef) bool { return uintptr(unsafe.Pointer(a.getOrig())) < uintptr(unsafe.Pointer(b.getOrig())) }) for i := 1; i < es.Len(); i++ { assert.Less(t, uintptr(unsafe.Pointer(es.At(i-1).getOrig())), uintptr(unsafe.Pointer(es.At(i).getOrig()))) } es.Sort(func(a, b EntityRef) bool { return uintptr(unsafe.Pointer(a.getOrig())) > uintptr(unsafe.Pointer(b.getOrig())) }) for i := 1; i < es.Len(); i++ { assert.Greater(t, uintptr(unsafe.Pointer(es.At(i-1).getOrig())), uintptr(unsafe.Pointer(es.At(i).getOrig()))) } } func generateTestEntityRefSlice() EntityRefSlice { ms := NewEntityRefSlice() *ms.getOrig() = internal.GenTestEntityRefPtrSlice() return ms } opentelemetry-collector-0.141.0/pdata/xpdata/entity/resource_entities.go000066400000000000000000000020431511331344600265050ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity // import "go.opentelemetry.io/collector/pdata/xpdata/entity" import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // ResourceEntityRefs returns the EntityRefs associated with this Resource. // Once EntityRefs is stabilized in the proto definition, // this function will be available in the pcommon package as part of a Resource method. func ResourceEntityRefs(res pcommon.Resource) EntityRefSlice { ir := internal.ResourceWrapper(res) return newEntityRefSlice(&internal.GetResourceOrig(ir).EntityRefs, internal.GetResourceState(ir)) } // ResourceEntities returns the Entities associated with this Resource. // The returned EntityMap shares the resource's attributes map, so modifications // to entity attributes are immediately reflected in the resource. func ResourceEntities(res pcommon.Resource) EntityMap { return EntityMap{ refs: ResourceEntityRefs(res), attributes: res.Attributes(), } } opentelemetry-collector-0.141.0/pdata/xpdata/entity/resource_entities_test.go000066400000000000000000000015131511331344600275450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package entity import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestResourceEntityRefs(t *testing.T) { res := pcommon.NewResource() refs := ResourceEntityRefs(res) assert.Equal(t, 0, refs.Len()) ref := refs.AppendEmpty() ref.SetType("service") assert.Equal(t, 1, refs.Len()) assert.Equal(t, "service", refs.At(0).Type()) } func TestResourceEntities(t *testing.T) { res := pcommon.NewResource() entities := ResourceEntities(res) assert.Equal(t, 0, entities.Len()) e := entities.PutEmpty("service") assert.Equal(t, 1, entities.Len()) retrieved, ok := entities.Get("service") assert.True(t, ok) assert.Equal(t, "service", retrieved.Type()) assert.Equal(t, "service", e.Type()) } opentelemetry-collector-0.141.0/pdata/xpdata/fuzz_test.go000066400000000000000000000016051511331344600234760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xpdata import ( "bytes" "testing" "github.com/stretchr/testify/require" ) var unexpectedBytes = "expected the same bytes from unmarshaling and marshaling." func FuzzUnmarshalJSONValue(f *testing.F) { f.Fuzz(func(t *testing.T, data []byte) { u1 := &JSONUnmarshaler{} ld1, err := u1.UnmarshalValue(data) if err != nil { return } m1 := &JSONMarshaler{} b1, err := m1.MarshalValue(ld1) require.NoError(t, err, "failed to marshal valid struct") u2 := &JSONUnmarshaler{} ld2, err := u2.UnmarshalValue(b1) require.NoError(t, err, "failed to unmarshal valid bytes") m2 := &JSONMarshaler{} b2, err := m2.MarshalValue(ld2) require.NoError(t, err, "failed to marshal valid struct") require.True(t, bytes.Equal(b1, b2), "%s. \nexpected %d but got %d\n", unexpectedBytes, b1, b2) }) } opentelemetry-collector-0.141.0/pdata/xpdata/go.mod000066400000000000000000000025341511331344600222220ustar00rootroot00000000000000module go.opentelemetry.io/collector/pdata/xpdata go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/client v1.47.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/otel/trace v1.38.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => .. replace go.opentelemetry.io/collector/pdata/pprofile => ../pprofile replace go.opentelemetry.io/collector/pdata/testdata => ../testdata replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/pdata/xpdata/go.sum000066400000000000000000000107341511331344600222500ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/pdata/xpdata/json.go000066400000000000000000000020431511331344600224070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xpdata // import "go.opentelemetry.io/collector/pdata/xpdata" import ( "slices" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/internal/json" "go.opentelemetry.io/collector/pdata/pcommon" ) type JSONMarshaler struct{} func (*JSONMarshaler) MarshalValue(value pcommon.Value) ([]byte, error) { av := internal.GetValueOrig(internal.ValueWrapper(value)) dest := json.BorrowStream(nil) defer json.ReturnStream(dest) av.MarshalJSON(dest) if dest.Error() != nil { return nil, dest.Error() } return slices.Clone(dest.Buffer()), nil } type JSONUnmarshaler struct{} func (*JSONUnmarshaler) UnmarshalValue(buf []byte) (pcommon.Value, error) { iter := json.BorrowIterator(buf) defer json.ReturnIterator(iter) value := &internal.AnyValue{} value.UnmarshalJSON(iter) if iter.Error() != nil { return pcommon.NewValueEmpty(), iter.Error() } return pcommon.Value(internal.NewValueWrapper(value, internal.NewState())), nil } opentelemetry-collector-0.141.0/pdata/xpdata/json_test.go000066400000000000000000000046611511331344600234560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xpdata import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestMarshalAndUnmarshalValue(t *testing.T) { for name, src := range genTestEncodingValues() { t.Run(name, func(t *testing.T) { m := &JSONMarshaler{} b, err := m.MarshalValue(src) require.NoError(t, err) u := &JSONUnmarshaler{} dest, err := u.UnmarshalValue(b) require.NoError(t, err) require.Equal(t, src, dest) }) } } func TestUnmarshalValueUnknown(t *testing.T) { m := &JSONUnmarshaler{} b, err := m.UnmarshalValue([]byte(`{"unknown": "string"}`)) require.NoError(t, err) assert.Equal(t, pcommon.NewValueEmpty(), b) } func genTestEncodingValues() map[string]pcommon.Value { return map[string]pcommon.Value{ "empty": pcommon.NewValueEmpty(), "StringValue/default": pcommon.NewValueStr(""), "StringValue/test": pcommon.NewValueStr("test_stringvalue"), "BoolValue/default": pcommon.NewValueBool(false), "BoolValue/test": pcommon.NewValueBool(true), "IntValue/default": pcommon.NewValueInt(0), "IntValue/test": pcommon.NewValueInt(13), "DoubleValue/default": pcommon.NewValueDouble(0), "DoubleValue/test": pcommon.NewValueDouble(3.1415926), "ArrayValue/default": pcommon.NewValueSlice(), "ArrayValue/test": func() pcommon.Value { s := pcommon.NewValueSlice() s.Slice().AppendEmpty().SetStr("test1") s.Slice().AppendEmpty().SetInt(13) s.Slice().AppendEmpty().SetBool(true) s.Slice().AppendEmpty().SetDouble(3.1415926) s1 := s.Slice().AppendEmpty().SetEmptySlice() s1.AppendEmpty().SetStr("nested") m := s.Slice().AppendEmpty().SetEmptyMap() m.PutStr("key1", "value1") return s }(), "KvlistValue/default": pcommon.NewValueMap(), "KvlistValue/test": func() pcommon.Value { m := pcommon.NewValueMap() m.Map().PutStr("key1", "value1") m.Map().PutInt("key2", 13) m.Map().PutBool("key3", true) m.Map().PutDouble("key4", 3.1415926) m.Map().PutEmpty("key5").SetStr("value5") s := m.Map().PutEmptySlice("key6") s.AppendEmpty().SetStr("nested1") m1 := m.Map().PutEmptyMap("key6") m1.PutStr("nestedKey1", "nestedValue1") return m }(), "BytesValue/test": func() pcommon.Value { v := pcommon.NewValueBytes() v.Bytes().FromRaw([]byte{1, 2, 3}) return v }(), } } opentelemetry-collector-0.141.0/pdata/xpdata/map_builder.go000066400000000000000000000037631511331344600237330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xpdata // import "go.opentelemetry.io/collector/pdata/xpdata" import ( "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pcommon" ) // MapBuilder is an experimental struct which can be used to create a pcommon.Map more efficiently // than by repeated use of the Put family of methods, which check for duplicate keys on every call // (a linear time operation). // A zero-initialized MapBuilder is ready for use. type MapBuilder struct { state internal.State pairs []internal.KeyValue } // EnsureCapacity increases the capacity of this MapBuilder instance, if necessary, // to ensure that it can hold at least the number of elements specified by the capacity argument. func (mb *MapBuilder) EnsureCapacity(capacity int) { oldValues := mb.pairs if capacity <= cap(oldValues) { return } mb.pairs = make([]internal.KeyValue, len(oldValues), capacity) copy(mb.pairs, oldValues) } func (mb *MapBuilder) getValue(i int) pcommon.Value { return pcommon.Value(internal.NewValueWrapper(&mb.pairs[i].Value, &mb.state)) } // AppendEmpty appends a key/value pair to the MapBuilder and return the inserted value. // This method does not check for duplicate keys and has an amortized constant time complexity. func (mb *MapBuilder) AppendEmpty(k string) pcommon.Value { mb.pairs = append(mb.pairs, internal.KeyValue{Key: k}) return mb.getValue(len(mb.pairs) - 1) } // UnsafeIntoMap transfers the contents of a MapBuilder into a MapWrapper, without checking for duplicate keys. // If the MapBuilder contains duplicate keys, the behavior of the resulting MapWrapper is unspecified. // This operation has constant time complexity and makes no allocations. // After this operation, the MapBuilder is reset to an empty state. func (mb *MapBuilder) UnsafeIntoMap(m pcommon.Map) { internal.GetMapState(internal.MapWrapper(m)).AssertMutable() *internal.GetMapOrig(internal.MapWrapper(m)) = mb.pairs mb.pairs = nil } opentelemetry-collector-0.141.0/pdata/xpdata/map_builder_test.go000066400000000000000000000012721511331344600247630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xpdata_test import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/xpdata" ) func TestMapBuilder(t *testing.T) { var mb xpdata.MapBuilder mb.EnsureCapacity(3) mb.AppendEmpty("key1").SetStr("val") mb.AppendEmpty("key2").SetInt(42) m := pcommon.NewMap() mb.UnsafeIntoMap(m) assert.Equal(t, 2, m.Len()) val, ok := m.Get("key1") assert.True(t, ok && val.Type() == pcommon.ValueTypeStr && val.Str() == "val") val, ok = m.Get("key2") assert.True(t, ok && val.Type() == pcommon.ValueTypeInt && val.Int() == 42) } opentelemetry-collector-0.141.0/pdata/xpdata/metadata.yaml000066400000000000000000000001721511331344600235540ustar00rootroot00000000000000type: xpdata github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pdata opentelemetry-collector-0.141.0/pdata/xpdata/pref/000077500000000000000000000000001511331344600220445ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/xpdata/pref/gate.go000066400000000000000000000015531511331344600233170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pref // import "go.opentelemetry.io/collector/pdata/xpdata/pref" import ( "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/internal" ) // UseProtoPooling temporary expose public to allow testing. var UseProtoPooling = internal.UseProtoPooling var EnableRefCounting = featuregate.GlobalRegistry().MustRegister( "pdata.enableRefCounting", featuregate.StageBeta, featuregate.WithRegisterDescription("When enabled, enables using ref counting to know when pdata memory can be freed up. This featuregate is here only to protect if unexpected bugs happens because of ref counting logic."), featuregate.WithRegisterReferenceURL("https://github.com/open-telemetry/opentelemetry-collector/issues/13631"), featuregate.WithRegisterFromVersion("v0.133.0"), ) opentelemetry-collector-0.141.0/pdata/xpdata/pref/logs.go000066400000000000000000000024341511331344600233420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pref // import "go.opentelemetry.io/collector/pdata/xpdata/pref" import ( "reflect" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/plog" ) // MarkPipelineOwnedLogs marks the plog.Logs data as owned by the pipeline, returns true if the data were // previously not owned by the pipeline, otherwise false. func MarkPipelineOwnedLogs(ld plog.Logs) bool { return internal.GetLogsState(internal.LogsWrapper(ld)).MarkPipelineOwned() } func RefLogs(ld plog.Logs) { if EnableRefCounting.IsEnabled() { internal.GetLogsState(internal.LogsWrapper(ld)).Ref() } } func UnrefLogs(ld plog.Logs) { if EnableRefCounting.IsEnabled() { if !internal.GetLogsState(internal.LogsWrapper(ld)).Unref() { return } // Don't call DeleteExportLogsServiceRequest without the gate because we reset the data and that may still cause issues. if internal.UseProtoPooling.IsEnabled() { internal.DeleteExportLogsServiceRequest(internal.GetLogsOrig(internal.LogsWrapper(ld)), true) } } } // TODO: Generate this in pdata. func EqualLogs(ld1, ld2 plog.Logs) bool { return reflect.DeepEqual(internal.GetLogsOrig(internal.LogsWrapper(ld1)), internal.GetLogsOrig(internal.LogsWrapper(ld2))) } opentelemetry-collector-0.141.0/pdata/xpdata/pref/metrics.go000066400000000000000000000025631511331344600240470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pref // import "go.opentelemetry.io/collector/pdata/xpdata/pref" import ( "reflect" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pmetric" ) // MarkPipelineOwnedMetrics marks the pmetric.Metrics data as owned by the pipeline, returns true if the data were // previously not owned by the pipeline, otherwise false. func MarkPipelineOwnedMetrics(md pmetric.Metrics) bool { return internal.GetMetricsState(internal.MetricsWrapper(md)).MarkPipelineOwned() } func RefMetrics(md pmetric.Metrics) { if EnableRefCounting.IsEnabled() { internal.GetMetricsState(internal.MetricsWrapper(md)).Ref() } } func UnrefMetrics(md pmetric.Metrics) { if EnableRefCounting.IsEnabled() { if !internal.GetMetricsState(internal.MetricsWrapper(md)).Unref() { return } // Don't call DeleteExportLogsServiceRequest without the gate because we reset the data and that may still cause issues. if internal.UseProtoPooling.IsEnabled() { internal.DeleteExportMetricsServiceRequest(internal.GetMetricsOrig(internal.MetricsWrapper(md)), true) } } } // TODO: Generate this in pdata. func EqualMetrics(md1, md2 pmetric.Metrics) bool { return reflect.DeepEqual(internal.GetMetricsOrig(internal.MetricsWrapper(md1)), internal.GetMetricsOrig(internal.MetricsWrapper(md2))) } opentelemetry-collector-0.141.0/pdata/xpdata/pref/profiles.go000066400000000000000000000026201511331344600242160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pref // import "go.opentelemetry.io/collector/pdata/xpdata/pref" import ( "reflect" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pprofile" ) // MarkPipelineOwnedProfiles marks the pprofile.Profiles data as owned by the pipeline, returns true if the data were // previously not owned by the pipeline, otherwise false. func MarkPipelineOwnedProfiles(pd pprofile.Profiles) bool { return internal.GetProfilesState(internal.ProfilesWrapper(pd)).MarkPipelineOwned() } func RefProfiles(pd pprofile.Profiles) { if EnableRefCounting.IsEnabled() { internal.GetProfilesState(internal.ProfilesWrapper(pd)).Ref() } } func UnrefProfiles(pd pprofile.Profiles) { if EnableRefCounting.IsEnabled() { if !internal.GetProfilesState(internal.ProfilesWrapper(pd)).Unref() { return } // Don't call DeleteExportLogsServiceRequest without the gate because we reset the data and that may still cause issues. if internal.UseProtoPooling.IsEnabled() { internal.DeleteExportProfilesServiceRequest(internal.GetProfilesOrig(internal.ProfilesWrapper(pd)), true) } } } // TODO: Generate this in pdata. func EqualProfiles(pd1, pd2 pprofile.Profiles) bool { return reflect.DeepEqual(internal.GetProfilesOrig(internal.ProfilesWrapper(pd1)), internal.GetProfilesOrig(internal.ProfilesWrapper(pd2))) } opentelemetry-collector-0.141.0/pdata/xpdata/pref/traces.go000066400000000000000000000024551511331344600236620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pref // import "go.opentelemetry.io/collector/pdata/xpdata/pref" import ( "reflect" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/ptrace" ) // MarkPipelineOwnedTraces marks the ptrace.Traces data as owned by the pipeline, returns true if the data were // previously not owned by the pipeline, otherwise false. func MarkPipelineOwnedTraces(td ptrace.Traces) bool { return internal.GetTracesState(internal.TracesWrapper(td)).MarkPipelineOwned() } func RefTraces(td ptrace.Traces) { internal.GetTracesState(internal.TracesWrapper(td)).Ref() } func UnrefTraces(td ptrace.Traces) { if EnableRefCounting.IsEnabled() { if !internal.GetTracesState(internal.TracesWrapper(td)).Unref() { return } // Don't call DeleteExportLogsServiceRequest without the gate because we reset the data and that may still cause issues. if internal.UseProtoPooling.IsEnabled() { internal.DeleteExportTraceServiceRequest(internal.GetTracesOrig(internal.TracesWrapper(td)), true) } } } // TODO: Generate this in pdata. func EqualTraces(td1, td2 ptrace.Traces) bool { return reflect.DeepEqual(internal.GetTracesOrig(internal.TracesWrapper(td1)), internal.GetTracesOrig(internal.TracesWrapper(td2))) } opentelemetry-collector-0.141.0/pdata/xpdata/request/000077500000000000000000000000001511331344600226005ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/xpdata/request/context.go000066400000000000000000000113061511331344600246140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "net" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/pdata/internal" ) // encodeContext encodes the context into a map of strings. func encodeContext(ctx context.Context) *internal.RequestContext { rc := internal.RequestContext{} encodeSpanContext(ctx, &rc) encodeClientMetadata(ctx, &rc) encodeClientAddress(ctx, &rc) return &rc } func encodeSpanContext(ctx context.Context, rc *internal.RequestContext) { spanCtx := trace.SpanContextFromContext(ctx) if !spanCtx.IsValid() { return } rc.SpanContext = &internal.SpanContext{ TraceID: internal.TraceID(spanCtx.TraceID()), SpanID: internal.SpanID(spanCtx.SpanID()), TraceFlags: uint32(spanCtx.TraceFlags()), TraceState: spanCtx.TraceState().String(), Remote: spanCtx.IsRemote(), } } func encodeClientMetadata(ctx context.Context, rc *internal.RequestContext) { clientMetadata := client.FromContext(ctx).Metadata for k := range clientMetadata.Keys() { vals := clientMetadata.Get(k) switch len(vals) { case 1: rc.ClientMetadata = append(rc.ClientMetadata, internal.KeyValue{ Key: k, Value: internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: vals[0]}}, }) default: metadataArray := make([]internal.AnyValue, 0, len(vals)) for i := range vals { metadataArray = append(metadataArray, internal.AnyValue{Value: &internal.AnyValue_StringValue{StringValue: vals[i]}}) } rc.ClientMetadata = append(rc.ClientMetadata, internal.KeyValue{ Key: k, Value: internal.AnyValue{Value: &internal.AnyValue_ArrayValue{ArrayValue: &internal.ArrayValue{Values: metadataArray}}}, }) } } } func encodeClientAddress(ctx context.Context, rc *internal.RequestContext) { switch a := client.FromContext(ctx).Addr.(type) { case *net.IPAddr: rc.ClientAddress = &internal.RequestContext_IP{IP: &internal.IPAddr{ IP: a.IP, Zone: a.Zone, }} case *net.TCPAddr: rc.ClientAddress = &internal.RequestContext_TCP{TCP: &internal.TCPAddr{ IP: a.IP, Port: int64(a.Port), Zone: a.Zone, }} case *net.UDPAddr: rc.ClientAddress = &internal.RequestContext_UDP{UDP: &internal.UDPAddr{ IP: a.IP, Port: int64(a.Port), Zone: a.Zone, }} case *net.UnixAddr: rc.ClientAddress = &internal.RequestContext_Unix{Unix: &internal.UnixAddr{ Name: a.Name, Net: a.Net, }} } } // decodeContext decodes the context from the bytes map. func decodeContext(ctx context.Context, rc *internal.RequestContext) context.Context { if rc == nil { return ctx } ctx = decodeSpanContext(ctx, rc.SpanContext) metadataMap := decodeClientMetadata(rc.ClientMetadata) clientAddress := decodeClientAddress(rc) if len(metadataMap) > 0 || clientAddress != nil { ctx = client.NewContext(ctx, client.Info{ Metadata: client.NewMetadata(metadataMap), Addr: clientAddress, }) } return ctx } func decodeSpanContext(ctx context.Context, sc *internal.SpanContext) context.Context { if sc == nil { return ctx } traceID := trace.TraceID(sc.TraceID) spanID := trace.SpanID(sc.SpanID) traceState, _ := trace.ParseTraceState(sc.TraceState) return trace.ContextWithSpanContext(context.Background(), trace.NewSpanContext(trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: trace.TraceFlags(sc.TraceFlags), TraceState: traceState, Remote: sc.Remote, })) } func decodeClientMetadata(clientMetadata []internal.KeyValue) map[string][]string { if len(clientMetadata) == 0 { return nil } metadataMap := make(map[string][]string, len(clientMetadata)) for _, kv := range clientMetadata { switch val := kv.Value.Value.(type) { case *internal.AnyValue_StringValue: metadataMap[kv.Key] = make([]string, 1) metadataMap[kv.Key][0] = val.StringValue case *internal.AnyValue_ArrayValue: metadataMap[kv.Key] = make([]string, len(val.ArrayValue.Values)) for i, v := range val.ArrayValue.Values { metadataMap[kv.Key][i] = v.GetStringValue() } } } return metadataMap } func decodeClientAddress(rc *internal.RequestContext) net.Addr { switch a := rc.ClientAddress.(type) { case *internal.RequestContext_IP: return &net.IPAddr{ IP: a.IP.IP, Zone: a.IP.Zone, } case *internal.RequestContext_TCP: return &net.TCPAddr{ IP: a.TCP.IP, Port: int(a.TCP.Port), Zone: a.TCP.Zone, } case *internal.RequestContext_UDP: return &net.UDPAddr{ IP: a.UDP.IP, Port: int(a.UDP.Port), Zone: a.UDP.Zone, } case *internal.RequestContext_Unix: return &net.UnixAddr{ Name: a.Unix.Name, Net: a.Unix.Net, } } return nil } opentelemetry-collector-0.141.0/pdata/xpdata/request/context_test.go000066400000000000000000000044051511331344600256550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "net" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/pdata/internal" ) func TestEncodeDecodeContext(t *testing.T) { spanCtx := fakeSpanContext(t) clientMetadata := client.NewMetadata(map[string][]string{ "key1": {"value1"}, "key2": {"value2", "value3"}, }) tests := []struct { name string clientInfo client.Info }{ { name: "without_client_address", clientInfo: client.Info{Metadata: clientMetadata}, }, { name: "with_client_IP_address", clientInfo: client.Info{ Metadata: clientMetadata, Addr: &net.IPAddr{ IP: net.IPv6loopback, Zone: "eth0", }, }, }, { name: "with_client_TCP_address", clientInfo: client.Info{ Metadata: clientMetadata, Addr: &net.TCPAddr{ IP: net.IPv4(127, 0, 0, 1), Port: 8080, }, }, }, { name: "with_client_UDP_address", clientInfo: client.Info{ Metadata: clientMetadata, Addr: &net.UDPAddr{ IP: net.IPv4(127, 0, 0, 1), Port: 8080, }, }, }, { name: "with_client_unix_address", clientInfo: client.Info{ Metadata: clientMetadata, Addr: &net.UnixAddr{ Name: "/var/run/test.sock", Net: "unixpacket", }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Encode a context with a span and client metadata ctx := trace.ContextWithSpanContext(context.Background(), spanCtx) ctx = client.NewContext(ctx, tt.clientInfo) reqCtx := encodeContext(ctx) buf := make([]byte, reqCtx.SizeProto()) reqCtx.MarshalProto(buf) // Decode the context gotReqCtx := internal.RequestContext{} require.NoError(t, gotReqCtx.UnmarshalProto(buf)) gotCtx := decodeContext(context.Background(), &gotReqCtx) assert.Equal(t, spanCtx, trace.SpanContextFromContext(gotCtx)) assert.Equal(t, tt.clientInfo, client.FromContext(gotCtx)) }) } // Decode a nil context assert.Equal(t, context.Background(), decodeContext(context.Background(), nil)) } opentelemetry-collector-0.141.0/pdata/xpdata/request/internal/000077500000000000000000000000001511331344600244145ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pdata/xpdata/request/internal/request.proto000066400000000000000000000051471511331344600272000ustar00rootroot00000000000000syntax = "proto3"; package opentelemetry.collector.pdata.xpdata.internal; option go_package = "go.opentelemetry.io/collector/pdata/xpdata/internal"; import "gogoproto/gogo.proto"; import "opentelemetry/proto/trace/v1/trace.proto"; import "opentelemetry/proto/metrics/v1/metrics.proto"; import "opentelemetry/proto/logs/v1/logs.proto"; import "opentelemetry/proto/common/v1/common.proto"; import "opentelemetry/proto/profiles/v1development/profiles.proto"; // SpanContext represents a span context encoded associated with a telemetry export request. message SpanContext { bytes trace_id = 1; bytes span_id = 2; fixed32 trace_flags = 3; string trace_state = 4; bool remote = 5; } message IPAddr { bytes ip = 1; string zone = 2; } message TCPAddr { bytes ip = 1; int64 port = 2; string zone = 3; } message UDPAddr { bytes ip = 1; int64 port = 2; string zone = 3; } message UnixAddr { string name = 1; string net = 2; } // RequestContext represents metadata associated with a telemetry export request. message RequestContext { SpanContext span_context = 1; // ClientMetadata contains additional metadata about the client making the request. repeated opentelemetry.proto.common.v1.KeyValue client_metadata = 2 [ (gogoproto.nullable) = false ]; // ClientAddress contains the address of the client making the request. oneof client_address { IPAddr ip = 3; TCPAddr tcp = 4; UDPAddr udp = 5; UnixAddr unix = 6; } } // The following messages are wrappers around standard OpenTelemetry data types. // They embed request-level context and a version discriminator to ensure they are not wire-compatible with // the canonical OpenTelemetry proto messages. // // Each wrapper reserves field tag 1 for a `fixed32` (protobuf wire type 5) format_version field, which makes it // structurally incompatible with the standard OTLP messages which use tag 1 for the data message field (protobuf wire type 2). // This ensures old and new formats cannot be confused during decoding. message TracesRequest { fixed32 format_version = 1; RequestContext request_context = 2; opentelemetry.proto.trace.v1.TracesData traces_data = 3; } message MetricsRequest { fixed32 format_version = 1; RequestContext request_context = 2; opentelemetry.proto.metrics.v1.MetricsData metrics_data = 3; } message LogsRequest { fixed32 format_version = 1; RequestContext request_context = 2; opentelemetry.proto.logs.v1.LogsData logs_data = 3; } message ProfilesRequest { fixed32 format_version = 1; RequestContext request_context = 2; opentelemetry.proto.profiles.v1development.ProfilesData profiles_data = 3; } opentelemetry-collector-0.141.0/pdata/xpdata/request/logs_request.go000066400000000000000000000022551511331344600256470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "fmt" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/plog" ) // MarshalLogs marshals plog.Logs along with the context into a byte slice. func MarshalLogs(ctx context.Context, ld plog.Logs) ([]byte, error) { lr := internal.LogsRequest{ FormatVersion: requestFormatVersion, LogsData: internal.LogsToProto(internal.LogsWrapper(ld)), RequestContext: encodeContext(ctx), } buf := make([]byte, lr.SizeProto()) lr.MarshalProto(buf) return buf, nil } // UnmarshalLogs unmarshals a byte slice into plog.Logs and the context. func UnmarshalLogs(buf []byte) (context.Context, plog.Logs, error) { ctx := context.Background() if !isRequestPayloadV1(buf) { return ctx, plog.Logs{}, ErrInvalidFormat } lr := internal.LogsRequest{} if err := lr.UnmarshalProto(buf); err != nil { return ctx, plog.Logs{}, fmt.Errorf("failed to unmarshal logs request: %w", err) } return decodeContext(ctx, lr.RequestContext), plog.Logs(internal.LogsFromProto(lr.LogsData)), nil } opentelemetry-collector-0.141.0/pdata/xpdata/request/logs_request_test.go000066400000000000000000000026551511331344600267120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMarshalUnmarshalLogsRequest(t *testing.T) { logs := testdata.GenerateLogs(3) // unmarshal logs request with a context spanCtx := fakeSpanContext(t) buf, err := MarshalLogs(trace.ContextWithSpanContext(context.Background(), spanCtx), logs) require.NoError(t, err) gotCtx, gotLogs, err := UnmarshalLogs(buf) require.NoError(t, err) assert.Equal(t, spanCtx, trace.SpanContextFromContext(gotCtx)) assert.Equal(t, logs, gotLogs) // unmarshal logs request with empty context buf, err = MarshalLogs(context.Background(), logs) require.NoError(t, err) gotCtx, gotLogs, err = UnmarshalLogs(buf) require.NoError(t, err) assert.Equal(t, context.Background(), gotCtx) assert.Equal(t, logs, gotLogs) // unmarshal corrupted data _, _, err = UnmarshalLogs(buf[:len(buf)-1]) require.ErrorContains(t, err, "failed to unmarshal logs request") // unmarshal invalid format (bare logs) buf, err = (&plog.ProtoMarshaler{}).MarshalLogs(logs) require.NoError(t, err) _, _, err = UnmarshalLogs(buf) require.ErrorIs(t, err, ErrInvalidFormat) } opentelemetry-collector-0.141.0/pdata/xpdata/request/metrics_request.go000066400000000000000000000023731511331344600263520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "fmt" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pmetric" ) // MarshalMetrics marshals pmetric.Metrics along with the context into a byte slice. func MarshalMetrics(ctx context.Context, ld pmetric.Metrics) ([]byte, error) { mr := internal.MetricsRequest{ FormatVersion: requestFormatVersion, MetricsData: internal.MetricsToProto(internal.MetricsWrapper(ld)), RequestContext: encodeContext(ctx), } buf := make([]byte, mr.SizeProto()) mr.MarshalProto(buf) return buf, nil } // UnmarshalMetrics unmarshals a byte slice into pmetric.Metrics and the context. func UnmarshalMetrics(buf []byte) (context.Context, pmetric.Metrics, error) { ctx := context.Background() if !isRequestPayloadV1(buf) { return ctx, pmetric.Metrics{}, ErrInvalidFormat } mr := internal.MetricsRequest{} if err := mr.UnmarshalProto(buf); err != nil { return ctx, pmetric.Metrics{}, fmt.Errorf("failed to unmarshal metrics request: %w", err) } return decodeContext(ctx, mr.RequestContext), pmetric.Metrics(internal.MetricsFromProto(mr.MetricsData)), nil } opentelemetry-collector-0.141.0/pdata/xpdata/request/metrics_request_test.go000066400000000000000000000027701511331344600274120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMarshalUnmarshalMetricsRequest(t *testing.T) { metrics := testdata.GenerateMetrics(3) // unmarshal metrics request with a context spanCtx := fakeSpanContext(t) buf, err := MarshalMetrics(trace.ContextWithSpanContext(context.Background(), spanCtx), metrics) require.NoError(t, err) gotCtx, gotMetrics, err := UnmarshalMetrics(buf) require.NoError(t, err) assert.Equal(t, spanCtx, trace.SpanContextFromContext(gotCtx)) assert.Equal(t, metrics, gotMetrics) // unmarshal metrics request with empty context buf, err = MarshalMetrics(context.Background(), metrics) require.NoError(t, err) gotCtx, gotMetrics, err = UnmarshalMetrics(buf) require.NoError(t, err) assert.Equal(t, context.Background(), gotCtx) assert.Equal(t, metrics, gotMetrics) // unmarshal corrupted data _, _, err = UnmarshalMetrics(buf[:len(buf)-1]) require.ErrorContains(t, err, "failed to unmarshal metrics request") // unmarshal invalid format (bare metrics) buf, err = (&pmetric.ProtoMarshaler{}).MarshalMetrics(metrics) require.NoError(t, err) _, _, err = UnmarshalMetrics(buf) require.ErrorIs(t, err, ErrInvalidFormat) } opentelemetry-collector-0.141.0/pdata/xpdata/request/profiles_request.go000066400000000000000000000024251511331344600265250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "fmt" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/pprofile" ) // MarshalProfiles marshals pprofile.Profiles along with the context into a byte slice. func MarshalProfiles(ctx context.Context, ld pprofile.Profiles) ([]byte, error) { pr := internal.ProfilesRequest{ FormatVersion: requestFormatVersion, ProfilesData: internal.ProfilesToProto(internal.ProfilesWrapper(ld)), RequestContext: encodeContext(ctx), } buf := make([]byte, pr.SizeProto()) pr.MarshalProto(buf) return buf, nil } // UnmarshalProfiles unmarshals a byte slice into pprofile.Profiles and the context. func UnmarshalProfiles(buf []byte) (context.Context, pprofile.Profiles, error) { ctx := context.Background() if !isRequestPayloadV1(buf) { return ctx, pprofile.Profiles{}, ErrInvalidFormat } pr := internal.ProfilesRequest{} if err := pr.UnmarshalProto(buf); err != nil { return ctx, pprofile.Profiles{}, fmt.Errorf("failed to unmarshal profiles request: %w", err) } return decodeContext(ctx, pr.RequestContext), pprofile.Profiles(internal.ProfilesFromProto(pr.ProfilesData)), nil } opentelemetry-collector-0.141.0/pdata/xpdata/request/profiles_request_test.go000066400000000000000000000030211511331344600275550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMarshalUnmarshalProfilesRequest(t *testing.T) { profiles := testdata.GenerateProfiles(3) // unmarshal profiles request with a context spanCtx := fakeSpanContext(t) buf, err := MarshalProfiles(trace.ContextWithSpanContext(context.Background(), spanCtx), profiles) require.NoError(t, err) gotCtx, gotProfiles, err := UnmarshalProfiles(buf) require.NoError(t, err) assert.Equal(t, spanCtx, trace.SpanContextFromContext(gotCtx)) assert.Equal(t, profiles, gotProfiles) // unmarshal profiles request with empty context buf, err = MarshalProfiles(context.Background(), profiles) require.NoError(t, err) gotCtx, gotProfiles, err = UnmarshalProfiles(buf) require.NoError(t, err) assert.Equal(t, context.Background(), gotCtx) assert.Equal(t, profiles, gotProfiles) // unmarshal corrupted data _, _, err = UnmarshalProfiles(buf[:len(buf)-1]) require.ErrorContains(t, err, "failed to unmarshal profiles request") // unmarshal invalid format (bare profiles) buf, err = (&pprofile.ProtoMarshaler{}).MarshalProfiles(profiles) require.NoError(t, err) _, _, err = UnmarshalProfiles(buf) require.ErrorIs(t, err, ErrInvalidFormat) } opentelemetry-collector-0.141.0/pdata/xpdata/request/requesttest.go000066400000000000000000000014041511331344600255160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" ) func fakeSpanContext(tb testing.TB) trace.SpanContext { traceID, err := trace.TraceIDFromHex("0102030405060708090a0b0c0d0e0f10") require.NoError(tb, err) spanID, err := trace.SpanIDFromHex("0102030405060708") require.NoError(tb, err) traceState, err := trace.ParseTraceState("key1=value1,key2=value2,key3=value3") require.NoError(tb, err) return trace.NewSpanContext(trace.SpanContextConfig{ TraceID: traceID, SpanID: spanID, TraceFlags: 0x01, TraceState: traceState, Remote: true, }) } opentelemetry-collector-0.141.0/pdata/xpdata/request/traces_request.go000066400000000000000000000023411511331344600261600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "fmt" "go.opentelemetry.io/collector/pdata/internal" "go.opentelemetry.io/collector/pdata/ptrace" ) // MarshalTraces marshals ptrace.Traces along with the context into a byte slice. func MarshalTraces(ctx context.Context, ld ptrace.Traces) ([]byte, error) { tr := internal.TracesRequest{ FormatVersion: requestFormatVersion, TracesData: internal.TracesToProto(internal.TracesWrapper(ld)), RequestContext: encodeContext(ctx), } buf := make([]byte, tr.SizeProto()) tr.MarshalProto(buf) return buf, nil } // UnmarshalTraces unmarshals a byte slice into ptrace.Traces and the context. func UnmarshalTraces(buf []byte) (context.Context, ptrace.Traces, error) { ctx := context.Background() if !isRequestPayloadV1(buf) { return ctx, ptrace.Traces{}, ErrInvalidFormat } tr := internal.TracesRequest{} if err := tr.UnmarshalProto(buf); err != nil { return ctx, ptrace.Traces{}, fmt.Errorf("failed to unmarshal traces request: %w", err) } return decodeContext(ctx, tr.RequestContext), ptrace.Traces(internal.TracesFromProto(tr.TracesData)), nil } opentelemetry-collector-0.141.0/pdata/xpdata/request/traces_request_test.go000066400000000000000000000027371511331344600272300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) func TestMarshalUnmarshalTracesRequest(t *testing.T) { traces := testdata.GenerateTraces(3) // unmarshal traces request with a context spanCtx := fakeSpanContext(t) buf, err := MarshalTraces(trace.ContextWithSpanContext(context.Background(), spanCtx), traces) require.NoError(t, err) gotCtx, gotTraces, err := UnmarshalTraces(buf) require.NoError(t, err) assert.Equal(t, spanCtx, trace.SpanContextFromContext(gotCtx)) assert.Equal(t, traces, gotTraces) // unmarshal traces request with empty context buf, err = MarshalTraces(context.Background(), traces) require.NoError(t, err) gotCtx, gotTraces, err = UnmarshalTraces(buf) require.NoError(t, err) assert.Equal(t, context.Background(), gotCtx) assert.Equal(t, traces, gotTraces) // unmarshal corrupted data _, _, err = UnmarshalTraces(buf[:len(buf)-1]) require.ErrorContains(t, err, "failed to unmarshal traces request") // unmarshal invalid format (bare traces) buf, err = (&ptrace.ProtoMarshaler{}).MarshalTraces(traces) require.NoError(t, err) _, _, err = UnmarshalTraces(buf) require.ErrorIs(t, err, ErrInvalidFormat) } opentelemetry-collector-0.141.0/pdata/xpdata/request/version_check.go000066400000000000000000000015301511331344600257500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request // import "go.opentelemetry.io/collector/pdata/xpdata/request" import ( "encoding/binary" "errors" ) const ( // field 1 << 3, wire type 5 (fixed32) protoTag1TypeByte = 0x0D // version of the request payload format set in the `format_version` field requestFormatVersion = uint32(1) ) var ErrInvalidFormat = errors.New("invalid request payload format") // isRequestPayloadV1 returns true if the given payload represents one of the wrappers around standard OpenTelemetry // data types defined in internal/request.go and has the version set to 1. func isRequestPayloadV1(data []byte) bool { if len(data) < 5 { return false } if data[0] != protoTag1TypeByte { return false } return binary.LittleEndian.Uint32(data[1:5]) == requestFormatVersion } opentelemetry-collector-0.141.0/pdata/xpdata/request/version_check_test.go000066400000000000000000000027221511331344600270130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package request import ( "context" "encoding/binary" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestIsRequestPayloadV1(t *testing.T) { // too short assert.False(t, isRequestPayloadV1([]byte{protoTag1TypeByte, 0x00})) buf := make([]byte, 5) // wrong type: field 1, wire type 2 (length-delimited) buf[0] = 0x0A assert.False(t, isRequestPayloadV1([]byte{protoTag1TypeByte, 0x00})) // wrong version buf[0] = protoTag1TypeByte binary.LittleEndian.PutUint32(buf[1:], 2) assert.False(t, isRequestPayloadV1(buf)) binary.LittleEndian.PutUint32(buf[1:], requestFormatVersion) assert.True(t, isRequestPayloadV1(buf)) buf, err := MarshalMetrics(context.Background(), pmetric.NewMetrics()) require.NoError(t, err) assert.True(t, isRequestPayloadV1(buf)) buf, err = MarshalTraces(context.Background(), ptrace.NewTraces()) require.NoError(t, err) assert.True(t, isRequestPayloadV1(buf)) buf, err = MarshalLogs(context.Background(), plog.NewLogs()) require.NoError(t, err) assert.True(t, isRequestPayloadV1(buf)) buf, err = MarshalProfiles(context.Background(), pprofile.NewProfiles()) require.NoError(t, err) assert.True(t, isRequestPayloadV1(buf)) } opentelemetry-collector-0.141.0/pipeline/000077500000000000000000000000001511331344600203435ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pipeline/Makefile000066400000000000000000000000331511331344600217770ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/pipeline/go.mod000066400000000000000000000003711511331344600214520ustar00rootroot00000000000000module go.opentelemetry.io/collector/pipeline go 1.24.0 require github.com/stretchr/testify v1.11.1 require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) opentelemetry-collector-0.141.0/pipeline/go.sum000066400000000000000000000015631511331344600215030ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/pipeline/internal/000077500000000000000000000000001511331344600221575ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pipeline/internal/globalsignal/000077500000000000000000000000001511331344600246155ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pipeline/internal/globalsignal/signal.go000066400000000000000000000022351511331344600264230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package globalsignal // import "go.opentelemetry.io/collector/pipeline/internal/globalsignal" import ( "encoding" "fmt" ) var ( SignalProfiles = Signal{name: "profiles"} SignalTraces = Signal{name: "traces"} SignalMetrics = Signal{name: "metrics"} SignalLogs = Signal{name: "logs"} _ encoding.TextMarshaler = (*Signal)(nil) _ encoding.TextUnmarshaler = (*Signal)(nil) ) // Signal represents the signals supported by the collector. type Signal struct { name string } // String returns the string representation of the signal. func (s Signal) String() string { return s.name } // MarshalText marshals the Signal. func (s Signal) MarshalText() ([]byte, error) { return []byte(s.name), nil } // UnmarshalText marshals the Signal. func (s *Signal) UnmarshalText(text []byte) error { switch string(text) { case SignalProfiles.name: *s = SignalProfiles case SignalTraces.name: *s = SignalTraces case SignalMetrics.name: *s = SignalMetrics case SignalLogs.name: *s = SignalLogs default: return fmt.Errorf("unknown pipeline signal: %q", string(text)) } return nil } opentelemetry-collector-0.141.0/pipeline/internal/globalsignal/signal_test.go000066400000000000000000000027031511331344600274620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package globalsignal import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSignal_String(t *testing.T) { assert.Equal(t, "traces", SignalTraces.String()) assert.Equal(t, "metrics", SignalMetrics.String()) assert.Equal(t, "logs", SignalLogs.String()) assert.Equal(t, "profiles", SignalProfiles.String()) } func TestSignal_MarshalText(t *testing.T) { b, err := SignalTraces.MarshalText() require.NoError(t, err) assert.Equal(t, []byte("traces"), b) b, err = SignalMetrics.MarshalText() require.NoError(t, err) assert.Equal(t, []byte("metrics"), b) b, err = SignalLogs.MarshalText() require.NoError(t, err) assert.Equal(t, []byte("logs"), b) b, err = SignalProfiles.MarshalText() require.NoError(t, err) assert.Equal(t, []byte("profiles"), b) var s Signal b, err = s.MarshalText() require.NoError(t, err) assert.Equal(t, []byte(""), b) } func TestSignal_UnmarshalText(t *testing.T) { var s Signal require.NoError(t, s.UnmarshalText([]byte("traces"))) assert.Equal(t, SignalTraces, s) require.NoError(t, s.UnmarshalText([]byte("metrics"))) assert.Equal(t, SignalMetrics, s) require.NoError(t, s.UnmarshalText([]byte("logs"))) assert.Equal(t, SignalLogs, s) require.NoError(t, s.UnmarshalText([]byte("profiles"))) assert.Equal(t, SignalProfiles, s) require.Error(t, s.UnmarshalText([]byte("unknown"))) } opentelemetry-collector-0.141.0/pipeline/pipeline.go000066400000000000000000000055221511331344600225030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pipeline // import "go.opentelemetry.io/collector/pipeline" import ( "errors" "fmt" "regexp" "strings" ) // typeAndNameSeparator is the separator that is used between type and name in type/name composite keys. const typeAndNameSeparator = "/" // ID represents the identity for a pipeline. It combines two values: // * signal - the Signal of the pipeline. // * name - the name of that pipeline. type ID struct { signal Signal `mapstructure:"-"` name string `mapstructure:"-"` } // NewID returns a new ID with the given Signal and empty name. func NewID(signal Signal) ID { return NewIDWithName(signal, "") } // NewIDWithName returns a new ID with the given Signal and name. func NewIDWithName(signal Signal, name string) ID { return ID{signal: signal, name: name} } // Signal returns the Signal of the ID. func (i ID) Signal() Signal { return i.signal } // Name returns the name of the ID. func (i ID) Name() string { return i.name } // MarshalText implements the encoding.TextMarshaler interface. // This marshals the Signal and name as one string in the config. func (i ID) MarshalText() (text []byte, err error) { return []byte(i.String()), nil } // UnmarshalText implements the encoding.TextUnmarshaler interface. func (i *ID) UnmarshalText(text []byte) error { idStr := string(text) signalStr, nameStr, hasName := strings.Cut(idStr, typeAndNameSeparator) signalStr = strings.TrimSpace(signalStr) if signalStr == "" { if hasName { return fmt.Errorf("in %q id: the part before %s should not be empty", idStr, typeAndNameSeparator) } return errors.New("id must not be empty") } if hasName { // "name" part is present. nameStr = strings.TrimSpace(nameStr) if nameStr == "" { return fmt.Errorf("in %q id: the part after %s should not be empty", idStr, typeAndNameSeparator) } if err := validateName(nameStr); err != nil { return fmt.Errorf("in %q id: %w", nameStr, err) } } if err := i.signal.UnmarshalText([]byte(signalStr)); err != nil { return fmt.Errorf("in %q id: %w", idStr, err) } i.name = nameStr return nil } // String returns the ID string representation as "signal[/name]" format. func (i ID) String() string { if i.name == "" { return i.signal.String() } return i.signal.String() + typeAndNameSeparator + i.name } // nameRegexp is used to validate the name of an ID. A name can consist of // 1 to 1024 unicode characters excluding whitespace, control characters, and // symbols. var nameRegexp = regexp.MustCompile(`^[^\pZ\pC\pS]+$`) func validateName(nameStr string) error { if len(nameStr) > 1024 { return fmt.Errorf("name %q is longer than 1024 characters (%d characters)", nameStr, len(nameStr)) } if !nameRegexp.MatchString(nameStr) { return fmt.Errorf("invalid character(s) in name %q", nameStr) } return nil } opentelemetry-collector-0.141.0/pipeline/pipeline_test.go000066400000000000000000000053771511331344600235520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pipeline import ( "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/pipeline/internal/globalsignal" ) func Test_NewID(t *testing.T) { id := NewID(SignalTraces) assert.Equal(t, ID{signal: SignalTraces}, id) } func Test_NewIDWithName(t *testing.T) { id := NewIDWithName(SignalTraces, "test") assert.Equal(t, ID{signal: SignalTraces, name: "test"}, id) } func TestMarshalText(t *testing.T) { id := NewIDWithName(SignalTraces, "name") got, err := id.MarshalText() require.NoError(t, err) assert.Equal(t, id.String(), string(got)) } func TestUnmarshalText(t *testing.T) { testCases := []struct { idStr string expectedErr bool expectedID ID }{ { idStr: "traces", expectedID: ID{signal: globalsignal.SignalTraces, name: ""}, }, { idStr: "traces/valid_name", expectedID: ID{signal: globalsignal.SignalTraces, name: "valid_name"}, }, { idStr: " traces / valid_name ", expectedID: ID{signal: globalsignal.SignalTraces, name: "valid_name"}, }, { idStr: "traces/ไธญๆ–‡ๅฅฝ", expectedID: ID{signal: globalsignal.SignalTraces, name: "ไธญๆ–‡ๅฅฝ"}, }, { idStr: "traces/name-with-dashes", expectedID: ID{signal: globalsignal.SignalTraces, name: "name-with-dashes"}, }, // issue 10816 { idStr: "traces/Linux-Messages-File_01J49HCH3SWFXRVASWFZFRT3J2__processor0__logs", expectedID: ID{signal: globalsignal.SignalTraces, name: "Linux-Messages-File_01J49HCH3SWFXRVASWFZFRT3J2__processor0__logs"}, }, { idStr: "traces/1", expectedID: ID{signal: globalsignal.SignalTraces, name: "1"}, }, { idStr: "/valid_name", expectedErr: true, }, { idStr: " /valid_name", expectedErr: true, }, { idStr: "traces/", expectedErr: true, }, { idStr: "traces/ ", expectedErr: true, }, { idStr: " ", expectedErr: true, }, { idStr: "traces/invalid name", expectedErr: true, }, { idStr: "traces/" + strings.Repeat("a", 1025), expectedErr: true, }, { idStr: "INVALID", expectedErr: true, }, { idStr: "INVALID/name", expectedErr: true, }, } for _, test := range testCases { t.Run(test.idStr, func(t *testing.T) { id := ID{} err := id.UnmarshalText([]byte(test.idStr)) if test.expectedErr { assert.Error(t, err) return } require.NoError(t, err) assert.Equal(t, test.expectedID, id) assert.Equal(t, test.expectedID.Signal(), id.Signal()) assert.Equal(t, test.expectedID.Name(), id.Name()) assert.Equal(t, test.expectedID.String(), id.String()) }) } } opentelemetry-collector-0.141.0/pipeline/signal.go000066400000000000000000000011721511331344600221500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pipeline // import "go.opentelemetry.io/collector/pipeline" import ( "errors" "go.opentelemetry.io/collector/pipeline/internal/globalsignal" ) // Signal represents the signals supported by the collector. We currently support // collecting metrics, traces and logs, this can expand in the future. type Signal = globalsignal.Signal var ErrSignalNotSupported = errors.New("telemetry type is not supported") var ( SignalTraces = globalsignal.SignalTraces SignalMetrics = globalsignal.SignalMetrics SignalLogs = globalsignal.SignalLogs ) opentelemetry-collector-0.141.0/pipeline/xpipeline/000077500000000000000000000000001511331344600223405ustar00rootroot00000000000000opentelemetry-collector-0.141.0/pipeline/xpipeline/Makefile000066400000000000000000000000361511331344600237770ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/pipeline/xpipeline/config.go000066400000000000000000000004271511331344600241370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xpipeline // import "go.opentelemetry.io/collector/pipeline/xpipeline" import "go.opentelemetry.io/collector/pipeline/internal/globalsignal" var SignalProfiles = globalsignal.SignalProfiles opentelemetry-collector-0.141.0/pipeline/xpipeline/go.mod000066400000000000000000000002621511331344600234460ustar00rootroot00000000000000module go.opentelemetry.io/collector/pipeline/xpipeline go 1.24.0 require go.opentelemetry.io/collector/pipeline v1.47.0 replace go.opentelemetry.io/collector/pipeline => ../ opentelemetry-collector-0.141.0/pipeline/xpipeline/go.sum000066400000000000000000000012421511331344600234720ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/000077500000000000000000000000001511331344600205555ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/Makefile000066400000000000000000000000331511331344600222110ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/processor/README.md000066400000000000000000000137541511331344600220460ustar00rootroot00000000000000# General Information Processors are used at various stages of a pipeline. Generally, a processor pre-processes data before it is exported (e.g. modify attributes or sample). Some important aspects of pipelines and processors to be aware of: - [Recommended Processors](#recommended-processors) - [Data Ownership](#data-ownership) - [Exclusive Ownership](#exclusive-ownership) - [Shared Ownership](#shared-ownership) - [Ordering Processors](#ordering-processors) - [Creating Custom Processor](#creating-custom-processors) Supported processors (sorted alphabetically): - [Batch Processor](batchprocessor/README.md) - [Memory Limiter Processor](memorylimiterprocessor/README.md) The [contrib repository](https://github.com/open-telemetry/opentelemetry-collector-contrib) has more processors that can be added to a custom build of the Collector. ## Recommended Processors By default, no processors are enabled. Depending on the data source, it may be recommended that multiple processors be enabled. Processors must be enabled for every data source and not all processors support all data sources. In addition, it is important to note that the order of processors matters. The order in each section below is the best practice. Refer to the individual processor documentation for more information. 1. [memory_limiter](memorylimiterprocessor/README.md) 2. Any sampling or initial filtering processors 3. Any processor relying on sending source from `Context` (e.g. `k8sattributes`) 3. [batch](batchprocessor/README.md), although prefer using the exporter's batching capabilities 4. Any other processors ## Data Ownership The ownership of the `pdata.Traces`, `pdata.Metrics` and `pdata.Logs` data in a pipeline is passed as the data travels through the pipeline. The data is created by the receiver and then the ownership is passed to the first processor when `ConsumeTraces`/`ConsumeMetrics`/`ConsumeLogs` function is called. Note: the receiver may be attached to multiple pipelines, in which case the same data will be passed to all attached pipelines via a data fan-out connector. From data ownership perspective pipelines can work in 2 modes: * Exclusive data ownership * Shared data ownership The mode is defined during startup based on data modification intent reported by the processors. The intent is reported by each processor via `MutatesData` field of the struct returned by `Capabilities` function. If any processor in the pipeline declares an intent to modify the data then that pipeline will work in exclusive ownership mode. In addition, any other pipeline that receives data from a receiver that is attached to a pipeline with exclusive ownership mode will be also operating in exclusive ownership mode. ### Exclusive Ownership In exclusive ownership mode the data is owned exclusively by a particular processor at a given moment of time, and the processor is free to modify the data it owns. Exclusive ownership mode is only applicable for pipelines that receive data from the same receiver. If a pipeline is marked to be in exclusive ownership mode then any data received from a shared receiver will be cloned at the fan-out connector before passing further to each pipeline. This ensures that each pipeline has its own exclusive copy of data, and the data can be safely modified in the pipeline. The exclusive ownership of data allows processors to freely modify the data while they own it (e.g. see `attributesprocessor`). The duration of ownership of the data by processor is from the beginning of `ConsumeTraces`/`ConsumeMetrics`/`ConsumeLogs` call until the processor calls the next processor's `ConsumeTraces`/`ConsumeMetrics`/`ConsumeLogs` function, which passes the ownership to the next processor. After that the processor must no longer read or write the data since it may be concurrently modified by the new owner. Exclusive Ownership mode allows to easily implement processors that need to modify the data by simply declaring such intent. ### Shared Ownership In shared ownership mode no particular processor owns the data and no processor is allowed the modify the shared data. In this mode no cloning is performed at the fan-out connector of receivers that are attached to multiple pipelines. In this case all such pipelines will see the same single shared copy of the data. Processors in pipelines operating in shared ownership mode are prohibited from modifying the original data that they receive via `ConsumeTraces`/`ConsumeMetrics`/`ConsumeLogs` call. Processors may only read the data but must not modify the data. If the processor needs to modify the data while performing the processing but does not want to incur the cost of data cloning that Exclusive mode brings then the processor can declare that it does not modify the data and use any different technique that ensures original data is not modified. For example, the processor can implement copy-on-write approach for individual sub-parts of `pdata.Traces`/`pdata.Metrics`/`pdata.Logs` argument. Any approach that does not mutate the original `pdata.Traces`/`pdata.Metrics`/`pdata.Logs` is allowed. If the processor uses such technique it should declare that it does not intend to modify the original data by setting `MutatesData=false` in its capabilities to avoid marking the pipeline for Exclusive ownership and to avoid the cost of data cloning described in Exclusive Ownership section. ## Ordering Processors The order processors are specified in a pipeline is important as this is the order in which each processor is applied. ## Creating Custom Processors To create a custom processor for the OpenTelemetry Collector, you need to implement the processor interface, define the processor's configuration, and register it with the Collector. The process typically involves creating a factory, implementing the required processing logic, and handling configuration options. For a practical example and guidance, refer to the [`processorhelper`](https://pkg.go.dev/go.opentelemetry.io/collector/processor/processorhelper) package, which provides utilities and patterns to simplify processor development. opentelemetry-collector-0.141.0/processor/batchprocessor/000077500000000000000000000000001511331344600235765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/batchprocessor/Makefile000066400000000000000000000000361511331344600252350ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/processor/batchprocessor/README.md000066400000000000000000000120361511331344600250570ustar00rootroot00000000000000# Batch Processor | Status | | | ------------- |-----------| | Stability | [beta]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprocessor%2Fbatch%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprocessor%2Fbatch) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprocessor%2Fbatch%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprocessor%2Fbatch) | [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 The batch processor accepts spans, metrics, or logs and places them into batches. Batching helps better compress the data and reduce the number of outgoing connections required to transmit the data. This processor supports both size and time based batching. The batch processor should be defined in the pipeline after the `memory_limiter` as well as any sampling processors. This is because batching should happen after any data drops such as sampling. Please refer to [config.go](./config.go) for the config spec. The following configuration options can be modified: - `send_batch_size` (default = 8192): Number of spans, metric data points, or log records after which a batch will be sent regardless of the timeout. `send_batch_size` acts as a trigger and does not affect the size of the batch. If you need to enforce batch size limits sent to the next component in the pipeline see `send_batch_max_size`. - `timeout` (default = 200ms): Time duration after which a batch will be sent regardless of size. If set to zero, `send_batch_size` is ignored as data will be sent immediately, subject to only `send_batch_max_size`. - `send_batch_max_size` (default = 0): The upper limit of the batch size. `0` means no upper limit of the batch size. This property ensures that larger batches are split into smaller units. It must be greater than or equal to `send_batch_size`. - `metadata_keys` (default = empty): When set, this processor will create one batcher instance per distinct combination of values in the `client.Metadata`. - `metadata_cardinality_limit` (default = 1000): When `metadata_keys` is not empty, this setting limits the number of unique combinations of metadata key values that will be processed over the lifetime of the process. See notes about metadata batching below. Examples: This configuration contains one default batch processor and a second with custom settings. The `batch/2` processor will buffer up to 10000 spans, metric data points, or log records for up to 10 seconds without splitting data items to enforce a maximum batch size. ```yaml processors: batch: batch/2: send_batch_size: 10000 timeout: 10s ``` This configuration will enforce a maximum batch size limit of 10000 spans, metric data points, or log records without introducing any artificial delays. ```yaml processors: batch: send_batch_max_size: 10000 timeout: 0s ``` Refer to [config.yaml](./testdata/config.yaml) for detailed examples on using the processor. ## Batching and client metadata Batching by metadata enables support for multi-tenant OpenTelemetry Collector pipelines with batching over groups of data having the same authorization metadata. For example: ```yaml processors: batch: # batch data by tenant-id metadata_keys: - tenant_id # limit to 10 batcher processes before raising errors metadata_cardinality_limit: 10 ``` Receivers should be configured with `include_metadata: true` so that metadata keys are available to the processor. Note that each distinct combination of metadata triggers the allocation of a new background task in the Collector that runs for the lifetime of the process, and each background task holds one pending batch of up to `send_batch_size` records. Batching by metadata can therefore substantially increase the amount of memory dedicated to batching. The maximum number of distinct combinations is limited to the configured `metadata_cardinality_limit`, which defaults to 1000 to limit memory impact. Users of the batching processor configured with metadata keys should consider use of an Auth extension to validate the relevant metadata-key values. The number of batch processors currently in use is exported as the `otelcol_processor_batch_metadata_cardinality` metric. opentelemetry-collector-0.141.0/processor/batchprocessor/batch_processor.go000066400000000000000000000373531511331344600273200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor // import "go.opentelemetry.io/collector/processor/batchprocessor" import ( "context" "errors" "fmt" "runtime" "sort" "strings" "sync" "time" "go.opentelemetry.io/otel/attribute" "go.uber.org/zap" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/xpdata/pref" "go.opentelemetry.io/collector/processor" ) // errTooManyBatchers is returned when the MetadataCardinalityLimit has been reached. var errTooManyBatchers = consumererror.NewPermanent(errors.New("too many batcher metadata-value combinations")) // batch_processor is a component that accepts spans and metrics, places them // into batches and sends downstream. // // batch_processor implements consumer.Traces and consumer.Metrics // // Batches are sent out with any of the following conditions: // - batch size reaches cfg.SendBatchSize // - cfg.Timeout is elapsed since the timestamp when the previous batch was sent out. type batchProcessor[T any] struct { logger *zap.Logger timeout time.Duration sendBatchSize int sendBatchMaxSize int // batchFunc is a factory for new batch objects corresponding // with the appropriate signal. batchFunc func() batch[T] shutdownC chan struct{} goroutines sync.WaitGroup telemetry *batchProcessorTelemetry // batcher will be either *singletonBatcher or *multiBatcher batcher batcher[T] } // batcher is describes a *singletonBatcher or *multiBatcher. type batcher[T any] interface { // start initializes background resources used by this batcher. start(ctx context.Context) error // consume incorporates a new item of data into the pending batch. consume(ctx context.Context, data T) error // currentMetadataCardinality returns the number of shards. currentMetadataCardinality() int } // shard is a single instance of the batch logic. When metadata // keys are in use, one of these is created per distinct combination // of values. type shard[T any] struct { // processor refers to this processor, for access to common // configuration. processor *batchProcessor[T] // exportCtx is a context with the metadata key-values // corresponding with this shard set. exportCtx context.Context // timer informs the shard send a batch. timer *time.Timer // newItem is used to receive data items from producers. newItem chan T // batch is an in-flight data item containing one of the // underlying data types. batch batch[T] } // batch is an interface generalizing the individual signal types. type batch[T any] interface { // export the current batch export(ctx context.Context, req T) error // split returns a full request built from pending items. split(sendBatchMaxSize int) (sentBatchSize int, req T) // itemCount returns the size of the current batch itemCount() int // add item to the current batch add(item T) // sizeBytes counts the OTLP encoding size of the batch sizeBytes(item T) int } // newBatchProcessor returns a new batch processor component. func newBatchProcessor[T any](set processor.Settings, cfg *Config, batchFunc func() batch[T]) (*batchProcessor[T], error) { // use lower-case, to be consistent with http/2 headers. mks := make([]string, len(cfg.MetadataKeys)) for i, k := range cfg.MetadataKeys { mks[i] = strings.ToLower(k) } sort.Strings(mks) bp := &batchProcessor[T]{ logger: set.Logger, sendBatchSize: int(cfg.SendBatchSize), sendBatchMaxSize: int(cfg.SendBatchMaxSize), timeout: cfg.Timeout, batchFunc: batchFunc, shutdownC: make(chan struct{}, 1), } if len(mks) == 0 { bp.batcher = &singleShardBatcher[T]{ processor: bp, single: bp.newShard(nil), } } else { bp.batcher = &multiShardBatcher[T]{ metadataKeys: mks, metadataLimit: int(cfg.MetadataCardinalityLimit), processor: bp, } } bpt, err := newBatchProcessorTelemetry(set, bp.batcher.currentMetadataCardinality) if err != nil { return nil, fmt.Errorf("error creating batch processor telemetry: %w", err) } bp.telemetry = bpt return bp, nil } // newShard gets or creates a batcher corresponding with attrs. func (bp *batchProcessor[T]) newShard(md map[string][]string) *shard[T] { exportCtx := client.NewContext(context.Background(), client.Info{ Metadata: client.NewMetadata(md), }) b := &shard[T]{ processor: bp, newItem: make(chan T, runtime.NumCPU()), exportCtx: exportCtx, batch: bp.batchFunc(), } return b } func (bp *batchProcessor[T]) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: true} } // Start is invoked during service startup. func (bp *batchProcessor[T]) Start(ctx context.Context, _ component.Host) error { return bp.batcher.start(ctx) } // Shutdown is invoked during service shutdown. func (bp *batchProcessor[T]) Shutdown(context.Context) error { close(bp.shutdownC) // Wait until all goroutines are done. bp.goroutines.Wait() return nil } func (b *shard[T]) start() { b.processor.goroutines.Add(1) go b.startLoop() } func (b *shard[T]) startLoop() { defer b.processor.goroutines.Done() // timerCh ensures we only block when there is a // timer, since <- from a nil channel is blocking. var timerCh <-chan time.Time if b.processor.timeout != 0 && b.processor.sendBatchSize != 0 { b.timer = time.NewTimer(b.processor.timeout) timerCh = b.timer.C } for { select { case <-b.processor.shutdownC: DONE: for { select { case item := <-b.newItem: b.processItem(item) default: break DONE } } // This is the close of the channel if b.batch.itemCount() > 0 { // TODO: Set a timeout on sendTraces or // make it cancellable using the context that Shutdown gets as a parameter b.sendItems(triggerTimeout) } return case item := <-b.newItem: b.processItem(item) case <-timerCh: if b.batch.itemCount() > 0 { b.sendItems(triggerTimeout) } b.resetTimer() } } } func (b *shard[T]) processItem(item T) { b.batch.add(item) sent := false for b.batch.itemCount() > 0 && (!b.hasTimer() || b.batch.itemCount() >= b.processor.sendBatchSize) { sent = true b.sendItems(triggerBatchSize) } if sent { b.stopTimer() b.resetTimer() } } func (b *shard[T]) hasTimer() bool { return b.timer != nil } func (b *shard[T]) stopTimer() { if b.hasTimer() && !b.timer.Stop() { <-b.timer.C } } func (b *shard[T]) resetTimer() { if b.hasTimer() { b.timer.Reset(b.processor.timeout) } } func (b *shard[T]) sendItems(trigger trigger) { sent, req := b.batch.split(b.processor.sendBatchMaxSize) bpt := b.processor.telemetry var bytes int // Check if the instrument is enabled to calculate the size of the batch in bytes. // See https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric/internal/x#readme-instrument-enabled batchSendSizeBytes := bpt.telemetryBuilder.ProcessorBatchBatchSendSizeBytes instr, ok := batchSendSizeBytes.(interface{ Enabled(context.Context) bool }) if !ok || instr.Enabled(bpt.exportCtx) { bytes = b.batch.sizeBytes(req) } err := b.batch.export(b.exportCtx, req) if err != nil { b.processor.logger.Warn("Sender failed", zap.Error(err)) return } bpt.record(trigger, int64(sent), int64(bytes)) } // singleShardBatcher is used when metadataKeys is empty, to avoid the // additional lock and map operations used in multiBatcher. type singleShardBatcher[T any] struct { processor *batchProcessor[T] single *shard[T] } func (sb *singleShardBatcher[T]) start(context.Context) error { sb.single.start() return nil } func (sb *singleShardBatcher[T]) consume(_ context.Context, data T) error { sb.single.newItem <- data return nil } func (sb *singleShardBatcher[T]) currentMetadataCardinality() int { return 1 } // multiShardBatcher is used when metadataKeys is not empty. type multiShardBatcher[T any] struct { // metadataKeys is the configured list of metadata keys. When // empty, the `singleton` batcher is used. When non-empty, // each distinct combination of metadata keys and values // triggers a new batcher, counted in `goroutines`. metadataKeys []string // metadataLimit is the limiting size of the batchers map. metadataLimit int processor *batchProcessor[T] batchers sync.Map // Guards the size and the storing logic to ensure no more than limit items are stored. // If we are willing to allow "some" extra items than the limit this can be removed and size can be made atomic. lock sync.Mutex size int } func (mb *multiShardBatcher[T]) start(context.Context) error { return nil } func (mb *multiShardBatcher[T]) consume(ctx context.Context, data T) error { // Get each metadata key value, form the corresponding // attribute set for use as a map lookup key. info := client.FromContext(ctx) md := map[string][]string{} var attrs []attribute.KeyValue for _, k := range mb.metadataKeys { // Lookup the value in the incoming metadata, copy it // into the outgoing metadata, and create a unique // value for the attributeSet. vs := info.Metadata.Get(k) md[k] = vs if len(vs) == 1 { attrs = append(attrs, attribute.String(k, vs[0])) } else { attrs = append(attrs, attribute.StringSlice(k, vs)) } } aset := attribute.NewSet(attrs...) b, ok := mb.batchers.Load(aset) if !ok { mb.lock.Lock() if mb.metadataLimit != 0 && mb.size >= mb.metadataLimit { mb.lock.Unlock() return errTooManyBatchers } // aset.ToSlice() returns the sorted, deduplicated, // and name-lowercased list of attributes. var loaded bool b, loaded = mb.batchers.LoadOrStore(aset, mb.processor.newShard(md)) if !loaded { // Start the goroutine only if we added the object to the map, otherwise is already started. b.(*shard[T]).start() mb.size++ } mb.lock.Unlock() } b.(*shard[T]).newItem <- data return nil } func (mb *multiShardBatcher[T]) currentMetadataCardinality() int { mb.lock.Lock() defer mb.lock.Unlock() return mb.size } type tracesBatchProcessor struct { *batchProcessor[ptrace.Traces] } // newTracesBatchProcessor creates a new batch processor that batches traces by size or with timeout func newTracesBatchProcessor(set processor.Settings, next consumer.Traces, cfg *Config) (processor.Traces, error) { bp, err := newBatchProcessor(set, cfg, func() batch[ptrace.Traces] { return newBatchTraces(next) }) if err != nil { return nil, err } return &tracesBatchProcessor{batchProcessor: bp}, nil } func (t *tracesBatchProcessor) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { pref.RefTraces(td) return t.batcher.consume(ctx, td) } type metricsBatchProcessor struct { *batchProcessor[pmetric.Metrics] } // newMetricsBatchProcessor creates a new batch processor that batches metrics by size or with timeout func newMetricsBatchProcessor(set processor.Settings, next consumer.Metrics, cfg *Config) (processor.Metrics, error) { bp, err := newBatchProcessor(set, cfg, func() batch[pmetric.Metrics] { return newMetricsBatch(next) }) if err != nil { return nil, err } return &metricsBatchProcessor{batchProcessor: bp}, nil } // ConsumeMetrics implements processor.Metrics func (m *metricsBatchProcessor) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { pref.RefMetrics(md) return m.batcher.consume(ctx, md) } type logsBatchProcessor struct { *batchProcessor[plog.Logs] } // newLogsBatchProcessor creates a new batch processor that batches logs by size or with timeout func newLogsBatchProcessor(set processor.Settings, next consumer.Logs, cfg *Config) (processor.Logs, error) { bp, err := newBatchProcessor(set, cfg, func() batch[plog.Logs] { return newBatchLogs(next) }) if err != nil { return nil, err } return &logsBatchProcessor{batchProcessor: bp}, nil } // ConsumeLogs implements processor.Logs func (l *logsBatchProcessor) ConsumeLogs(ctx context.Context, ld plog.Logs) error { pref.RefLogs(ld) return l.batcher.consume(ctx, ld) } type batchTraces struct { nextConsumer consumer.Traces traceData ptrace.Traces spanCount int sizer ptrace.Sizer } func newBatchTraces(nextConsumer consumer.Traces) *batchTraces { return &batchTraces{nextConsumer: nextConsumer, traceData: ptrace.NewTraces(), sizer: &ptrace.ProtoMarshaler{}} } // add updates current batchTraces by adding new TraceData object func (bt *batchTraces) add(td ptrace.Traces) { defer pref.UnrefTraces(td) newSpanCount := td.SpanCount() if newSpanCount == 0 { return } bt.spanCount += newSpanCount td.ResourceSpans().MoveAndAppendTo(bt.traceData.ResourceSpans()) } func (bt *batchTraces) sizeBytes(td ptrace.Traces) int { return bt.sizer.TracesSize(td) } func (bt *batchTraces) export(ctx context.Context, td ptrace.Traces) error { return bt.nextConsumer.ConsumeTraces(ctx, td) } func (bt *batchTraces) split(sendBatchMaxSize int) (int, ptrace.Traces) { var td ptrace.Traces var sent int if sendBatchMaxSize > 0 && bt.itemCount() > sendBatchMaxSize { td = splitTraces(sendBatchMaxSize, bt.traceData) bt.spanCount -= sendBatchMaxSize sent = sendBatchMaxSize } else { td = bt.traceData sent = bt.spanCount bt.traceData = ptrace.NewTraces() bt.spanCount = 0 } return sent, td } func (bt *batchTraces) itemCount() int { return bt.spanCount } type batchMetrics struct { nextConsumer consumer.Metrics metricData pmetric.Metrics dataPointCount int sizer pmetric.Sizer } func newMetricsBatch(nextConsumer consumer.Metrics) *batchMetrics { return &batchMetrics{nextConsumer: nextConsumer, metricData: pmetric.NewMetrics(), sizer: &pmetric.ProtoMarshaler{}} } func (bm *batchMetrics) sizeBytes(md pmetric.Metrics) int { return bm.sizer.MetricsSize(md) } func (bm *batchMetrics) export(ctx context.Context, md pmetric.Metrics) error { return bm.nextConsumer.ConsumeMetrics(ctx, md) } func (bm *batchMetrics) split(sendBatchMaxSize int) (int, pmetric.Metrics) { var md pmetric.Metrics var sent int if sendBatchMaxSize > 0 && bm.dataPointCount > sendBatchMaxSize { md = splitMetrics(sendBatchMaxSize, bm.metricData) bm.dataPointCount -= sendBatchMaxSize sent = sendBatchMaxSize } else { md = bm.metricData sent = bm.dataPointCount bm.metricData = pmetric.NewMetrics() bm.dataPointCount = 0 } return sent, md } func (bm *batchMetrics) itemCount() int { return bm.dataPointCount } func (bm *batchMetrics) add(md pmetric.Metrics) { defer pref.UnrefMetrics(md) newDataPointCount := md.DataPointCount() if newDataPointCount == 0 { return } bm.dataPointCount += newDataPointCount md.ResourceMetrics().MoveAndAppendTo(bm.metricData.ResourceMetrics()) } type batchLogs struct { nextConsumer consumer.Logs logData plog.Logs logCount int sizer plog.Sizer } func newBatchLogs(nextConsumer consumer.Logs) *batchLogs { return &batchLogs{nextConsumer: nextConsumer, logData: plog.NewLogs(), sizer: &plog.ProtoMarshaler{}} } func (bl *batchLogs) sizeBytes(ld plog.Logs) int { return bl.sizer.LogsSize(ld) } func (bl *batchLogs) export(ctx context.Context, ld plog.Logs) error { return bl.nextConsumer.ConsumeLogs(ctx, ld) } func (bl *batchLogs) split(sendBatchMaxSize int) (int, plog.Logs) { var ld plog.Logs var sent int if sendBatchMaxSize > 0 && bl.logCount > sendBatchMaxSize { ld = splitLogs(sendBatchMaxSize, bl.logData) bl.logCount -= sendBatchMaxSize sent = sendBatchMaxSize } else { ld = bl.logData sent = bl.logCount bl.logData = plog.NewLogs() bl.logCount = 0 } return sent, ld } func (bl *batchLogs) itemCount() int { return bl.logCount } func (bl *batchLogs) add(ld plog.Logs) { defer pref.UnrefLogs(ld) newLogsCount := ld.LogRecordCount() if newLogsCount == 0 { return } bl.logCount += newLogsCount ld.ResourceLogs().MoveAndAppendTo(bl.logData.ResourceLogs()) } opentelemetry-collector-0.141.0/processor/batchprocessor/batch_processor_test.go000066400000000000000000001243101511331344600303450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor import ( "context" "fmt" "math" "strconv" "sync" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/client" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/processor/batchprocessor/internal/metadata" "go.opentelemetry.io/collector/processor/batchprocessor/internal/metadatatest" "go.opentelemetry.io/collector/processor/processortest" ) func TestProcessorShutdown(t *testing.T) { factory := NewFactory() ctx := context.Background() processorCreationSet := processortest.NewNopSettings(metadata.Type) for range 5 { require.NotPanics(t, func() { tProc, err := factory.CreateTraces(ctx, processorCreationSet, factory.CreateDefaultConfig(), consumertest.NewNop()) require.NoError(t, err) _ = tProc.Shutdown(ctx) }) require.NotPanics(t, func() { mProc, err := factory.CreateMetrics(ctx, processorCreationSet, factory.CreateDefaultConfig(), consumertest.NewNop()) require.NoError(t, err) _ = mProc.Shutdown(ctx) }) require.NotPanics(t, func() { lProc, err := factory.CreateLogs(ctx, processorCreationSet, factory.CreateDefaultConfig(), consumertest.NewNop()) require.NoError(t, err) _ = lProc.Shutdown(ctx) }) } } func TestProcessorLifecycle(t *testing.T) { factory := NewFactory() ctx := context.Background() processorCreationSet := processortest.NewNopSettings(metadata.Type) for range 5 { tProc, err := factory.CreateTraces(ctx, processorCreationSet, factory.CreateDefaultConfig(), consumertest.NewNop()) require.NoError(t, err) require.NoError(t, tProc.Start(ctx, componenttest.NewNopHost())) require.NoError(t, tProc.Shutdown(ctx)) mProc, err := factory.CreateMetrics(ctx, processorCreationSet, factory.CreateDefaultConfig(), consumertest.NewNop()) require.NoError(t, err) require.NoError(t, mProc.Start(ctx, componenttest.NewNopHost())) require.NoError(t, mProc.Shutdown(ctx)) lProc, err := factory.CreateLogs(ctx, processorCreationSet, factory.CreateDefaultConfig(), consumertest.NewNop()) require.NoError(t, err) require.NoError(t, lProc.Start(ctx, componenttest.NewNopHost())) require.NoError(t, lProc.Shutdown(ctx)) } } func TestBatchProcessorSpansDelivered(t *testing.T) { sink := new(consumertest.TracesSink) cfg := createDefaultConfig().(*Config) cfg.SendBatchSize = 128 traces, err := NewFactory().CreateTraces(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) requestCount := 1000 spansPerRequest := 100 sentResourceSpans := ptrace.NewTraces().ResourceSpans() for requestNum := range requestCount { td := testdata.GenerateTraces(spansPerRequest) spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() for spanIndex := range spansPerRequest { spans.At(spanIndex).SetName(getTestSpanName(requestNum, spanIndex)) } td.ResourceSpans().At(0).CopyTo(sentResourceSpans.AppendEmpty()) require.NoError(t, traces.ConsumeTraces(context.Background(), td)) } // Added to test logic that check for empty resources. td := ptrace.NewTraces() assert.NoError(t, traces.ConsumeTraces(context.Background(), td)) require.NoError(t, traces.Shutdown(context.Background())) require.Equal(t, requestCount*spansPerRequest, sink.SpanCount()) receivedTraces := sink.AllTraces() spansReceivedByName := spansReceivedByName(receivedTraces) for requestNum := range requestCount { spans := sentResourceSpans.At(requestNum).ScopeSpans().At(0).Spans() for spanIndex := range spansPerRequest { require.Equal(t, spans.At(spanIndex), spansReceivedByName[getTestSpanName(requestNum, spanIndex)]) } } } func TestBatchProcessorSpansDeliveredEnforceBatchSize(t *testing.T) { sink := new(consumertest.TracesSink) cfg := createDefaultConfig().(*Config) cfg.SendBatchSize = 128 cfg.SendBatchMaxSize = 130 traces, err := NewFactory().CreateTraces(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) requestCount := 1000 spansPerRequest := 150 for requestNum := range requestCount { td := testdata.GenerateTraces(spansPerRequest) spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() for spanIndex := range spansPerRequest { spans.At(spanIndex).SetName(getTestSpanName(requestNum, spanIndex)) } require.NoError(t, traces.ConsumeTraces(context.Background(), td)) } // Added to test logic that check for empty resources. td := ptrace.NewTraces() require.NoError(t, traces.ConsumeTraces(context.Background(), td)) // wait for all spans to be reported for sink.SpanCount() != requestCount*spansPerRequest { <-time.After(cfg.Timeout) } require.NoError(t, traces.Shutdown(context.Background())) require.Equal(t, requestCount*spansPerRequest, sink.SpanCount()) for i := 0; i < len(sink.AllTraces())-1; i++ { assert.Equal(t, int(cfg.SendBatchMaxSize), sink.AllTraces()[i].SpanCount()) } // the last batch has the remaining size assert.Equal(t, (requestCount*spansPerRequest)%int(cfg.SendBatchMaxSize), sink.AllTraces()[len(sink.AllTraces())-1].SpanCount()) } func TestBatchProcessorSentBySize(t *testing.T) { const ( sendBatchSize = 20 requestCount = 100 spansPerRequest = 5 expectedBatchesNum = requestCount * spansPerRequest / sendBatchSize expectedBatchingFactor = sendBatchSize / spansPerRequest ) tel := componenttest.NewTelemetry() sizer := &ptrace.ProtoMarshaler{} sink := new(consumertest.TracesSink) cfg := createDefaultConfig().(*Config) cfg.SendBatchSize = sendBatchSize cfg.Timeout = 500 * time.Millisecond traces, err := NewFactory().CreateTraces(context.Background(), metadatatest.NewSettings(tel), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() sizeSum := 0 for range requestCount { td := testdata.GenerateTraces(spansPerRequest) require.NoError(t, traces.ConsumeTraces(context.Background(), td)) } require.NoError(t, traces.Shutdown(context.Background())) elapsed := time.Since(start) require.LessOrEqual(t, elapsed.Nanoseconds(), cfg.Timeout.Nanoseconds()) require.Equal(t, requestCount*spansPerRequest, sink.SpanCount()) receivedTraces := sink.AllTraces() require.Len(t, receivedTraces, expectedBatchesNum) for _, td := range receivedTraces { sizeSum += sizer.TracesSize(td) rss := td.ResourceSpans() require.Equal(t, expectedBatchingFactor, rss.Len()) for i := range expectedBatchingFactor { require.Equal(t, spansPerRequest, rss.At(i).ScopeSpans().At(0).Spans().Len()) } } metadatatest.AssertEqualProcessorBatchBatchSendSizeBytes(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000, 900_000, 1000_000, 2000_000, 3000_000, 4000_000, 5000_000, 6000_000, 7000_000, 8000_000, 9000_000, }, BucketCounts: []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, uint64(expectedBatchesNum), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(sizeSum), Min: metricdata.NewExtrema(int64(sizeSum / expectedBatchesNum)), Max: metricdata.NewExtrema(int64(sizeSum / expectedBatchesNum)), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSendSize(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}, BucketCounts: []uint64{0, uint64(expectedBatchesNum), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(sink.SpanCount()), Min: metricdata.NewExtrema(int64(sendBatchSize)), Max: metricdata.NewExtrema(int64(sendBatchSize)), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSizeTriggerSend(t, tel, []metricdata.DataPoint[int64]{ { Value: int64(expectedBatchesNum), Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchMetadataCardinality(t, tel, []metricdata.DataPoint[int64]{ { Value: 1, Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) require.NoError(t, tel.Shutdown(context.Background())) } func TestBatchProcessorSentBySizeWithMaxSize(t *testing.T) { const ( sendBatchSize = 20 sendBatchMaxSize = 37 requestCount = 1 spansPerRequest = 500 totalSpans = requestCount * spansPerRequest ) tel := componenttest.NewTelemetry() sizer := &ptrace.ProtoMarshaler{} sink := new(consumertest.TracesSink) cfg := createDefaultConfig().(*Config) cfg.SendBatchSize = uint32(sendBatchSize) cfg.SendBatchMaxSize = uint32(sendBatchMaxSize) cfg.Timeout = 500 * time.Millisecond traces, err := NewFactory().CreateTraces(context.Background(), metadatatest.NewSettings(tel), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() sizeSum := 0 for range requestCount { td := testdata.GenerateTraces(spansPerRequest) require.NoError(t, traces.ConsumeTraces(context.Background(), td)) } require.NoError(t, traces.Shutdown(context.Background())) elapsed := time.Since(start) require.LessOrEqual(t, elapsed.Nanoseconds(), cfg.Timeout.Nanoseconds()) // The max batch size is not a divisor of the total number of spans expectedBatchesNum := math.Ceil(float64(totalSpans) / float64(sendBatchMaxSize)) require.Equal(t, totalSpans, sink.SpanCount()) receivedTraces := sink.AllTraces() require.Len(t, receivedTraces, int(expectedBatchesNum)) // we have to count the size after it was processed since splitTraces will cause some // repeated ResourceSpan data to be sent through the processor minSize := math.MaxInt maxSize := math.MinInt for _, td := range receivedTraces { minSize = min(minSize, sizer.TracesSize(td)) maxSize = max(maxSize, sizer.TracesSize(td)) sizeSum += sizer.TracesSize(td) } metadatatest.AssertEqualProcessorBatchBatchSendSizeBytes(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000, 900_000, 1000_000, 2000_000, 3000_000, 4000_000, 5000_000, 6000_000, 7000_000, 8000_000, 9000_000, }, BucketCounts: []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, uint64(expectedBatchesNum - 1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(sizeSum), Min: metricdata.NewExtrema(int64(minSize)), Max: metricdata.NewExtrema(int64(maxSize)), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSendSize(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}, BucketCounts: []uint64{0, 1, uint64(expectedBatchesNum - 1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(sink.SpanCount()), Min: metricdata.NewExtrema(int64(sendBatchSize - 1)), Max: metricdata.NewExtrema(int64(cfg.SendBatchMaxSize)), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSizeTriggerSend(t, tel, []metricdata.DataPoint[int64]{ { Value: int64(expectedBatchesNum - 1), Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchMetadataCardinality(t, tel, []metricdata.DataPoint[int64]{ { Value: 1, Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) require.NoError(t, tel.Shutdown(context.Background())) } func TestBatchProcessorSentByTimeout(t *testing.T) { sink := new(consumertest.TracesSink) cfg := createDefaultConfig().(*Config) sendBatchSize := 100 cfg.SendBatchSize = uint32(sendBatchSize) cfg.Timeout = 100 * time.Millisecond requestCount := 5 spansPerRequest := 10 start := time.Now() traces, err := NewFactory().CreateTraces(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) for range requestCount { td := testdata.GenerateTraces(spansPerRequest) require.NoError(t, traces.ConsumeTraces(context.Background(), td)) } // Wait for at least one batch to be sent. for sink.SpanCount() == 0 { <-time.After(cfg.Timeout) } elapsed := time.Since(start) require.LessOrEqual(t, cfg.Timeout.Nanoseconds(), elapsed.Nanoseconds()) // This should not change the results in the sink, verified by the expectedBatchesNum require.NoError(t, traces.Shutdown(context.Background())) expectedBatchesNum := 1 expectedBatchingFactor := 5 require.Equal(t, requestCount*spansPerRequest, sink.SpanCount()) receivedTraces := sink.AllTraces() require.Len(t, receivedTraces, expectedBatchesNum) for _, td := range receivedTraces { rss := td.ResourceSpans() require.Equal(t, expectedBatchingFactor, rss.Len()) for i := range expectedBatchingFactor { require.Equal(t, spansPerRequest, rss.At(i).ScopeSpans().At(0).Spans().Len()) } } } func TestBatchProcessorTraceSendWhenClosing(t *testing.T) { cfg := &Config{ Timeout: 3 * time.Second, SendBatchSize: 1000, } sink := new(consumertest.TracesSink) traces, err := NewFactory().CreateTraces(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) requestCount := 10 spansPerRequest := 10 for range requestCount { td := testdata.GenerateTraces(spansPerRequest) require.NoError(t, traces.ConsumeTraces(context.Background(), td)) } require.NoError(t, traces.Shutdown(context.Background())) require.Equal(t, requestCount*spansPerRequest, sink.SpanCount()) require.Len(t, sink.AllTraces(), 1) } func TestBatchMetricProcessor_ReceivingData(t *testing.T) { // Instantiate the batch processor with low config values to test data // gets sent through the processor. cfg := &Config{ Timeout: 200 * time.Millisecond, SendBatchSize: 50, } requestCount := 100 metricsPerRequest := 5 sink := new(consumertest.MetricsSink) metrics, err := NewFactory().CreateMetrics(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) sentResourceMetrics := pmetric.NewMetrics().ResourceMetrics() for requestNum := range requestCount { md := testdata.GenerateMetrics(metricsPerRequest) ms := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() for metricIndex := range metricsPerRequest { ms.At(metricIndex).SetName(getTestMetricName(requestNum, metricIndex)) } md.ResourceMetrics().At(0).CopyTo(sentResourceMetrics.AppendEmpty()) require.NoError(t, metrics.ConsumeMetrics(context.Background(), md)) } // Added to test case with empty resources sent. md := pmetric.NewMetrics() assert.NoError(t, metrics.ConsumeMetrics(context.Background(), md)) require.NoError(t, metrics.Shutdown(context.Background())) require.Equal(t, requestCount*2*metricsPerRequest, sink.DataPointCount()) receivedMds := sink.AllMetrics() metricsReceivedByName := metricsReceivedByName(receivedMds) for requestNum := range requestCount { ms := sentResourceMetrics.At(requestNum).ScopeMetrics().At(0).Metrics() for metricIndex := range metricsPerRequest { require.Equal(t, ms.At(metricIndex), metricsReceivedByName[getTestMetricName(requestNum, metricIndex)]) } } } func TestBatchMetricProcessorBatchSize(t *testing.T) { tel := componenttest.NewTelemetry() sizer := &pmetric.ProtoMarshaler{} // Instantiate the batch processor with low config values to test data // gets sent through the processor. cfg := &Config{ Timeout: 100 * time.Millisecond, SendBatchSize: 50, } const ( requestCount = 100 metricsPerRequest = 5 dataPointsPerMetric = 2 // Since the int counter uses two datapoints. dataPointsPerRequest = metricsPerRequest * dataPointsPerMetric ) sink := new(consumertest.MetricsSink) metrics, err := NewFactory().CreateMetrics(context.Background(), metadatatest.NewSettings(tel), cfg, sink) require.NoError(t, err) require.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() size := 0 for range requestCount { md := testdata.GenerateMetrics(metricsPerRequest) size += sizer.MetricsSize(md) require.NoError(t, metrics.ConsumeMetrics(context.Background(), md)) } require.NoError(t, metrics.Shutdown(context.Background())) elapsed := time.Since(start) require.LessOrEqual(t, elapsed.Nanoseconds(), cfg.Timeout.Nanoseconds()) expectedBatchesNum := requestCount * dataPointsPerRequest / cfg.SendBatchSize expectedBatchingFactor := int(cfg.SendBatchSize) / dataPointsPerRequest require.Equal(t, requestCount*2*metricsPerRequest, sink.DataPointCount()) receivedMds := sink.AllMetrics() require.Len(t, receivedMds, int(expectedBatchesNum)) for _, md := range receivedMds { require.Equal(t, expectedBatchingFactor, md.ResourceMetrics().Len()) for i := range expectedBatchingFactor { require.Equal(t, metricsPerRequest, md.ResourceMetrics().At(i).ScopeMetrics().At(0).Metrics().Len()) } } metadatatest.AssertEqualProcessorBatchBatchSendSizeBytes(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000, 900_000, 1000_000, 2000_000, 3000_000, 4000_000, 5000_000, 6000_000, 7000_000, 8000_000, 9000_000, }, BucketCounts: []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, uint64(expectedBatchesNum), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(size), Min: metricdata.NewExtrema(int64(size / int(expectedBatchesNum))), Max: metricdata.NewExtrema(int64(size / int(expectedBatchesNum))), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSendSize(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}, BucketCounts: []uint64{0, 0, uint64(expectedBatchesNum), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(sink.DataPointCount()), Min: metricdata.NewExtrema(int64(cfg.SendBatchSize)), Max: metricdata.NewExtrema(int64(cfg.SendBatchSize)), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSizeTriggerSend(t, tel, []metricdata.DataPoint[int64]{ { Value: int64(expectedBatchesNum), Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchMetadataCardinality(t, tel, []metricdata.DataPoint[int64]{ { Value: 1, Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) require.NoError(t, tel.Shutdown(context.Background())) } func TestBatchMetrics_UnevenBatchMaxSize(t *testing.T) { ctx := context.Background() sink := new(metricsSink) metricsCount := 50 dataPointsPerMetric := 2 sendBatchMaxSize := 99 batchMetrics := newMetricsBatch(sink) md := testdata.GenerateMetrics(metricsCount) batchMetrics.add(md) require.Equal(t, dataPointsPerMetric*metricsCount, batchMetrics.dataPointCount) sent, req := batchMetrics.split(sendBatchMaxSize) sendErr := batchMetrics.export(ctx, req) require.NoError(t, sendErr) require.Equal(t, sendBatchMaxSize, sent) remainingDataPointCount := metricsCount*dataPointsPerMetric - sendBatchMaxSize require.Equal(t, remainingDataPointCount, batchMetrics.dataPointCount) } func TestBatchMetricsProcessor_Timeout(t *testing.T) { cfg := &Config{ Timeout: 100 * time.Millisecond, SendBatchSize: 101, } requestCount := 5 metricsPerRequest := 10 sink := new(consumertest.MetricsSink) metrics, err := NewFactory().CreateMetrics(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() for range requestCount { md := testdata.GenerateMetrics(metricsPerRequest) require.NoError(t, metrics.ConsumeMetrics(context.Background(), md)) } // Wait for at least one batch to be sent. for sink.DataPointCount() == 0 { <-time.After(cfg.Timeout) } elapsed := time.Since(start) require.LessOrEqual(t, cfg.Timeout.Nanoseconds(), elapsed.Nanoseconds()) // This should not change the results in the sink, verified by the expectedBatchesNum require.NoError(t, metrics.Shutdown(context.Background())) expectedBatchesNum := 1 expectedBatchingFactor := 5 require.Equal(t, requestCount*2*metricsPerRequest, sink.DataPointCount()) receivedMds := sink.AllMetrics() require.Len(t, receivedMds, expectedBatchesNum) for _, md := range receivedMds { require.Equal(t, expectedBatchingFactor, md.ResourceMetrics().Len()) for i := range expectedBatchingFactor { require.Equal(t, metricsPerRequest, md.ResourceMetrics().At(i).ScopeMetrics().At(0).Metrics().Len()) } } } func TestBatchMetricProcessor_Shutdown(t *testing.T) { cfg := &Config{ Timeout: 3 * time.Second, SendBatchSize: 1000, } requestCount := 5 metricsPerRequest := 10 sink := new(consumertest.MetricsSink) metrics, err := NewFactory().CreateMetrics(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) for range requestCount { md := testdata.GenerateMetrics(metricsPerRequest) require.NoError(t, metrics.ConsumeMetrics(context.Background(), md)) } require.NoError(t, metrics.Shutdown(context.Background())) require.Equal(t, requestCount*2*metricsPerRequest, sink.DataPointCount()) require.Len(t, sink.AllMetrics(), 1) } func getTestSpanName(requestNum, index int) string { return fmt.Sprintf("test-span-%d-%d", requestNum, index) } func spansReceivedByName(tds []ptrace.Traces) map[string]ptrace.Span { spansReceivedByName := map[string]ptrace.Span{} for i := range tds { rss := tds[i].ResourceSpans() for i := 0; i < rss.Len(); i++ { ilss := rss.At(i).ScopeSpans() for j := 0; j < ilss.Len(); j++ { spans := ilss.At(j).Spans() for k := 0; k < spans.Len(); k++ { span := spans.At(k) spansReceivedByName[spans.At(k).Name()] = span } } } } return spansReceivedByName } func metricsReceivedByName(mds []pmetric.Metrics) map[string]pmetric.Metric { metricsReceivedByName := map[string]pmetric.Metric{} for _, md := range mds { rms := md.ResourceMetrics() for i := 0; i < rms.Len(); i++ { ilms := rms.At(i).ScopeMetrics() for j := 0; j < ilms.Len(); j++ { metrics := ilms.At(j).Metrics() for k := 0; k < metrics.Len(); k++ { metric := metrics.At(k) metricsReceivedByName[metric.Name()] = metric } } } } return metricsReceivedByName } func getTestMetricName(requestNum, index int) string { return fmt.Sprintf("test-metric-int-%d-%d", requestNum, index) } func BenchmarkTraceSizeBytes(b *testing.B) { sizer := &ptrace.ProtoMarshaler{} td := testdata.GenerateTraces(8192) for b.Loop() { fmt.Println(sizer.TracesSize(td)) } } func BenchmarkTraceSizeSpanCount(b *testing.B) { td := testdata.GenerateTraces(8192) for b.Loop() { td.SpanCount() } } func BenchmarkBatchMetricProcessor2k(b *testing.B) { b.StopTimer() cfg := &Config{ Timeout: 100 * time.Millisecond, SendBatchSize: 2000, } runMetricsProcessorBenchmark(b, cfg) } func BenchmarkMultiBatchMetricProcessor2k(b *testing.B) { b.StopTimer() cfg := &Config{ Timeout: 100 * time.Millisecond, SendBatchSize: 2000, MetadataKeys: []string{"test", "test2"}, } runMetricsProcessorBenchmark(b, cfg) } func runMetricsProcessorBenchmark(b *testing.B, cfg *Config) { ctx := context.Background() sink := new(metricsSink) metrics, err := NewFactory().CreateMetrics(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(b, err) require.NoError(b, metrics.Start(ctx, componenttest.NewNopHost())) const metricsPerRequest = 150_000 b.StartTimer() b.RunParallel(func(pb *testing.PB) { for pb.Next() { require.NoError(b, metrics.ConsumeMetrics(ctx, testdata.GenerateMetrics(metricsPerRequest))) } }) b.StopTimer() require.NoError(b, metrics.Shutdown(ctx)) require.Equal(b, b.N*metricsPerRequest, sink.metricsCount) } type metricsSink struct { mu sync.Mutex metricsCount int } func (sme *metricsSink) Capabilities() consumer.Capabilities { return consumer.Capabilities{ MutatesData: false, } } func (sme *metricsSink) ConsumeMetrics(_ context.Context, md pmetric.Metrics) error { sme.mu.Lock() defer sme.mu.Unlock() sme.metricsCount += md.MetricCount() return nil } func TestBatchLogProcessor_ReceivingData(t *testing.T) { // Instantiate the batch processor with low config values to test data // gets sent through the processor. cfg := &Config{ Timeout: 200 * time.Millisecond, SendBatchSize: 50, } requestCount := 100 logsPerRequest := 5 sink := new(consumertest.LogsSink) logs, err := NewFactory().CreateLogs(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) sentResourceLogs := plog.NewLogs().ResourceLogs() for requestNum := range requestCount { ld := testdata.GenerateLogs(logsPerRequest) lrs := ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords() for logIndex := range logsPerRequest { lrs.At(logIndex).SetSeverityText(getTestLogSeverityText(requestNum, logIndex)) } ld.ResourceLogs().At(0).CopyTo(sentResourceLogs.AppendEmpty()) require.NoError(t, logs.ConsumeLogs(context.Background(), ld)) } // Added to test case with empty resources sent. ld := plog.NewLogs() assert.NoError(t, logs.ConsumeLogs(context.Background(), ld)) require.NoError(t, logs.Shutdown(context.Background())) require.Equal(t, requestCount*logsPerRequest, sink.LogRecordCount()) receivedMds := sink.AllLogs() logsReceivedBySeverityText := logsReceivedBySeverityText(receivedMds) for requestNum := range requestCount { lrs := sentResourceLogs.At(requestNum).ScopeLogs().At(0).LogRecords() for logIndex := range logsPerRequest { require.Equal(t, lrs.At(logIndex), logsReceivedBySeverityText[getTestLogSeverityText(requestNum, logIndex)]) } } } func TestBatchLogProcessor_BatchSize(t *testing.T) { tel := componenttest.NewTelemetry() sizer := &plog.ProtoMarshaler{} // Instantiate the batch processor with low config values to test data // gets sent through the processor. cfg := &Config{ Timeout: 100 * time.Millisecond, SendBatchSize: 50, } const ( requestCount = 100 logsPerRequest = 5 ) sink := new(consumertest.LogsSink) logs, err := NewFactory().CreateLogs(context.Background(), metadatatest.NewSettings(tel), cfg, sink) require.NoError(t, err) require.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() size := 0 for range requestCount { ld := testdata.GenerateLogs(logsPerRequest) size += sizer.LogsSize(ld) require.NoError(t, logs.ConsumeLogs(context.Background(), ld)) } require.NoError(t, logs.Shutdown(context.Background())) elapsed := time.Since(start) require.LessOrEqual(t, elapsed.Nanoseconds(), cfg.Timeout.Nanoseconds()) expectedBatchesNum := requestCount * logsPerRequest / cfg.SendBatchSize expectedBatchingFactor := int(cfg.SendBatchSize) / logsPerRequest require.Equal(t, requestCount*logsPerRequest, sink.LogRecordCount()) receivedMds := sink.AllLogs() require.Len(t, receivedMds, int(expectedBatchesNum)) for _, ld := range receivedMds { require.Equal(t, expectedBatchingFactor, ld.ResourceLogs().Len()) for i := range expectedBatchingFactor { require.Equal(t, logsPerRequest, ld.ResourceLogs().At(i).ScopeLogs().At(0).LogRecords().Len()) } } metadatatest.AssertEqualProcessorBatchBatchSendSizeBytes(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000, 900_000, 1000_000, 2000_000, 3000_000, 4000_000, 5000_000, 6000_000, 7000_000, 8000_000, 9000_000, }, BucketCounts: []uint64{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, uint64(expectedBatchesNum), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(size), Min: metricdata.NewExtrema(int64(size / int(expectedBatchesNum))), Max: metricdata.NewExtrema(int64(size / int(expectedBatchesNum))), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSendSize(t, tel, []metricdata.HistogramDataPoint[int64]{ { Attributes: attribute.NewSet(attribute.String("processor", "batch")), Count: uint64(expectedBatchesNum), Bounds: []float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}, BucketCounts: []uint64{0, 0, uint64(expectedBatchesNum), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, Sum: int64(sink.LogRecordCount()), Min: metricdata.NewExtrema(int64(cfg.SendBatchSize)), Max: metricdata.NewExtrema(int64(cfg.SendBatchSize)), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchBatchSizeTriggerSend(t, tel, []metricdata.DataPoint[int64]{ { Value: int64(expectedBatchesNum), Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorBatchMetadataCardinality(t, tel, []metricdata.DataPoint[int64]{ { Value: 1, Attributes: attribute.NewSet(attribute.String("processor", "batch")), }, }, metricdatatest.IgnoreTimestamp()) require.NoError(t, tel.Shutdown(context.Background())) } func TestBatchLogsProcessor_Timeout(t *testing.T) { cfg := &Config{ Timeout: 100 * time.Millisecond, SendBatchSize: 100, } requestCount := 5 logsPerRequest := 10 sink := new(consumertest.LogsSink) logs, err := NewFactory().CreateLogs(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) start := time.Now() for range requestCount { ld := testdata.GenerateLogs(logsPerRequest) require.NoError(t, logs.ConsumeLogs(context.Background(), ld)) } // Wait for at least one batch to be sent. for sink.LogRecordCount() == 0 { <-time.After(cfg.Timeout) } elapsed := time.Since(start) require.LessOrEqual(t, cfg.Timeout.Nanoseconds(), elapsed.Nanoseconds()) // This should not change the results in the sink, verified by the expectedBatchesNum require.NoError(t, logs.Shutdown(context.Background())) expectedBatchesNum := 1 expectedBatchingFactor := 5 require.Equal(t, requestCount*logsPerRequest, sink.LogRecordCount()) receivedMds := sink.AllLogs() require.Len(t, receivedMds, expectedBatchesNum) for _, ld := range receivedMds { require.Equal(t, expectedBatchingFactor, ld.ResourceLogs().Len()) for i := range expectedBatchingFactor { require.Equal(t, logsPerRequest, ld.ResourceLogs().At(i).ScopeLogs().At(0).LogRecords().Len()) } } } func TestBatchLogProcessor_Shutdown(t *testing.T) { cfg := &Config{ Timeout: 3 * time.Second, SendBatchSize: 1000, } requestCount := 5 logsPerRequest := 10 sink := new(consumertest.LogsSink) logs, err := NewFactory().CreateLogs(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) for range requestCount { ld := testdata.GenerateLogs(logsPerRequest) require.NoError(t, logs.ConsumeLogs(context.Background(), ld)) } require.NoError(t, logs.Shutdown(context.Background())) require.Equal(t, requestCount*logsPerRequest, sink.LogRecordCount()) require.Len(t, sink.AllLogs(), 1) } func getTestLogSeverityText(requestNum, index int) string { return fmt.Sprintf("test-log-int-%d-%d", requestNum, index) } func logsReceivedBySeverityText(lds []plog.Logs) map[string]plog.LogRecord { logsReceivedBySeverityText := map[string]plog.LogRecord{} for i := range lds { ld := lds[i] rms := ld.ResourceLogs() for i := 0; i < rms.Len(); i++ { ilms := rms.At(i).ScopeLogs() for j := 0; j < ilms.Len(); j++ { logs := ilms.At(j).LogRecords() for k := 0; k < logs.Len(); k++ { log := logs.At(k) logsReceivedBySeverityText[log.SeverityText()] = log } } } } return logsReceivedBySeverityText } func TestShutdown(t *testing.T) { factory := NewFactory() processortest.VerifyShutdown(t, factory, factory.CreateDefaultConfig()) } type metadataTracesSink struct { *consumertest.TracesSink lock sync.Mutex spanCountByToken12 map[string]int } func formatTwo(first, second []string) string { return fmt.Sprintf("%s;%s", first, second) } func (mts *metadataTracesSink) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { info := client.FromContext(ctx) token1 := info.Metadata.Get("token1") token2 := info.Metadata.Get("token2") mts.lock.Lock() defer mts.lock.Unlock() mts.spanCountByToken12[formatTwo( token1, token2, )] += td.SpanCount() return mts.TracesSink.ConsumeTraces(ctx, td) } func TestBatchProcessorSpansBatchedByMetadata(t *testing.T) { sink := &metadataTracesSink{ TracesSink: &consumertest.TracesSink{}, spanCountByToken12: map[string]int{}, } cfg := createDefaultConfig().(*Config) cfg.SendBatchSize = 1000 cfg.Timeout = 10 * time.Minute cfg.MetadataKeys = []string{"token1", "token2"} traces, err := NewFactory().CreateTraces(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) bg := context.Background() callCtxs := []context.Context{ client.NewContext(bg, client.Info{ Metadata: client.NewMetadata(map[string][]string{ "token1": {"single"}, "token3": {"n/a"}, }), }), client.NewContext(bg, client.Info{ Metadata: client.NewMetadata(map[string][]string{ "token1": {"single"}, "token2": {"one", "two"}, "token4": {"n/a"}, }), }), client.NewContext(bg, client.Info{ Metadata: client.NewMetadata(map[string][]string{ "token1": nil, "token2": {"single"}, }), }), client.NewContext(bg, client.Info{ Metadata: client.NewMetadata(map[string][]string{ "token1": {"one", "two", "three"}, "token2": {"single"}, "token3": {"n/a"}, "token4": {"n/a", "d/c"}, }), }), } expectByContext := make([]int, len(callCtxs)) requestCount := 1000 spansPerRequest := 33 sentResourceSpans := ptrace.NewTraces().ResourceSpans() for requestNum := range requestCount { td := testdata.GenerateTraces(spansPerRequest) spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() for spanIndex := range spansPerRequest { spans.At(spanIndex).SetName(getTestSpanName(requestNum, spanIndex)) } td.ResourceSpans().At(0).CopyTo(sentResourceSpans.AppendEmpty()) // use round-robin to assign context. num := requestNum % len(callCtxs) expectByContext[num] += spansPerRequest require.NoError(t, traces.ConsumeTraces(callCtxs[num], td)) } require.NoError(t, traces.Shutdown(context.Background())) // The following tests are the same as TestBatchProcessorSpansDelivered(). require.Equal(t, requestCount*spansPerRequest, sink.SpanCount()) receivedTraces := sink.AllTraces() spansReceivedByName := spansReceivedByName(receivedTraces) for requestNum := range requestCount { spans := sentResourceSpans.At(requestNum).ScopeSpans().At(0).Spans() for spanIndex := range spansPerRequest { require.Equal(t, spans.At(spanIndex), spansReceivedByName[getTestSpanName(requestNum, spanIndex)]) } } // This test ensures each context had the expected number of spans. require.Len(t, sink.spanCountByToken12, len(callCtxs)) for idx, ctx := range callCtxs { md := client.FromContext(ctx).Metadata exp := formatTwo(md.Get("token1"), md.Get("token2")) require.Equal(t, expectByContext[idx], sink.spanCountByToken12[exp]) } } func TestBatchProcessorDuplicateMetadataKeys(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.MetadataKeys = []string{"myTOKEN", "mytoken"} err := cfg.Validate() require.ErrorContains(t, err, "duplicate") require.ErrorContains(t, err, "mytoken") } func TestBatchProcessorMetadataCardinalityLimit(t *testing.T) { const cardLimit = 10 sink := new(consumertest.TracesSink) cfg := createDefaultConfig().(*Config) cfg.MetadataKeys = []string{"token"} cfg.MetadataCardinalityLimit = cardLimit traces, err := NewFactory().CreateTraces(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) bg := context.Background() for requestNum := range cardLimit { td := testdata.GenerateTraces(1) ctx := client.NewContext(bg, client.Info{ Metadata: client.NewMetadata(map[string][]string{ "token": {strconv.Itoa(requestNum)}, }), }) require.NoError(t, traces.ConsumeTraces(ctx, td)) } td := testdata.GenerateTraces(1) ctx := client.NewContext(bg, client.Info{ Metadata: client.NewMetadata(map[string][]string{ "token": {"limit_exceeded"}, }), }) err = traces.ConsumeTraces(ctx, td) require.Error(t, err) assert.True(t, consumererror.IsPermanent(err)) require.ErrorContains(t, err, "too many") require.NoError(t, traces.Shutdown(context.Background())) } func TestBatchZeroConfig(t *testing.T) { // This is a no-op configuration. No need for a timer, no // minimum, no maximum, just a pass through. cfg := &Config{} require.NoError(t, cfg.Validate()) const requestCount = 5 const logsPerRequest = 10 sink := new(consumertest.LogsSink) logs, err := NewFactory().CreateLogs(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) defer func() { require.NoError(t, logs.Shutdown(context.Background())) }() expect := 0 for requestNum := range requestCount { cnt := logsPerRequest + requestNum expect += cnt ld := testdata.GenerateLogs(cnt) require.NoError(t, logs.ConsumeLogs(context.Background(), ld)) } // Wait for all batches. require.Eventually(t, func() bool { return sink.LogRecordCount() == expect }, time.Second, 5*time.Millisecond) // Expect them to be the original sizes. receivedMds := sink.AllLogs() require.Len(t, receivedMds, requestCount) for i, ld := range receivedMds { require.Equal(t, 1, ld.ResourceLogs().Len()) require.Equal(t, logsPerRequest+i, ld.LogRecordCount()) } } func TestBatchSplitOnly(t *testing.T) { const maxBatch = 10 const requestCount = 5 const logsPerRequest = 100 cfg := &Config{ SendBatchMaxSize: maxBatch, } require.NoError(t, cfg.Validate()) sink := new(consumertest.LogsSink) logs, err := NewFactory().CreateLogs(context.Background(), processortest.NewNopSettings(metadata.Type), cfg, sink) require.NoError(t, err) require.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) defer func() { require.NoError(t, logs.Shutdown(context.Background())) }() for range requestCount { ld := testdata.GenerateLogs(logsPerRequest) require.NoError(t, logs.ConsumeLogs(context.Background(), ld)) } // Wait for all batches. require.Eventually(t, func() bool { return sink.LogRecordCount() == logsPerRequest*requestCount }, time.Second, 5*time.Millisecond) // Expect them to be the limited by maxBatch. receivedMds := sink.AllLogs() require.Len(t, receivedMds, requestCount*logsPerRequest/maxBatch) for _, ld := range receivedMds { require.Equal(t, maxBatch, ld.LogRecordCount()) } } opentelemetry-collector-0.141.0/processor/batchprocessor/config.go000066400000000000000000000047111511331344600253750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor // import "go.opentelemetry.io/collector/processor/batchprocessor" import ( "errors" "fmt" "strings" "time" "go.opentelemetry.io/collector/component" ) // Config defines configuration for batch processor. type Config struct { // Timeout sets the time after which a batch will be sent regardless of size. // When this is set to zero, batched data will be sent immediately. Timeout time.Duration `mapstructure:"timeout"` // SendBatchSize is the size of a batch which after hit, will trigger it to be sent. // When this is set to zero, the batch size is ignored and data will be sent immediately // subject to only send_batch_max_size. SendBatchSize uint32 `mapstructure:"send_batch_size"` // SendBatchMaxSize is the maximum size of a batch. It must be larger than SendBatchSize. // Larger batches are split into smaller units. // Default value is 0, that means no maximum size. SendBatchMaxSize uint32 `mapstructure:"send_batch_max_size"` // MetadataKeys is a list of client.Metadata keys that will be // used to form distinct batchers. If this setting is empty, // a single batcher instance will be used. When this setting // is not empty, one batcher will be used per distinct // combination of values for the listed metadata keys. // // Empty value and unset metadata are treated as distinct cases. // // Entries are case-insensitive. Duplicated entries will // trigger a validation error. MetadataKeys []string `mapstructure:"metadata_keys"` // MetadataCardinalityLimit indicates the maximum number of // batcher instances that will be created through a distinct // combination of MetadataKeys. MetadataCardinalityLimit uint32 `mapstructure:"metadata_cardinality_limit"` // prevent unkeyed literal initialization _ struct{} } var _ component.Config = (*Config)(nil) // Validate checks if the processor configuration is valid func (cfg *Config) Validate() error { if cfg.SendBatchMaxSize > 0 && cfg.SendBatchMaxSize < cfg.SendBatchSize { return errors.New("send_batch_max_size must be greater or equal to send_batch_size") } uniq := map[string]bool{} for _, k := range cfg.MetadataKeys { l := strings.ToLower(k) if _, has := uniq[l]; has { return fmt.Errorf("duplicate entry in metadata_keys: %q (case-insensitive)", l) } uniq[l] = true } if cfg.Timeout < 0 { return errors.New("timeout must be greater or equal to 0") } return nil } opentelemetry-collector-0.141.0/processor/batchprocessor/config_test.go000066400000000000000000000033051511331344600264320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor import ( "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestUnmarshalDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) } func TestUnmarshalConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) assert.Equal(t, &Config{ SendBatchSize: uint32(10000), SendBatchMaxSize: uint32(11000), Timeout: time.Second * 10, MetadataCardinalityLimit: 1000, }, cfg) } func TestValidateConfig_DefaultBatchMaxSize(t *testing.T) { cfg := &Config{ SendBatchSize: 100, SendBatchMaxSize: 0, } assert.NoError(t, cfg.Validate()) } func TestValidateConfig_ValidBatchSizes(t *testing.T) { cfg := &Config{ SendBatchSize: 100, SendBatchMaxSize: 1000, } assert.NoError(t, cfg.Validate()) } func TestValidateConfig_InvalidBatchSize(t *testing.T) { cfg := &Config{ SendBatchSize: 1000, SendBatchMaxSize: 100, } assert.Error(t, cfg.Validate()) } func TestValidateConfig_InvalidTimeout(t *testing.T) { cfg := &Config{ Timeout: -time.Second, } assert.Error(t, cfg.Validate()) } func TestValidateConfig_ValidZero(t *testing.T) { cfg := &Config{} assert.NoError(t, cfg.Validate()) } opentelemetry-collector-0.141.0/processor/batchprocessor/documentation.md000066400000000000000000000027761511331344600270050ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # batch ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_processor_batch_batch_send_size Number of units in the batch [Development] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | {units} | Histogram | Int | Development | ### otelcol_processor_batch_batch_send_size_bytes Number of bytes in batch that was sent. Only available on detailed level. [Development] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | By | Histogram | Int | Development | ### otelcol_processor_batch_batch_size_trigger_send Number of times the batch was sent due to a size trigger [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {times} | Sum | Int | true | Development | ### otelcol_processor_batch_metadata_cardinality Number of distinct metadata value combinations being processed [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {combinations} | Sum | Int | false | Development | ### otelcol_processor_batch_timeout_trigger_send Number of times the batch was sent due to a timeout trigger [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {times} | Sum | Int | true | Development | opentelemetry-collector-0.141.0/processor/batchprocessor/factory.go000066400000000000000000000036431511331344600256020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package batchprocessor // import "go.opentelemetry.io/collector/processor/batchprocessor" import ( "context" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/batchprocessor/internal/metadata" ) const ( defaultSendBatchSize = uint32(8192) defaultTimeout = 200 * time.Millisecond // defaultMetadataCardinalityLimit should be set to the number // of metadata configurations the user expects to submit to // the collector. defaultMetadataCardinalityLimit = 1000 ) // NewFactory returns a new factory for the Batch processor. func NewFactory() processor.Factory { return processor.NewFactory( metadata.Type, createDefaultConfig, processor.WithTraces(createTraces, metadata.TracesStability), processor.WithMetrics(createMetrics, metadata.MetricsStability), processor.WithLogs(createLogs, metadata.LogsStability)) } func createDefaultConfig() component.Config { return &Config{ SendBatchSize: defaultSendBatchSize, Timeout: defaultTimeout, MetadataCardinalityLimit: defaultMetadataCardinalityLimit, } } func createTraces( _ context.Context, set processor.Settings, cfg component.Config, nextConsumer consumer.Traces, ) (processor.Traces, error) { return newTracesBatchProcessor(set, nextConsumer, cfg.(*Config)) } func createMetrics( _ context.Context, set processor.Settings, cfg component.Config, nextConsumer consumer.Metrics, ) (processor.Metrics, error) { return newMetricsBatchProcessor(set, nextConsumer, cfg.(*Config)) } func createLogs( _ context.Context, set processor.Settings, cfg component.Config, nextConsumer consumer.Logs, ) (processor.Logs, error) { return newLogsBatchProcessor(set, nextConsumer, cfg.(*Config)) } opentelemetry-collector-0.141.0/processor/batchprocessor/factory_test.go000066400000000000000000000024501511331344600266340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor import ( "context" "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/processor/processortest" ) func TestCreateDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") assert.NoError(t, componenttest.CheckConfigStruct(cfg)) } func TestCreateProcessor(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() creationSet := processortest.NewNopSettings(factory.Type()) tp, err := factory.CreateTraces(context.Background(), creationSet, cfg, nil) assert.NotNil(t, tp) assert.NoError(t, err, "cannot create trace processor") assert.NoError(t, tp.Shutdown(context.Background())) mp, err := factory.CreateMetrics(context.Background(), creationSet, cfg, nil) assert.NotNil(t, mp) assert.NoError(t, err, "cannot create metric processor") assert.NoError(t, mp.Shutdown(context.Background())) lp, err := factory.CreateLogs(context.Background(), creationSet, cfg, nil) assert.NotNil(t, lp) assert.NoError(t, err, "cannot create logs processor") assert.NoError(t, lp.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/batchprocessor/generated_component_test.go000066400000000000000000000120351511331344600312050ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package batchprocessor import ( "context" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" ) var typ = component.MustNewType("batch") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "metrics", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "traces", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(processor.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(processor.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(processor.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) } } func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/processor/batchprocessor/generated_package_test.go000066400000000000000000000002551511331344600305770ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package batchprocessor import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/processor/batchprocessor/go.mod000066400000000000000000000102621511331344600247050ustar00rootroot00000000000000module go.opentelemetry.io/collector/processor/batchprocessor go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/client v1.47.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pdata/xpdata v0.141.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/component/componentstatus v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.141.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/processor => ../ replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/consumer => ../../consumer retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/processor/xprocessor => ../xprocessor replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/processor/processortest => ../processortest replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/processor/batchprocessor/go.sum000066400000000000000000000205601511331344600247340ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/batchprocessor/internal/000077500000000000000000000000001511331344600254125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/batchprocessor/internal/metadata/000077500000000000000000000000001511331344600271725ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/batchprocessor/internal/metadata/generated_status.go000066400000000000000000000006161511331344600330650ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("batch") ScopeName = "go.opentelemetry.io/collector/processor/batchprocessor" ) const ( TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelBeta LogsStability = component.StabilityLevelBeta ) opentelemetry-collector-0.141.0/processor/batchprocessor/internal/metadata/generated_telemetry.go000066400000000000000000000114741511331344600335600ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "context" "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/embedded" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/processor/batchprocessor") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/processor/batchprocessor") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration ProcessorBatchBatchSendSize metric.Int64Histogram ProcessorBatchBatchSendSizeBytes metric.Int64Histogram ProcessorBatchBatchSizeTriggerSend metric.Int64Counter ProcessorBatchMetadataCardinality metric.Int64ObservableUpDownCounter ProcessorBatchTimeoutTriggerSend metric.Int64Counter } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // RegisterProcessorBatchMetadataCardinalityCallback sets callback for observable ProcessorBatchMetadataCardinality metric. func (builder *TelemetryBuilder) RegisterProcessorBatchMetadataCardinalityCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ProcessorBatchMetadataCardinality, obs: o}) return nil }, builder.ProcessorBatchMetadataCardinality) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } type observerInt64 struct { embedded.Int64Observer inst metric.Int64Observable obs metric.Observer } func (oi *observerInt64) Observe(value int64, opts ...metric.ObserveOption) { oi.obs.ObserveInt64(oi.inst, value, opts...) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.ProcessorBatchBatchSendSize, err = builder.meter.Int64Histogram( "otelcol_processor_batch_batch_send_size", metric.WithDescription("Number of units in the batch [Development]"), metric.WithUnit("{units}"), metric.WithExplicitBucketBoundaries([]float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000}...), ) errs = errors.Join(errs, err) builder.ProcessorBatchBatchSendSizeBytes, err = builder.meter.Int64Histogram( "otelcol_processor_batch_batch_send_size_bytes", metric.WithDescription("Number of bytes in batch that was sent. Only available on detailed level. [Development]"), metric.WithUnit("By"), metric.WithExplicitBucketBoundaries([]float64{10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1e+06, 2e+06, 3e+06, 4e+06, 5e+06, 6e+06, 7e+06, 8e+06, 9e+06}...), ) errs = errors.Join(errs, err) builder.ProcessorBatchBatchSizeTriggerSend, err = builder.meter.Int64Counter( "otelcol_processor_batch_batch_size_trigger_send", metric.WithDescription("Number of times the batch was sent due to a size trigger [Development]"), metric.WithUnit("{times}"), ) errs = errors.Join(errs, err) builder.ProcessorBatchMetadataCardinality, err = builder.meter.Int64ObservableUpDownCounter( "otelcol_processor_batch_metadata_cardinality", metric.WithDescription("Number of distinct metadata value combinations being processed [Development]"), metric.WithUnit("{combinations}"), ) errs = errors.Join(errs, err) builder.ProcessorBatchTimeoutTriggerSend, err = builder.meter.Int64Counter( "otelcol_processor_batch_timeout_trigger_send", metric.WithDescription("Number of times the batch was sent due to a timeout trigger [Development]"), metric.WithUnit("{times}"), ) errs = errors.Join(errs, err) return &builder, errs } generated_telemetry_test.go000066400000000000000000000035031511331344600345320ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/batchprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/processor/batchprocessor", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/processor/batchprocessor", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/processor/batchprocessor/internal/metadatatest/000077500000000000000000000000001511331344600300725ustar00rootroot00000000000000generated_telemetrytest.go000066400000000000000000000075431511331344600353030ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/batchprocessor/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" ) func NewSettings(tt *componenttest.Telemetry) processor.Settings { set := processortest.NewNopSettings(processortest.NopType) set.ID = component.NewID(component.MustNewType("batch")) set.TelemetrySettings = tt.NewTelemetrySettings() return set } func AssertEqualProcessorBatchBatchSendSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.HistogramDataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_batch_batch_send_size", Description: "Number of units in the batch [Development]", Unit: "{units}", Data: metricdata.Histogram[int64]{ Temporality: metricdata.CumulativeTemporality, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_batch_batch_send_size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorBatchBatchSendSizeBytes(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.HistogramDataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_batch_batch_send_size_bytes", Description: "Number of bytes in batch that was sent. Only available on detailed level. [Development]", Unit: "By", Data: metricdata.Histogram[int64]{ Temporality: metricdata.CumulativeTemporality, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_batch_batch_send_size_bytes") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorBatchBatchSizeTriggerSend(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_batch_batch_size_trigger_send", Description: "Number of times the batch was sent due to a size trigger [Development]", Unit: "{times}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_batch_batch_size_trigger_send") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorBatchMetadataCardinality(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_batch_metadata_cardinality", Description: "Number of distinct metadata value combinations being processed [Development]", Unit: "{combinations}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: false, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_batch_metadata_cardinality") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorBatchTimeoutTriggerSend(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_batch_timeout_trigger_send", Description: "Number of times the batch was sent due to a timeout trigger [Development]", Unit: "{times}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_batch_timeout_trigger_send") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } generated_telemetrytest_test.go000066400000000000000000000035311511331344600363330ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/batchprocessor/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/processor/batchprocessor/internal/metadata" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() require.NoError(t, tb.RegisterProcessorBatchMetadataCardinalityCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) tb.ProcessorBatchBatchSendSize.Record(context.Background(), 1) tb.ProcessorBatchBatchSendSizeBytes.Record(context.Background(), 1) tb.ProcessorBatchBatchSizeTriggerSend.Add(context.Background(), 1) tb.ProcessorBatchTimeoutTriggerSend.Add(context.Background(), 1) AssertEqualProcessorBatchBatchSendSize(t, testTel, []metricdata.HistogramDataPoint[int64]{{}}, metricdatatest.IgnoreValue(), metricdatatest.IgnoreTimestamp()) AssertEqualProcessorBatchBatchSendSizeBytes(t, testTel, []metricdata.HistogramDataPoint[int64]{{}}, metricdatatest.IgnoreValue(), metricdatatest.IgnoreTimestamp()) AssertEqualProcessorBatchBatchSizeTriggerSend(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorBatchMetadataCardinality(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorBatchTimeoutTriggerSend(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/batchprocessor/metadata.yaml000066400000000000000000000053121511331344600262430ustar00rootroot00000000000000type: batch github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: processor stability: beta: [traces, metrics, logs] distributions: [core, contrib, k8s] tests: telemetry: metrics: processor_batch_batch_send_size: enabled: true stability: level: development description: Number of units in the batch unit: "{units}" histogram: value_type: int bucket_boundaries: [ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100000, ] processor_batch_batch_send_size_bytes: enabled: true stability: level: development description: Number of bytes in batch that was sent. Only available on detailed level. unit: By histogram: value_type: int bucket_boundaries: [ 10, 25, 50, 75, 100, 250, 500, 750, 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 20000, 30000, 50000, 100_000, 200_000, 300_000, 400_000, 500_000, 600_000, 700_000, 800_000, 900_000, 1000_000, 2000_000, 3000_000, 4000_000, 5000_000, 6000_000, 7000_000, 8000_000, 9000_000, ] processor_batch_batch_size_trigger_send: enabled: true stability: level: development description: Number of times the batch was sent due to a size trigger unit: "{times}" sum: value_type: int monotonic: true processor_batch_metadata_cardinality: enabled: true stability: level: development description: Number of distinct metadata value combinations being processed unit: "{combinations}" sum: value_type: int async: true processor_batch_timeout_trigger_send: enabled: true stability: level: development description: Number of times the batch was sent due to a timeout trigger unit: "{times}" sum: value_type: int monotonic: true opentelemetry-collector-0.141.0/processor/batchprocessor/metrics.go000066400000000000000000000037031511331344600255760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor // import "go.opentelemetry.io/collector/processor/batchprocessor" import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/batchprocessor/internal/metadata" "go.opentelemetry.io/collector/processor/internal" ) type trigger int const ( triggerTimeout trigger = iota triggerBatchSize ) type batchProcessorTelemetry struct { exportCtx context.Context processorAttr metric.MeasurementOption telemetryBuilder *metadata.TelemetryBuilder } func newBatchProcessorTelemetry(set processor.Settings, currentMetadataCardinality func() int) (*batchProcessorTelemetry, error) { attrs := metric.WithAttributeSet(attribute.NewSet(attribute.String(internal.ProcessorKey, set.ID.String()))) telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return nil, err } err = telemetryBuilder.RegisterProcessorBatchMetadataCardinalityCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(int64(currentMetadataCardinality()), attrs) return nil }) if err != nil { return nil, err } return &batchProcessorTelemetry{ exportCtx: context.Background(), telemetryBuilder: telemetryBuilder, processorAttr: attrs, }, nil } func (bpt *batchProcessorTelemetry) record(trigger trigger, sent, bytes int64) { switch trigger { case triggerBatchSize: bpt.telemetryBuilder.ProcessorBatchBatchSizeTriggerSend.Add(bpt.exportCtx, 1, bpt.processorAttr) case triggerTimeout: bpt.telemetryBuilder.ProcessorBatchTimeoutTriggerSend.Add(bpt.exportCtx, 1, bpt.processorAttr) } bpt.telemetryBuilder.ProcessorBatchBatchSendSize.Record(bpt.exportCtx, sent, bpt.processorAttr) bpt.telemetryBuilder.ProcessorBatchBatchSendSizeBytes.Record(bpt.exportCtx, bytes, bpt.processorAttr) } opentelemetry-collector-0.141.0/processor/batchprocessor/splitlogs.go000066400000000000000000000040311511331344600261430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor // import "go.opentelemetry.io/collector/processor/batchprocessor" import ( "go.opentelemetry.io/collector/pdata/plog" ) // splitLogs removes logrecords from the input data and returns a new data of the specified size. func splitLogs(size int, src plog.Logs) plog.Logs { if src.LogRecordCount() <= size { return src } totalCopiedLogRecords := 0 dest := plog.NewLogs() src.ResourceLogs().RemoveIf(func(srcRl plog.ResourceLogs) bool { // If we are done skip everything else. if totalCopiedLogRecords == size { return false } // If it fully fits srcRlLRC := resourceLRC(srcRl) if (totalCopiedLogRecords + srcRlLRC) <= size { totalCopiedLogRecords += srcRlLRC srcRl.MoveTo(dest.ResourceLogs().AppendEmpty()) return true } destRl := dest.ResourceLogs().AppendEmpty() srcRl.Resource().CopyTo(destRl.Resource()) srcRl.ScopeLogs().RemoveIf(func(srcIll plog.ScopeLogs) bool { // If we are done skip everything else. if totalCopiedLogRecords == size { return false } // If possible to move all metrics do that. srcIllLRC := srcIll.LogRecords().Len() if size >= srcIllLRC+totalCopiedLogRecords { totalCopiedLogRecords += srcIllLRC srcIll.MoveTo(destRl.ScopeLogs().AppendEmpty()) return true } destIll := destRl.ScopeLogs().AppendEmpty() srcIll.Scope().CopyTo(destIll.Scope()) srcIll.LogRecords().RemoveIf(func(srcMetric plog.LogRecord) bool { // If we are done skip everything else. if totalCopiedLogRecords == size { return false } srcMetric.MoveTo(destIll.LogRecords().AppendEmpty()) totalCopiedLogRecords++ return true }) return false }) return srcRl.ScopeLogs().Len() == 0 }) return dest } // resourceLRC calculates the total number of log records in the plog.ResourceLogs. func resourceLRC(rs plog.ResourceLogs) (count int) { for k := 0; k < rs.ScopeLogs().Len(); k++ { count += rs.ScopeLogs().At(k).LogRecords().Len() } return count } opentelemetry-collector-0.141.0/processor/batchprocessor/splitlogs_test.go000066400000000000000000000136371511331344600272160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" ) func TestSplitLogs_noop(t *testing.T) { td := testdata.GenerateLogs(20) splitSize := 40 split := splitLogs(splitSize, td) assert.Equal(t, td, split) i := 0 td.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().RemoveIf(func(plog.LogRecord) bool { i++ return i > 5 }) assert.Equal(t, td, split) } func TestSplitLogs(t *testing.T) { ld := testdata.GenerateLogs(20) logs := ld.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(0, i)) } cp := plog.NewLogs() cpLogs := cp.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords() cpLogs.EnsureCapacity(5) ld.ResourceLogs().At(0).Resource().CopyTo( cp.ResourceLogs().At(0).Resource()) ld.ResourceLogs().At(0).ScopeLogs().At(0).Scope().CopyTo( cp.ResourceLogs().At(0).ScopeLogs().At(0).Scope()) logs.At(0).CopyTo(cpLogs.AppendEmpty()) logs.At(1).CopyTo(cpLogs.AppendEmpty()) logs.At(2).CopyTo(cpLogs.AppendEmpty()) logs.At(3).CopyTo(cpLogs.AppendEmpty()) logs.At(4).CopyTo(cpLogs.AppendEmpty()) splitSize := 5 split := splitLogs(splitSize, ld) assert.Equal(t, splitSize, split.LogRecordCount()) assert.Equal(t, cp, split) assert.Equal(t, 15, ld.LogRecordCount()) assert.Equal(t, "test-log-int-0-0", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-0-4", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(4).SeverityText()) split = splitLogs(splitSize, ld) assert.Equal(t, 10, ld.LogRecordCount()) assert.Equal(t, "test-log-int-0-5", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-0-9", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(4).SeverityText()) split = splitLogs(splitSize, ld) assert.Equal(t, 5, ld.LogRecordCount()) assert.Equal(t, "test-log-int-0-10", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-0-14", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(4).SeverityText()) split = splitLogs(splitSize, ld) assert.Equal(t, 5, ld.LogRecordCount()) assert.Equal(t, "test-log-int-0-15", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-0-19", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(4).SeverityText()) } func TestSplitLogsMultipleResourceLogs(t *testing.T) { td := testdata.GenerateLogs(20) logs := td.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(0, i)) } // add second index to resource logs testdata.GenerateLogs(20). ResourceLogs().At(0).CopyTo(td.ResourceLogs().AppendEmpty()) logs = td.ResourceLogs().At(1).ScopeLogs().At(0).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(1, i)) } splitSize := 5 split := splitLogs(splitSize, td) assert.Equal(t, splitSize, split.LogRecordCount()) assert.Equal(t, 35, td.LogRecordCount()) assert.Equal(t, "test-log-int-0-0", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-0-4", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(4).SeverityText()) } func TestSplitLogsMultipleResourceLogs_split_size_greater_than_log_size(t *testing.T) { td := testdata.GenerateLogs(20) logs := td.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(0, i)) } // add second index to resource logs testdata.GenerateLogs(20). ResourceLogs().At(0).CopyTo(td.ResourceLogs().AppendEmpty()) logs = td.ResourceLogs().At(1).ScopeLogs().At(0).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(1, i)) } splitSize := 25 split := splitLogs(splitSize, td) assert.Equal(t, splitSize, split.LogRecordCount()) assert.Equal(t, 40-splitSize, td.LogRecordCount()) assert.Equal(t, 1, td.ResourceLogs().Len()) assert.Equal(t, "test-log-int-0-0", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-0-19", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(19).SeverityText()) assert.Equal(t, "test-log-int-1-0", split.ResourceLogs().At(1).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-1-4", split.ResourceLogs().At(1).ScopeLogs().At(0).LogRecords().At(4).SeverityText()) } func TestSplitLogsMultipleILL(t *testing.T) { td := testdata.GenerateLogs(20) logs := td.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(0, i)) } // add second index to ILL td.ResourceLogs().At(0).ScopeLogs().At(0). CopyTo(td.ResourceLogs().At(0).ScopeLogs().AppendEmpty()) logs = td.ResourceLogs().At(0).ScopeLogs().At(1).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(1, i)) } // add third index to ILL td.ResourceLogs().At(0).ScopeLogs().At(0). CopyTo(td.ResourceLogs().At(0).ScopeLogs().AppendEmpty()) logs = td.ResourceLogs().At(0).ScopeLogs().At(2).LogRecords() for i := 0; i < logs.Len(); i++ { logs.At(i).SetSeverityText(getTestLogSeverityText(2, i)) } splitSize := 40 split := splitLogs(splitSize, td) assert.Equal(t, splitSize, split.LogRecordCount()) assert.Equal(t, 20, td.LogRecordCount()) assert.Equal(t, "test-log-int-0-0", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(0).SeverityText()) assert.Equal(t, "test-log-int-0-4", split.ResourceLogs().At(0).ScopeLogs().At(0).LogRecords().At(4).SeverityText()) } opentelemetry-collector-0.141.0/processor/batchprocessor/splitmetrics.go000066400000000000000000000142471511331344600266570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor // import "go.opentelemetry.io/collector/processor/batchprocessor" import ( "go.opentelemetry.io/collector/pdata/pmetric" ) // splitMetrics removes metrics from the input data and returns a new data of the specified size. func splitMetrics(size int, src pmetric.Metrics) pmetric.Metrics { dataPoints := src.DataPointCount() if dataPoints <= size { return src } totalCopiedDataPoints := 0 dest := pmetric.NewMetrics() src.ResourceMetrics().RemoveIf(func(srcRs pmetric.ResourceMetrics) bool { // If we are done skip everything else. if totalCopiedDataPoints == size { return false } // If it fully fits srcRsDataPointCount := resourceMetricsDPC(srcRs) if (totalCopiedDataPoints + srcRsDataPointCount) <= size { totalCopiedDataPoints += srcRsDataPointCount srcRs.MoveTo(dest.ResourceMetrics().AppendEmpty()) return true } destRs := dest.ResourceMetrics().AppendEmpty() srcRs.Resource().CopyTo(destRs.Resource()) srcRs.ScopeMetrics().RemoveIf(func(srcIlm pmetric.ScopeMetrics) bool { // If we are done skip everything else. if totalCopiedDataPoints == size { return false } // If possible to move all metrics do that. srcIlmDataPointCount := scopeMetricsDPC(srcIlm) if srcIlmDataPointCount+totalCopiedDataPoints <= size { totalCopiedDataPoints += srcIlmDataPointCount srcIlm.MoveTo(destRs.ScopeMetrics().AppendEmpty()) return true } destIlm := destRs.ScopeMetrics().AppendEmpty() srcIlm.Scope().CopyTo(destIlm.Scope()) srcIlm.Metrics().RemoveIf(func(srcMetric pmetric.Metric) bool { // If we are done skip everything else. if totalCopiedDataPoints == size { return false } // If possible to move all points do that. srcMetricPointCount := metricDPC(srcMetric) if srcMetricPointCount+totalCopiedDataPoints <= size { totalCopiedDataPoints += srcMetricPointCount srcMetric.MoveTo(destIlm.Metrics().AppendEmpty()) return true } // If the metric has more data points than free slots we should split it. copiedDataPoints, remove := splitMetric(srcMetric, destIlm.Metrics().AppendEmpty(), size-totalCopiedDataPoints) totalCopiedDataPoints += copiedDataPoints return remove }) return false }) return srcRs.ScopeMetrics().Len() == 0 }) return dest } // resourceMetricsDPC calculates the total number of data points in the pmetric.ResourceMetrics. func resourceMetricsDPC(rs pmetric.ResourceMetrics) int { dataPointCount := 0 ilms := rs.ScopeMetrics() for k := 0; k < ilms.Len(); k++ { dataPointCount += scopeMetricsDPC(ilms.At(k)) } return dataPointCount } // scopeMetricsDPC calculates the total number of data points in the pmetric.ScopeMetrics. func scopeMetricsDPC(ilm pmetric.ScopeMetrics) int { dataPointCount := 0 ms := ilm.Metrics() for k := 0; k < ms.Len(); k++ { dataPointCount += metricDPC(ms.At(k)) } return dataPointCount } // metricDPC calculates the total number of data points in the pmetric.Metric. func metricDPC(ms pmetric.Metric) int { switch ms.Type() { case pmetric.MetricTypeGauge: return ms.Gauge().DataPoints().Len() case pmetric.MetricTypeSum: return ms.Sum().DataPoints().Len() case pmetric.MetricTypeHistogram: return ms.Histogram().DataPoints().Len() case pmetric.MetricTypeExponentialHistogram: return ms.ExponentialHistogram().DataPoints().Len() case pmetric.MetricTypeSummary: return ms.Summary().DataPoints().Len() } return 0 } // splitMetric removes metric points from the input data and moves data of the specified size to destination. // Returns size of moved data and boolean describing, whether the metric should be removed from original slice. func splitMetric(ms, dest pmetric.Metric, size int) (int, bool) { dest.SetName(ms.Name()) dest.SetDescription(ms.Description()) dest.SetUnit(ms.Unit()) switch ms.Type() { case pmetric.MetricTypeGauge: return splitNumberDataPoints(ms.Gauge().DataPoints(), dest.SetEmptyGauge().DataPoints(), size) case pmetric.MetricTypeSum: destSum := dest.SetEmptySum() destSum.SetAggregationTemporality(ms.Sum().AggregationTemporality()) destSum.SetIsMonotonic(ms.Sum().IsMonotonic()) return splitNumberDataPoints(ms.Sum().DataPoints(), destSum.DataPoints(), size) case pmetric.MetricTypeHistogram: destHistogram := dest.SetEmptyHistogram() destHistogram.SetAggregationTemporality(ms.Histogram().AggregationTemporality()) return splitHistogramDataPoints(ms.Histogram().DataPoints(), destHistogram.DataPoints(), size) case pmetric.MetricTypeExponentialHistogram: destHistogram := dest.SetEmptyExponentialHistogram() destHistogram.SetAggregationTemporality(ms.ExponentialHistogram().AggregationTemporality()) return splitExponentialHistogramDataPoints(ms.ExponentialHistogram().DataPoints(), destHistogram.DataPoints(), size) case pmetric.MetricTypeSummary: return splitSummaryDataPoints(ms.Summary().DataPoints(), dest.SetEmptySummary().DataPoints(), size) } return size, false } func splitNumberDataPoints(src, dst pmetric.NumberDataPointSlice, size int) (int, bool) { dst.EnsureCapacity(size) i := 0 src.RemoveIf(func(dp pmetric.NumberDataPoint) bool { if i < size { dp.MoveTo(dst.AppendEmpty()) i++ return true } return false }) return size, false } func splitHistogramDataPoints(src, dst pmetric.HistogramDataPointSlice, size int) (int, bool) { dst.EnsureCapacity(size) i := 0 src.RemoveIf(func(dp pmetric.HistogramDataPoint) bool { if i < size { dp.MoveTo(dst.AppendEmpty()) i++ return true } return false }) return size, false } func splitExponentialHistogramDataPoints(src, dst pmetric.ExponentialHistogramDataPointSlice, size int) (int, bool) { dst.EnsureCapacity(size) i := 0 src.RemoveIf(func(dp pmetric.ExponentialHistogramDataPoint) bool { if i < size { dp.MoveTo(dst.AppendEmpty()) i++ return true } return false }) return size, false } func splitSummaryDataPoints(src, dst pmetric.SummaryDataPointSlice, size int) (int, bool) { dst.EnsureCapacity(size) i := 0 src.RemoveIf(func(dp pmetric.SummaryDataPoint) bool { if i < size { dp.MoveTo(dst.AppendEmpty()) i++ return true } return false }) return size, false } opentelemetry-collector-0.141.0/processor/batchprocessor/splitmetrics_test.go000066400000000000000000000344001511331344600277070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" ) func TestSplitMetrics_noop(t *testing.T) { td := testdata.GenerateMetrics(20) splitSize := 40 split := splitMetrics(splitSize, td) assert.Equal(t, td, split) i := 0 td.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().RemoveIf(func(pmetric.Metric) bool { i++ return i > 5 }) assert.Equal(t, td, split) } func TestSplitMetrics(t *testing.T) { md := testdata.GenerateMetrics(20) metrics := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() dataPointCount := metricDPC(metrics.At(0)) for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(0, i)) assert.Equal(t, dataPointCount, metricDPC(metrics.At(i))) } cp := pmetric.NewMetrics() cpMetrics := cp.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() cpMetrics.EnsureCapacity(5) md.ResourceMetrics().At(0).ScopeMetrics().At(0).Scope().CopyTo( cp.ResourceMetrics().At(0).ScopeMetrics().At(0).Scope()) md.ResourceMetrics().At(0).Resource().CopyTo( cp.ResourceMetrics().At(0).Resource()) metrics.At(0).CopyTo(cpMetrics.AppendEmpty()) metrics.At(1).CopyTo(cpMetrics.AppendEmpty()) metrics.At(2).CopyTo(cpMetrics.AppendEmpty()) metrics.At(3).CopyTo(cpMetrics.AppendEmpty()) metrics.At(4).CopyTo(cpMetrics.AppendEmpty()) splitMetricCount := 5 splitSize := splitMetricCount * dataPointCount split := splitMetrics(splitSize, md) assert.Equal(t, splitMetricCount, split.MetricCount()) assert.Equal(t, cp, split) assert.Equal(t, 15, md.MetricCount()) assert.Equal(t, "test-metric-int-0-0", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-4", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 10, md.MetricCount()) assert.Equal(t, "test-metric-int-0-5", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-9", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 5, md.MetricCount()) assert.Equal(t, "test-metric-int-0-10", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-14", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 5, md.MetricCount()) assert.Equal(t, "test-metric-int-0-15", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-19", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) } func TestSplitMetricsMultipleResourceSpans(t *testing.T) { md := testdata.GenerateMetrics(20) metrics := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() dataPointCount := metricDPC(metrics.At(0)) for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(0, i)) assert.Equal(t, dataPointCount, metricDPC(metrics.At(i))) } // add second index to resource metrics testdata.GenerateMetrics(20). ResourceMetrics().At(0).CopyTo(md.ResourceMetrics().AppendEmpty()) metrics = md.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(1, i)) } splitMetricCount := 5 splitSize := splitMetricCount * dataPointCount split := splitMetrics(splitSize, md) assert.Equal(t, splitMetricCount, split.MetricCount()) assert.Equal(t, 35, md.MetricCount()) assert.Equal(t, "test-metric-int-0-0", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-4", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) } func TestSplitMetricsMultipleResourceSpans_SplitSizeGreaterThanMetricSize(t *testing.T) { td := testdata.GenerateMetrics(20) metrics := td.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() dataPointCount := metricDPC(metrics.At(0)) for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(0, i)) assert.Equal(t, dataPointCount, metricDPC(metrics.At(i))) } // add second index to resource metrics testdata.GenerateMetrics(20). ResourceMetrics().At(0).CopyTo(td.ResourceMetrics().AppendEmpty()) metrics = td.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(1, i)) } splitMetricCount := 25 splitSize := splitMetricCount * dataPointCount split := splitMetrics(splitSize, td) assert.Equal(t, splitMetricCount, split.MetricCount()) assert.Equal(t, 40-splitMetricCount, td.MetricCount()) assert.Equal(t, 1, td.ResourceMetrics().Len()) assert.Equal(t, "test-metric-int-0-0", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-19", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(19).Name()) assert.Equal(t, "test-metric-int-1-0", split.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-1-4", split.ResourceMetrics().At(1).ScopeMetrics().At(0).Metrics().At(4).Name()) } func TestSplitMetricsUneven(t *testing.T) { md := testdata.GenerateMetrics(10) metrics := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() dataPointCount := 2 for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(0, i)) assert.Equal(t, dataPointCount, metricDPC(metrics.At(i))) } splitSize := 9 split := splitMetrics(splitSize, md) assert.Equal(t, 5, split.MetricCount()) assert.Equal(t, 6, md.MetricCount()) assert.Equal(t, "test-metric-int-0-0", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-4", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 5, split.MetricCount()) assert.Equal(t, 1, md.MetricCount()) assert.Equal(t, "test-metric-int-0-4", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-8", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 1, split.MetricCount()) assert.Equal(t, "test-metric-int-0-9", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) } func TestSplitMetricsAllTypes(t *testing.T) { md := testdata.GenerateMetricsAllTypes() dataPointCount := 2 metrics := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(0, i)) assert.Equal(t, dataPointCount, metricDPC(metrics.At(i))) } splitSize := 2 // Start with 7 metric types, and 2 points per-metric. Split out the first, // and then split by 2 for the rest so that each metric is split in half. // Verify that descriptors are preserved for all data types across splits. split := splitMetrics(1, md) assert.Equal(t, 1, split.MetricCount()) assert.Equal(t, 7, md.MetricCount()) gaugeInt := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) assert.Equal(t, 1, gaugeInt.Gauge().DataPoints().Len()) assert.Equal(t, "test-metric-int-0-0", gaugeInt.Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 2, split.MetricCount()) assert.Equal(t, 6, md.MetricCount()) gaugeInt = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) gaugeDouble := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1) assert.Equal(t, 1, gaugeInt.Gauge().DataPoints().Len()) assert.Equal(t, "test-metric-int-0-0", gaugeInt.Name()) assert.Equal(t, 1, gaugeDouble.Gauge().DataPoints().Len()) assert.Equal(t, "test-metric-int-0-1", gaugeDouble.Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 2, split.MetricCount()) assert.Equal(t, 5, md.MetricCount()) gaugeDouble = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) sumInt := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1) assert.Equal(t, 1, gaugeDouble.Gauge().DataPoints().Len()) assert.Equal(t, "test-metric-int-0-1", gaugeDouble.Name()) assert.Equal(t, 1, sumInt.Sum().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, sumInt.Sum().AggregationTemporality()) assert.True(t, sumInt.Sum().IsMonotonic()) assert.Equal(t, "test-metric-int-0-2", sumInt.Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 2, split.MetricCount()) assert.Equal(t, 4, md.MetricCount()) sumInt = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) sumDouble := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1) assert.Equal(t, 1, sumInt.Sum().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, sumInt.Sum().AggregationTemporality()) assert.True(t, sumInt.Sum().IsMonotonic()) assert.Equal(t, "test-metric-int-0-2", sumInt.Name()) assert.Equal(t, 1, sumDouble.Sum().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, sumDouble.Sum().AggregationTemporality()) assert.True(t, sumDouble.Sum().IsMonotonic()) assert.Equal(t, "test-metric-int-0-3", sumDouble.Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 2, split.MetricCount()) assert.Equal(t, 3, md.MetricCount()) sumDouble = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) histogram := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1) assert.Equal(t, 1, sumDouble.Sum().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, sumDouble.Sum().AggregationTemporality()) assert.True(t, sumDouble.Sum().IsMonotonic()) assert.Equal(t, "test-metric-int-0-3", sumDouble.Name()) assert.Equal(t, 1, histogram.Histogram().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, histogram.Histogram().AggregationTemporality()) assert.Equal(t, "test-metric-int-0-4", histogram.Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 2, split.MetricCount()) assert.Equal(t, 2, md.MetricCount()) histogram = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) exponentialHistogram := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1) assert.Equal(t, 1, histogram.Histogram().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityCumulative, histogram.Histogram().AggregationTemporality()) assert.Equal(t, "test-metric-int-0-4", histogram.Name()) assert.Equal(t, 1, exponentialHistogram.ExponentialHistogram().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityDelta, exponentialHistogram.ExponentialHistogram().AggregationTemporality()) assert.Equal(t, "test-metric-int-0-5", exponentialHistogram.Name()) split = splitMetrics(splitSize, md) assert.Equal(t, 2, split.MetricCount()) assert.Equal(t, 1, md.MetricCount()) exponentialHistogram = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) summary := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(1) assert.Equal(t, 1, exponentialHistogram.ExponentialHistogram().DataPoints().Len()) assert.Equal(t, pmetric.AggregationTemporalityDelta, exponentialHistogram.ExponentialHistogram().AggregationTemporality()) assert.Equal(t, "test-metric-int-0-5", exponentialHistogram.Name()) assert.Equal(t, 1, summary.Summary().DataPoints().Len()) assert.Equal(t, "test-metric-int-0-6", summary.Name()) split = splitMetrics(splitSize, md) summary = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) assert.Equal(t, 1, summary.Summary().DataPoints().Len()) assert.Equal(t, "test-metric-int-0-6", summary.Name()) } func TestSplitMetricsBatchSizeSmallerThanDataPointCount(t *testing.T) { md := testdata.GenerateMetrics(2) metrics := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() dataPointCount := 2 for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(0, i)) assert.Equal(t, dataPointCount, metricDPC(metrics.At(i))) } splitSize := 1 split := splitMetrics(splitSize, md) splitMetric := split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) assert.Equal(t, 1, split.MetricCount()) assert.Equal(t, 2, md.MetricCount()) assert.Equal(t, "test-metric-int-0-0", splitMetric.Name()) split = splitMetrics(splitSize, md) splitMetric = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) assert.Equal(t, 1, split.MetricCount()) assert.Equal(t, 1, md.MetricCount()) assert.Equal(t, "test-metric-int-0-0", splitMetric.Name()) split = splitMetrics(splitSize, md) splitMetric = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) assert.Equal(t, 1, split.MetricCount()) assert.Equal(t, 1, md.MetricCount()) assert.Equal(t, "test-metric-int-0-1", splitMetric.Name()) split = splitMetrics(splitSize, md) splitMetric = split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0) assert.Equal(t, 1, split.MetricCount()) assert.Equal(t, 1, md.MetricCount()) assert.Equal(t, "test-metric-int-0-1", splitMetric.Name()) } func TestSplitMetricsMultipleILM(t *testing.T) { md := testdata.GenerateMetrics(20) metrics := md.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics() dataPointCount := metricDPC(metrics.At(0)) for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(0, i)) assert.Equal(t, dataPointCount, metricDPC(metrics.At(i))) } // add second index to ilm md.ResourceMetrics().At(0).ScopeMetrics().At(0). CopyTo(md.ResourceMetrics().At(0).ScopeMetrics().AppendEmpty()) // add a third index to ilm md.ResourceMetrics().At(0).ScopeMetrics().At(0). CopyTo(md.ResourceMetrics().At(0).ScopeMetrics().AppendEmpty()) metrics = md.ResourceMetrics().At(0).ScopeMetrics().At(2).Metrics() for i := 0; i < metrics.Len(); i++ { metrics.At(i).SetName(getTestMetricName(2, i)) } splitMetricCount := 40 splitSize := splitMetricCount * dataPointCount split := splitMetrics(splitSize, md) assert.Equal(t, splitMetricCount, split.MetricCount()) assert.Equal(t, 20, md.MetricCount()) assert.Equal(t, "test-metric-int-0-0", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(0).Name()) assert.Equal(t, "test-metric-int-0-4", split.ResourceMetrics().At(0).ScopeMetrics().At(0).Metrics().At(4).Name()) } opentelemetry-collector-0.141.0/processor/batchprocessor/splittraces.go000066400000000000000000000037411511331344600264670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor // import "go.opentelemetry.io/collector/processor/batchprocessor" import ( "go.opentelemetry.io/collector/pdata/ptrace" ) // splitTraces removes spans from the input trace and returns a new trace of the specified size. func splitTraces(size int, src ptrace.Traces) ptrace.Traces { if src.SpanCount() <= size { return src } totalCopiedSpans := 0 dest := ptrace.NewTraces() src.ResourceSpans().RemoveIf(func(srcRs ptrace.ResourceSpans) bool { // If we are done skip everything else. if totalCopiedSpans == size { return false } // If it fully fits srcRsSC := resourceSC(srcRs) if (totalCopiedSpans + srcRsSC) <= size { totalCopiedSpans += srcRsSC srcRs.MoveTo(dest.ResourceSpans().AppendEmpty()) return true } destRs := dest.ResourceSpans().AppendEmpty() srcRs.Resource().CopyTo(destRs.Resource()) srcRs.ScopeSpans().RemoveIf(func(srcIls ptrace.ScopeSpans) bool { // If we are done skip everything else. if totalCopiedSpans == size { return false } // If possible to move all metrics do that. srcIlsSC := srcIls.Spans().Len() if size-totalCopiedSpans >= srcIlsSC { totalCopiedSpans += srcIlsSC srcIls.MoveTo(destRs.ScopeSpans().AppendEmpty()) return true } destIls := destRs.ScopeSpans().AppendEmpty() srcIls.Scope().CopyTo(destIls.Scope()) srcIls.Spans().RemoveIf(func(srcSpan ptrace.Span) bool { // If we are done skip everything else. if totalCopiedSpans == size { return false } srcSpan.MoveTo(destIls.Spans().AppendEmpty()) totalCopiedSpans++ return true }) return false }) return srcRs.ScopeSpans().Len() == 0 }) return dest } // resourceSC calculates the total number of spans in the ptrace.ResourceSpans. func resourceSC(rs ptrace.ResourceSpans) (count int) { for k := 0; k < rs.ScopeSpans().Len(); k++ { count += rs.ScopeSpans().At(k).Spans().Len() } return count } opentelemetry-collector-0.141.0/processor/batchprocessor/splittraces_test.go000066400000000000000000000131241511331344600275220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package batchprocessor import ( "testing" "github.com/stretchr/testify/assert" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) func TestSplitTraces_noop(t *testing.T) { td := testdata.GenerateTraces(20) splitSize := 40 split := splitTraces(splitSize, td) assert.Equal(t, td, split) i := 0 td.ResourceSpans().At(0).ScopeSpans().At(0).Spans().RemoveIf(func(ptrace.Span) bool { i++ return i > 5 }) assert.Equal(t, td, split) } func TestSplitTraces(t *testing.T) { td := testdata.GenerateTraces(20) spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(0, i)) } cp := ptrace.NewTraces() cpSpans := cp.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans() cpSpans.EnsureCapacity(5) td.ResourceSpans().At(0).Resource().CopyTo( cp.ResourceSpans().At(0).Resource()) td.ResourceSpans().At(0).ScopeSpans().At(0).Scope().CopyTo( cp.ResourceSpans().At(0).ScopeSpans().At(0).Scope()) spans.At(0).CopyTo(cpSpans.AppendEmpty()) spans.At(1).CopyTo(cpSpans.AppendEmpty()) spans.At(2).CopyTo(cpSpans.AppendEmpty()) spans.At(3).CopyTo(cpSpans.AppendEmpty()) spans.At(4).CopyTo(cpSpans.AppendEmpty()) splitSize := 5 split := splitTraces(splitSize, td) assert.Equal(t, splitSize, split.SpanCount()) assert.Equal(t, cp, split) assert.Equal(t, 15, td.SpanCount()) assert.Equal(t, "test-span-0-0", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-0-4", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(4).Name()) split = splitTraces(splitSize, td) assert.Equal(t, 10, td.SpanCount()) assert.Equal(t, "test-span-0-5", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-0-9", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(4).Name()) split = splitTraces(splitSize, td) assert.Equal(t, 5, td.SpanCount()) assert.Equal(t, "test-span-0-10", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-0-14", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(4).Name()) split = splitTraces(splitSize, td) assert.Equal(t, 5, td.SpanCount()) assert.Equal(t, "test-span-0-15", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-0-19", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(4).Name()) } func TestSplitTracesMultipleResourceSpans(t *testing.T) { td := testdata.GenerateTraces(20) spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(0, i)) } // add second index to resource spans testdata.GenerateTraces(20). ResourceSpans().At(0).CopyTo(td.ResourceSpans().AppendEmpty()) spans = td.ResourceSpans().At(1).ScopeSpans().At(0).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(1, i)) } splitSize := 5 split := splitTraces(splitSize, td) assert.Equal(t, splitSize, split.SpanCount()) assert.Equal(t, 35, td.SpanCount()) assert.Equal(t, "test-span-0-0", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-0-4", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(4).Name()) } func TestSplitTracesMultipleResourceSpans_SplitSizeGreaterThanSpanSize(t *testing.T) { td := testdata.GenerateTraces(20) spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(0, i)) } // add second index to resource spans testdata.GenerateTraces(20). ResourceSpans().At(0).CopyTo(td.ResourceSpans().AppendEmpty()) spans = td.ResourceSpans().At(1).ScopeSpans().At(0).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(1, i)) } splitSize := 25 split := splitTraces(splitSize, td) assert.Equal(t, splitSize, split.SpanCount()) assert.Equal(t, 40-splitSize, td.SpanCount()) assert.Equal(t, 1, td.ResourceSpans().Len()) assert.Equal(t, "test-span-0-0", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-0-19", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(19).Name()) assert.Equal(t, "test-span-1-0", split.ResourceSpans().At(1).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-1-4", split.ResourceSpans().At(1).ScopeSpans().At(0).Spans().At(4).Name()) } func TestSplitTracesMultipleILS(t *testing.T) { td := testdata.GenerateTraces(20) spans := td.ResourceSpans().At(0).ScopeSpans().At(0).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(0, i)) } // add second index to ILS td.ResourceSpans().At(0).ScopeSpans().At(0). CopyTo(td.ResourceSpans().At(0).ScopeSpans().AppendEmpty()) spans = td.ResourceSpans().At(0).ScopeSpans().At(1).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(1, i)) } // add third index to ILS td.ResourceSpans().At(0).ScopeSpans().At(0). CopyTo(td.ResourceSpans().At(0).ScopeSpans().AppendEmpty()) spans = td.ResourceSpans().At(0).ScopeSpans().At(2).Spans() for i := 0; i < spans.Len(); i++ { spans.At(i).SetName(getTestSpanName(2, i)) } splitSize := 40 split := splitTraces(splitSize, td) assert.Equal(t, splitSize, split.SpanCount()) assert.Equal(t, 20, td.SpanCount()) assert.Equal(t, "test-span-0-0", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) assert.Equal(t, "test-span-0-4", split.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(4).Name()) } opentelemetry-collector-0.141.0/processor/batchprocessor/testdata/000077500000000000000000000000001511331344600254075ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/batchprocessor/testdata/config.yaml000066400000000000000000000000771511331344600275440ustar00rootroot00000000000000timeout: 10s send_batch_size: 10000 send_batch_max_size: 11000 opentelemetry-collector-0.141.0/processor/go.mod000066400000000000000000000036461511331344600216740ustar00rootroot00000000000000module go.opentelemetry.io/collector/processor go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/consumer => ../consumer replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../consumer/consumertest replace go.opentelemetry.io/collector/pipeline => ../pipeline replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/processor/go.sum000066400000000000000000000124431511331344600217140ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/internal/000077500000000000000000000000001511331344600223715ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/internal/err.go000066400000000000000000000005751511331344600235170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/processor/internal" import ( "fmt" "go.opentelemetry.io/collector/component" ) func ErrIDMismatch(id component.ID, typ component.Type) error { return fmt.Errorf("component type mismatch: component ID %q does not have type %q", id, typ) } opentelemetry-collector-0.141.0/processor/internal/obsmetrics.go000066400000000000000000000005401511331344600250710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/processor/internal" const ( MetricNameSep = "_" // ProcessorKey is the key used to identify processors in metrics and traces. ProcessorKey = "processor" ProcessorMetricPrefix = ProcessorKey + MetricNameSep ) opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/000077500000000000000000000000001511331344600254135ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/Makefile000066400000000000000000000000361511331344600270520ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/README.md000066400000000000000000000165521511331344600267030ustar00rootroot00000000000000# Memory Limiter Processor | Status | | | ------------- |-----------| | Stability | [alpha]: profiles | | | [beta]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Aprocessor%2Fmemorylimiter%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Aprocessor%2Fmemorylimiter) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Aprocessor%2Fmemorylimiter%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Aprocessor%2Fmemorylimiter) | [alpha]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#alpha [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 ## Overview The memory limiter processor is used to prevent out of memory situations on the collector. Given that the amount and type of data the collector processes is environment-specific and resource utilization of the collector is also dependent on the configured processors, it is important to put checks in place regarding memory usage. ## Functionality The memory limiter processor performs periodic checks of memory usage and will begin refusing data and forcing GC to reduce memory consumption when defined limits have been exceeded. The processor uses soft and hard memory limits. The hard limit is defined via the `limit_mib` configuration option, and is always above or equal to the soft limit. The difference between the soft limit and hard limit is defined via the `spike_limit_mib` configuration option. The processor will enter memory limited mode and will start refusing the data when memory usage exceeds the soft limit. This is done by returning errors to the preceding component in the pipeline that made the ConsumeLogs/Trace/Metrics function call. In memory limited mode the error returned by ConsumeLogs/Trace/Metrics function is a non-permanent error. When receivers see this error they are expected to retry sending the same data. The receivers may also apply backpressure to their own data sources in order to slow the inflow of data into the Collector, and to allow memory usage to go below the set limits. > Warning: Data will be permanently lost if the component preceding the memory limiter > in the telemetry pipeline does not correctly retry sending data after it has > been refused by the memory limiter. > We consider such components to be incorrectly implemented. When the memory usage is above the hard limit the processor will additionally force garbage collection to be performed. Normal operation is resumed when memory usage drops below the soft limit, meaning data will no longer be refused and the processor won't force garbage collection to be performed. ## Best Practices Note that while the processor can help mitigate out of memory situations, it is not a replacement for properly sizing and configuring the collector. Keep in mind that if the soft limit is crossed, the collector will return errors to all receive operations until enough memory is freed. This may eventually result in dropped data since the receivers may not be able to retry the data indefinitely. It is highly recommended to configure the `GOMEMLIMIT` [environment variable](https://pkg.go.dev/runtime#hdr-Environment_Variables) as well as the `memory_limiter` processor on every collector. `GOMEMLIMIT` should be set to 80% of the hard memory limit of your collector. For the `memory_limiter` processor, the best practice is to add it as the first processor in a pipeline. This is to ensure that backpressure can be sent to applicable receivers and minimize the likelihood of dropped data when the `memory_limiter` gets triggered. The value of the `spike_limit_mib` configuration option should be selected in a way that ensures that memory usage cannot increase by more than this value within a single memory check interval. Otherwise, memory usage may exceed the hard limit, even if temporarily. A good starting point for `spike_limit_mib` is 20% of the hard limit. Bigger `spike_limit_mib` values may be necessary for spiky traffic or for longer check intervals. ## Configuration Please refer to [memorylimiter.go](../../internal/memorylimiter/memorylimiter.go) for the config spec. The following configuration options **must be changed**: - `check_interval` (default = 0s): Time between measurements of memory usage. The recommended value is 1 second. If the expected traffic to the Collector is very spiky then decrease the `check_interval` or increase `spike_limit_mib` to avoid memory usage going over the hard limit. - `limit_mib` (default = 0): Maximum amount of memory, in MiB, targeted to be allocated by the process heap. Note that typically the total memory usage of process will be about 50MiB higher than this value. This defines the hard limit. - `spike_limit_mib` (default = 20% of `limit_mib`): Maximum spike expected between the measurements of memory usage. The value must be less than `limit_mib`. The soft limit value will be equal to (limit_mib - spike_limit_mib). The recommended value for `spike_limit_mib` is about 20% `limit_mib`. - `limit_percentage` (default = 0): Maximum amount of total memory targeted to be allocated by the process heap. This configuration is supported on Linux systems with cgroups and it's intended to be used in dynamic platforms like docker. This option is used to calculate `memory_limit` from the total available memory. For instance setting of 75% with the total memory of 1GiB will result in the limit of 750 MiB. The fixed memory setting (`limit_mib`) takes precedence over the percentage configuration. - `spike_limit_percentage` (default = 20% of `limit_percentage`): Maximum spike expected between the measurements of memory usage. The value must be less than `limit_percentage`. This option is used to calculate `spike_limit_mib` from the total available memory. For instance setting of 25% with the total memory of 1GiB will result in the spike limit of 250MiB. This option is intended to be used only with `limit_percentage`. Examples: ```yaml processors: memory_limiter: check_interval: 1s limit_mib: 4000 spike_limit_mib: 800 ``` - Hard limit will be set to **4000 MiB**. - Soft limit will be set to 4000 - 800 = **3200 MiB**. ```yaml processors: memory_limiter: check_interval: 1s limit_percentage: 80 spike_limit_percentage: 15 ``` On a machine with 1000 MiB total memory available: - Hard limit will be set to 1000 * 0.80 = **800 MiB**. - Soft limit will be set to 1000 * 0.80 - 1000 * 0.15 = 1000 * 0.65 = **650 MiB**. Refer to [config.yaml](../../internal/memorylimiter/testdata/config.yaml) for detailed examples on using the processor. opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/config.go000066400000000000000000000004331511331344600272070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterprocessor // import "go.opentelemetry.io/collector/processor/memorylimiterprocessor" import "go.opentelemetry.io/collector/internal/memorylimiter" type Config = memorylimiter.Config opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/documentation.md000066400000000000000000000040211511331344600306030ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # memory_limiter ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_processor_accepted_log_records Number of log records successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Deprecated | ### otelcol_processor_accepted_metric_points Number of metric points successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Deprecated | ### otelcol_processor_accepted_spans Number of spans successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Deprecated | ### otelcol_processor_refused_log_records Number of log records that were rejected by the next component in the pipeline. [Deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Deprecated | ### otelcol_processor_refused_metric_points Number of metric points that were rejected by the next component in the pipeline. [Deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Deprecated | ### otelcol_processor_refused_spans Number of spans that were rejected by the next component in the pipeline. [Deprecated since v0.110.0] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Deprecated | opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/factory.go000066400000000000000000000112561511331344600274160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package memorylimiterprocessor // import "go.opentelemetry.io/collector/processor/memorylimiterprocessor" import ( "context" "sync" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/memorylimiter" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal/metadata" "go.opentelemetry.io/collector/processor/processorhelper" "go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper" "go.opentelemetry.io/collector/processor/xprocessor" ) var processorCapabilities = consumer.Capabilities{MutatesData: false} type factory struct { // memoryLimiters stores memoryLimiter instances with unique configs that multiple processors can reuse. // This avoids running multiple memory checks (ie: GC) for every processor using the same processor config. memoryLimiters map[component.Config]*memoryLimiterProcessor lock sync.Mutex } // NewFactory returns a new factory for the Memory Limiter processor. func NewFactory() xprocessor.Factory { f := &factory{ memoryLimiters: map[component.Config]*memoryLimiterProcessor{}, } return xprocessor.NewFactory( metadata.Type, createDefaultConfig, xprocessor.WithTraces(f.createTraces, metadata.TracesStability), xprocessor.WithMetrics(f.createMetrics, metadata.MetricsStability), xprocessor.WithLogs(f.createLogs, metadata.LogsStability), xprocessor.WithProfiles(f.createProfiles, metadata.ProfilesStability)) } // CreateDefaultConfig creates the default configuration for processor. Notice // that the default configuration is expected to fail for this processor. func createDefaultConfig() component.Config { return memorylimiter.NewDefaultConfig() } func (f *factory) createTraces( ctx context.Context, set processor.Settings, cfg component.Config, nextConsumer consumer.Traces, ) (processor.Traces, error) { memLimiter, err := f.getMemoryLimiter(set, cfg) if err != nil { return nil, err } return processorhelper.NewTraces(ctx, set, cfg, nextConsumer, memLimiter.processTraces, processorhelper.WithCapabilities(processorCapabilities), processorhelper.WithStart(memLimiter.start), processorhelper.WithShutdown(memLimiter.shutdown)) } func (f *factory) createMetrics( ctx context.Context, set processor.Settings, cfg component.Config, nextConsumer consumer.Metrics, ) (processor.Metrics, error) { memLimiter, err := f.getMemoryLimiter(set, cfg) if err != nil { return nil, err } return processorhelper.NewMetrics(ctx, set, cfg, nextConsumer, memLimiter.processMetrics, processorhelper.WithCapabilities(processorCapabilities), processorhelper.WithStart(memLimiter.start), processorhelper.WithShutdown(memLimiter.shutdown)) } func (f *factory) createLogs( ctx context.Context, set processor.Settings, cfg component.Config, nextConsumer consumer.Logs, ) (processor.Logs, error) { memLimiter, err := f.getMemoryLimiter(set, cfg) if err != nil { return nil, err } return processorhelper.NewLogs(ctx, set, cfg, nextConsumer, memLimiter.processLogs, processorhelper.WithCapabilities(processorCapabilities), processorhelper.WithStart(memLimiter.start), processorhelper.WithShutdown(memLimiter.shutdown)) } func (f *factory) createProfiles( ctx context.Context, set processor.Settings, cfg component.Config, nextConsumer xconsumer.Profiles, ) (xprocessor.Profiles, error) { memLimiter, err := f.getMemoryLimiter(set, cfg) if err != nil { return nil, err } return xprocessorhelper.NewProfiles( ctx, set, cfg, nextConsumer, memLimiter.processProfiles, xprocessorhelper.WithCapabilities(processorCapabilities), xprocessorhelper.WithStart(memLimiter.start), xprocessorhelper.WithShutdown(memLimiter.shutdown), ) } // getMemoryLimiter checks if we have a cached memoryLimiter with a specific config, // otherwise initialize and add one to the store. func (f *factory) getMemoryLimiter(set processor.Settings, cfg component.Config) (*memoryLimiterProcessor, error) { f.lock.Lock() defer f.lock.Unlock() if memLimiter, ok := f.memoryLimiters[cfg]; ok { return memLimiter, nil } set.TelemetrySettings = telemetry.DropInjectedAttributes( set.TelemetrySettings, telemetry.SignalKey, telemetry.PipelineIDKey, telemetry.ComponentIDKey, ) set.Logger.Debug("created singleton logger") memLimiter, err := newMemoryLimiterProcessor(set, cfg.(*Config)) if err != nil { return nil, err } f.memoryLimiters[cfg] = memLimiter return memLimiter, nil } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/factory_test.go000066400000000000000000000057251511331344600304610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterprocessor import ( "context" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/internal/telemetry/telemetrytest" "go.opentelemetry.io/collector/processor/processortest" ) func TestCreateDefaultConfig(t *testing.T) { factory := NewFactory() require.NotNil(t, factory) cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") assert.NoError(t, componenttest.CheckConfigStruct(cfg)) } func TestCreateProcessor(t *testing.T) { factory := NewFactory() require.NotNil(t, factory) cfg := factory.CreateDefaultConfig() // Create processor with a valid config. pCfg := cfg.(*Config) pCfg.MemoryLimitMiB = 5722 pCfg.MemorySpikeLimitMiB = 1907 pCfg.CheckInterval = 100 * time.Millisecond set := processortest.NewNopSettings(factory.Type()) var droppedAttrs []string set.Logger = telemetrytest.MockInjectorLogger(set.Logger, &droppedAttrs) tp, err := factory.CreateTraces(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) assert.NotNil(t, tp) // test if we can shutdown a monitoring routine that has not started require.NoError(t, tp.Shutdown(context.Background())) require.NoError(t, tp.Start(context.Background(), componenttest.NewNopHost())) mp, err := factory.CreateMetrics(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) assert.NotNil(t, mp) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) lp, err := factory.CreateLogs(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) assert.NotNil(t, lp) require.NoError(t, lp.Start(context.Background(), componenttest.NewNopHost())) pp, err := factory.CreateProfiles(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) assert.NotNil(t, pp) require.NoError(t, pp.Start(context.Background(), componenttest.NewNopHost())) // Test that we've dropped the relevant injected attributes exactly once assert.ElementsMatch(t, droppedAttrs, []string{ telemetry.SignalKey, telemetry.ComponentIDKey, telemetry.PipelineIDKey, }) assert.NoError(t, lp.Shutdown(context.Background())) assert.NoError(t, tp.Shutdown(context.Background())) assert.NoError(t, mp.Shutdown(context.Background())) assert.NoError(t, pp.Shutdown(context.Background())) // verify that no monitoring routine is running require.NoError(t, tp.Shutdown(context.Background())) // start and shutdown a new monitoring routine assert.NoError(t, lp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, lp.Shutdown(context.Background())) // calling it again should throw no error require.NoError(t, lp.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/generated_component_test.go000066400000000000000000000120561511331344600330250ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package memorylimiterprocessor import ( "context" "testing" "time" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" ) var typ = component.MustNewType("memory_limiter") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "metrics", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "traces", createFn: func(ctx context.Context, set processor.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { c, err := tt.createFn(context.Background(), processortest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() err = c.Start(context.Background(), host) require.NoError(t, err) require.NotPanics(t, func() { switch tt.name { case "logs": e, ok := c.(processor.Logs) require.True(t, ok) logs := generateLifecycleTestLogs() if !e.Capabilities().MutatesData { logs.MarkReadOnly() } err = e.ConsumeLogs(context.Background(), logs) case "metrics": e, ok := c.(processor.Metrics) require.True(t, ok) metrics := generateLifecycleTestMetrics() if !e.Capabilities().MutatesData { metrics.MarkReadOnly() } err = e.ConsumeMetrics(context.Background(), metrics) case "traces": e, ok := c.(processor.Traces) require.True(t, ok) traces := generateLifecycleTestTraces() if !e.Capabilities().MutatesData { traces.MarkReadOnly() } err = e.ConsumeTraces(context.Background(), traces) } }) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) } } func generateLifecycleTestLogs() plog.Logs { logs := plog.NewLogs() rl := logs.ResourceLogs().AppendEmpty() rl.Resource().Attributes().PutStr("resource", "R1") l := rl.ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() l.Body().SetStr("test log message") l.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return logs } func generateLifecycleTestMetrics() pmetric.Metrics { metrics := pmetric.NewMetrics() rm := metrics.ResourceMetrics().AppendEmpty() rm.Resource().Attributes().PutStr("resource", "R1") m := rm.ScopeMetrics().AppendEmpty().Metrics().AppendEmpty() m.SetName("test_metric") dp := m.SetEmptyGauge().DataPoints().AppendEmpty() dp.Attributes().PutStr("test_attr", "value_1") dp.SetIntValue(123) dp.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) return metrics } func generateLifecycleTestTraces() ptrace.Traces { traces := ptrace.NewTraces() rs := traces.ResourceSpans().AppendEmpty() rs.Resource().Attributes().PutStr("resource", "R1") span := rs.ScopeSpans().AppendEmpty().Spans().AppendEmpty() span.Attributes().PutStr("test_attr", "value_1") span.SetName("test_span") span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(-1 * time.Second))) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now())) return traces } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/generated_package_test.go000066400000000000000000000002651511331344600324150ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package memorylimiterprocessor import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/go.mod000066400000000000000000000122371511331344600265260ustar00rootroot00000000000000module go.opentelemetry.io/collector/processor/memorylimiterprocessor go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/internal/memorylimiter v0.141.0 go.opentelemetry.io/collector/internal/telemetry v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/processorhelper v0.141.0 go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper v0.141.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/collector/processor/xprocessor v0.141.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // 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-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/shirou/gopsutil/v4 v4.25.10 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/component/componentstatus v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.141.0 // indirect go.opentelemetry.io/otel/sdk v1.38.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/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/processor => ../ replace go.opentelemetry.io/collector/processor/processortest => ../processortest replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/consumer => ../../consumer retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/processor/xprocessor => ../xprocessor replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/internal/memorylimiter => ../../internal/memorylimiter replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper => ../processorhelper/xprocessorhelper replace go.opentelemetry.io/collector/processor/processorhelper => ../processorhelper replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/go.sum000066400000000000000000000243741511331344600265600ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/000077500000000000000000000000001511331344600272275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/metadata/000077500000000000000000000000001511331344600310075ustar00rootroot00000000000000generated_status.go000066400000000000000000000007251511331344600346240ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("memory_limiter") ScopeName = "go.opentelemetry.io/collector/processor/memorylimiterprocessor" ) const ( ProfilesStability = component.StabilityLevelAlpha TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelBeta LogsStability = component.StabilityLevelBeta ) generated_telemetry.go000066400000000000000000000075551511331344600353230ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/processor/memorylimiterprocessor") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/processor/memorylimiterprocessor") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration ProcessorAcceptedLogRecords metric.Int64Counter ProcessorAcceptedMetricPoints metric.Int64Counter ProcessorAcceptedSpans metric.Int64Counter ProcessorRefusedLogRecords metric.Int64Counter ProcessorRefusedMetricPoints metric.Int64Counter ProcessorRefusedSpans metric.Int64Counter } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.ProcessorAcceptedLogRecords, err = builder.meter.Int64Counter( "otelcol_processor_accepted_log_records", metric.WithDescription("Number of log records successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ProcessorAcceptedMetricPoints, err = builder.meter.Int64Counter( "otelcol_processor_accepted_metric_points", metric.WithDescription("Number of metric points successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ProcessorAcceptedSpans, err = builder.meter.Int64Counter( "otelcol_processor_accepted_spans", metric.WithDescription("Number of spans successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) builder.ProcessorRefusedLogRecords, err = builder.meter.Int64Counter( "otelcol_processor_refused_log_records", metric.WithDescription("Number of log records that were rejected by the next component in the pipeline. [Deprecated since v0.110.0]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ProcessorRefusedMetricPoints, err = builder.meter.Int64Counter( "otelcol_processor_refused_metric_points", metric.WithDescription("Number of metric points that were rejected by the next component in the pipeline. [Deprecated since v0.110.0]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ProcessorRefusedSpans, err = builder.meter.Int64Counter( "otelcol_processor_refused_spans", metric.WithDescription("Number of spans that were rejected by the next component in the pipeline. [Deprecated since v0.110.0]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) return &builder, errs } generated_telemetry_test.go000066400000000000000000000035231511331344600363510ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/processor/memorylimiterprocessor", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/processor/memorylimiterprocessor", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/metadatatest/000077500000000000000000000000001511331344600317075ustar00rootroot00000000000000generated_telemetrytest.go000066400000000000000000000111611511331344600371070ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" ) func NewSettings(tt *componenttest.Telemetry) processor.Settings { set := processortest.NewNopSettings(processortest.NopType) set.ID = component.NewID(component.MustNewType("memory_limiter")) set.TelemetrySettings = tt.NewTelemetrySettings() return set } func AssertEqualProcessorAcceptedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_accepted_log_records", Description: "Number of log records successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_accepted_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorAcceptedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_accepted_metric_points", Description: "Number of metric points successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_accepted_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorAcceptedSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_accepted_spans", Description: "Number of spans successfully pushed into the next component in the pipeline. [Deprecated since v0.110.0]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_accepted_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorRefusedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_refused_log_records", Description: "Number of log records that were rejected by the next component in the pipeline. [Deprecated since v0.110.0]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_refused_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorRefusedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_refused_metric_points", Description: "Number of metric points that were rejected by the next component in the pipeline. [Deprecated since v0.110.0]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_refused_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorRefusedSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_refused_spans", Description: "Number of spans that were rejected by the next component in the pipeline. [Deprecated since v0.110.0]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_refused_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } generated_telemetrytest_test.go000066400000000000000000000034171511331344600401530ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal/metadata" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() tb.ProcessorAcceptedLogRecords.Add(context.Background(), 1) tb.ProcessorAcceptedMetricPoints.Add(context.Background(), 1) tb.ProcessorAcceptedSpans.Add(context.Background(), 1) tb.ProcessorRefusedLogRecords.Add(context.Background(), 1) tb.ProcessorRefusedMetricPoints.Add(context.Background(), 1) tb.ProcessorRefusedSpans.Add(context.Background(), 1) AssertEqualProcessorAcceptedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorAcceptedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorAcceptedSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorRefusedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorRefusedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorRefusedSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/mock_exporter.go000066400000000000000000000035661511331344600324510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal" import ( "context" "sync/atomic" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" ) type MockExporter struct { destAvailable atomic.Bool acceptedLogCount atomic.Int64 deliveredLogCount atomic.Int64 Logs consumertest.LogsSink } var _ consumer.Logs = (*MockExporter)(nil) func (e *MockExporter) Capabilities() consumer.Capabilities { return consumer.Capabilities{} } func (e *MockExporter) ConsumeLogs(ctx context.Context, ld plog.Logs) error { e.acceptedLogCount.Add(int64(ld.LogRecordCount())) if !e.destAvailable.Load() { // Destination is not available. Queue the logs in the exporter. return e.Logs.ConsumeLogs(ctx, ld) } // Destination is available, immediately deliver. e.deliveredLogCount.Add(int64(ld.LogRecordCount())) return nil } func (e *MockExporter) SetDestAvailable(available bool) { if available { // Pretend we delivered all queued accepted logs. e.deliveredLogCount.Add(int64(e.Logs.LogRecordCount())) // Get rid of the delivered logs so that memory can be collected. e.Logs.Reset() // Now mark destination available so that subsequent ConsumeLogs // don't queue the logs anymore. e.destAvailable.Store(true) } else { e.destAvailable.Store(false) } } func (e *MockExporter) AcceptedLogCount() int { return int(e.acceptedLogCount.Load()) } func (e *MockExporter) DeliveredLogCount() int { return int(e.deliveredLogCount.Load()) } func NewMockExporter() *MockExporter { return &MockExporter{ destAvailable: atomic.Bool{}, acceptedLogCount: atomic.Int64{}, deliveredLogCount: atomic.Int64{}, Logs: consumertest.LogsSink{}, } } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/internal/mock_receiver.go000066400000000000000000000027671511331344600324070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal" import ( "context" "strings" "sync" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/pdata/plog" ) type MockReceiver struct { ProduceCount int NextConsumer consumer.Logs lastConsumeResult error mux sync.Mutex } func (m *MockReceiver) Start() { go m.produce() } // This function demonstrates how the receivers should behave when the ConsumeLogs/Traces/Metrics // call returns an error. func (m *MockReceiver) produce() { for i := 0; i < m.ProduceCount; i++ { // Create a large log to consume some memory. ld := plog.NewLogs() lr := ld.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() kiloStr := strings.Repeat("x", 10*1024) lr.SetSeverityText(kiloStr) retry: // Send to the pipeline. err := m.NextConsumer.ConsumeLogs(context.Background(), ld) // Remember the result to be used in the tests. m.mux.Lock() m.lastConsumeResult = err m.mux.Unlock() if err != nil { // Sending to the pipeline failed. if !consumererror.IsPermanent(err) { // Retryable error. Try the same data again. goto retry } // Permanent error. Drop it. } } } func (m *MockReceiver) LastConsumeResult() error { m.mux.Lock() defer m.mux.Unlock() return m.lastConsumeResult } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/memorylimiter.go000066400000000000000000000067721511331344600306540ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterprocessor // import "go.opentelemetry.io/collector/processor/memorylimiterprocessor" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/internal/memorylimiter" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/processor" ) type memoryLimiterProcessor struct { memlimiter *memorylimiter.MemoryLimiter obsrep *obsReport } // newMemoryLimiter returns a new memorylimiter processor. func newMemoryLimiterProcessor(set processor.Settings, cfg *Config) (*memoryLimiterProcessor, error) { ml, err := memorylimiter.NewMemoryLimiter(cfg, set.Logger) if err != nil { return nil, err } obsrep, err := newObsReport(set) if err != nil { return nil, err } p := &memoryLimiterProcessor{ memlimiter: ml, obsrep: obsrep, } return p, nil } func (p *memoryLimiterProcessor) start(ctx context.Context, host component.Host) error { return p.memlimiter.Start(ctx, host) } func (p *memoryLimiterProcessor) shutdown(ctx context.Context) error { return p.memlimiter.Shutdown(ctx) } func (p *memoryLimiterProcessor) processTraces(ctx context.Context, td ptrace.Traces) (ptrace.Traces, error) { numSpans := td.SpanCount() if p.memlimiter.MustRefuse() { // TODO: // https://github.com/open-telemetry/opentelemetry-collector/issues/12463 p.obsrep.refused(ctx, numSpans, pipeline.SignalTraces) return td, memorylimiter.ErrDataRefused } // Even if the next consumer returns error record the data as accepted by // this processor. p.obsrep.accepted(ctx, numSpans, pipeline.SignalTraces) return td, nil } func (p *memoryLimiterProcessor) processMetrics(ctx context.Context, md pmetric.Metrics) (pmetric.Metrics, error) { numDataPoints := md.DataPointCount() if p.memlimiter.MustRefuse() { // TODO: // https://github.com/open-telemetry/opentelemetry-collector/issues/12463 p.obsrep.refused(ctx, numDataPoints, pipeline.SignalMetrics) return md, memorylimiter.ErrDataRefused } // Even if the next consumer returns error record the data as accepted by // this processor. p.obsrep.accepted(ctx, numDataPoints, pipeline.SignalMetrics) return md, nil } func (p *memoryLimiterProcessor) processLogs(ctx context.Context, ld plog.Logs) (plog.Logs, error) { numRecords := ld.LogRecordCount() if p.memlimiter.MustRefuse() { // TODO: // https://github.com/open-telemetry/opentelemetry-collector/issues/12463 p.obsrep.refused(ctx, numRecords, pipeline.SignalLogs) return ld, memorylimiter.ErrDataRefused } // Even if the next consumer returns error record the data as accepted by // this processor. p.obsrep.accepted(ctx, numRecords, pipeline.SignalLogs) return ld, nil } func (p *memoryLimiterProcessor) processProfiles(ctx context.Context, td pprofile.Profiles) (pprofile.Profiles, error) { numProfiles := td.SampleCount() if p.memlimiter.MustRefuse() { // TODO: // https://github.com/open-telemetry/opentelemetry-collector/issues/12463 p.obsrep.refused(ctx, numProfiles, xpipeline.SignalProfiles) return td, memorylimiter.ErrDataRefused } // Even if the next consumer returns error record the data as accepted by // this processor. p.obsrep.accepted(ctx, numProfiles, xpipeline.SignalProfiles) return td, nil } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/memorylimiter_test.go000066400000000000000000000347631511331344600317140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterprocessor import ( "context" "runtime" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/internal/memorylimiter" "go.opentelemetry.io/collector/internal/memorylimiter/iruntime" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal" "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal/metadata" "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal/metadatatest" "go.opentelemetry.io/collector/processor/processorhelper" "go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper" "go.opentelemetry.io/collector/processor/processortest" ) func TestNoDataLoss(t *testing.T) { // Create an exporter. exporter := internal.NewMockExporter() // Mark exporter's destination unavailable. The exporter will accept data and will queue it, // thus increasing the memory usage of the Collector. exporter.SetDestAvailable(false) // Create a memory limiter processor. cfg := createDefaultConfig().(*Config) // Check frequently to make the test quick. cfg.CheckInterval = time.Millisecond * 10 // By how much we expect memory usage to increase because of queuing up of produced data. const expectedMemoryIncreaseMiB = 10 var ms runtime.MemStats runtime.ReadMemStats(&ms) // Set the limit to current usage plus expected increase. This means initially we will not be limited. cfg.MemoryLimitMiB = uint32(ms.Alloc/(1024*1024) + expectedMemoryIncreaseMiB) cfg.MemorySpikeLimitMiB = 1 set := processortest.NewNopSettings(metadata.Type) limiter, err := newMemoryLimiterProcessor(set, cfg) require.NoError(t, err) processor, err := processorhelper.NewLogs(context.Background(), processor.Settings{ ID: component.MustNewID("nop"), TelemetrySettings: componenttest.NewNopTelemetrySettings(), }, cfg, exporter, limiter.processLogs, processorhelper.WithStart(limiter.start), processorhelper.WithShutdown(limiter.shutdown)) require.NoError(t, err) // Create a receiver. receiver := &internal.MockReceiver{ ProduceCount: 1e5, // Must produce enough logs to make sure memory increases by at least expectedMemoryIncreaseMiB NextConsumer: processor, } err = processor.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) // Start producing data. receiver.Start() // The exporter was created such that its destination is not available. // This will result in queuing of produced data inside the exporter and memory usage // will increase. // We must eventually hit the memory limit and the receiver must see an error from memory limiter. require.Eventually(t, func() bool { // Did last ConsumeLogs call return an error? return receiver.LastConsumeResult() != nil }, 5*time.Second, 1*time.Millisecond) // We are now memory limited and receiver can't produce data anymore. // Now make the exporter's destination available. exporter.SetDestAvailable(true) // We should now see that exporter's queue is purged and memory usage goes down. // Eventually we must see that receiver's ConsumeLog call returns success again. require.Eventually(t, func() bool { return receiver.LastConsumeResult() == nil }, 5*time.Second, 1*time.Millisecond) // And eventually the exporter must confirm that it delivered exact number of produced logs. require.Eventually(t, func() bool { d := exporter.DeliveredLogCount() t.Logf("received: %d, expected: %d\n", d, receiver.ProduceCount) return receiver.ProduceCount == d }, 5*time.Second, 100*time.Millisecond) // Double check that the number of logs accepted by exporter matches the number of produced by receiver. assert.Equal(t, receiver.ProduceCount, exporter.AcceptedLogCount()) err = processor.Shutdown(context.Background()) require.NoError(t, err) } // TestMetricsMemoryPressureResponse manipulates results from querying memory and // check expected side effects. func TestMetricsMemoryPressureResponse(t *testing.T) { md := pmetric.NewMetrics() tests := []struct { name string mlCfg *Config memAlloc uint64 expectError bool }{ { name: "Below memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 800, expectError: false, }, { name: "Above memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 1800, expectError: true, }, { name: "Below memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 10, }, memAlloc: 800, expectError: false, }, { name: "Above memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 11, }, memAlloc: 800, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() memorylimiter.GetMemoryFn = totalMemory memorylimiter.ReadMemStatsFn = func(ms *runtime.MemStats) { ms.Alloc = tt.memAlloc } ml, err := newMemoryLimiterProcessor(processortest.NewNopSettings(metadata.Type), tt.mlCfg) require.NoError(t, err) mp, err := processorhelper.NewMetrics( ctx, processortest.NewNopSettings(metadata.Type), tt.mlCfg, consumertest.NewNop(), ml.processMetrics, processorhelper.WithCapabilities(processorCapabilities), processorhelper.WithStart(ml.start), processorhelper.WithShutdown(ml.shutdown)) require.NoError(t, err) assert.NoError(t, mp.Start(ctx, &host{})) ml.memlimiter.CheckMemLimits() err = mp.ConsumeMetrics(ctx, md) if tt.expectError { assert.Equal(t, memorylimiter.ErrDataRefused, err) } else { require.NoError(t, err) } assert.NoError(t, mp.Shutdown(ctx)) }) } t.Cleanup(func() { memorylimiter.GetMemoryFn = iruntime.TotalMemory memorylimiter.ReadMemStatsFn = runtime.ReadMemStats }) } func TestMetricsTelemetry(t *testing.T) { tel := componenttest.NewTelemetry() cfg := &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 10, } metrics, err := NewFactory().CreateMetrics(context.Background(), metadatatest.NewSettings(tel), cfg, consumertest.NewNop()) require.NoError(t, err) require.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) md := pmetric.NewMetrics() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() for range 10 { require.NoError(t, metrics.ConsumeMetrics(context.Background(), md)) } require.NoError(t, metrics.Shutdown(context.Background())) metadatatest.AssertEqualProcessorAcceptedMetricPoints(t, tel, []metricdata.DataPoint[int64]{ { Value: 10, Attributes: attribute.NewSet(attribute.String("processor", "memory_limiter")), }, }, metricdatatest.IgnoreTimestamp()) require.NoError(t, tel.Shutdown(context.Background())) } // TestTraceMemoryPressureResponse manipulates results from querying memory and // check expected side effects. func TestTraceMemoryPressureResponse(t *testing.T) { td := ptrace.NewTraces() tests := []struct { name string mlCfg *Config memAlloc uint64 expectError bool }{ { name: "Below memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 800, expectError: false, }, { name: "Above memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 1800, expectError: true, }, { name: "Below memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 10, }, memAlloc: 800, expectError: false, }, { name: "Above memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 11, }, memAlloc: 800, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() memorylimiter.GetMemoryFn = totalMemory memorylimiter.ReadMemStatsFn = func(ms *runtime.MemStats) { ms.Alloc = tt.memAlloc } ml, err := newMemoryLimiterProcessor(processortest.NewNopSettings(metadata.Type), tt.mlCfg) require.NoError(t, err) tp, err := processorhelper.NewTraces( ctx, processortest.NewNopSettings(metadata.Type), tt.mlCfg, consumertest.NewNop(), ml.processTraces, processorhelper.WithCapabilities(processorCapabilities), processorhelper.WithStart(ml.start), processorhelper.WithShutdown(ml.shutdown)) require.NoError(t, err) assert.NoError(t, tp.Start(ctx, &host{})) ml.memlimiter.CheckMemLimits() err = tp.ConsumeTraces(ctx, td) if tt.expectError { assert.Equal(t, memorylimiter.ErrDataRefused, err) } else { require.NoError(t, err) } assert.NoError(t, tp.Shutdown(ctx)) }) } t.Cleanup(func() { memorylimiter.GetMemoryFn = iruntime.TotalMemory memorylimiter.ReadMemStatsFn = runtime.ReadMemStats }) } // TestLogMemoryPressureResponse manipulates results from querying memory and // check expected side effects. func TestLogMemoryPressureResponse(t *testing.T) { ld := plog.NewLogs() tests := []struct { name string mlCfg *Config memAlloc uint64 expectError bool }{ { name: "Below memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 800, expectError: false, }, { name: "Above memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 1800, expectError: true, }, { name: "Below memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 10, }, memAlloc: 800, expectError: false, }, { name: "Above memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 11, }, memAlloc: 800, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() memorylimiter.GetMemoryFn = totalMemory memorylimiter.ReadMemStatsFn = func(ms *runtime.MemStats) { ms.Alloc = tt.memAlloc } ml, err := newMemoryLimiterProcessor(processortest.NewNopSettings(metadata.Type), tt.mlCfg) require.NoError(t, err) tp, err := processorhelper.NewLogs( ctx, processortest.NewNopSettings(metadata.Type), tt.mlCfg, consumertest.NewNop(), ml.processLogs, processorhelper.WithCapabilities(processorCapabilities), processorhelper.WithStart(ml.start), processorhelper.WithShutdown(ml.shutdown)) require.NoError(t, err) assert.NoError(t, tp.Start(ctx, &host{})) ml.memlimiter.CheckMemLimits() err = tp.ConsumeLogs(ctx, ld) if tt.expectError { assert.Equal(t, memorylimiter.ErrDataRefused, err) } else { require.NoError(t, err) } assert.NoError(t, tp.Shutdown(ctx)) }) } t.Cleanup(func() { memorylimiter.GetMemoryFn = iruntime.TotalMemory memorylimiter.ReadMemStatsFn = runtime.ReadMemStats }) } // TestProfileMemoryPressureResponse manipulates results from querying memory and // check expected side effects. func TestProfileMemoryPressureResponse(t *testing.T) { pd := pprofile.NewProfiles() tests := []struct { name string mlCfg *Config memAlloc uint64 expectError bool }{ { name: "Below memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 800, expectError: false, }, { name: "Above memAllocLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 1, }, memAlloc: 1800, expectError: true, }, { name: "Below memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 10, }, memAlloc: 800, expectError: false, }, { name: "Above memSpikeLimit", mlCfg: &Config{ CheckInterval: time.Second, MemoryLimitPercentage: 50, MemorySpikePercentage: 11, }, memAlloc: 800, expectError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() memorylimiter.GetMemoryFn = totalMemory memorylimiter.ReadMemStatsFn = func(ms *runtime.MemStats) { ms.Alloc = tt.memAlloc } ml, err := newMemoryLimiterProcessor(processortest.NewNopSettings(metadata.Type), tt.mlCfg) require.NoError(t, err) tp, err := xprocessorhelper.NewProfiles( ctx, processortest.NewNopSettings(metadata.Type), tt.mlCfg, consumertest.NewNop(), ml.processProfiles, xprocessorhelper.WithCapabilities(processorCapabilities), xprocessorhelper.WithStart(ml.start), xprocessorhelper.WithShutdown(ml.shutdown)) require.NoError(t, err) assert.NoError(t, tp.Start(ctx, &host{})) ml.memlimiter.CheckMemLimits() err = tp.ConsumeProfiles(ctx, pd) if tt.expectError { assert.Equal(t, memorylimiter.ErrDataRefused, err) } else { require.NoError(t, err) } assert.NoError(t, tp.Shutdown(ctx)) }) } t.Cleanup(func() { memorylimiter.GetMemoryFn = iruntime.TotalMemory memorylimiter.ReadMemStatsFn = runtime.ReadMemStats }) } type host struct { component.Host } func (h *host) GetExtensions() map[component.ID]component.Component { ret := make(map[component.ID]component.Component) return ret } func totalMemory() (uint64, error) { return uint64(2048), nil } opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/metadata.yaml000066400000000000000000000041711511331344600300620ustar00rootroot00000000000000type: memory_limiter github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: processor stability: alpha: [profiles] beta: [traces, metrics, logs] distributions: [core, contrib, k8s] tests: config: check_interval: 5s limit_mib: 400 spike_limit_mib: 50 telemetry: metrics: processor_accepted_log_records: enabled: true description: Number of log records successfully pushed into the next component in the pipeline. stability: level: deprecated from: v0.110.0 unit: "{records}" sum: value_type: int monotonic: true processor_accepted_metric_points: enabled: true description: Number of metric points successfully pushed into the next component in the pipeline. stability: level: deprecated from: v0.110.0 unit: "{datapoints}" sum: value_type: int monotonic: true processor_accepted_spans: enabled: true description: Number of spans successfully pushed into the next component in the pipeline. stability: level: deprecated from: v0.110.0 unit: "{spans}" sum: value_type: int monotonic: true processor_refused_log_records: enabled: true description: Number of log records that were rejected by the next component in the pipeline. stability: level: deprecated from: v0.110.0 unit: "{records}" sum: value_type: int monotonic: true processor_refused_metric_points: enabled: true description: Number of metric points that were rejected by the next component in the pipeline. stability: level: deprecated from: v0.110.0 unit: "{datapoints}" sum: value_type: int monotonic: true processor_refused_spans: enabled: true description: Number of spans that were rejected by the next component in the pipeline. stability: level: deprecated from: v0.110.0 unit: "{spans}" sum: value_type: int monotonic: true opentelemetry-collector-0.141.0/processor/memorylimiterprocessor/obsreport.go000066400000000000000000000036761511331344600277750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package memorylimiterprocessor // import "go.opentelemetry.io/collector/processor/memorylimiterprocessor" import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/internal" "go.opentelemetry.io/collector/processor/memorylimiterprocessor/internal/metadata" ) type obsReport struct { otelAttrs metric.MeasurementOption telemetryBuilder *metadata.TelemetryBuilder } func newObsReport(set processor.Settings) (*obsReport, error) { telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return nil, err } return &obsReport{ otelAttrs: metric.WithAttributeSet(attribute.NewSet(attribute.String(internal.ProcessorKey, set.ID.String()))), telemetryBuilder: telemetryBuilder, }, nil } // accepted reports that the num data was accepted. func (or *obsReport) accepted(ctx context.Context, num int, signal pipeline.Signal) { switch signal { case pipeline.SignalTraces: or.telemetryBuilder.ProcessorAcceptedSpans.Add(ctx, int64(num), or.otelAttrs) case pipeline.SignalMetrics: or.telemetryBuilder.ProcessorAcceptedMetricPoints.Add(ctx, int64(num), or.otelAttrs) case pipeline.SignalLogs: or.telemetryBuilder.ProcessorAcceptedLogRecords.Add(ctx, int64(num), or.otelAttrs) } } // refused reports that the num data was refused. func (or *obsReport) refused(ctx context.Context, num int, signal pipeline.Signal) { switch signal { case pipeline.SignalTraces: or.telemetryBuilder.ProcessorRefusedSpans.Add(ctx, int64(num), or.otelAttrs) case pipeline.SignalMetrics: or.telemetryBuilder.ProcessorRefusedMetricPoints.Add(ctx, int64(num), or.otelAttrs) case pipeline.SignalLogs: or.telemetryBuilder.ProcessorRefusedLogRecords.Add(ctx, int64(num), or.otelAttrs) } } opentelemetry-collector-0.141.0/processor/package_test.go000066400000000000000000000003121511331344600235320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processor import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/processor/processor.go000066400000000000000000000150051511331344600231240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processor // import "go.opentelemetry.io/collector/processor" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor/internal" ) // Traces is a processor that can consume traces. type Traces interface { component.Component consumer.Traces } // Metrics is a processor that can consume metrics. type Metrics interface { component.Component consumer.Metrics } // Logs is a processor that can consume logs. type Logs interface { component.Component consumer.Logs } // Settings is passed to Create* functions in Factory. type Settings struct { // ID returns the ID of the component that will be created. ID component.ID component.TelemetrySettings // BuildInfo can be used by components for informational purposes BuildInfo component.BuildInfo // prevent unkeyed literal initialization _ struct{} } // Factory is Factory interface for processors. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. type Factory interface { component.Factory // CreateTraces creates a Traces processor based on this config. // If the processor type does not support traces, // this function returns the error [pipeline.ErrSignalNotSupported]. // Implementers can assume `next` is never nil. CreateTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Traces, error) // TracesStability gets the stability level of the Traces processor. TracesStability() component.StabilityLevel // CreateMetrics creates a Metrics processor based on this config. // If the processor type does not support metrics, // this function returns the error [pipeline.ErrSignalNotSupported]. // Implementers can assume `next` is never nil. CreateMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Metrics, error) // MetricsStability gets the stability level of the Metrics processor. MetricsStability() component.StabilityLevel // CreateLogs creates a Logs processor based on the config. // If the processor type does not support logs, // this function returns the error [pipeline.ErrSignalNotSupported]. // Implementers can assume `next` is never nil. CreateLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Logs, error) // LogsStability gets the stability level of the Logs processor. LogsStability() component.StabilityLevel unexportedFactoryFunc() } // FactoryOption apply changes to Options. type FactoryOption interface { // applyOption applies the option. applyOption(o *factory) } var _ FactoryOption = (*factoryOptionFunc)(nil) // factoryOptionFunc is a FactoryOption created through a function. type factoryOptionFunc func(*factory) func (f factoryOptionFunc) applyOption(o *factory) { f(o) } type factory struct { cfgType component.Type component.CreateDefaultConfigFunc createTracesFunc CreateTracesFunc tracesStabilityLevel component.StabilityLevel createMetricsFunc CreateMetricsFunc metricsStabilityLevel component.StabilityLevel createLogsFunc CreateLogsFunc logsStabilityLevel component.StabilityLevel } func (f *factory) Type() component.Type { return f.cfgType } func (f *factory) unexportedFactoryFunc() {} func (f *factory) TracesStability() component.StabilityLevel { return f.tracesStabilityLevel } func (f *factory) MetricsStability() component.StabilityLevel { return f.metricsStabilityLevel } func (f *factory) LogsStability() component.StabilityLevel { return f.logsStabilityLevel } func (f *factory) CreateTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Traces, error) { if f.createTracesFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createTracesFunc(ctx, set, cfg, next) } func (f *factory) CreateMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Metrics, error) { if f.createMetricsFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createMetricsFunc(ctx, set, cfg, next) } func (f *factory) CreateLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Logs, error) { if f.createLogsFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createLogsFunc(ctx, set, cfg, next) } // CreateTracesFunc is the equivalent of Factory.CreateTraces(). type CreateTracesFunc func(context.Context, Settings, component.Config, consumer.Traces) (Traces, error) // CreateMetricsFunc is the equivalent of Factory.CreateMetrics(). type CreateMetricsFunc func(context.Context, Settings, component.Config, consumer.Metrics) (Metrics, error) // CreateLogsFunc is the equivalent of Factory.CreateLogs. type CreateLogsFunc func(context.Context, Settings, component.Config, consumer.Logs) (Logs, error) // WithTraces overrides the default "error not supported" implementation for CreateTraces and the default "undefined" stability level. func WithTraces(createTraces CreateTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.tracesStabilityLevel = sl o.createTracesFunc = createTraces }) } // WithMetrics overrides the default "error not supported" implementation for CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.metricsStabilityLevel = sl o.createMetricsFunc = createMetrics }) } // WithLogs overrides the default "error not supported" implementation for CreateLogs and the default "undefined" stability level. func WithLogs(createLogs CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.logsStabilityLevel = sl o.createLogsFunc = createLogs }) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { f := &factory{ cfgType: cfgType, CreateDefaultConfigFunc: createDefaultConfig, } for _, opt := range options { opt.applyOption(f) } return f } opentelemetry-collector-0.141.0/processor/processor_test.go000066400000000000000000000066221511331344600241700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processor import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor/internal" ) var ( testType = component.MustNewType("test") testID = component.NewID(testType) ) func TestNewFactory(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) _, err := f.CreateTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) _, err = f.CreateMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) _, err = f.CreateLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) } func TestNewFactoryWithOptions(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }, WithTraces(createTraces, component.StabilityLevelAlpha), WithMetrics(createMetrics, component.StabilityLevelBeta), WithLogs(createLogs, component.StabilityLevelUnmaintained)) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) wrongID := component.MustNewID("wrong") wrongIDErrStr := internal.ErrIDMismatch(wrongID, testType).Error() assert.Equal(t, component.StabilityLevelAlpha, f.TracesStability()) _, err := f.CreateTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) _, err = f.CreateTraces(context.Background(), Settings{ID: wrongID}, &defaultCfg, consumertest.NewNop()) require.EqualError(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelBeta, f.MetricsStability()) _, err = f.CreateMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) _, err = f.CreateMetrics(context.Background(), Settings{ID: wrongID}, &defaultCfg, consumertest.NewNop()) require.EqualError(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelUnmaintained, f.LogsStability()) _, err = f.CreateLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) _, err = f.CreateLogs(context.Background(), Settings{ID: wrongID}, &defaultCfg, consumertest.NewNop()) require.EqualError(t, err, wrongIDErrStr) } var nopInstance = &nopProcessor{ Consumer: consumertest.NewNop(), } // nopProcessor stores consumed traces and metrics for testing purposes. type nopProcessor struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createTraces(context.Context, Settings, component.Config, consumer.Traces) (Traces, error) { return nopInstance, nil } func createMetrics(context.Context, Settings, component.Config, consumer.Metrics) (Metrics, error) { return nopInstance, nil } func createLogs(context.Context, Settings, component.Config, consumer.Logs) (Logs, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/processor/processorhelper/000077500000000000000000000000001511331344600237745ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processorhelper/Makefile000066400000000000000000000000361511331344600254330ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/processor/processorhelper/documentation.md000066400000000000000000000016261511331344600271740ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # processorhelper ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_processor_incoming_items Number of items passed to the processor. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {items} | Sum | Int | true | Alpha | ### otelcol_processor_internal_duration Duration of time taken to process a batch of telemetry data through the processor. [Alpha] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | s | Histogram | Double | Alpha | ### otelcol_processor_outgoing_items Number of items emitted from the processor. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {items} | Sum | Int | true | Alpha | opentelemetry-collector-0.141.0/processor/processorhelper/example_test.go000066400000000000000000000053711511331344600270230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper_test import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processorhelper" ) // typeStr defines the unique type identifier for the processor. var typeStr = component.MustNewType("example") // exampleConfig holds configuration settings for the processor. type exampleConfig struct{} // exampleProcessor implements the OpenTelemetry processor interface. type exampleProcessor struct { cancel context.CancelFunc config exampleConfig } // Example demonstrates the usage of the processor factory. func Example() { // Instantiate the processor factory and print its type. exampleProcessor := NewFactory() fmt.Println(exampleProcessor.Type()) // Output: // example } // NewFactory creates a new processor factory. func NewFactory() processor.Factory { return processor.NewFactory( typeStr, createDefaultConfig, processor.WithMetrics(createExampleProcessor, component.StabilityLevelAlpha), ) } // createDefaultConfig returns the default configuration for the processor. func createDefaultConfig() component.Config { return &exampleConfig{} } // createExampleProcessor initializes an instance of the example processor. func createExampleProcessor(ctx context.Context, params processor.Settings, baseCfg component.Config, next consumer.Metrics) (processor.Metrics, error) { // Convert baseCfg to the correct type. cfg := baseCfg.(*exampleConfig) // Create a new processor instance. pcsr := newExampleProcessor(ctx, cfg) // Wrap the processor with the helper utilities. return processorhelper.NewMetrics( ctx, params, cfg, next, pcsr.consumeMetrics, processorhelper.WithCapabilities(consumer.Capabilities{MutatesData: true}), processorhelper.WithShutdown(pcsr.shutdown), ) } // newExampleProcessor constructs a new instance of the example processor. func newExampleProcessor(ctx context.Context, cfg *exampleConfig) *exampleProcessor { pcsr := &exampleProcessor{ config: *cfg, } // Create a cancelable context. _, pcsr.cancel = context.WithCancel(ctx) return pcsr } // ConsumeMetrics modify metrics adding one attribute to resource. func (pcsr *exampleProcessor) consumeMetrics(_ context.Context, md pmetric.Metrics) (pmetric.Metrics, error) { rm := md.ResourceMetrics() for i := 0; i < rm.Len(); i++ { rm.At(i).Resource().Attributes().PutStr("processed_by", "exampleProcessor") } return md, nil } // Shutdown properly stops the processor and releases resources. func (pcsr *exampleProcessor) shutdown(_ context.Context) error { pcsr.cancel() return nil } opentelemetry-collector-0.141.0/processor/processorhelper/generated_package_test.go000066400000000000000000000002561511331344600307760ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package processorhelper import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/processor/processorhelper/go.mod000066400000000000000000000060041511331344600251020ustar00rootroot00000000000000module go.opentelemetry.io/collector/processor/processorhelper go 1.24.0 replace go.opentelemetry.io/collector/processor => ../ require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/component/componentstatus v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.141.0 // indirect go.opentelemetry.io/collector/processor/xprocessor v0.141.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/processor/xprocessor => ../xprocessor replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/processor/processortest => ../processortest replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/processor/processorhelper/go.sum000066400000000000000000000140451511331344600251330ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/processorhelper/internal/000077500000000000000000000000001511331344600256105ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processorhelper/internal/metadata/000077500000000000000000000000001511331344600273705ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processorhelper/internal/metadata/generated_telemetry.go000066400000000000000000000051371511331344600337550ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/processor/processorhelper") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/processor/processorhelper") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration ProcessorIncomingItems metric.Int64Counter ProcessorInternalDuration metric.Float64Histogram ProcessorOutgoingItems metric.Int64Counter } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.ProcessorIncomingItems, err = builder.meter.Int64Counter( "otelcol_processor_incoming_items", metric.WithDescription("Number of items passed to the processor. [Alpha]"), metric.WithUnit("{items}"), ) errs = errors.Join(errs, err) builder.ProcessorInternalDuration, err = builder.meter.Float64Histogram( "otelcol_processor_internal_duration", metric.WithDescription("Duration of time taken to process a batch of telemetry data through the processor. [Alpha]"), metric.WithUnit("s"), ) errs = errors.Join(errs, err) builder.ProcessorOutgoingItems, err = builder.meter.Int64Counter( "otelcol_processor_outgoing_items", metric.WithDescription("Number of items emitted from the processor. [Alpha]"), metric.WithUnit("{items}"), ) errs = errors.Join(errs, err) return &builder, errs } generated_telemetry_test.go000066400000000000000000000035051511331344600347320ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processorhelper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/processor/processorhelper", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/processor/processorhelper", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/processor/processorhelper/internal/metadatatest/000077500000000000000000000000001511331344600302705ustar00rootroot00000000000000generated_telemetrytest.go000066400000000000000000000041271511331344600354740ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processorhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" ) func AssertEqualProcessorIncomingItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_incoming_items", Description: "Number of items passed to the processor. [Alpha]", Unit: "{items}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_incoming_items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorInternalDuration(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.HistogramDataPoint[float64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_internal_duration", Description: "Duration of time taken to process a batch of telemetry data through the processor. [Alpha]", Unit: "s", Data: metricdata.Histogram[float64]{ Temporality: metricdata.CumulativeTemporality, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_internal_duration") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorOutgoingItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_processor_outgoing_items", Description: "Number of items emitted from the processor. [Alpha]", Unit: "{items}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_processor_outgoing_items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } generated_telemetrytest_test.go000066400000000000000000000023401511331344600365260ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processorhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/processor/processorhelper/internal/metadata" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() tb.ProcessorIncomingItems.Add(context.Background(), 1) tb.ProcessorInternalDuration.Record(context.Background(), 1) tb.ProcessorOutgoingItems.Add(context.Background(), 1) AssertEqualProcessorIncomingItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorInternalDuration(t, testTel, []metricdata.HistogramDataPoint[float64]{{}}, metricdatatest.IgnoreValue(), metricdatatest.IgnoreTimestamp()) AssertEqualProcessorOutgoingItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/processorhelper/logs.go000066400000000000000000000042221511331344600252670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper // import "go.opentelemetry.io/collector/processor/processorhelper" import ( "context" "errors" "time" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" ) // ProcessLogsFunc is a helper function that processes the incoming data and returns the data to be sent to the next component. // If error is returned then returned data are ignored. It MUST not call the next component. type ProcessLogsFunc func(context.Context, plog.Logs) (plog.Logs, error) type logs struct { component.StartFunc component.ShutdownFunc consumer.Logs } // NewLogs creates a processor.Logs that ensure context propagation and the right tags are set. func NewLogs( _ context.Context, set processor.Settings, _ component.Config, nextConsumer consumer.Logs, logsFunc ProcessLogsFunc, options ...Option, ) (processor.Logs, error) { if logsFunc == nil { return nil, errors.New("nil logsFunc") } obs, err := newObsReport(set, pipeline.SignalLogs) if err != nil { return nil, err } eventOptions := spanAttributes(set.ID) bs := fromOptions(options) logsConsumer, err := consumer.NewLogs(func(ctx context.Context, ld plog.Logs) error { span := trace.SpanFromContext(ctx) span.AddEvent("Start processing.", eventOptions) startTime := time.Now() recordsIn := ld.LogRecordCount() var errFunc error ld, errFunc = logsFunc(ctx, ld) obs.recordInternalDuration(ctx, startTime) span.AddEvent("End processing.", eventOptions) if errFunc != nil { obs.recordInOut(ctx, recordsIn, 0) if errors.Is(errFunc, ErrSkipProcessingData) { return nil } return errFunc } recordsOut := ld.LogRecordCount() obs.recordInOut(ctx, recordsIn, recordsOut) return nextConsumer.ConsumeLogs(ctx, ld) }, bs.consumerOptions...) if err != nil { return nil, err } return &logs{ StartFunc: bs.StartFunc, ShutdownFunc: bs.ShutdownFunc, Logs: logsConsumer, }, nil } opentelemetry-collector-0.141.0/processor/processorhelper/logs_test.go000066400000000000000000000177021511331344600263350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper import ( "context" "errors" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processorhelper/internal/metadatatest" "go.opentelemetry.io/collector/processor/processortest" ) var testLogsCfg = struct{}{} func TestNewLogs(t *testing.T) { lp, err := NewLogs(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), newTestLProcessor(nil)) require.NoError(t, err) assert.True(t, lp.Capabilities().MutatesData) assert.NoError(t, lp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, lp.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, lp.Shutdown(context.Background())) } func TestNewLogs_WithOptions(t *testing.T) { want := errors.New("my_error") lp, err := NewLogs(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), newTestLProcessor(nil), WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want }), WithCapabilities(consumer.Capabilities{MutatesData: false})) require.NoError(t, err) assert.Equal(t, want, lp.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, lp.Shutdown(context.Background())) assert.False(t, lp.Capabilities().MutatesData) } func TestNewLogs_NilRequiredFields(t *testing.T) { _, err := NewLogs(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), nil) assert.Error(t, err) } func TestNewLogs_ProcessLogError(t *testing.T) { want := errors.New("my_error") lp, err := NewLogs(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), newTestLProcessor(want)) require.NoError(t, err) assert.Equal(t, want, lp.ConsumeLogs(context.Background(), plog.NewLogs())) } func TestNewLogs_ProcessLogsErrSkipProcessingData(t *testing.T) { lp, err := NewLogs(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), newTestLProcessor(ErrSkipProcessingData)) require.NoError(t, err) assert.NoError(t, lp.ConsumeLogs(context.Background(), plog.NewLogs())) } func newTestLProcessor(retError error) ProcessLogsFunc { return func(_ context.Context, ld plog.Logs) (plog.Logs, error) { return ld, retError } } func TestLogsConcurrency(t *testing.T) { logsFunc := func(_ context.Context, ld plog.Logs) (plog.Logs, error) { return ld, nil } incomingLogs := plog.NewLogs() incomingLogRecords := incomingLogs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords() // Add 3 records to the incoming incomingLogRecords.AppendEmpty() incomingLogRecords.AppendEmpty() incomingLogRecords.AppendEmpty() lp, err := NewLogs(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), logsFunc) require.NoError(t, err) assert.NoError(t, lp.Start(context.Background(), componenttest.NewNopHost())) var wg sync.WaitGroup for range 10 { wg.Add(1) go func() { defer wg.Done() for range 10000 { assert.NoError(t, lp.ConsumeLogs(context.Background(), incomingLogs)) } }() } wg.Wait() assert.NoError(t, lp.Shutdown(context.Background())) } func TestLogs_RecordInOut(t *testing.T) { // Regardless of how many logs are ingested, emit just one mockAggregate := func(_ context.Context, _ plog.Logs) (plog.Logs, error) { ld := plog.NewLogs() ld.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() return ld, nil } incomingLogs := plog.NewLogs() incomingLogRecords := incomingLogs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords() // Add 3 records to the incoming incomingLogRecords.AppendEmpty() incomingLogRecords.AppendEmpty() incomingLogRecords.AppendEmpty() tel := componenttest.NewTelemetry() lp, err := NewLogs(context.Background(), newSettings(tel), &testLogsCfg, consumertest.NewNop(), mockAggregate) require.NoError(t, err) assert.NoError(t, lp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, lp.ConsumeLogs(context.Background(), incomingLogs)) assert.NoError(t, lp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorIncomingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 3, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "logs")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorOutgoingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 1, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "logs")), }, }, metricdatatest.IgnoreTimestamp()) } func TestLogs_RecordIn_ErrorOut(t *testing.T) { // Regardless of input, return error mockErr := func(_ context.Context, _ plog.Logs) (plog.Logs, error) { return plog.NewLogs(), errors.New("fake") } incomingLogs := plog.NewLogs() incomingLogRecords := incomingLogs.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords() // Add 3 records to the incoming incomingLogRecords.AppendEmpty() incomingLogRecords.AppendEmpty() incomingLogRecords.AppendEmpty() tel := componenttest.NewTelemetry() lp, err := NewLogs(context.Background(), newSettings(tel), &testLogsCfg, consumertest.NewNop(), mockErr) require.NoError(t, err) require.NoError(t, lp.Start(context.Background(), componenttest.NewNopHost())) require.Error(t, lp.ConsumeLogs(context.Background(), incomingLogs)) require.NoError(t, lp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorIncomingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 3, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "logs")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorOutgoingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 0, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "logs")), }, }, metricdatatest.IgnoreTimestamp()) } func TestLogs_ProcessInternalDuration(t *testing.T) { mockAggregate := func(_ context.Context, _ plog.Logs) (plog.Logs, error) { ld := plog.NewLogs() ld.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() return ld, nil } incomingLogs := plog.NewLogs() tel := componenttest.NewTelemetry() lp, err := NewLogs(context.Background(), newSettings(tel), &testLogsCfg, consumertest.NewNop(), mockAggregate) require.NoError(t, err) assert.NoError(t, lp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, lp.ConsumeLogs(context.Background(), incomingLogs)) assert.NoError(t, lp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorInternalDuration(t, tel, []metricdata.HistogramDataPoint[float64]{ { Count: 1, BucketCounts: []uint64{1}, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "logs")), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) } func newSettings(tel *componenttest.Telemetry) processor.Settings { set := processortest.NewNopSettings(component.MustNewType("processorhelper")) set.TelemetrySettings = tel.NewTelemetrySettings() return set } opentelemetry-collector-0.141.0/processor/processorhelper/metadata.yaml000066400000000000000000000016461511331344600264470ustar00rootroot00000000000000type: processorhelper github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg stability: beta: [traces, metrics, logs] telemetry: metrics: processor_incoming_items: enabled: true stability: level: alpha description: Number of items passed to the processor. unit: "{items}" sum: value_type: int monotonic: true processor_internal_duration: enabled: true stability: level: alpha description: Duration of time taken to process a batch of telemetry data through the processor. unit: s histogram: async: false value_type: double processor_outgoing_items: enabled: true stability: level: alpha description: Number of items emitted from the processor. unit: "{items}" sum: value_type: int monotonic: true opentelemetry-collector-0.141.0/processor/processorhelper/metrics.go000066400000000000000000000043361511331344600257770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper // import "go.opentelemetry.io/collector/processor/processorhelper" import ( "context" "errors" "time" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" ) // ProcessMetricsFunc is a helper function that processes the incoming data and returns the data to be sent to the next component. // If error is returned then returned data are ignored. It MUST not call the next component. type ProcessMetricsFunc func(context.Context, pmetric.Metrics) (pmetric.Metrics, error) type metrics struct { component.StartFunc component.ShutdownFunc consumer.Metrics } // NewMetrics creates a processor.Metrics that ensure context propagation and the right tags are set. func NewMetrics( _ context.Context, set processor.Settings, _ component.Config, nextConsumer consumer.Metrics, metricsFunc ProcessMetricsFunc, options ...Option, ) (processor.Metrics, error) { if metricsFunc == nil { return nil, errors.New("nil metricsFunc") } obs, err := newObsReport(set, pipeline.SignalMetrics) if err != nil { return nil, err } eventOptions := spanAttributes(set.ID) bs := fromOptions(options) metricsConsumer, err := consumer.NewMetrics(func(ctx context.Context, md pmetric.Metrics) error { span := trace.SpanFromContext(ctx) span.AddEvent("Start processing.", eventOptions) startTime := time.Now() pointsIn := md.DataPointCount() var errFunc error md, errFunc = metricsFunc(ctx, md) obs.recordInternalDuration(ctx, startTime) span.AddEvent("End processing.", eventOptions) if errFunc != nil { obs.recordInOut(ctx, pointsIn, 0) if errors.Is(errFunc, ErrSkipProcessingData) { return nil } return errFunc } pointsOut := md.DataPointCount() obs.recordInOut(ctx, pointsIn, pointsOut) return nextConsumer.ConsumeMetrics(ctx, md) }, bs.consumerOptions...) if err != nil { return nil, err } return &metrics{ StartFunc: bs.StartFunc, ShutdownFunc: bs.ShutdownFunc, Metrics: metricsConsumer, }, nil } opentelemetry-collector-0.141.0/processor/processorhelper/metrics_test.go000066400000000000000000000207521511331344600270360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper import ( "context" "errors" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/processor/processorhelper/internal/metadatatest" "go.opentelemetry.io/collector/processor/processortest" ) var testMetricsCfg = struct{}{} func TestNewMetrics(t *testing.T) { mp, err := NewMetrics(context.Background(), processortest.NewNopSettings(processortest.NopType), &testMetricsCfg, consumertest.NewNop(), newTestMProcessor(nil)) require.NoError(t, err) assert.True(t, mp.Capabilities().MutatesData) assert.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, mp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, mp.Shutdown(context.Background())) } func TestNewMetrics_WithOptions(t *testing.T) { want := errors.New("my_error") mp, err := NewMetrics(context.Background(), processortest.NewNopSettings(processortest.NopType), &testMetricsCfg, consumertest.NewNop(), newTestMProcessor(nil), WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want }), WithCapabilities(consumer.Capabilities{MutatesData: false})) require.NoError(t, err) assert.Equal(t, want, mp.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, mp.Shutdown(context.Background())) assert.False(t, mp.Capabilities().MutatesData) } func TestNewMetrics_NilRequiredFields(t *testing.T) { _, err := NewMetrics(context.Background(), processortest.NewNopSettings(processortest.NopType), &testMetricsCfg, consumertest.NewNop(), nil) assert.Error(t, err) } func TestNewMetrics_ProcessMetricsError(t *testing.T) { want := errors.New("my_error") mp, err := NewMetrics(context.Background(), processortest.NewNopSettings(processortest.NopType), &testMetricsCfg, consumertest.NewNop(), newTestMProcessor(want)) require.NoError(t, err) assert.Equal(t, want, mp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) } func TestNewMetrics_ProcessMetricsErrSkipProcessingData(t *testing.T) { mp, err := NewMetrics(context.Background(), processortest.NewNopSettings(processortest.NopType), &testMetricsCfg, consumertest.NewNop(), newTestMProcessor(ErrSkipProcessingData)) require.NoError(t, err) assert.NoError(t, mp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) } func newTestMProcessor(retError error) ProcessMetricsFunc { return func(_ context.Context, md pmetric.Metrics) (pmetric.Metrics, error) { return md, retError } } func TestMetricsConcurrency(t *testing.T) { metricsFunc := func(_ context.Context, md pmetric.Metrics) (pmetric.Metrics, error) { return md, nil } incomingMetrics := pmetric.NewMetrics() dps := incomingMetrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints() // Add 2 data points to the incoming dps.AppendEmpty() dps.AppendEmpty() mp, err := NewMetrics(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), metricsFunc) require.NoError(t, err) assert.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) var wg sync.WaitGroup for range 10 { wg.Add(1) go func() { defer wg.Done() for range 10000 { assert.NoError(t, mp.ConsumeMetrics(context.Background(), incomingMetrics)) } }() } wg.Wait() assert.NoError(t, mp.Shutdown(context.Background())) } func TestMetrics_RecordInOut(t *testing.T) { // Regardless of how many data points are ingested, emit 3 mockAggregate := func(_ context.Context, _ pmetric.Metrics) (pmetric.Metrics, error) { md := pmetric.NewMetrics() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() return md, nil } incomingMetrics := pmetric.NewMetrics() dps := incomingMetrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints() // Add 2 data points to the incoming dps.AppendEmpty() dps.AppendEmpty() tel := componenttest.NewTelemetry() mp, err := NewMetrics(context.Background(), newSettings(tel), &testMetricsCfg, consumertest.NewNop(), mockAggregate) require.NoError(t, err) assert.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, mp.ConsumeMetrics(context.Background(), incomingMetrics)) assert.NoError(t, mp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorIncomingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 2, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "metrics")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorOutgoingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 3, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "metrics")), }, }, metricdatatest.IgnoreTimestamp()) } func TestMetrics_RecordIn_ErrorOut(t *testing.T) { /// Regardless of input, return error mockErr := func(_ context.Context, _ pmetric.Metrics) (pmetric.Metrics, error) { return pmetric.NewMetrics(), errors.New("fake") } incomingMetrics := pmetric.NewMetrics() dps := incomingMetrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints() // Add 2 data points to the incoming dps.AppendEmpty() dps.AppendEmpty() tel := componenttest.NewTelemetry() mp, err := NewMetrics(context.Background(), newSettings(tel), &testMetricsCfg, consumertest.NewNop(), mockErr) require.NoError(t, err) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) require.Error(t, mp.ConsumeMetrics(context.Background(), incomingMetrics)) require.NoError(t, mp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorIncomingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 2, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "metrics")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorOutgoingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 0, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "metrics")), }, }, metricdatatest.IgnoreTimestamp()) } func TestMetrics_ProcessInternalDuration(t *testing.T) { mockAggregate := func(_ context.Context, _ pmetric.Metrics) (pmetric.Metrics, error) { md := pmetric.NewMetrics() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() return md, nil } incomingMetrics := pmetric.NewMetrics() tel := componenttest.NewTelemetry() mp, err := NewMetrics(context.Background(), newSettings(tel), &testMetricsCfg, consumertest.NewNop(), mockAggregate) require.NoError(t, err) assert.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, mp.ConsumeMetrics(context.Background(), incomingMetrics)) assert.NoError(t, mp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorInternalDuration(t, tel, []metricdata.HistogramDataPoint[float64]{ { Count: 1, BucketCounts: []uint64{1}, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "metrics")), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) } opentelemetry-collector-0.141.0/processor/processorhelper/obsreport.go000066400000000000000000000030211511331344600263360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper // import "go.opentelemetry.io/collector/processor/processorhelper" import ( "context" "time" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/internal" "go.opentelemetry.io/collector/processor/processorhelper/internal/metadata" ) const signalKey = "otel.signal" type obsReport struct { otelAttrs metric.MeasurementOption telemetryBuilder *metadata.TelemetryBuilder } func newObsReport(set processor.Settings, signal pipeline.Signal) (*obsReport, error) { telemetryBuilder, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return nil, err } return &obsReport{ otelAttrs: metric.WithAttributeSet(attribute.NewSet( attribute.String(internal.ProcessorKey, set.ID.String()), attribute.String(signalKey, signal.String()), )), telemetryBuilder: telemetryBuilder, }, nil } func (or *obsReport) recordInOut(ctx context.Context, incoming, outgoing int) { or.telemetryBuilder.ProcessorIncomingItems.Add(ctx, int64(incoming), or.otelAttrs) or.telemetryBuilder.ProcessorOutgoingItems.Add(ctx, int64(outgoing), or.otelAttrs) } func (or *obsReport) recordInternalDuration(ctx context.Context, startTime time.Time) { duration := time.Since(startTime) or.telemetryBuilder.ProcessorInternalDuration.Record(ctx, duration.Seconds(), or.otelAttrs) } opentelemetry-collector-0.141.0/processor/processorhelper/processor.go000066400000000000000000000050671511331344600263520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package processorhelper // import "go.opentelemetry.io/collector/processor/processorhelper" import ( "errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/processor/internal" ) // ErrSkipProcessingData is a sentinel value to indicate when traces or metrics should intentionally be dropped // from further processing in the pipeline because the data is determined to be irrelevant. A processor can return this error // to stop further processing without propagating an error back up the pipeline to logs. var ErrSkipProcessingData = errors.New("sentinel error to skip processing data from the remainder of the pipeline") // Option apply changes to internalOptions. type Option interface { apply(*baseSettings) } type optionFunc func(*baseSettings) func (of optionFunc) apply(e *baseSettings) { of(e) } // WithStart overrides the default Start function for an processor. // The default shutdown function does nothing and always returns nil. func WithStart(start component.StartFunc) Option { return optionFunc(func(o *baseSettings) { o.StartFunc = start }) } // WithShutdown overrides the default Shutdown function for an processor. // The default shutdown function does nothing and always returns nil. func WithShutdown(shutdown component.ShutdownFunc) Option { return optionFunc(func(o *baseSettings) { o.ShutdownFunc = shutdown }) } // WithCapabilities overrides the default GetCapabilities function for an processor. // The default GetCapabilities function returns mutable capabilities. func WithCapabilities(capabilities consumer.Capabilities) Option { return optionFunc(func(o *baseSettings) { o.consumerOptions = append(o.consumerOptions, consumer.WithCapabilities(capabilities)) }) } type baseSettings struct { component.StartFunc component.ShutdownFunc consumerOptions []consumer.Option } // fromOptions returns the internal settings starting from the default and applying all options. func fromOptions(options []Option) *baseSettings { // Start from the default options: opts := &baseSettings{ consumerOptions: []consumer.Option{consumer.WithCapabilities(consumer.Capabilities{MutatesData: true})}, } for _, op := range options { op.apply(opts) } return opts } func spanAttributes(id component.ID) trace.EventOption { return trace.WithAttributes(attribute.String(internal.ProcessorKey, id.String())) } opentelemetry-collector-0.141.0/processor/processorhelper/traces.go000066400000000000000000000042621511331344600256100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper // import "go.opentelemetry.io/collector/processor/processorhelper" import ( "context" "errors" "time" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" ) // ProcessTracesFunc is a helper function that processes the incoming data and returns the data to be sent to the next component. // If error is returned then returned data are ignored. It MUST not call the next component. type ProcessTracesFunc func(context.Context, ptrace.Traces) (ptrace.Traces, error) type traces struct { component.StartFunc component.ShutdownFunc consumer.Traces } // NewTraces creates a processor.Traces that ensure context propagation and the right tags are set. func NewTraces( _ context.Context, set processor.Settings, _ component.Config, nextConsumer consumer.Traces, tracesFunc ProcessTracesFunc, options ...Option, ) (processor.Traces, error) { if tracesFunc == nil { return nil, errors.New("nil tracesFunc") } obs, err := newObsReport(set, pipeline.SignalTraces) if err != nil { return nil, err } eventOptions := spanAttributes(set.ID) bs := fromOptions(options) traceConsumer, err := consumer.NewTraces(func(ctx context.Context, td ptrace.Traces) error { span := trace.SpanFromContext(ctx) span.AddEvent("Start processing.", eventOptions) startTime := time.Now() spansIn := td.SpanCount() var errFunc error td, errFunc = tracesFunc(ctx, td) obs.recordInternalDuration(ctx, startTime) span.AddEvent("End processing.", eventOptions) if errFunc != nil { obs.recordInOut(ctx, spansIn, 0) if errors.Is(errFunc, ErrSkipProcessingData) { return nil } return errFunc } spansOut := td.SpanCount() obs.recordInOut(ctx, spansIn, spansOut) return nextConsumer.ConsumeTraces(ctx, td) }, bs.consumerOptions...) if err != nil { return nil, err } return &traces{ StartFunc: bs.StartFunc, ShutdownFunc: bs.ShutdownFunc, Traces: traceConsumer, }, nil } opentelemetry-collector-0.141.0/processor/processorhelper/traces_test.go000066400000000000000000000176101511331344600266500ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processorhelper import ( "context" "errors" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor/processorhelper/internal/metadatatest" "go.opentelemetry.io/collector/processor/processortest" ) var testTracesCfg = struct{}{} func TestNewTraces(t *testing.T) { tp, err := NewTraces(context.Background(), processortest.NewNopSettings(processortest.NopType), &testTracesCfg, consumertest.NewNop(), newTestTProcessor(nil)) require.NoError(t, err) assert.True(t, tp.Capabilities().MutatesData) assert.NoError(t, tp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tp.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, tp.Shutdown(context.Background())) } func TestNewTraces_WithOptions(t *testing.T) { want := errors.New("my_error") tp, err := NewTraces(context.Background(), processortest.NewNopSettings(processortest.NopType), &testTracesCfg, consumertest.NewNop(), newTestTProcessor(nil), WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want }), WithCapabilities(consumer.Capabilities{MutatesData: false})) require.NoError(t, err) assert.Equal(t, want, tp.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, tp.Shutdown(context.Background())) assert.False(t, tp.Capabilities().MutatesData) } func TestNewTraces_NilRequiredFields(t *testing.T) { _, err := NewTraces(context.Background(), processortest.NewNopSettings(processortest.NopType), &testTracesCfg, consumertest.NewNop(), nil) assert.Error(t, err) } func TestNewTraces_ProcessTraceError(t *testing.T) { want := errors.New("my_error") tp, err := NewTraces(context.Background(), processortest.NewNopSettings(processortest.NopType), &testTracesCfg, consumertest.NewNop(), newTestTProcessor(want)) require.NoError(t, err) assert.Equal(t, want, tp.ConsumeTraces(context.Background(), ptrace.NewTraces())) } func TestNewTraces_ProcessTracesErrSkipProcessingData(t *testing.T) { tp, err := NewTraces(context.Background(), processortest.NewNopSettings(processortest.NopType), &testTracesCfg, consumertest.NewNop(), newTestTProcessor(ErrSkipProcessingData)) require.NoError(t, err) assert.NoError(t, tp.ConsumeTraces(context.Background(), ptrace.NewTraces())) } func newTestTProcessor(retError error) ProcessTracesFunc { return func(_ context.Context, td ptrace.Traces) (ptrace.Traces, error) { return td, retError } } func TestTracesConcurrency(t *testing.T) { tracesFunc := func(_ context.Context, td ptrace.Traces) (ptrace.Traces, error) { return td, nil } incomingTraces := ptrace.NewTraces() incomingSpans := incomingTraces.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans() // Add 4 records to the incoming incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() mp, err := NewTraces(context.Background(), processortest.NewNopSettings(processortest.NopType), &testLogsCfg, consumertest.NewNop(), tracesFunc) require.NoError(t, err) assert.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) var wg sync.WaitGroup for range 10 { wg.Add(1) go func() { defer wg.Done() for range 10000 { assert.NoError(t, mp.ConsumeTraces(context.Background(), incomingTraces)) } }() } wg.Wait() assert.NoError(t, mp.Shutdown(context.Background())) } func TestTraces_RecordInOut(t *testing.T) { // Regardless of how many spans are ingested, emit just one mockAggregate := func(_ context.Context, _ ptrace.Traces) (ptrace.Traces, error) { td := ptrace.NewTraces() td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() return td, nil } incomingTraces := ptrace.NewTraces() incomingSpans := incomingTraces.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans() // Add 4 records to the incoming incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() tel := componenttest.NewTelemetry() tp, err := NewTraces(context.Background(), newSettings(tel), &testLogsCfg, consumertest.NewNop(), mockAggregate) require.NoError(t, err) assert.NoError(t, tp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tp.ConsumeTraces(context.Background(), incomingTraces)) assert.NoError(t, tp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorIncomingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 4, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "traces")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorOutgoingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 1, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "traces")), }, }, metricdatatest.IgnoreTimestamp()) } func TestTraces_RecordIn_ErrorOut(t *testing.T) { // Regardless of input, return error mockErr := func(_ context.Context, _ ptrace.Traces) (ptrace.Traces, error) { return ptrace.NewTraces(), errors.New("fake") } incomingTraces := ptrace.NewTraces() incomingSpans := incomingTraces.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans() // Add 4 records to the incoming incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() incomingSpans.AppendEmpty() tel := componenttest.NewTelemetry() tp, err := NewTraces(context.Background(), newSettings(tel), &testLogsCfg, consumertest.NewNop(), mockErr) require.NoError(t, err) require.NoError(t, tp.Start(context.Background(), componenttest.NewNopHost())) require.Error(t, tp.ConsumeTraces(context.Background(), incomingTraces)) require.NoError(t, tp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorIncomingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 4, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "traces")), }, }, metricdatatest.IgnoreTimestamp()) metadatatest.AssertEqualProcessorOutgoingItems(t, tel, []metricdata.DataPoint[int64]{ { Value: 0, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "traces")), }, }, metricdatatest.IgnoreTimestamp()) } func TestTraces_ProcessInternalDuration(t *testing.T) { mockAggregate := func(_ context.Context, _ ptrace.Traces) (ptrace.Traces, error) { td := ptrace.NewTraces() td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() return td, nil } incomingTraces := ptrace.NewTraces() tel := componenttest.NewTelemetry() tp, err := NewTraces(context.Background(), newSettings(tel), &testLogsCfg, consumertest.NewNop(), mockAggregate) require.NoError(t, err) assert.NoError(t, tp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, tp.ConsumeTraces(context.Background(), incomingTraces)) assert.NoError(t, tp.Shutdown(context.Background())) metadatatest.AssertEqualProcessorInternalDuration(t, tel, []metricdata.HistogramDataPoint[float64]{ { Count: 1, BucketCounts: []uint64{1}, Attributes: attribute.NewSet(attribute.String("processor", "processorhelper"), attribute.String("otel.signal", "traces")), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) } opentelemetry-collector-0.141.0/processor/processorhelper/xprocessorhelper/000077500000000000000000000000001511331344600274035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processorhelper/xprocessorhelper/Makefile000066400000000000000000000000411511331344600310360ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/processor/processorhelper/xprocessorhelper/go.mod000066400000000000000000000063411511331344600305150ustar00rootroot00000000000000module go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/processorhelper v0.141.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/collector/processor/xprocessor v0.141.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/component/componentstatus v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/testdata v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/consumer/consumertest => ../../../consumer/consumertest replace go.opentelemetry.io/collector/pdata/pprofile => ../../../pdata/pprofile replace go.opentelemetry.io/collector/pdata/testdata => ../../../pdata/testdata replace go.opentelemetry.io/collector/processor => ../../../processor replace go.opentelemetry.io/collector/consumer => ../../../consumer replace go.opentelemetry.io/collector/consumer/xconsumer => ../../../consumer/xconsumer replace go.opentelemetry.io/collector/component => ../../../component replace go.opentelemetry.io/collector/component/componenttest => ../../../component/componenttest replace go.opentelemetry.io/collector/pdata => ../../../pdata replace go.opentelemetry.io/collector/pipeline => ../../../pipeline replace go.opentelemetry.io/collector/component/componentstatus => ../../../component/componentstatus replace go.opentelemetry.io/collector/processor/processortest => ../../processortest replace go.opentelemetry.io/collector/processor/processorhelper => ../ replace go.opentelemetry.io/collector/processor/xprocessor => ../../xprocessor replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/processor/processorhelper/xprocessorhelper/go.sum000066400000000000000000000140451511331344600305420ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/processorhelper/xprocessorhelper/processor.go000066400000000000000000000035201511331344600317510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xprocessorhelper // import "go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper" import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" ) // Option apply changes to internalOptions. type Option interface { apply(*baseSettings) } type optionFunc func(*baseSettings) func (of optionFunc) apply(e *baseSettings) { of(e) } // WithStart overrides the default Start function for an processor. // The default shutdown function does nothing and always returns nil. func WithStart(start component.StartFunc) Option { return optionFunc(func(o *baseSettings) { o.StartFunc = start }) } // WithShutdown overrides the default Shutdown function for an processor. // The default shutdown function does nothing and always returns nil. func WithShutdown(shutdown component.ShutdownFunc) Option { return optionFunc(func(o *baseSettings) { o.ShutdownFunc = shutdown }) } // WithCapabilities overrides the default GetCapabilities function for an processor. // The default GetCapabilities function returns mutable capabilities. func WithCapabilities(capabilities consumer.Capabilities) Option { return optionFunc(func(o *baseSettings) { o.consumerOptions = append(o.consumerOptions, consumer.WithCapabilities(capabilities)) }) } type baseSettings struct { component.StartFunc component.ShutdownFunc consumerOptions []consumer.Option } // fromOptions returns the internal settings starting from the default and applying all options. func fromOptions(options []Option) *baseSettings { // Start from the default options: opts := &baseSettings{ consumerOptions: []consumer.Option{consumer.WithCapabilities(consumer.Capabilities{MutatesData: true})}, } for _, op := range options { op.apply(opts) } return opts } opentelemetry-collector-0.141.0/processor/processorhelper/xprocessorhelper/profiles.go000066400000000000000000000034331511331344600315600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xprocessorhelper // import "go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper" import ( "context" "errors" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processorhelper" "go.opentelemetry.io/collector/processor/xprocessor" ) // ProcessProfilesFunc is a helper function that processes the incoming data and returns the data to be sent to the next component. // If error is returned then returned data are ignored. It MUST not call the next component. type ProcessProfilesFunc func(context.Context, pprofile.Profiles) (pprofile.Profiles, error) type profiles struct { component.StartFunc component.ShutdownFunc xconsumer.Profiles } // NewProfiles creates a xprocessor.Profiles that ensure context propagation. func NewProfiles( _ context.Context, _ processor.Settings, _ component.Config, nextConsumer xconsumer.Profiles, profilesFunc ProcessProfilesFunc, options ...Option, ) (xprocessor.Profiles, error) { if profilesFunc == nil { return nil, errors.New("nil profilesFunc") } bs := fromOptions(options) profilesConsumer, err := xconsumer.NewProfiles(func(ctx context.Context, pd pprofile.Profiles) (err error) { pd, err = profilesFunc(ctx, pd) if err != nil { if errors.Is(err, processorhelper.ErrSkipProcessingData) { return nil } return err } return nextConsumer.ConsumeProfiles(ctx, pd) }, bs.consumerOptions...) if err != nil { return nil, err } return &profiles{ StartFunc: bs.StartFunc, ShutdownFunc: bs.ShutdownFunc, Profiles: profilesConsumer, }, nil } opentelemetry-collector-0.141.0/processor/processorhelper/xprocessorhelper/profiles_test.go000066400000000000000000000074211511331344600326200ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xprocessorhelper import ( "context" "errors" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/processor/processorhelper" "go.opentelemetry.io/collector/processor/processortest" ) var testProfilesCfg = struct{}{} func TestNewProfiles(t *testing.T) { pp, err := NewProfiles(context.Background(), processortest.NewNopSettings(processortest.NopType), &testProfilesCfg, consumertest.NewNop(), newTestPProcessor(nil)) require.NoError(t, err) assert.True(t, pp.Capabilities().MutatesData) assert.NoError(t, pp.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, pp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, pp.Shutdown(context.Background())) } func TestNewProfiles_WithOptions(t *testing.T) { want := errors.New("my_error") pp, err := NewProfiles(context.Background(), processortest.NewNopSettings(processortest.NopType), &testProfilesCfg, consumertest.NewNop(), newTestPProcessor(nil), WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want }), WithCapabilities(consumer.Capabilities{MutatesData: false})) require.NoError(t, err) assert.Equal(t, want, pp.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, pp.Shutdown(context.Background())) assert.False(t, pp.Capabilities().MutatesData) } func TestNewProfiles_NilRequiredFields(t *testing.T) { _, err := NewProfiles(context.Background(), processortest.NewNopSettings(processortest.NopType), &testProfilesCfg, consumertest.NewNop(), nil) assert.Error(t, err) } func TestNewProfiles_ProcessProfileError(t *testing.T) { want := errors.New("my_error") pp, err := NewProfiles(context.Background(), processortest.NewNopSettings(processortest.NopType), &testProfilesCfg, consumertest.NewNop(), newTestPProcessor(want)) require.NoError(t, err) assert.Equal(t, want, pp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) } func TestNewProfiles_ProcessProfilesErrSkipProcessingData(t *testing.T) { pp, err := NewProfiles(context.Background(), processortest.NewNopSettings(processortest.NopType), &testProfilesCfg, consumertest.NewNop(), newTestPProcessor(processorhelper.ErrSkipProcessingData)) require.NoError(t, err) assert.NoError(t, pp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) } func newTestPProcessor(retError error) ProcessProfilesFunc { return func(_ context.Context, pd pprofile.Profiles) (pprofile.Profiles, error) { return pd, retError } } func TestProfilesConcurrency(t *testing.T) { profilesFunc := func(_ context.Context, pd pprofile.Profiles) (pprofile.Profiles, error) { return pd, nil } incomingProfiles := pprofile.NewProfiles() ps := incomingProfiles.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles() // Add 3 profiles to the incoming ps.AppendEmpty() ps.AppendEmpty() ps.AppendEmpty() pp, err := NewProfiles(context.Background(), processortest.NewNopSettings(processortest.NopType), &testProfilesCfg, consumertest.NewNop(), profilesFunc) require.NoError(t, err) assert.NoError(t, pp.Start(context.Background(), componenttest.NewNopHost())) var wg sync.WaitGroup for range 10 { wg.Add(1) go func() { defer wg.Done() for range 10000 { assert.NoError(t, pp.ConsumeProfiles(context.Background(), incomingProfiles)) } }() } wg.Wait() assert.NoError(t, pp.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/processortest/000077500000000000000000000000001511331344600234745ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/processortest/Makefile000066400000000000000000000000361511331344600251330ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/processor/processortest/go.mod000066400000000000000000000055741511331344600246150ustar00rootroot00000000000000module go.opentelemetry.io/collector/processor/processortest go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componentstatus v0.141.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/xprocessor v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/processor => ../../processor replace go.opentelemetry.io/collector/processor/xprocessor => ../../processor/xprocessor replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/processor/processortest/go.sum000066400000000000000000000140451511331344600246330ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/processortest/nop_processor.go000066400000000000000000000043071511331344600267220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processortest // import "go.opentelemetry.io/collector/processor/processortest" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/xprocessor" ) var NopType = component.MustNewType("nop") // NewNopSettings returns a new nop settings for Create* functions with the given type. func NewNopSettings(typ component.Type) processor.Settings { return processor.Settings{ ID: component.NewID(typ), TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } // NewNopFactory returns a component.ProcessorFactory that constructs nop processors. func NewNopFactory() processor.Factory { return xprocessor.NewFactory( NopType, func() component.Config { return &nopConfig{} }, xprocessor.WithTraces(createTraces, component.StabilityLevelStable), xprocessor.WithMetrics(createMetrics, component.StabilityLevelStable), xprocessor.WithLogs(createLogs, component.StabilityLevelStable), xprocessor.WithProfiles(createProfiles, component.StabilityLevelAlpha), ) } func createTraces(context.Context, processor.Settings, component.Config, consumer.Traces) (processor.Traces, error) { return nopInstance, nil } func createMetrics(context.Context, processor.Settings, component.Config, consumer.Metrics) (processor.Metrics, error) { return nopInstance, nil } func createLogs(context.Context, processor.Settings, component.Config, consumer.Logs) (processor.Logs, error) { return nopInstance, nil } func createProfiles(context.Context, processor.Settings, component.Config, xconsumer.Profiles) (xprocessor.Profiles, error) { return nopInstance, nil } type nopConfig struct{} var nopInstance = &nop{ Consumer: consumertest.NewNop(), } // nop acts as a processor for testing purposes. type nop struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } opentelemetry-collector-0.141.0/processor/processortest/nop_processor_test.go000066400000000000000000000052071511331344600277610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processortest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor/xprocessor" ) func TestNewNopFactory(t *testing.T) { factory := NewNopFactory() require.NotNil(t, factory) assert.Equal(t, component.MustNewType("nop"), factory.Type()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &nopConfig{}, cfg) traces, err := factory.CreateTraces(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, traces.Capabilities()) assert.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, traces.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, traces.Shutdown(context.Background())) metrics, err := factory.CreateMetrics(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, metrics.Capabilities()) assert.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metrics.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metrics.Shutdown(context.Background())) logs, err := factory.CreateLogs(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, logs.Capabilities()) assert.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logs.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logs.Shutdown(context.Background())) profiles, err := factory.(xprocessor.Factory).CreateProfiles(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, profiles.Capabilities()) assert.NoError(t, profiles.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, profiles.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.NoError(t, profiles.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/processortest/package_test.go000066400000000000000000000003161511331344600264550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processortest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/processor/processortest/shutdown_verifier.go000066400000000000000000000072241511331344600275760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processortest // import "go.opentelemetry.io/collector/processor/processortest" import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "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/pdata/testdata" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" ) func verifyTracesDoesNotProduceAfterShutdown(t *testing.T, factory processor.Factory, cfg component.Config) { // Create a proc and output its produce to a sink. nextSink := new(consumertest.TracesSink) proc, err := factory.CreateTraces(context.Background(), NewNopSettings(factory.Type()), cfg, nextSink) if errors.Is(err, pipeline.ErrSignalNotSupported) { return } require.NoError(t, err) assert.NoError(t, proc.Start(context.Background(), componenttest.NewNopHost())) // Send some traces to the proc. const generatedCount = 10 for range generatedCount { require.NoError(t, proc.ConsumeTraces(context.Background(), testdata.GenerateTraces(1))) } // Now shutdown the proc. assert.NoError(t, proc.Shutdown(context.Background())) // The Shutdown() is done. It means the proc must have sent everything we // gave it to the next sink. assert.Equal(t, generatedCount, nextSink.SpanCount()) } func verifyLogsDoesNotProduceAfterShutdown(t *testing.T, factory processor.Factory, cfg component.Config) { // Create a proc and output its produce to a sink. nextSink := new(consumertest.LogsSink) proc, err := factory.CreateLogs(context.Background(), NewNopSettings(factory.Type()), cfg, nextSink) if errors.Is(err, pipeline.ErrSignalNotSupported) { return } require.NoError(t, err) assert.NoError(t, proc.Start(context.Background(), componenttest.NewNopHost())) // Send some logs to the proc. const generatedCount = 10 for range generatedCount { require.NoError(t, proc.ConsumeLogs(context.Background(), testdata.GenerateLogs(1))) } // Now shutdown the proc. assert.NoError(t, proc.Shutdown(context.Background())) // The Shutdown() is done. It means the proc must have sent everything we // gave it to the next sink. assert.Equal(t, generatedCount, nextSink.LogRecordCount()) } func verifyMetricsDoesNotProduceAfterShutdown(t *testing.T, factory processor.Factory, cfg component.Config) { // Create a proc and output its produce to a sink. nextSink := new(consumertest.MetricsSink) proc, err := factory.CreateMetrics(context.Background(), NewNopSettings(factory.Type()), cfg, nextSink) if errors.Is(err, pipeline.ErrSignalNotSupported) { return } require.NoError(t, err) assert.NoError(t, proc.Start(context.Background(), componenttest.NewNopHost())) // Send some metrics to the proc. testdata.GenerateMetrics creates metrics with 2 data points each. const generatedCount = 10 for range generatedCount { require.NoError(t, proc.ConsumeMetrics(context.Background(), testdata.GenerateMetrics(1))) } // Now shutdown the proc. assert.NoError(t, proc.Shutdown(context.Background())) // The Shutdown() is done. It means the proc must have sent everything we // gave it to the next sink. assert.Equal(t, generatedCount*2, nextSink.DataPointCount()) } // VerifyShutdown verifies the processor doesn't produce telemetry data after shutdown. func VerifyShutdown(t *testing.T, factory processor.Factory, cfg component.Config) { verifyTracesDoesNotProduceAfterShutdown(t, factory, cfg) verifyLogsDoesNotProduceAfterShutdown(t, factory, cfg) verifyMetricsDoesNotProduceAfterShutdown(t, factory, cfg) } opentelemetry-collector-0.141.0/processor/processortest/shutdown_verifier_test.go000066400000000000000000000057531511331344600306420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processortest import ( "context" "testing" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/processor" ) func TestShutdownVerifier(t *testing.T) { f := processor.NewFactory( component.MustNewType("passthrough"), func() component.Config { return struct{}{} }, processor.WithTraces(createPassthroughTraces, component.StabilityLevelStable), processor.WithMetrics(createPassthroughMetrics, component.StabilityLevelStable), processor.WithLogs(createPassthroughLogs, component.StabilityLevelStable), ) VerifyShutdown(t, f, &struct{}{}) } func TestShutdownVerifierLogsOnly(t *testing.T) { f := processor.NewFactory( component.MustNewType("passthrough"), func() component.Config { return struct{}{} }, processor.WithLogs(createPassthroughLogs, component.StabilityLevelStable), ) VerifyShutdown(t, f, &struct{}{}) } func TestShutdownVerifierMetricsOnly(t *testing.T) { f := processor.NewFactory( component.MustNewType("passthrough"), func() component.Config { return struct{}{} }, processor.WithMetrics(createPassthroughMetrics, component.StabilityLevelStable), ) VerifyShutdown(t, f, &struct{}{}) } func TestShutdownVerifierTracesOnly(t *testing.T) { f := processor.NewFactory( component.MustNewType("passthrough"), func() component.Config { return struct{}{} }, processor.WithTraces(createPassthroughTraces, component.StabilityLevelStable), ) VerifyShutdown(t, f, &struct{}{}) } type passthrough struct { processor.Traces nextLogs consumer.Logs nextMetrics consumer.Metrics nextTraces consumer.Traces } func (passthrough) Start(context.Context, component.Host) error { return nil } func (passthrough) Shutdown(context.Context) error { return nil } func (passthrough) Capabilities() consumer.Capabilities { return consumer.Capabilities{} } func createPassthroughLogs(_ context.Context, _ processor.Settings, _ component.Config, logs consumer.Logs) (processor.Logs, error) { return passthrough{ nextLogs: logs, }, nil } func createPassthroughMetrics(_ context.Context, _ processor.Settings, _ component.Config, metrics consumer.Metrics) (processor.Metrics, error) { return passthrough{ nextMetrics: metrics, }, nil } func createPassthroughTraces(_ context.Context, _ processor.Settings, _ component.Config, traces consumer.Traces) (processor.Traces, error) { return passthrough{ nextTraces: traces, }, nil } func (p passthrough) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { return p.nextTraces.ConsumeTraces(ctx, td) } func (p passthrough) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { return p.nextMetrics.ConsumeMetrics(ctx, md) } func (p passthrough) ConsumeLogs(ctx context.Context, ld plog.Logs) error { return p.nextLogs.ConsumeLogs(ctx, ld) } opentelemetry-collector-0.141.0/processor/processortest/unhealthy_processor.go000066400000000000000000000037251511331344600301320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processortest // import "go.opentelemetry.io/collector/processor/processortest" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/processor" ) // NewUnhealthyProcessorFactory returns a processor.Factory that constructs nop processors. func NewUnhealthyProcessorFactory() processor.Factory { return processor.NewFactory( component.MustNewType("unhealthy"), func() component.Config { return &struct{}{} }, processor.WithTraces(createUnhealthyTraces, component.StabilityLevelStable), processor.WithMetrics(createUnhealthyMetrics, component.StabilityLevelStable), processor.WithLogs(createUnhealthyLogs, component.StabilityLevelStable), ) } func createUnhealthyTraces(_ context.Context, set processor.Settings, _ component.Config, _ consumer.Traces) (processor.Traces, error) { return &unhealthy{ Consumer: consumertest.NewNop(), telemetry: set.TelemetrySettings, }, nil } func createUnhealthyMetrics(_ context.Context, set processor.Settings, _ component.Config, _ consumer.Metrics) (processor.Metrics, error) { return &unhealthy{ Consumer: consumertest.NewNop(), telemetry: set.TelemetrySettings, }, nil } func createUnhealthyLogs(_ context.Context, set processor.Settings, _ component.Config, _ consumer.Logs) (processor.Logs, error) { return &unhealthy{ Consumer: consumertest.NewNop(), telemetry: set.TelemetrySettings, }, nil } type unhealthy struct { component.StartFunc component.ShutdownFunc consumertest.Consumer telemetry component.TelemetrySettings } func (p unhealthy) Start(_ context.Context, host component.Host) error { go func() { componentstatus.ReportStatus(host, componentstatus.NewEvent(componentstatus.StatusRecoverableError)) }() return nil } opentelemetry-collector-0.141.0/processor/processortest/unhealthy_processor_test.go000066400000000000000000000041651511331344600311700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package processortest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestNewUnhealthyProcessorFactory(t *testing.T) { factory := NewUnhealthyProcessorFactory() require.NotNil(t, factory) assert.Equal(t, component.MustNewType("unhealthy"), factory.Type()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &struct{}{}, cfg) traces, err := factory.CreateTraces(context.Background(), NewNopSettings(factory.Type()), cfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, traces.Capabilities()) assert.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, traces.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.NoError(t, traces.Shutdown(context.Background())) metrics, err := factory.CreateMetrics(context.Background(), NewNopSettings(factory.Type()), cfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, metrics.Capabilities()) assert.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metrics.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.NoError(t, metrics.Shutdown(context.Background())) logs, err := factory.CreateLogs(context.Background(), NewNopSettings(factory.Type()), cfg, consumertest.NewNop()) require.NoError(t, err) assert.Equal(t, consumer.Capabilities{MutatesData: false}, logs.Capabilities()) assert.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logs.ConsumeLogs(context.Background(), plog.NewLogs())) assert.NoError(t, logs.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/processor/xprocessor/000077500000000000000000000000001511331344600227645ustar00rootroot00000000000000opentelemetry-collector-0.141.0/processor/xprocessor/Makefile000066400000000000000000000000361511331344600244230ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/processor/xprocessor/go.mod000066400000000000000000000040351511331344600240740ustar00rootroot00000000000000module go.opentelemetry.io/collector/processor/xprocessor go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/processor v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/consumer v1.47.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/processor => ../ replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/processor/xprocessor/go.sum000066400000000000000000000124431511331344600241230ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/processor/xprocessor/metadata.yaml000066400000000000000000000003371511331344600254330ustar00rootroot00000000000000type: xprocessor github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg codeowners: active: - mx-psi - dmathieu stability: development: [profiles] opentelemetry-collector-0.141.0/processor/xprocessor/processor.go000066400000000000000000000102661511331344600253370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xprocessor // import "go.opentelemetry.io/collector/processor/xprocessor" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/internal" ) // Factory is a component.Factory interface for processors. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. type Factory interface { processor.Factory // CreateProfiles creates a Profiles processor based on this config. // If the processor type does not support tracing or if the config is not valid, // an error will be returned instead. CreateProfiles(ctx context.Context, set processor.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) // ProfilesStability gets the stability level of the Profiles processor. ProfilesStability() component.StabilityLevel } // Profiles is a processor that can consume profiles. type Profiles interface { component.Component xconsumer.Profiles } // CreateProfilesFunc is the equivalent of Factory.CreateProfiles(). // CreateProfilesFunc is the equivalent of Factory.CreateProfiles(). type CreateProfilesFunc func(context.Context, processor.Settings, component.Config, xconsumer.Profiles) (Profiles, error) // FactoryOption apply changes to ReceiverOptions. type FactoryOption interface { // applyOption applies the option. applyOption(o *factoryOpts) } // factoryOptionFunc is an ReceiverFactoryOption created through a function. type factoryOptionFunc func(*factoryOpts) func (f factoryOptionFunc) applyOption(o *factoryOpts) { f(o) } type factory struct { processor.Factory createProfilesFunc CreateProfilesFunc profilesStabilityLevel component.StabilityLevel } func (f factory) ProfilesStability() component.StabilityLevel { return f.profilesStabilityLevel } func (f factory) CreateProfiles(ctx context.Context, set processor.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) { if f.createProfilesFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createProfilesFunc(ctx, set, cfg, next) } type factoryOpts struct { opts []processor.FactoryOption *factory } // WithTraces overrides the default "error not supported" implementation for CreateTraces and the default "undefined" stability level. func WithTraces(createTraces processor.CreateTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, processor.WithTraces(createTraces, sl)) }) } // WithMetrics overrides the default "error not supported" implementation for CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics processor.CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, processor.WithMetrics(createMetrics, sl)) }) } // WithLogs overrides the default "error not supported" implementation for CreateLogs and the default "undefined" stability level. func WithLogs(createLogs processor.CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, processor.WithLogs(createLogs, sl)) }) } // WithProfiles overrides the default "error not supported" implementation for CreateProfiles and the default "undefined" stability level. func WithProfiles(createProfiles CreateProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesStabilityLevel = sl o.createProfilesFunc = createProfiles }) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { opts := factoryOpts{factory: &factory{}} for _, opt := range options { opt.applyOption(&opts) } opts.Factory = processor.NewFactory(cfgType, createDefaultConfig, opts.opts...) return opts.factory } opentelemetry-collector-0.141.0/processor/xprocessor/processor_test.go000066400000000000000000000033471511331344600264000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xprocessor import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/internal" ) var testID = component.MustNewID("test") func TestNewFactoryWithProfiles(t *testing.T) { testType := component.MustNewType("test") defaultCfg := struct{}{} factory := NewFactory( testType, func() component.Config { return &defaultCfg }, WithProfiles(createProfiles, component.StabilityLevelAlpha), ) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelAlpha, factory.ProfilesStability()) _, err := factory.CreateProfiles(context.Background(), processor.Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.NoError(t, err) wrongID := component.MustNewID("wrong") wrongIDErrStr := internal.ErrIDMismatch(wrongID, testType).Error() _, err = factory.CreateProfiles(context.Background(), processor.Settings{ID: wrongID}, &defaultCfg, consumertest.NewNop()) assert.EqualError(t, err, wrongIDErrStr) } var nopInstance = &nopProcessor{ Consumer: consumertest.NewNop(), } // nopProcessor stores consumed traces and metrics for testing purposes. type nopProcessor struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createProfiles(context.Context, processor.Settings, component.Config, xconsumer.Profiles) (Profiles, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/receiver/000077500000000000000000000000001511331344600203425ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/Makefile000066400000000000000000000000331511331344600217760ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/receiver/README.md000066400000000000000000000040111511331344600216150ustar00rootroot00000000000000# General Information A receiver is how data gets into the OpenTelemetry Collector. Generally, a receiver accepts data in a specified format, translates it into the internal format and passes it to [processors](../processor/README.md) and [exporters](../exporter/README.md) defined in the applicable pipelines. This repository hosts the following receiver available in traces, metrics and logs pipelines: - [OTLP Receiver](otlpreceiver/README.md) The [contrib repository](https://github.com/open-telemetry/opentelemetry-collector-contrib) has more receivers available in its builds. ## Configuring Receivers Receivers are configured via YAML under the top-level `receivers` tag. There must be at least one enabled receiver for a configuration to be considered valid. The following is a sample configuration for the `examplereceiver`. ```yaml receivers: # Receiver 1. # : examplereceiver: # : endpoint: 1.2.3.4:8080 # ... # Receiver 2. # /: examplereceiver/settings: # : endpoint: 0.0.0.0:9211 ``` A receiver instance is referenced by its full name in other parts of the config, such as in pipelines. A full name consists of the receiver type, '/' and the name appended to the receiver type in the configuration. All receiver full names must be unique. For the example above: - Receiver 1 has full name `examplereceiver`. - Receiver 2 has full name `examplereceiver/settings`. Receivers are enabled upon being added to a pipeline. For example: ```yaml service: pipelines: # Valid pipelines are: traces, metrics or logs # Trace pipeline 1. traces: receivers: [examplereceiver, examplereceiver/settings] processors: [] exporters: [exampleexporter] # Trace pipeline 2. traces/another: receivers: [examplereceiver, examplereceiver/settings] processors: [] exporters: [exampleexporter] ``` > At least one receiver must be enabled per pipeline to be a valid configuration. opentelemetry-collector-0.141.0/receiver/doc.go000066400000000000000000000034061511331344600214410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package receiver defines components that allow the Collector to receive metrics, traces and logs. // // A receiver receives data from a source (either from a remote source via network // or scrapes from a local host) and pushes the data to the pipelines it is attached // to by calling the nextConsumer.Consume*() function. // // # Error Handling // // The nextConsumer.Consume*() function may return an error to indicate that the data was not // accepted. This error should be handled as documented in the consumererror package. // // Depending on the error type, the receiver must indicate to the source from which it received the // data the type of error in a protocol-dependent way, if that is supported by the receiving protocol. // For example, a receiver for the OTLP/HTTP protocol would use the HTTP status codes as defined in // the OTLP specification. // // # Acknowledgment and Checkpointing // // The receivers that receive data via a network protocol that support acknowledgments // MUST follow this order of operations: // - Receive data from some sender (typically from a network). // - Push received data to the pipeline by calling nextConsumer.Consume*() function. // - Acknowledge successful data receipt to the sender if Consume*() succeeded or // return a failure to the sender if Consume*() returned an error. // // This ensures there are strong delivery guarantees once the data is acknowledged // by the Collector. // // Similarly, receivers that use checkpointing to remember the position of last processed // data (e.g. via storage extension) MUST store the checkpoint only AFTER the Consume*() // call returns. package receiver // import "go.opentelemetry.io/collector/receiver" opentelemetry-collector-0.141.0/receiver/example_test.go000066400000000000000000000063521511331344600233710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receiver_test import ( "context" "fmt" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/receiver" ) var typeStr = component.MustNewType("example") type exampleConfig struct { Interval time.Duration } // Reciver must implement the Start() and Shutdown() methods so the receiver type can be compliant // with the receiver.Traces interface. type exampleReceiver struct { host component.Host cancel context.CancelFunc nextConsumer consumer.Traces config exampleConfig } func (rcvr *exampleReceiver) Start(ctx context.Context, host component.Host) error { rcvr.host = host ctx, rcvr.cancel = context.WithCancel(ctx) go func() { ticker := time.NewTicker(rcvr.config.Interval) defer ticker.Stop() for { select { case <-ticker.C: // Your receiver processing code should come here err := rcvr.nextConsumer.ConsumeTraces(ctx, generateTrace()) if err != nil { fmt.Println("Error when consuming trace: %w", err) } case <-ctx.Done(): return } } }() return nil } func (rcvr *exampleReceiver) Shutdown(_ context.Context) error { if rcvr.cancel != nil { rcvr.cancel() } return nil } func generateTrace() ptrace.Traces { traces := ptrace.NewTraces() // In reallity you may need to fetch or receive and transform // some telemetry data. // For this example we will just generate some dummy data resourceSpan := traces.ResourceSpans().AppendEmpty() resource := resourceSpan.Resource() attrs := resource.Attributes() attrs.PutInt("id", 1) scopeSpans := resourceSpan.ScopeSpans().AppendEmpty() scopeSpans.Scope().SetName("example-system") scopeSpans.Scope().SetVersion("v1.0") traceID := pcommon.TraceID([]byte("1")) spanID := pcommon.SpanID([]byte("2")) span := scopeSpans.Spans().AppendEmpty() span.SetTraceID(traceID) span.SetSpanID(spanID) span.SetName("Operation 1") span.SetKind(ptrace.SpanKindClient) span.Status().SetCode(ptrace.StatusCodeOk) span.SetStartTimestamp(pcommon.NewTimestampFromTime(time.Now())) span.SetEndTimestamp(pcommon.NewTimestampFromTime(time.Now().Add(4 * time.Millisecond))) // Other resources and spans could also be added. return traces } func createDefaultConfig() component.Config { return &exampleConfig{ Interval: time.Minute, } } func createExampleReceiver(_ context.Context, _ receiver.Settings, baseCfg component.Config, consumer consumer.Traces, ) (receiver.Traces, error) { exampleCfg := baseCfg.(*exampleConfig) rcvr := &exampleReceiver{ nextConsumer: consumer, config: *exampleCfg, } return rcvr, nil } func NewFactory() receiver.Factory { return receiver.NewFactory( typeStr, createDefaultConfig, receiver.WithTraces(createExampleReceiver, component.StabilityLevelAlpha)) } func Example() { // The NewFactory method can then be used on the Collector's initialization process // on your components.go file. // In this example we will just instantiate and print it's type exampleReceiver := NewFactory() fmt.Println(exampleReceiver.Type()) // Output: // example } opentelemetry-collector-0.141.0/receiver/go.mod000066400000000000000000000037331511331344600214560ustar00rootroot00000000000000module go.opentelemetry.io/collector/receiver go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/consumer => ../consumer replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../consumer/consumertest retract v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module replace go.opentelemetry.io/collector/pipeline => ../pipeline replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/receiver/go.sum000066400000000000000000000124431511331344600215010ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/receiver/internal/000077500000000000000000000000001511331344600221565ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/internal/err.go000066400000000000000000000005741511331344600233030ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/receiver/internal" import ( "fmt" "go.opentelemetry.io/collector/component" ) func ErrIDMismatch(id component.ID, typ component.Type) error { return fmt.Errorf("component type mismatch: component ID %q does not have type %q", id, typ) } opentelemetry-collector-0.141.0/receiver/nopreceiver/000077500000000000000000000000001511331344600226635ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/nopreceiver/Makefile000066400000000000000000000000361511331344600243220ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/receiver/nopreceiver/README.md000066400000000000000000000033021511331344600241400ustar00rootroot00000000000000# No-op Receiver | Status | | | ------------- |-----------| | Stability | [beta]: traces, metrics, logs | | Distributions | [core], [contrib] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fnop%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fnop) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fnop%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fnop) | | [Code Owners](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/CONTRIBUTING.md#becoming-a-code-owner) | [@evan-bradley](https://www.github.com/evan-bradley) | [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 Serves as a placeholder receiver in a pipeline. This can be useful if you want to e.g. start a Collector with only extensions enabled. ## Getting Started All that is required to enable the No-op receiver is to include it in the receiver definitions. It takes no configuration. ```yaml receivers: nop: ``` opentelemetry-collector-0.141.0/receiver/nopreceiver/doc.go000066400000000000000000000004011511331344600237520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package nopreceiver serves as a placeholder receiver. package nopreceiver // import "go.opentelemetry.io/collector/receiver/nopreceiver" opentelemetry-collector-0.141.0/receiver/nopreceiver/generated_component_test.go000066400000000000000000000060011511331344600302660ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package nopreceiver import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" ) var typ = component.MustNewType("nop") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "metrics", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "traces", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/receiver/nopreceiver/generated_package_test.go000066400000000000000000000002521511331344600276610ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package nopreceiver import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/nopreceiver/go.mod000066400000000000000000000072161511331344600237770ustar00rootroot00000000000000module go.opentelemetry.io/collector/receiver/nopreceiver go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/receiver => ../ replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/receiver/xreceiver => ../xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../receivertest replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/receiver/nopreceiver/go.sum000066400000000000000000000205601511331344600240210ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/receiver/nopreceiver/internal/000077500000000000000000000000001511331344600244775ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/nopreceiver/internal/metadata/000077500000000000000000000000001511331344600262575ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/nopreceiver/internal/metadata/generated_logs.go000066400000000000000000000060351511331344600315740ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver" ) // LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations // required to produce log representation defined in metadata and user config. type LogsBuilder struct { logsBuffer plog.Logs logRecordsBuffer plog.LogRecordSlice buildInfo component.BuildInfo // contains version information. } // LogBuilderOption applies changes to default logs builder. type LogBuilderOption interface { apply(*LogsBuilder) } func NewLogsBuilder(settings receiver.Settings) *LogsBuilder { lb := &LogsBuilder{ logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, } return lb } // ResourceLogsOption applies changes to provided resource logs. type ResourceLogsOption interface { apply(plog.ResourceLogs) } type resourceLogsOptionFunc func(plog.ResourceLogs) func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { rlof(rl) } // WithLogsResource sets the provided resource on the emitted ResourceLogs. // It's recommended to use ResourceBuilder to create the resource. func WithLogsResource(res pcommon.Resource) ResourceLogsOption { return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { res.CopyTo(rl.Resource()) }) } // AppendLogRecord adds a log record to the logs builder. func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) } // EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for // recording another set of log records as part of another resource. This function can be helpful when one scraper // needs to emit logs from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceLogsOption arguments. func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { rl := plog.NewResourceLogs() ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) for _, op := range options { op.apply(rl) } if lb.logRecordsBuffer.Len() > 0 { lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) lb.logRecordsBuffer = plog.NewLogRecordSlice() } if ils.LogRecords().Len() > 0 { rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) } } // Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for // recording another set of logs. This function will be responsible for applying all the transformations required to // produce logs representation defined in metadata and user config. func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { lb.EmitForResource(options...) logs := lb.logsBuffer lb.logsBuffer = plog.NewLogs() return logs } opentelemetry-collector-0.141.0/receiver/nopreceiver/internal/metadata/generated_logs_test.go000066400000000000000000000036611511331344600326350ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "time" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver/receivertest" ) func TestLogsBuilderAppendLogRecord(t *testing.T) { observedZapCore, _ := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder(settings) res := pcommon.NewResource() // append the first log record lr := plog.NewLogRecord() lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr.Attributes().PutStr("type", "log") lr.Body().SetStr("the first log record") // append the second log record lr2 := plog.NewLogRecord() lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr2.Attributes().PutStr("type", "event") lr2.Body().SetStr("the second log record") lb.AppendLogRecord(lr) lb.AppendLogRecord(lr2) logs := lb.Emit(WithLogsResource(res)) assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, 1, rl.ScopeLogs().Len()) sl := rl.ScopeLogs().At(0) assert.Equal(t, ScopeName, sl.Scope().Name()) assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) assert.Equal(t, 2, sl.LogRecords().Len()) attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "log", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "event", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) } opentelemetry-collector-0.141.0/receiver/nopreceiver/internal/metadata/generated_status.go000066400000000000000000000006101511331344600321440ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("nop") ScopeName = "go.opentelemetry.io/collector/receiver/nopreceiver" ) const ( TracesStability = component.StabilityLevelBeta MetricsStability = component.StabilityLevelBeta LogsStability = component.StabilityLevelBeta ) opentelemetry-collector-0.141.0/receiver/nopreceiver/metadata.yaml000066400000000000000000000003711511331344600253300ustar00rootroot00000000000000type: nop github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true codeowners: active: - evan-bradley class: receiver stability: beta: [traces, metrics, logs] distributions: [core, contrib] opentelemetry-collector-0.141.0/receiver/nopreceiver/nop_receiver.go000066400000000000000000000024441511331344600256760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package nopreceiver // import "go.opentelemetry.io/collector/receiver/nopreceiver" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/nopreceiver/internal/metadata" ) // NewFactory returns a receiver.Factory that constructs nop receivers. func NewFactory() receiver.Factory { return receiver.NewFactory( metadata.Type, func() component.Config { return &struct{}{} }, receiver.WithTraces(createTraces, metadata.TracesStability), receiver.WithMetrics(createMetrics, metadata.MetricsStability), receiver.WithLogs(createLogs, metadata.LogsStability)) } func createTraces(context.Context, receiver.Settings, component.Config, consumer.Traces) (receiver.Traces, error) { return nopInstance, nil } func createMetrics(context.Context, receiver.Settings, component.Config, consumer.Metrics) (receiver.Metrics, error) { return nopInstance, nil } func createLogs(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { return nopInstance, nil } var nopInstance = &nopReceiver{} type nopReceiver struct { component.StartFunc component.ShutdownFunc } opentelemetry-collector-0.141.0/receiver/nopreceiver/nop_receiver_test.go000066400000000000000000000031331511331344600267310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package nopreceiver // import "go.opentelemetry.io/collector/receiver/nopreceiver" import ( "context" "testing" "github.com/stretchr/testify/assert" "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/receiver/receivertest" ) func TestNewNopFactory(t *testing.T) { factory := NewFactory() require.NotNil(t, factory) assert.Equal(t, component.MustNewType("nop"), factory.Type()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &struct{}{}, cfg) traces, err := factory.CreateTraces(context.Background(), receivertest.NewNopSettings(receivertest.NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, traces.Shutdown(context.Background())) metrics, err := factory.CreateMetrics(context.Background(), receivertest.NewNopSettings(receivertest.NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metrics.Shutdown(context.Background())) logs, err := factory.CreateLogs(context.Background(), receivertest.NewNopSettings(receivertest.NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logs.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/000077500000000000000000000000001511331344600230455ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/Makefile000066400000000000000000000000361511331344600245040ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/receiver/otlpreceiver/README.md000066400000000000000000000127751511331344600243400ustar00rootroot00000000000000# OTLP Receiver | Status | | | ------------- |-----------| | Stability | [development]: profiles | | | [stable]: traces, metrics, logs | | Distributions | [core], [contrib], [k8s], [otlp] | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Areceiver%2Fotlp%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Areceiver%2Fotlp) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Areceiver%2Fotlp%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Areceiver%2Fotlp) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development [stable]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#stable [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 [otlp]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp Receives data via gRPC or HTTP using [OTLP]( https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md) format. ## Getting Started All that is required to enable the OTLP receiver is to include it in the receiver definitions. A protocol can be disabled by simply not specifying it in the list of protocols. ```yaml receivers: otlp: protocols: grpc: http: ``` The following settings are configurable: - `endpoint` (default = localhost:4317 for grpc protocol, localhost:4318 http protocol): host:port to which the receiver is going to receive data. The valid syntax is described at https://github.com/grpc/grpc/blob/master/doc/naming.md. See our [security best practices doc](https://opentelemetry.io/docs/security/config-best-practices/#protect-against-denial-of-service-attacks) to understand how to set the endpoint in different environments. ## Advanced Configuration Several helper files are leveraged to provide additional capabilities automatically: - [gRPC settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configgrpc/README.md) including CORS - [HTTP settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/confighttp/README.md) - [TLS and mTLS settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configtls/README.md) - [Auth settings](https://github.com/open-telemetry/opentelemetry-collector/blob/main/config/configauth/README.md) ## Writing with HTTP/JSON The OTLP receiver can receive trace export calls via HTTP/JSON in addition to gRPC. The HTTP/JSON address is the same as gRPC as the protocol is recognized and processed accordingly. Note the serialization format needs to be [OTLP JSON](https://opentelemetry.io/docs/specs/otlp/#json-protobuf-encoding). The HTTP/JSON configuration also provides `traces_url_path`, `metrics_url_path`, `logs_url_path`, and `profiles_url_path` configurations to allow the URL paths that signal data needs to be sent to be modified per signal type. These default to `/v1/traces`, `/v1/metrics`, `/v1/logs`, and `/v1/profiles` respectively. To write traces with HTTP/JSON, `POST` to `[address]/[traces_url_path]` for traces, to `[address]/[metrics_url_path]` for metrics, to `[address]/[logs_url_path]` for logs, and to `[address]/[profiles_url_path]` for profiles. The default port is `4318`. When using the `otlphttpexporter` peer to communicate with this component, use the `traces_endpoint`, `metrics_endpoint`, `logs_endpoint`, and `profiles_endpoint` settings in the `otlphttpexporter` to set the proper URL to match the address and URL signal path on the `otlpreceiver`. ### CORS (Cross-origin resource sharing) The HTTP/JSON endpoint can also optionally configure [CORS][cors] under `cors:`. Specify what origins (or wildcard patterns) to allow requests from as `allowed_origins`. To allow additional request headers outside of the [default safelist][cors-headers], set `allowed_headers`. Browsers can be instructed to [cache][cors-max-age] responses to preflight requests by setting `max_age`. [cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS [cors-headers]: https://developer.mozilla.org/en-US/docs/Glossary/CORS-safelisted_request_header [cors-max-age]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age ```yaml receivers: otlp: protocols: http: endpoint: "localhost:4318" cors: allowed_origins: - http://test.com # Origins can have wildcards with *, use * by itself to match any origin. - https://*.example.com allowed_headers: - Example-Header max_age: 7200 ``` [contrib]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib [core]: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol opentelemetry-collector-0.141.0/receiver/otlpreceiver/config.go000066400000000000000000000043321511331344600246430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver // import "go.opentelemetry.io/collector/receiver/otlpreceiver" import ( "encoding" "errors" "fmt" "net/url" "path" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configoptional" ) type SanitizedURLPath string var _ encoding.TextUnmarshaler = (*SanitizedURLPath)(nil) func (s *SanitizedURLPath) UnmarshalText(text []byte) error { u, err := url.Parse(string(text)) if err != nil { return fmt.Errorf("invalid HTTP URL path set for signal: %w", err) } if !path.IsAbs(u.Path) { u.Path = "/" + u.Path } *s = SanitizedURLPath(u.Path) return nil } type HTTPConfig struct { ServerConfig confighttp.ServerConfig `mapstructure:",squash"` // The URL path to receive traces on. If omitted "/v1/traces" will be used. TracesURLPath SanitizedURLPath `mapstructure:"traces_url_path,omitempty"` // The URL path to receive metrics on. If omitted "/v1/metrics" will be used. MetricsURLPath SanitizedURLPath `mapstructure:"metrics_url_path,omitempty"` // The URL path to receive logs on. If omitted "/v1/logs" will be used. LogsURLPath SanitizedURLPath `mapstructure:"logs_url_path,omitempty"` // prevent unkeyed literal initialization _ struct{} } // Protocols is the configuration for the supported protocols. type Protocols struct { GRPC configoptional.Optional[configgrpc.ServerConfig] `mapstructure:"grpc"` HTTP configoptional.Optional[HTTPConfig] `mapstructure:"http"` // prevent unkeyed literal initialization _ struct{} } // Config defines configuration for OTLP receiver. type Config struct { // Protocols is the configuration for the supported protocols, currently gRPC and HTTP (Proto and JSON). Protocols `mapstructure:"protocols"` // prevent unkeyed literal initialization _ struct{} } var _ component.Config = (*Config)(nil) // Validate checks the receiver configuration is valid func (cfg *Config) Validate() error { if !cfg.GRPC.HasValue() && !cfg.HTTP.HasValue() { return errors.New("must specify at least one protocol when using the OTLP receiver") } return nil } opentelemetry-collector-0.141.0/receiver/otlpreceiver/config.md000066400000000000000000000431621511331344600246420ustar00rootroot00000000000000# "otlp" Receiver Reference Config defines configuration for OTLP receiver. ### Config | Name | Type | Default | Docs | |-----------|---------------------------------------------------|------------|-------------------------------------------------------------------------------------------------------| | protocols | [otlpreceiver-Protocols](#otlpreceiver-protocols) | | Protocols is the configuration for the supported protocols, currently gRPC and HTTP (Proto and JSON). | ### otlpreceiver-Protocols | Name | Type | Default | Docs | |------|-----------------------------------------------------------------|------------|-----------------------------------------------------------------------------| | grpc | [configgrpc-GRPCServerSettings](#configgrpc-grpcserversettings) | | GRPCServerSettings defines common settings for a gRPC server configuration. | | http | [confighttp-HTTPServerSettings](#confighttp-httpserversettings) | | HTTPServerSettings defines settings for creating an HTTP server. | ### configgrpc-GRPCServerSettings | Name | Type | Default | Docs | |------------------------|-----------------------------------------------------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | endpoint | string | localhost:4317 | Endpoint configures the address for this network connection. For TCP and UDP networks, the address has the form "host:port". The host must be a literal IP address, or a host name that can be resolved to IP addresses. The port must be a literal port number or a service name. If the host is a literal IPv6 address it must be enclosed in square brackets, as in "[2001:db8::1]:80" or "[fe80::1%zone]:80". The zone specifies the scope of the literal IPv6 address as defined in RFC 4007. | | transport | string | tcp | Transport to use. Known protocols are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only), "udp", "udp4" (IPv4-only), "udp6" (IPv6-only), "ip", "ip4" (IPv4-only), "ip6" (IPv6-only), "unix", "unixgram" and "unixpacket". | | tls | [configtls-TLSServerSetting](#configtls-tlsserversetting) | | Configures the protocol to use TLS. The default value is nil, which will cause the protocol to not use TLS. | | max_recv_msg_size_mib | uint64 | | MaxRecvMsgSizeMiB sets the maximum size (in MiB) of messages accepted by the server. | | max_concurrent_streams | uint32 | | MaxConcurrentStreams sets the limit on the number of concurrent streams to each ServerTransport. It has effect only for streaming RPCs. | | read_buffer_size | int | 524288 | ReadBufferSize for gRPC server. See grpc.ReadBufferSize (https://godoc.org/google.golang.org/grpc#ReadBufferSize). | | write_buffer_size | int | | WriteBufferSize for gRPC server. See grpc.WriteBufferSize (https://godoc.org/google.golang.org/grpc#WriteBufferSize). | | keepalive | [configgrpc-KeepaliveServerConfig](#configgrpc-keepaliveserverconfig) | | Keepalive anchor for all the settings related to keepalive. | | auth | [configauth-Authentication](#configauth-authentication) | | Auth for this receiver | ### configtls-TLSServerSetting | Name | Type | Default | Docs | |----------------|--------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ca_file | string | | Path to the CA cert. For a client this verifies the server certificate. For a server this verifies client certificates. If empty uses system root CA. (optional) | | cert_file | string | | Path to the TLS cert to use for TLS required connections. (optional) | | key_file | string | | Path to the TLS key to use for TLS required connections. (optional) | | client_ca_file | string | | Path to the TLS cert to use by the server to verify a client certificate. (optional) This sets the ClientCAs and ClientAuth to RequireAndVerifyClientCert in the TLSConfig. Please refer to https://godoc.org/crypto/tls#Config for more information. (optional) | ### configgrpc-KeepaliveServerConfig | Name | Type | Default | Docs | |--------------------|---------------------------------------------------------------------------------|------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | server_parameters | [configgrpc-KeepaliveServerParameters](#configgrpc-keepaliveserverparameters) | | KeepaliveServerParameters allow configuration of the keepalive.ServerParameters. The same default values as keepalive.ServerParameters are applicable and get applied by the server. See https://godoc.org/google.golang.org/grpc/keepalive#ServerParameters for details. | | enforcement_policy | [configgrpc-KeepaliveEnforcementPolicy](#configgrpc-keepaliveenforcementpolicy) | | KeepaliveEnforcementPolicy allow configuration of the keepalive.EnforcementPolicy. The same default values as keepalive.EnforcementPolicy are applicable and get applied by the server. See https://godoc.org/google.golang.org/grpc/keepalive#EnforcementPolicy for details. | ### configgrpc-KeepaliveServerParameters | Name | Type | Default | Docs | |--------------------------|---------------------------------|------------|------| | max_connection_idle | [time-Duration](#time-duration) | | | | max_connection_age | [time-Duration](#time-duration) | | | | max_connection_age_grace | [time-Duration](#time-duration) | | | | time | [time-Duration](#time-duration) | | | | timeout | [time-Duration](#time-duration) | | | ### configgrpc-KeepaliveEnforcementPolicy | Name | Type | Default | Docs | |-----------------------|---------------------------------|------------|------| | min_time | [time-Duration](#time-duration) | | | | permit_without_stream | bool | | | ### configauth-Authentication | Name | Type | Default | Docs | |---------------|--------|------------|----------------------------------------------------------------------------------------------------------------| | authenticator | string | | AuthenticatorName specifies the name of the extension to use in order to authenticate the incoming data point. | ### confighttp-HTTPServerSettings | Name | Type | Default | Docs | |-----------------------|-----------------------------------------------------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------------| | endpoint | string | localhost:4318 | Endpoint configures the listening address for the server. | | tls | [configtls-TLSServerSetting](#configtls-tlsserversetting) | | TLSSetting struct exposes TLS client configuration. | | cors | [confighttp-CORSConfig](#confighttp-corsconfig) | | CORSConfig configures a receiver for HTTP cross-origin resource sharing (CORS). | | max_request_body_size | int | 20971520 | MaxRequestBodySize configures the maximum allowed body size in bytes for a single request. The default `20971520` means 20MiB | ### confighttp-CORSConfig | Name | Type | Default | Docs | |-----------------|----------|------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | allowed_origins | []string | | AllowedOrigins sets the allowed values of the Origin header for HTTP/JSON requests to an OTLP receiver. An origin may contain a wildcard (`*`) to replace 0 or more characters (e.g., `"https://*.example.com"`, or `"*"` to allow any origin). | | allowed_headers | []string | | AllowedHeaders sets what headers will be allowed in CORS requests. The Accept, Accept-Language, Content-Type, and Content-Language headers are implicitly allowed. If no headers are listed, X-Requested-With will also be accepted by default. Include `"*"` to allow any request header. | | max_age | int | | MaxAge sets the value of the Access-Control-Max-Age response header. Set it to the number of seconds that browsers should cache a CORS preflight response for. | ### configtls-TLSServerSetting | Name | Type | Default | Docs | |----------------|--------|------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ca_file | string | | Path to the CA cert. For a client this verifies the server certificate. For a server this verifies client certificates. If empty uses system root CA. (optional) | | cert_file | string | | Path to the TLS cert to use for TLS required connections. (optional) | | key_file | string | | Path to the TLS key to use for TLS required connections. (optional) | | client_ca_file | string | | Path to the TLS cert to use by the server to verify a client certificate. (optional) This sets the ClientCAs and ClientAuth to RequireAndVerifyClientCert in the TLSConfig. Please refer to https://godoc.org/crypto/tls#Config for more information. (optional) | ### time-Duration An optionally signed sequence of decimal numbers, each with a unit suffix, such as `300ms`, `-1.5h`, or `2h45m`. Valid time units are `ns`, `us`, `ms`, `s`, `m`, `h`. opentelemetry-collector-0.141.0/receiver/otlpreceiver/config_test.go000066400000000000000000000174601511331344600257100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver import ( "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configauth" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" ) func TestUnmarshalDefaultConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "default.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) expectedCfg := factory.CreateDefaultConfig().(*Config) expectedCfg.GRPC.GetOrInsertDefault() expectedCfg.HTTP.GetOrInsertDefault() assert.Equal(t, expectedCfg, cfg) } func TestUnmarshalConfigOnlyGRPC(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "only_grpc.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) defaultOnlyGRPC := factory.CreateDefaultConfig().(*Config) defaultOnlyGRPC.GRPC.GetOrInsertDefault() assert.Equal(t, defaultOnlyGRPC, cfg) } func TestUnmarshalConfigOnlyHTTP(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "only_http.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) defaultOnlyHTTP := factory.CreateDefaultConfig().(*Config) defaultOnlyHTTP.HTTP.GetOrInsertDefault() assert.Equal(t, defaultOnlyHTTP, cfg) } func TestUnmarshalConfigOnlyHTTPNull(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "only_http_null.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) defaultOnlyHTTP := factory.CreateDefaultConfig().(*Config) defaultOnlyHTTP.HTTP.GetOrInsertDefault() assert.Equal(t, defaultOnlyHTTP, cfg) } func TestUnmarshalConfigOnlyHTTPEmptyMap(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "only_http_empty_map.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) defaultOnlyHTTP := factory.CreateDefaultConfig().(*Config) defaultOnlyHTTP.HTTP.GetOrInsertDefault() assert.Equal(t, defaultOnlyHTTP, cfg) } func TestUnmarshalConfig(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) assert.Equal(t, &Config{ Protocols: Protocols{ GRPC: configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:4317", Transport: confignet.TransportTypeTCP, }, TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CertFile: "test.crt", KeyFile: "test.key", }, }), MaxRecvMsgSizeMiB: 32, MaxConcurrentStreams: 16, ReadBufferSize: 1024, WriteBufferSize: 1024, Keepalive: configoptional.Some(configgrpc.KeepaliveServerConfig{ ServerParameters: configoptional.Some(configgrpc.KeepaliveServerParameters{ MaxConnectionIdle: 11 * time.Second, MaxConnectionAge: 12 * time.Second, MaxConnectionAgeGrace: 13 * time.Second, Time: 30 * time.Second, Timeout: 5 * time.Second, }), EnforcementPolicy: configoptional.Some(configgrpc.KeepaliveEnforcementPolicy{ MinTime: 10 * time.Second, PermitWithoutStream: true, }), }), }), HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Auth: configoptional.Some(confighttp.AuthConfig{ Config: configauth.Config{ AuthenticatorID: component.MustNewID("test"), }, }), Endpoint: "localhost:4318", TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CertFile: "test.crt", KeyFile: "test.key", }, }), CORS: configoptional.Some(confighttp.CORSConfig{ AllowedOrigins: []string{"https://*.test.com", "https://test.com"}, MaxAge: 7200, }), KeepAlivesEnabled: true, }, TracesURLPath: "/traces", MetricsURLPath: "/v2/metrics", LogsURLPath: "/log/ingest", }), }, }, cfg) } func TestUnmarshalConfigUnix(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "uds.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) assert.Equal(t, &Config{ Protocols: Protocols{ GRPC: configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "/tmp/grpc_otlp.sock", Transport: confignet.TransportTypeUnix, }, ReadBufferSize: 512 * 1024, Keepalive: configoptional.Some(configgrpc.NewDefaultKeepaliveServerConfig()), }), HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: "/tmp/http_otlp.sock", KeepAlivesEnabled: true, }, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }), }, }, cfg) } // cspell:ignore htttp func TestUnmarshalConfigTypoDefaultProtocol(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "typo_default_proto_config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.ErrorContains(t, cm.Unmarshal(&cfg), "'protocols' has invalid keys: htttp") } func TestUnmarshalConfigInvalidProtocol(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "bad_proto_config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.ErrorContains(t, cm.Unmarshal(&cfg), "'protocols' has invalid keys: thrift") } func TestUnmarshalConfigEmptyProtocols(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "bad_no_proto_config.yaml")) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, cm.Unmarshal(&cfg)) assert.EqualError(t, xconfmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") } func TestUnmarshalConfigInvalidSignalPath(t *testing.T) { tests := []struct { name string testDataFn string }{ { name: "Invalid traces URL path", testDataFn: "invalid_traces_path.yaml", }, { name: "Invalid metrics URL path", testDataFn: "invalid_metrics_path.yaml", }, { name: "Invalid logs URL path", testDataFn: "invalid_logs_path.yaml", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", tt.testDataFn)) require.NoError(t, err) factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.ErrorContains(t, cm.Unmarshal(&cfg), "invalid HTTP URL path set for signal: parse \":invalid\": missing protocol scheme") }) } } func TestUnmarshalConfigEmpty(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.EqualError(t, xconfmap.Validate(cfg), "must specify at least one protocol when using the OTLP receiver") } opentelemetry-collector-0.141.0/receiver/otlpreceiver/doc.go000066400000000000000000000004001511331344600241330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package otlpreceiver receives data in OTLP format. package otlpreceiver // import "go.opentelemetry.io/collector/receiver/otlpreceiver" opentelemetry-collector-0.141.0/receiver/otlpreceiver/encoder.go000066400000000000000000000101231511331344600250100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver // import "go.opentelemetry.io/collector/receiver/otlpreceiver" import ( spb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" ) const ( pbContentType = "application/x-protobuf" jsonContentType = "application/json" ) var ( pbEncoder = &protoEncoder{} jsEncoder = &jsonEncoder{} ) type encoder interface { unmarshalTracesRequest(buf []byte) (ptraceotlp.ExportRequest, error) unmarshalMetricsRequest(buf []byte) (pmetricotlp.ExportRequest, error) unmarshalLogsRequest(buf []byte) (plogotlp.ExportRequest, error) unmarshalProfilesRequest(buf []byte) (pprofileotlp.ExportRequest, error) marshalTracesResponse(ptraceotlp.ExportResponse) ([]byte, error) marshalMetricsResponse(pmetricotlp.ExportResponse) ([]byte, error) marshalLogsResponse(plogotlp.ExportResponse) ([]byte, error) marshalProfilesResponse(pprofileotlp.ExportResponse) ([]byte, error) marshalStatus(rsp *spb.Status) ([]byte, error) contentType() string } type protoEncoder struct{} func (protoEncoder) unmarshalTracesRequest(buf []byte) (ptraceotlp.ExportRequest, error) { req := ptraceotlp.NewExportRequest() err := req.UnmarshalProto(buf) return req, err } func (protoEncoder) unmarshalMetricsRequest(buf []byte) (pmetricotlp.ExportRequest, error) { req := pmetricotlp.NewExportRequest() err := req.UnmarshalProto(buf) return req, err } func (protoEncoder) unmarshalLogsRequest(buf []byte) (plogotlp.ExportRequest, error) { req := plogotlp.NewExportRequest() err := req.UnmarshalProto(buf) return req, err } func (protoEncoder) unmarshalProfilesRequest(buf []byte) (pprofileotlp.ExportRequest, error) { req := pprofileotlp.NewExportRequest() err := req.UnmarshalProto(buf) return req, err } func (protoEncoder) marshalTracesResponse(resp ptraceotlp.ExportResponse) ([]byte, error) { return resp.MarshalProto() } func (protoEncoder) marshalMetricsResponse(resp pmetricotlp.ExportResponse) ([]byte, error) { return resp.MarshalProto() } func (protoEncoder) marshalLogsResponse(resp plogotlp.ExportResponse) ([]byte, error) { return resp.MarshalProto() } func (protoEncoder) marshalProfilesResponse(resp pprofileotlp.ExportResponse) ([]byte, error) { return resp.MarshalProto() } func (protoEncoder) marshalStatus(resp *spb.Status) ([]byte, error) { return proto.Marshal(resp) } func (protoEncoder) contentType() string { return pbContentType } type jsonEncoder struct{} func (jsonEncoder) unmarshalTracesRequest(buf []byte) (ptraceotlp.ExportRequest, error) { req := ptraceotlp.NewExportRequest() err := req.UnmarshalJSON(buf) return req, err } func (jsonEncoder) unmarshalMetricsRequest(buf []byte) (pmetricotlp.ExportRequest, error) { req := pmetricotlp.NewExportRequest() err := req.UnmarshalJSON(buf) return req, err } func (jsonEncoder) unmarshalLogsRequest(buf []byte) (plogotlp.ExportRequest, error) { req := plogotlp.NewExportRequest() err := req.UnmarshalJSON(buf) return req, err } func (jsonEncoder) unmarshalProfilesRequest(buf []byte) (pprofileotlp.ExportRequest, error) { req := pprofileotlp.NewExportRequest() err := req.UnmarshalJSON(buf) return req, err } func (jsonEncoder) marshalTracesResponse(resp ptraceotlp.ExportResponse) ([]byte, error) { return resp.MarshalJSON() } func (jsonEncoder) marshalMetricsResponse(resp pmetricotlp.ExportResponse) ([]byte, error) { return resp.MarshalJSON() } func (jsonEncoder) marshalLogsResponse(resp plogotlp.ExportResponse) ([]byte, error) { return resp.MarshalJSON() } func (jsonEncoder) marshalProfilesResponse(resp pprofileotlp.ExportResponse) ([]byte, error) { return resp.MarshalJSON() } func (jsonEncoder) marshalStatus(resp *spb.Status) ([]byte, error) { return protojson.Marshal(resp) } func (jsonEncoder) contentType() string { return jsonContentType } opentelemetry-collector-0.141.0/receiver/otlpreceiver/factory.go000066400000000000000000000107771511331344600250570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver // import "go.opentelemetry.io/collector/receiver/otlpreceiver" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/sharedcomponent" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metadata" "go.opentelemetry.io/collector/receiver/xreceiver" ) const ( defaultTracesURLPath = "/v1/traces" defaultMetricsURLPath = "/v1/metrics" defaultLogsURLPath = "/v1/logs" defaultProfilesURLPath = "/v1development/profiles" ) // NewFactory creates a new OTLP receiver factory. func NewFactory() receiver.Factory { return xreceiver.NewFactory( metadata.Type, createDefaultConfig, xreceiver.WithTraces(createTraces, metadata.TracesStability), xreceiver.WithMetrics(createMetrics, metadata.MetricsStability), xreceiver.WithLogs(createLog, metadata.LogsStability), xreceiver.WithProfiles(createProfiles, metadata.ProfilesStability), ) } // createDefaultConfig creates the default configuration for receiver. func createDefaultConfig() component.Config { grpcCfg := configgrpc.NewDefaultServerConfig() grpcCfg.NetAddr.Endpoint = "localhost:4317" // We almost write 0 bytes, so no need to tune WriteBufferSize. grpcCfg.ReadBufferSize = 512 * 1024 httpCfg := confighttp.NewDefaultServerConfig() httpCfg.Endpoint = "localhost:4318" // For backward compatibility: httpCfg.TLS = configoptional.None[configtls.ServerConfig]() httpCfg.WriteTimeout = 0 httpCfg.ReadHeaderTimeout = 0 httpCfg.IdleTimeout = 0 return &Config{ Protocols: Protocols{ GRPC: configoptional.Default(grpcCfg), HTTP: configoptional.Default(HTTPConfig{ ServerConfig: httpCfg, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }), }, } } // createTraces creates a trace receiver based on provided config. func createTraces( _ context.Context, set receiver.Settings, cfg component.Config, nextConsumer consumer.Traces, ) (receiver.Traces, error) { oCfg := cfg.(*Config) r, err := receivers.LoadOrStore( oCfg, func() (*otlpReceiver, error) { return newOtlpReceiver(oCfg, &set) }, ) if err != nil { return nil, err } r.Unwrap().registerTraceConsumer(nextConsumer) return r, nil } // createMetrics creates a metrics receiver based on provided config. func createMetrics( _ context.Context, set receiver.Settings, cfg component.Config, consumer consumer.Metrics, ) (receiver.Metrics, error) { oCfg := cfg.(*Config) r, err := receivers.LoadOrStore( oCfg, func() (*otlpReceiver, error) { return newOtlpReceiver(oCfg, &set) }, ) if err != nil { return nil, err } r.Unwrap().registerMetricsConsumer(consumer) return r, nil } // createLog creates a log receiver based on provided config. func createLog( _ context.Context, set receiver.Settings, cfg component.Config, consumer consumer.Logs, ) (receiver.Logs, error) { oCfg := cfg.(*Config) r, err := receivers.LoadOrStore( oCfg, func() (*otlpReceiver, error) { return newOtlpReceiver(oCfg, &set) }, ) if err != nil { return nil, err } r.Unwrap().registerLogsConsumer(consumer) return r, nil } // createProfiles creates a trace receiver based on provided config. func createProfiles( _ context.Context, set receiver.Settings, cfg component.Config, nextConsumer xconsumer.Profiles, ) (xreceiver.Profiles, error) { oCfg := cfg.(*Config) r, err := receivers.LoadOrStore( oCfg, func() (*otlpReceiver, error) { return newOtlpReceiver(oCfg, &set) }, ) if err != nil { return nil, err } r.Unwrap().registerProfilesConsumer(nextConsumer) return r, nil } // This is the map of already created OTLP receivers for particular configurations. // We maintain this map because the receiver.Factory is asked trace and metric receivers separately // when it gets CreateTraces() and CreateMetrics() but they must not // create separate objects, they must use one otlpReceiver object per configuration. // When the receiver is shutdown it should be removed from this map so the same configuration // can be recreated successfully. var receivers = sharedcomponent.NewMap[*Config, *otlpReceiver]() opentelemetry-collector-0.141.0/receiver/otlpreceiver/factory_test.go000066400000000000000000000273141511331344600261110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/internal/telemetry/telemetrytest" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metadata" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/receiver/xreceiver" ) func TestCreateDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() assert.NotNil(t, cfg, "failed to create default config") assert.NoError(t, componenttest.CheckConfigStruct(cfg)) } func TestCreateSameReceiver(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.GRPC.GetOrInsertDefault().NetAddr.Endpoint = testutil.GetAvailableLocalAddress(t) cfg.HTTP.GetOrInsertDefault().ServerConfig.Endpoint = testutil.GetAvailableLocalAddress(t) creationSet := receivertest.NewNopSettings(factory.Type()) var droppedAttrs []string creationSet.Logger = telemetrytest.MockInjectorLogger(creationSet.Logger, &droppedAttrs) tReceiver, err := factory.CreateTraces(context.Background(), creationSet, cfg, consumertest.NewNop()) assert.NotNil(t, tReceiver) require.NoError(t, err) mReceiver, err := factory.CreateMetrics(context.Background(), creationSet, cfg, consumertest.NewNop()) assert.NotNil(t, mReceiver) require.NoError(t, err) lReceiver, err := factory.CreateMetrics(context.Background(), creationSet, cfg, consumertest.NewNop()) assert.NotNil(t, lReceiver) require.NoError(t, err) pReceiver, err := factory.(xreceiver.Factory).CreateProfiles(context.Background(), creationSet, cfg, consumertest.NewNop()) assert.NotNil(t, pReceiver) require.NoError(t, err) assert.Same(t, tReceiver, mReceiver) assert.Same(t, tReceiver, lReceiver) assert.Same(t, tReceiver, pReceiver) // Test that we've dropped the relevant injected attributes exactly once assert.ElementsMatch(t, droppedAttrs, []string{telemetry.SignalKey}) } func TestCreateTraces(t *testing.T) { factory := NewFactory() defaultGRPCSettings := configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), Transport: confignet.TransportTypeTCP, }, }) defaultServerConfig := confighttp.NewDefaultServerConfig() defaultServerConfig.Endpoint = testutil.GetAvailableLocalAddress(t) defaultHTTPSettings := configoptional.Some(HTTPConfig{ ServerConfig: defaultServerConfig, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }) tests := []struct { name string cfg *Config wantStartErr bool wantErr bool sink consumer.Traces }{ { name: "default", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: defaultHTTPSettings, }, }, sink: consumertest.NewNop(), }, { name: "invalid_grpc_port", cfg: &Config{ Protocols: Protocols{ GRPC: configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:112233", Transport: confignet.TransportTypeTCP, }, }), HTTP: defaultHTTPSettings, }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "invalid_http_port", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: "localhost:112233", }, TracesURLPath: defaultTracesURLPath, }), }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "no_http_or_grcp_config", cfg: &Config{ Protocols: Protocols{}, }, sink: consumertest.NewNop(), }, } creationSet := receivertest.NewNopSettings(metadata.Type) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() tr, err := factory.CreateTraces(ctx, creationSet, tt.cfg, tt.sink) if tt.wantErr { assert.Error(t, err) return } require.NoError(t, err) if tt.wantStartErr { assert.Error(t, tr.Start(ctx, componenttest.NewNopHost())) } else { assert.NoError(t, tr.Start(ctx, componenttest.NewNopHost())) assert.NoError(t, tr.Shutdown(ctx)) } }) } } func TestCreateMetric(t *testing.T) { factory := NewFactory() defaultGRPCSettings := configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "127.0.0.1:0", Transport: confignet.TransportTypeTCP, }, }) defaultServerConfig := confighttp.NewDefaultServerConfig() defaultServerConfig.Endpoint = "127.0.0.1:0" defaultHTTPSettings := configoptional.Some(HTTPConfig{ ServerConfig: defaultServerConfig, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }) tests := []struct { name string cfg *Config wantStartErr bool wantErr bool sink consumer.Metrics }{ { name: "default", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: defaultHTTPSettings, }, }, sink: consumertest.NewNop(), }, { name: "invalid_grpc_address", cfg: &Config{ Protocols: Protocols{ GRPC: configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "327.0.0.1:1122", Transport: confignet.TransportTypeTCP, }, }), HTTP: defaultHTTPSettings, }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "invalid_http_address", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: "327.0.0.1:1122", }, MetricsURLPath: defaultMetricsURLPath, }), }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "no_http_or_grcp_config", cfg: &Config{ Protocols: Protocols{}, }, sink: consumertest.NewNop(), }, } creationSet := receivertest.NewNopSettings(metadata.Type) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() mr, err := factory.CreateMetrics(ctx, creationSet, tt.cfg, tt.sink) if tt.wantErr { assert.Error(t, err) return } require.NoError(t, err) if tt.wantStartErr { assert.Error(t, mr.Start(ctx, componenttest.NewNopHost())) } else { require.NoError(t, mr.Start(ctx, componenttest.NewNopHost())) assert.NoError(t, mr.Shutdown(ctx)) } }) } } func TestCreateLogs(t *testing.T) { factory := NewFactory() defaultGRPCSettings := configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), Transport: confignet.TransportTypeTCP, }, }) defaultServerConfig := confighttp.NewDefaultServerConfig() defaultServerConfig.Endpoint = testutil.GetAvailableLocalAddress(t) defaultHTTPSettings := configoptional.Some(HTTPConfig{ ServerConfig: defaultServerConfig, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }) tests := []struct { name string cfg *Config wantStartErr bool wantErr bool sink consumer.Logs }{ { name: "default", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: defaultHTTPSettings, }, }, sink: consumertest.NewNop(), }, { name: "invalid_grpc_address", cfg: &Config{ Protocols: Protocols{ GRPC: configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "327.0.0.1:1122", Transport: confignet.TransportTypeTCP, }, }), HTTP: defaultHTTPSettings, }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "invalid_http_address", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: "327.0.0.1:1122", }, LogsURLPath: defaultLogsURLPath, }), }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "no_http_or_grcp_config", cfg: &Config{ Protocols: Protocols{}, }, sink: consumertest.NewNop(), }, } creationSet := receivertest.NewNopSettings(metadata.Type) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() mr, err := factory.CreateLogs(ctx, creationSet, tt.cfg, tt.sink) if tt.wantErr { assert.Error(t, err) return } require.NoError(t, err) if tt.wantStartErr { assert.Error(t, mr.Start(ctx, componenttest.NewNopHost())) } else { require.NoError(t, mr.Start(ctx, componenttest.NewNopHost())) assert.NoError(t, mr.Shutdown(ctx)) } }) } } func TestCreateProfiles(t *testing.T) { factory := NewFactory() defaultGRPCSettings := configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), Transport: confignet.TransportTypeTCP, }, }) defaultServerConfig := confighttp.NewDefaultServerConfig() defaultServerConfig.Endpoint = testutil.GetAvailableLocalAddress(t) defaultHTTPSettings := configoptional.Some(HTTPConfig{ ServerConfig: defaultServerConfig, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }) tests := []struct { name string cfg *Config wantStartErr bool wantErr bool sink xconsumer.Profiles }{ { name: "default", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: defaultHTTPSettings, }, }, sink: consumertest.NewNop(), }, { name: "invalid_grpc_port", cfg: &Config{ Protocols: Protocols{ GRPC: configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: "localhost:112233", Transport: confignet.TransportTypeTCP, }, }), HTTP: defaultHTTPSettings, }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "invalid_http_port", cfg: &Config{ Protocols: Protocols{ GRPC: defaultGRPCSettings, HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: "localhost:112233", }, }), }, }, wantStartErr: true, sink: consumertest.NewNop(), }, { name: "no_http_or_grcp_config", cfg: &Config{ Protocols: Protocols{}, }, sink: consumertest.NewNop(), }, } creationSet := receivertest.NewNopSettings(metadata.Type) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() tr, err := factory.(xreceiver.Factory).CreateProfiles(ctx, creationSet, tt.cfg, tt.sink) if tt.wantErr { assert.Error(t, err) return } require.NoError(t, err) if tt.wantStartErr { assert.Error(t, tr.Start(ctx, componenttest.NewNopHost())) } else { assert.NoError(t, tr.Start(ctx, componenttest.NewNopHost())) assert.NoError(t, tr.Shutdown(ctx)) } }) } } opentelemetry-collector-0.141.0/receiver/otlpreceiver/fuzz_test.go000066400000000000000000000033011511331344600254260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver import ( "bytes" "net/http" "net/http/httptest" "testing" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/logs" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metrics" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/trace" "go.opentelemetry.io/collector/receiver/receivertest" ) func FuzzReceiverHandlers(f *testing.F) { f.Fuzz(func(_ *testing.T, data []byte, pb bool, handler int) { req, err := http.NewRequest(http.MethodPost, "", bytes.NewReader(data)) if err != nil { return } if pb { req.Header.Add("Content-Type", pbContentType) } else { req.Header.Add("Content-Type", jsonContentType) } set := receivertest.NewNopSettings(receivertest.NopType) set.TelemetrySettings = componenttest.NewNopTelemetrySettings() set.ID = otlpReceiverID cfg := createDefaultConfig().(*Config) r, err := newOtlpReceiver(cfg, &set) if err != nil { panic(err) } r.nextTraces = consumertest.NewNop() r.nextLogs = consumertest.NewNop() r.nextMetrics = consumertest.NewNop() r.nextProfiles = consumertest.NewNop() resp := httptest.NewRecorder() switch handler % 3 { case 0: httpTracesReceiver := trace.New(r.nextTraces, r.obsrepHTTP) handleTraces(resp, req, httpTracesReceiver) case 1: httpMetricsReceiver := metrics.New(r.nextMetrics, r.obsrepHTTP) handleMetrics(resp, req, httpMetricsReceiver) case 2: httpLogsReceiver := logs.New(r.nextLogs, r.obsrepHTTP) handleLogs(resp, req, httpLogsReceiver) } }) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/generated_component_test.go000066400000000000000000000060031511331344600304520ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package otlpreceiver import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" ) var typ = component.MustNewType("otlp") func TestComponentFactoryType(t *testing.T) { require.Equal(t, typ, NewFactory().Type()) } func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct(NewFactory().CreateDefaultConfig())) } func TestComponentLifecycle(t *testing.T) { factory := NewFactory() tests := []struct { createFn func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) name string }{ { name: "logs", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateLogs(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "metrics", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateMetrics(ctx, set, cfg, consumertest.NewNop()) }, }, { name: "traces", createFn: func(ctx context.Context, set receiver.Settings, cfg component.Config) (component.Component, error) { return factory.CreateTraces(ctx, set, cfg, consumertest.NewNop()) }, }, } cm, err := confmaptest.LoadConf("metadata.yaml") require.NoError(t, err) cfg := factory.CreateDefaultConfig() sub, err := cm.Sub("tests::config") require.NoError(t, err) require.NoError(t, sub.Unmarshal(&cfg)) for _, tt := range tests { t.Run(tt.name+"-shutdown", func(t *testing.T) { c, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) err = c.Shutdown(context.Background()) require.NoError(t, err) }) t.Run(tt.name+"-lifecycle", func(t *testing.T) { firstRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) host := newMdatagenNopHost() require.NoError(t, err) require.NoError(t, firstRcvr.Start(context.Background(), host)) require.NoError(t, firstRcvr.Shutdown(context.Background())) secondRcvr, err := tt.createFn(context.Background(), receivertest.NewNopSettings(typ), cfg) require.NoError(t, err) require.NoError(t, secondRcvr.Start(context.Background(), host)) require.NoError(t, secondRcvr.Shutdown(context.Background())) }) } } var _ component.Host = (*mdatagenNopHost)(nil) type mdatagenNopHost struct{} func newMdatagenNopHost() component.Host { return &mdatagenNopHost{} } func (mnh *mdatagenNopHost) GetExtensions() map[component.ID]component.Component { return nil } func (mnh *mdatagenNopHost) GetFactory(_ component.Kind, _ component.Type) component.Factory { return nil } opentelemetry-collector-0.141.0/receiver/otlpreceiver/generated_package_test.go000066400000000000000000000002531511331344600300440ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package otlpreceiver import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/go.mod000066400000000000000000000167501511331344600241640ustar00rootroot00000000000000module go.opentelemetry.io/collector/receiver/otlpreceiver go 1.24.0 require ( github.com/klauspost/compress v1.18.1 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector v0.141.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componentstatus v0.141.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/configauth v1.47.0 go.opentelemetry.io/collector/config/configgrpc v0.141.0 go.opentelemetry.io/collector/config/confighttp v0.141.0 go.opentelemetry.io/collector/config/confignet v1.47.0 go.opentelemetry.io/collector/config/configoptional v1.47.0 go.opentelemetry.io/collector/config/configtls v1.47.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/internal/sharedcomponent v0.141.0 go.opentelemetry.io/collector/internal/telemetry v0.141.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/receiverhelper v0.141.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/zap v1.27.1 google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 google.golang.org/grpc v1.77.0 google.golang.org/protobuf v1.36.10 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/mostynb/go-grpc-compression v1.2.3 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rs/cors v1.11.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configcompression v1.47.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/config/configopaque v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector => ../../ replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/config/configauth => ../../config/configauth replace go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression replace go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp replace go.opentelemetry.io/collector/config/configgrpc => ../../config/configgrpc replace go.opentelemetry.io/collector/config/confignet => ../../config/confignet replace go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/config/configtls => ../../config/configtls replace go.opentelemetry.io/collector/confmap => ../../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap replace go.opentelemetry.io/collector/extension => ../../extension replace go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/receiver => ../ replace go.opentelemetry.io/collector/receiver/receiverhelper => ../receiverhelper replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/client => ../../client replace go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus replace go.opentelemetry.io/collector/receiver/xreceiver => ../xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../receivertest replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/internal/sharedcomponent => ../../internal/sharedcomponent replace go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry retract ( v0.76.0 // Depends on retracted pdata v1.0.0-rc10 module, use v0.76.1 v0.69.0 // Release failed, use v0.69.1 ) replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/receiver/otlpreceiver/go.sum000066400000000000000000000261571511331344600242130ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/mostynb/go-grpc-compression v1.2.3 h1:42/BKWMy0KEJGSdWvzqIyOZ95YcR9mLPqKctH7Uo//I= github.com/mostynb/go-grpc-compression v1.2.3/go.mod h1:AghIxF3P57umzqM9yz795+y1Vjs47Km/Y2FE6ouQ7Lg= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0 h1:YH4g8lQroajqUwWbq/tr2QX1JFmEXaDLgG+ew9bLMWo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.63.0/go.mod h1:fvPi2qXDqFs8M4B4fmJhE92TyQs9Ydjlg3RvfUp+NbQ= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/000077500000000000000000000000001511331344600246615ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/errors/000077500000000000000000000000001511331344600261755ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/errors/errors.go000066400000000000000000000034011511331344600300360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package errors // import "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/errors" import ( "net/http" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/consumer/consumererror" ) func GetStatusFromError(err error) error { s, ok := status.FromError(err) if !ok { // Default to a retryable error // https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#failures code := codes.Unavailable if consumererror.IsPermanent(err) { // If an error is permanent but doesn't have an attached gRPC status, assume it is server-side. code = codes.Internal } s = status.New(code, err.Error()) } return s.Err() } func GetHTTPStatusCodeFromStatus(s *status.Status) int { // See https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#failures // to see if a code is retryable. // See https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#failures-1 // to see a list of retryable http status codes. switch s.Code() { // Retryable case codes.Canceled, codes.DeadlineExceeded, codes.Aborted, codes.OutOfRange, codes.Unavailable, codes.DataLoss: return http.StatusServiceUnavailable // Retryable case codes.ResourceExhausted: return http.StatusTooManyRequests // Not Retryable case codes.InvalidArgument: return http.StatusBadRequest // Not Retryable case codes.Unauthenticated: return http.StatusUnauthorized // Not Retryable case codes.PermissionDenied: return http.StatusForbidden // Not Retryable case codes.Unimplemented: return http.StatusNotFound // Not Retryable default: return http.StatusInternalServerError } } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/errors/errors_test.go000066400000000000000000000044771511331344600311130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package errors // import "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/util" import ( "errors" "net/http" "testing" "github.com/stretchr/testify/assert" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/consumer/consumererror" ) func Test_GetStatusFromError(t *testing.T) { tests := []struct { name string input error expected *status.Status }{ { name: "Status", input: status.Error(codes.Aborted, "test"), expected: status.New(codes.Aborted, "test"), }, { name: "Permanent Error", input: consumererror.NewPermanent(errors.New("test")), expected: status.New(codes.Internal, "Permanent error: test"), }, { name: "Non-Permanent Error", input: errors.New("test"), expected: status.New(codes.Unavailable, "test"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := GetStatusFromError(tt.input) assert.Equal(t, tt.expected.Err(), result) }) } } func Test_GetHTTPStatusCodeFromStatus(t *testing.T) { tests := []struct { name string input *status.Status expected int }{ { name: "Retryable Status", input: status.New(codes.Unavailable, "test"), expected: http.StatusServiceUnavailable, }, { name: "Non-retryable Status", input: status.New(codes.Internal, "test"), expected: http.StatusInternalServerError, }, { name: "Specifically 429", input: status.New(codes.ResourceExhausted, "test"), expected: http.StatusTooManyRequests, }, { name: "Specifically 400", input: status.New(codes.InvalidArgument, "test"), expected: http.StatusBadRequest, }, { name: "Specifically 401", input: status.New(codes.Unauthenticated, "test"), expected: http.StatusUnauthorized, }, { name: "Specifically 403", input: status.New(codes.PermissionDenied, "test"), expected: http.StatusForbidden, }, { name: "Specifically 404", input: status.New(codes.Unimplemented, "test"), expected: http.StatusNotFound, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := GetHTTPStatusCodeFromStatus(tt.input) assert.Equal(t, tt.expected, result) }) } } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/logs/000077500000000000000000000000001511331344600256255ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/logs/otlp.go000066400000000000000000000035771511331344600271460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package logs // import "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/logs" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/errors" "go.opentelemetry.io/collector/receiver/receiverhelper" ) const dataFormatProtobuf = "protobuf" // Receiver is the type used to handle logs from OpenTelemetry exporters. type Receiver struct { plogotlp.UnimplementedGRPCServer nextConsumer consumer.Logs obsreport *receiverhelper.ObsReport } // New creates a new Receiver reference. func New(nextConsumer consumer.Logs, obsreport *receiverhelper.ObsReport) *Receiver { return &Receiver{ nextConsumer: nextConsumer, obsreport: obsreport, } } // Export implements the service Export logs func. func (r *Receiver) Export(ctx context.Context, req plogotlp.ExportRequest) (plogotlp.ExportResponse, error) { ld := req.Logs() numSpans := ld.LogRecordCount() if numSpans == 0 { return plogotlp.NewExportResponse(), nil } ctx = r.obsreport.StartLogsOp(ctx) err := r.nextConsumer.ConsumeLogs(ctx, ld) r.obsreport.EndLogsOp(ctx, dataFormatProtobuf, numSpans, err) // Use appropriate status codes for permanent/non-permanent errors // If we return the error straightaway, then the grpc implementation will set status code to Unknown // Refer: https://github.com/grpc/grpc-go/blob/v1.59.0/server.go#L1345 // So, convert the error to appropriate grpc status and return the error // NonPermanent errors will be converted to codes.Unavailable (equivalent to HTTP 503) // Permanent errors will be converted to codes.InvalidArgument (equivalent to HTTP 400) if err != nil { return plogotlp.NewExportResponse(), errors.GetStatusFromError(err) } return plogotlp.NewExportResponse(), nil } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/logs/otlp_test.go000066400000000000000000000073201511331344600301730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package logs import ( "context" "errors" "net" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metadata" "go.opentelemetry.io/collector/receiver/receiverhelper" "go.opentelemetry.io/collector/receiver/receivertest" ) func TestExport(t *testing.T) { ld := testdata.GenerateLogs(1) req := plogotlp.NewExportRequestFromLogs(ld) logSink := new(consumertest.LogsSink) logClient := makeLogsServiceClient(t, logSink) resp, err := logClient.Export(context.Background(), req) require.NoError(t, err, "Failed to export trace: %v", err) require.NotNil(t, resp, "The response is missing") lds := logSink.AllLogs() require.Len(t, lds, 1) assert.Equal(t, ld, lds[0]) } func TestExport_EmptyRequest(t *testing.T) { logSink := new(consumertest.LogsSink) logClient := makeLogsServiceClient(t, logSink) resp, err := logClient.Export(context.Background(), plogotlp.NewExportRequest()) require.NoError(t, err, "Failed to export trace: %v", err) assert.NotNil(t, resp, "The response is missing") } func TestExport_NonPermanentErrorConsumer(t *testing.T) { ld := testdata.GenerateLogs(1) req := plogotlp.NewExportRequestFromLogs(ld) logClient := makeLogsServiceClient(t, consumertest.NewErr(errors.New("my error"))) resp, err := logClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Unavailable desc = my error") require.ErrorIs(t, err, status.Error(codes.Unavailable, "my error")) assert.Equal(t, plogotlp.ExportResponse{}, resp) } func TestExport_PermanentErrorConsumer(t *testing.T) { ld := testdata.GenerateLogs(1) req := plogotlp.NewExportRequestFromLogs(ld) logClient := makeLogsServiceClient(t, consumertest.NewErr(consumererror.NewPermanent(errors.New("my error")))) resp, err := logClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Internal desc = Permanent error: my error") require.ErrorIs(t, err, status.Error(codes.Internal, "Permanent error: my error")) assert.Equal(t, plogotlp.ExportResponse{}, resp) } func makeLogsServiceClient(t *testing.T, lc consumer.Logs) plogotlp.GRPCClient { addr := otlpReceiverOnGRPCServer(t, lc) cc, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err, "Failed to create the TraceServiceClient: %v", err) t.Cleanup(func() { require.NoError(t, cc.Close()) }) return plogotlp.NewGRPCClient(cc) } func otlpReceiverOnGRPCServer(t *testing.T, lc consumer.Logs) net.Addr { ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) t.Cleanup(func() { require.NoError(t, ln.Close()) }) set := receivertest.NewNopSettings(metadata.Type) set.ID = component.MustNewIDWithName("otlp", "log") obsreport, err := receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ ReceiverID: set.ID, Transport: "grpc", ReceiverCreateSettings: set, }) require.NoError(t, err) r := New(lc, obsreport) // Now run it as a gRPC server srv := grpc.NewServer() plogotlp.RegisterGRPCServer(srv, r) go func() { _ = srv.Serve(ln) }() return ln.Addr() } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/logs/package_test.go000066400000000000000000000003051511331344600306040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package logs import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metadata/000077500000000000000000000000001511331344600264415ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metadata/generated_logs.go000066400000000000000000000060351511331344600317560ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver" ) // LogsBuilder provides an interface for scrapers to report logs while taking care of all the transformations // required to produce log representation defined in metadata and user config. type LogsBuilder struct { logsBuffer plog.Logs logRecordsBuffer plog.LogRecordSlice buildInfo component.BuildInfo // contains version information. } // LogBuilderOption applies changes to default logs builder. type LogBuilderOption interface { apply(*LogsBuilder) } func NewLogsBuilder(settings receiver.Settings) *LogsBuilder { lb := &LogsBuilder{ logsBuffer: plog.NewLogs(), logRecordsBuffer: plog.NewLogRecordSlice(), buildInfo: settings.BuildInfo, } return lb } // ResourceLogsOption applies changes to provided resource logs. type ResourceLogsOption interface { apply(plog.ResourceLogs) } type resourceLogsOptionFunc func(plog.ResourceLogs) func (rlof resourceLogsOptionFunc) apply(rl plog.ResourceLogs) { rlof(rl) } // WithLogsResource sets the provided resource on the emitted ResourceLogs. // It's recommended to use ResourceBuilder to create the resource. func WithLogsResource(res pcommon.Resource) ResourceLogsOption { return resourceLogsOptionFunc(func(rl plog.ResourceLogs) { res.CopyTo(rl.Resource()) }) } // AppendLogRecord adds a log record to the logs builder. func (lb *LogsBuilder) AppendLogRecord(lr plog.LogRecord) { lr.MoveTo(lb.logRecordsBuffer.AppendEmpty()) } // EmitForResource saves all the generated logs under a new resource and updates the internal state to be ready for // recording another set of log records as part of another resource. This function can be helpful when one scraper // needs to emit logs from several resources. Otherwise calling this function is not required, // just `Emit` function can be called instead. // Resource attributes should be provided as ResourceLogsOption arguments. func (lb *LogsBuilder) EmitForResource(options ...ResourceLogsOption) { rl := plog.NewResourceLogs() ils := rl.ScopeLogs().AppendEmpty() ils.Scope().SetName(ScopeName) ils.Scope().SetVersion(lb.buildInfo.Version) for _, op := range options { op.apply(rl) } if lb.logRecordsBuffer.Len() > 0 { lb.logRecordsBuffer.MoveAndAppendTo(ils.LogRecords()) lb.logRecordsBuffer = plog.NewLogRecordSlice() } if ils.LogRecords().Len() > 0 { rl.MoveTo(lb.logsBuffer.ResourceLogs().AppendEmpty()) } } // Emit returns all the logs accumulated by the logs builder and updates the internal state to be ready for // recording another set of logs. This function will be responsible for applying all the transformations required to // produce logs representation defined in metadata and user config. func (lb *LogsBuilder) Emit(options ...ResourceLogsOption) plog.Logs { lb.EmitForResource(options...) logs := lb.logsBuffer lb.logsBuffer = plog.NewLogs() return logs } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metadata/generated_logs_test.go000066400000000000000000000036611511331344600330170ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "time" "github.com/stretchr/testify/assert" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/receiver/receivertest" ) func TestLogsBuilderAppendLogRecord(t *testing.T) { observedZapCore, _ := observer.New(zap.WarnLevel) settings := receivertest.NewNopSettings(receivertest.NopType) settings.Logger = zap.New(observedZapCore) lb := NewLogsBuilder(settings) res := pcommon.NewResource() // append the first log record lr := plog.NewLogRecord() lr.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr.Attributes().PutStr("type", "log") lr.Body().SetStr("the first log record") // append the second log record lr2 := plog.NewLogRecord() lr2.SetTimestamp(pcommon.NewTimestampFromTime(time.Now())) lr2.Attributes().PutStr("type", "event") lr2.Body().SetStr("the second log record") lb.AppendLogRecord(lr) lb.AppendLogRecord(lr2) logs := lb.Emit(WithLogsResource(res)) assert.Equal(t, 1, logs.ResourceLogs().Len()) rl := logs.ResourceLogs().At(0) assert.Equal(t, 1, rl.ScopeLogs().Len()) sl := rl.ScopeLogs().At(0) assert.Equal(t, ScopeName, sl.Scope().Name()) assert.Equal(t, lb.buildInfo.Version, sl.Scope().Version()) assert.Equal(t, 2, sl.LogRecords().Len()) attrVal, ok := sl.LogRecords().At(0).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "log", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(0).Body().Type()) assert.Equal(t, "the first log record", sl.LogRecords().At(0).Body().Str()) attrVal, ok = sl.LogRecords().At(1).Attributes().Get("type") assert.True(t, ok) assert.Equal(t, "event", attrVal.Str()) assert.Equal(t, pcommon.ValueTypeStr, sl.LogRecords().At(1).Body().Type()) assert.Equal(t, "the second log record", sl.LogRecords().At(1).Body().Str()) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metadata/generated_status.go000066400000000000000000000007141511331344600323330ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "go.opentelemetry.io/collector/component" ) var ( Type = component.MustNewType("otlp") ScopeName = "go.opentelemetry.io/collector/receiver/otlpreceiver" ) const ( ProfilesStability = component.StabilityLevelDevelopment TracesStability = component.StabilityLevelStable MetricsStability = component.StabilityLevelStable LogsStability = component.StabilityLevelStable ) opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metrics/000077500000000000000000000000001511331344600263275ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metrics/otlp.go000066400000000000000000000037071511331344600276430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package metrics // import "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metrics" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/errors" "go.opentelemetry.io/collector/receiver/receiverhelper" ) const dataFormatProtobuf = "protobuf" // Receiver is the type used to handle metrics from OpenTelemetry exporters. type Receiver struct { pmetricotlp.UnimplementedGRPCServer nextConsumer consumer.Metrics obsreport *receiverhelper.ObsReport } // New creates a new Receiver reference. func New(nextConsumer consumer.Metrics, obsreport *receiverhelper.ObsReport) *Receiver { return &Receiver{ nextConsumer: nextConsumer, obsreport: obsreport, } } // Export implements the service Export metrics func. func (r *Receiver) Export(ctx context.Context, req pmetricotlp.ExportRequest) (pmetricotlp.ExportResponse, error) { md := req.Metrics() dataPointCount := md.DataPointCount() if dataPointCount == 0 { return pmetricotlp.NewExportResponse(), nil } ctx = r.obsreport.StartMetricsOp(ctx) err := r.nextConsumer.ConsumeMetrics(ctx, md) r.obsreport.EndMetricsOp(ctx, dataFormatProtobuf, dataPointCount, err) // Use appropriate status codes for permanent/non-permanent errors // If we return the error straightaway, then the grpc implementation will set status code to Unknown // Refer: https://github.com/grpc/grpc-go/blob/v1.59.0/server.go#L1345 // So, convert the error to appropriate grpc status and return the error // NonPermanent errors will be converted to codes.Unavailable (equivalent to HTTP 503) // Permanent errors will be converted to codes.InvalidArgument (equivalent to HTTP 400) if err != nil { return pmetricotlp.NewExportResponse(), errors.GetStatusFromError(err) } return pmetricotlp.NewExportResponse(), nil } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metrics/otlp_test.go000066400000000000000000000074371511331344600307060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package metrics import ( "context" "errors" "net" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metadata" "go.opentelemetry.io/collector/receiver/receiverhelper" "go.opentelemetry.io/collector/receiver/receivertest" ) func TestExport(t *testing.T) { md := testdata.GenerateMetrics(1) req := pmetricotlp.NewExportRequestFromMetrics(md) metricSink := new(consumertest.MetricsSink) metricsClient := makeMetricsServiceClient(t, metricSink) resp, err := metricsClient.Export(context.Background(), req) require.NoError(t, err, "Failed to export metrics: %v", err) require.NotNil(t, resp, "The response is missing") mds := metricSink.AllMetrics() require.Len(t, mds, 1) assert.Equal(t, md, mds[0]) } func TestExport_EmptyRequest(t *testing.T) { metricSink := new(consumertest.MetricsSink) metricsClient := makeMetricsServiceClient(t, metricSink) resp, err := metricsClient.Export(context.Background(), pmetricotlp.NewExportRequest()) require.NoError(t, err) require.NotNil(t, resp) } func TestExport_NonPermanentErrorConsumer(t *testing.T) { md := testdata.GenerateMetrics(1) req := pmetricotlp.NewExportRequestFromMetrics(md) metricsClient := makeMetricsServiceClient(t, consumertest.NewErr(errors.New("my error"))) resp, err := metricsClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Unavailable desc = my error") require.ErrorIs(t, err, status.Error(codes.Unavailable, "my error")) assert.Equal(t, pmetricotlp.ExportResponse{}, resp) } func TestExport_PermanentErrorConsumer(t *testing.T) { ld := testdata.GenerateMetrics(1) req := pmetricotlp.NewExportRequestFromMetrics(ld) metricsClient := makeMetricsServiceClient(t, consumertest.NewErr(consumererror.NewPermanent(errors.New("my error")))) resp, err := metricsClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Internal desc = Permanent error: my error") require.ErrorIs(t, err, status.Error(codes.Internal, "Permanent error: my error")) assert.Equal(t, pmetricotlp.ExportResponse{}, resp) } func makeMetricsServiceClient(t *testing.T, mc consumer.Metrics) pmetricotlp.GRPCClient { addr := otlpReceiverOnGRPCServer(t, mc) cc, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err, "Failed to create the MetricsServiceClient: %v", err) t.Cleanup(func() { require.NoError(t, cc.Close()) }) return pmetricotlp.NewGRPCClient(cc) } func otlpReceiverOnGRPCServer(t *testing.T, mc consumer.Metrics) net.Addr { ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) t.Cleanup(func() { require.NoError(t, ln.Close()) }) set := receivertest.NewNopSettings(metadata.Type) set.ID = component.MustNewIDWithName("otlp", "metrics") obsreport, err := receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ ReceiverID: set.ID, Transport: "grpc", ReceiverCreateSettings: set, }) require.NoError(t, err) r := New(mc, obsreport) // Now run it as a gRPC server srv := grpc.NewServer() pmetricotlp.RegisterGRPCServer(srv, r) go func() { _ = srv.Serve(ln) }() return ln.Addr() } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/metrics/package_test.go000066400000000000000000000003101511331344600313020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package metrics import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/profiles/000077500000000000000000000000001511331344600265045ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/profiles/otlp.go000066400000000000000000000033431511331344600300140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package profiles // import "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/profiles" import ( "context" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/errors" ) // Receiver is the type used to handle spans from OpenTelemetry exporters. type Receiver struct { pprofileotlp.UnimplementedGRPCServer nextConsumer xconsumer.Profiles } // New creates a new Receiver reference. func New(nextConsumer xconsumer.Profiles) *Receiver { return &Receiver{ nextConsumer: nextConsumer, } } // Export implements the service Export profiles func. func (r *Receiver) Export(ctx context.Context, req pprofileotlp.ExportRequest) (pprofileotlp.ExportResponse, error) { td := req.Profiles() // We need to ensure that it propagates the receiver name as a tag numProfiles := td.SampleCount() if numProfiles == 0 { return pprofileotlp.NewExportResponse(), nil } err := r.nextConsumer.ConsumeProfiles(ctx, td) // Use appropriate status codes for permanent/non-permanent errors // If we return the error straightaway, then the grpc implementation will set status code to Unknown // Refer: https://github.com/grpc/grpc-go/blob/v1.59.0/server.go#L1345 // So, convert the error to appropriate grpc status and return the error // NonPermanent errors will be converted to codes.Unavailable (equivalent to HTTP 503) // Permanent errors will be converted to codes.InvalidArgument (equivalent to HTTP 400) if err != nil { return pprofileotlp.NewExportResponse(), errors.GetStatusFromError(err) } return pprofileotlp.NewExportResponse(), nil } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/profiles/otlp_test.go000066400000000000000000000065421511331344600310570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package profiles import ( "context" "errors" "net" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/pdata/testdata" ) func TestExport(t *testing.T) { td := testdata.GenerateProfiles(1) req := pprofileotlp.NewExportRequestFromProfiles(td) profileSink := new(consumertest.ProfilesSink) profileClient := makeProfileServiceClient(t, profileSink) resp, err := profileClient.Export(context.Background(), req) require.NoError(t, err, "Failed to export profile: %v", err) require.NotNil(t, resp, "The response is missing") require.Len(t, profileSink.AllProfiles(), 1) assert.Equal(t, td, profileSink.AllProfiles()[0]) } func TestExport_EmptyRequest(t *testing.T) { profileSink := new(consumertest.ProfilesSink) profileClient := makeProfileServiceClient(t, profileSink) resp, err := profileClient.Export(context.Background(), pprofileotlp.NewExportRequest()) require.NoError(t, err, "Failed to export profile: %v", err) assert.NotNil(t, resp, "The response is missing") } func TestExport_NonPermanentErrorConsumer(t *testing.T) { td := testdata.GenerateProfiles(1) req := pprofileotlp.NewExportRequestFromProfiles(td) profileClient := makeProfileServiceClient(t, consumertest.NewErr(errors.New("my error"))) resp, err := profileClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Unavailable desc = my error") require.ErrorIs(t, err, status.Error(codes.Unavailable, "my error")) assert.Equal(t, pprofileotlp.ExportResponse{}, resp) } func TestExport_PermanentErrorConsumer(t *testing.T) { ld := testdata.GenerateProfiles(1) req := pprofileotlp.NewExportRequestFromProfiles(ld) profileClient := makeProfileServiceClient(t, consumertest.NewErr(consumererror.NewPermanent(errors.New("my error")))) resp, err := profileClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Internal desc = Permanent error: my error") require.ErrorIs(t, err, status.Error(codes.Internal, "Permanent error: my error")) assert.Equal(t, pprofileotlp.ExportResponse{}, resp) } func makeProfileServiceClient(t *testing.T, tc xconsumer.Profiles) pprofileotlp.GRPCClient { addr := otlpReceiverOnGRPCServer(t, tc) cc, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err, "Failed to create the profileServiceClient: %v", err) t.Cleanup(func() { require.NoError(t, cc.Close()) }) return pprofileotlp.NewGRPCClient(cc) } func otlpReceiverOnGRPCServer(t *testing.T, tc xconsumer.Profiles) net.Addr { ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) t.Cleanup(func() { require.NoError(t, ln.Close()) }) r := New(tc) // Now run it as a gRPC server srv := grpc.NewServer() pprofileotlp.RegisterGRPCServer(srv, r) go func() { _ = srv.Serve(ln) }() return ln.Addr() } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/profiles/package_test.go000066400000000000000000000003111511331344600314600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package profiles import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/trace/000077500000000000000000000000001511331344600257575ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/trace/otlp.go000066400000000000000000000037371511331344600272760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package trace // import "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/trace" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/errors" "go.opentelemetry.io/collector/receiver/receiverhelper" ) const dataFormatProtobuf = "protobuf" // Receiver is the type used to handle spans from OpenTelemetry exporters. type Receiver struct { ptraceotlp.UnimplementedGRPCServer nextConsumer consumer.Traces obsreport *receiverhelper.ObsReport } // New creates a new Receiver reference. func New(nextConsumer consumer.Traces, obsreport *receiverhelper.ObsReport) *Receiver { return &Receiver{ nextConsumer: nextConsumer, obsreport: obsreport, } } // Export implements the service Export traces func. func (r *Receiver) Export(ctx context.Context, req ptraceotlp.ExportRequest) (ptraceotlp.ExportResponse, error) { td := req.Traces() // We need to ensure that it propagates the receiver name as a tag numSpans := td.SpanCount() if numSpans == 0 { return ptraceotlp.NewExportResponse(), nil } ctx = r.obsreport.StartTracesOp(ctx) err := r.nextConsumer.ConsumeTraces(ctx, td) r.obsreport.EndTracesOp(ctx, dataFormatProtobuf, numSpans, err) // Use appropriate status codes for permanent/non-permanent errors // If we return the error straightaway, then the grpc implementation will set status code to Unknown // Refer: https://github.com/grpc/grpc-go/blob/v1.59.0/server.go#L1345 // So, convert the error to appropriate grpc status and return the error // NonPermanent errors will be converted to codes.Unavailable (equivalent to HTTP 503) // Permanent errors will be converted to codes.InvalidArgument (equivalent to HTTP 400) if err != nil { return ptraceotlp.NewExportResponse(), errors.GetStatusFromError(err) } return ptraceotlp.NewExportResponse(), nil } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/trace/otlp_test.go000066400000000000000000000074431511331344600303330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package trace import ( "context" "errors" "net" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metadata" "go.opentelemetry.io/collector/receiver/receiverhelper" "go.opentelemetry.io/collector/receiver/receivertest" ) func TestExport(t *testing.T) { td := testdata.GenerateTraces(1) req := ptraceotlp.NewExportRequestFromTraces(td) traceSink := new(consumertest.TracesSink) traceClient := makeTraceServiceClient(t, traceSink) resp, err := traceClient.Export(context.Background(), req) require.NoError(t, err, "Failed to export trace: %v", err) require.NotNil(t, resp, "The response is missing") require.Len(t, traceSink.AllTraces(), 1) assert.Equal(t, td, traceSink.AllTraces()[0]) } func TestExport_EmptyRequest(t *testing.T) { traceSink := new(consumertest.TracesSink) traceClient := makeTraceServiceClient(t, traceSink) resp, err := traceClient.Export(context.Background(), ptraceotlp.NewExportRequest()) require.NoError(t, err, "Failed to export trace: %v", err) assert.NotNil(t, resp, "The response is missing") } func TestExport_NonPermanentErrorConsumer(t *testing.T) { td := testdata.GenerateTraces(1) req := ptraceotlp.NewExportRequestFromTraces(td) traceClient := makeTraceServiceClient(t, consumertest.NewErr(errors.New("my error"))) resp, err := traceClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Unavailable desc = my error") require.ErrorIs(t, err, status.Error(codes.Unavailable, "my error")) assert.Equal(t, ptraceotlp.ExportResponse{}, resp) } func TestExport_PermanentErrorConsumer(t *testing.T) { ld := testdata.GenerateTraces(1) req := ptraceotlp.NewExportRequestFromTraces(ld) traceClient := makeTraceServiceClient(t, consumertest.NewErr(consumererror.NewPermanent(errors.New("my error")))) resp, err := traceClient.Export(context.Background(), req) require.EqualError(t, err, "rpc error: code = Internal desc = Permanent error: my error") require.ErrorIs(t, err, status.Error(codes.Internal, "Permanent error: my error")) assert.Equal(t, ptraceotlp.ExportResponse{}, resp) } func makeTraceServiceClient(t *testing.T, tc consumer.Traces) ptraceotlp.GRPCClient { addr := otlpReceiverOnGRPCServer(t, tc) cc, err := grpc.NewClient(addr.String(), grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err, "Failed to create the TraceServiceClient: %v", err) t.Cleanup(func() { require.NoError(t, cc.Close()) }) return ptraceotlp.NewGRPCClient(cc) } func otlpReceiverOnGRPCServer(t *testing.T, tc consumer.Traces) net.Addr { ln, err := net.Listen("tcp", "localhost:") require.NoError(t, err, "Failed to find an available address to run the gRPC server: %v", err) t.Cleanup(func() { require.NoError(t, ln.Close()) }) set := receivertest.NewNopSettings(metadata.Type) set.ID = component.MustNewIDWithName("otlp", "trace") obsreport, err := receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ ReceiverID: set.ID, Transport: "grpc", ReceiverCreateSettings: set, }) require.NoError(t, err) r := New(tc, obsreport) // Now run it as a gRPC server srv := grpc.NewServer() ptraceotlp.RegisterGRPCServer(srv, r) go func() { _ = srv.Serve(ln) }() return ln.Addr() } opentelemetry-collector-0.141.0/receiver/otlpreceiver/internal/trace/package_test.go000066400000000000000000000003061511331344600307370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package trace import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/metadata.yaml000066400000000000000000000003641511331344600255140ustar00rootroot00000000000000type: otlp github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: receiver stability: stable: [traces, metrics, logs] development: [profiles] distributions: [core, contrib, k8s, otlp] opentelemetry-collector-0.141.0/receiver/otlpreceiver/otlp.go000066400000000000000000000157161511331344600243640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver // import "go.opentelemetry.io/collector/receiver/otlpreceiver" import ( "context" "errors" "net" "net/http" "sync" "go.uber.org/zap" "google.golang.org/grpc" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/pprofile/pprofileotlp" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/logs" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metrics" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/profiles" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/trace" "go.opentelemetry.io/collector/receiver/receiverhelper" ) // otlpReceiver is the type that exposes Trace and Metrics reception. type otlpReceiver struct { cfg *Config serverGRPC *grpc.Server serverHTTP *http.Server nextTraces consumer.Traces nextMetrics consumer.Metrics nextLogs consumer.Logs nextProfiles xconsumer.Profiles shutdownWG sync.WaitGroup obsrepGRPC *receiverhelper.ObsReport obsrepHTTP *receiverhelper.ObsReport settings *receiver.Settings } // newOtlpReceiver just creates the OpenTelemetry receiver services. It is the caller's // responsibility to invoke the respective Start*Reception methods as well // as the various Stop*Reception methods to end it. func newOtlpReceiver(cfg *Config, set *receiver.Settings) (*otlpReceiver, error) { set.TelemetrySettings = telemetry.DropInjectedAttributes(set.TelemetrySettings, telemetry.SignalKey) set.Logger.Debug("created signal-agnostic logger") r := &otlpReceiver{ cfg: cfg, nextTraces: nil, nextMetrics: nil, nextLogs: nil, nextProfiles: nil, settings: set, } var err error r.obsrepGRPC, err = receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ ReceiverID: set.ID, Transport: "grpc", ReceiverCreateSettings: *set, }) if err != nil { return nil, err } r.obsrepHTTP, err = receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ ReceiverID: set.ID, Transport: "http", ReceiverCreateSettings: *set, }) if err != nil { return nil, err } return r, nil } func (r *otlpReceiver) startGRPCServer(ctx context.Context, host component.Host) error { // If GRPC is not enabled, nothing to start. if !r.cfg.GRPC.HasValue() { return nil } grpcCfg := r.cfg.GRPC.Get() var err error if r.serverGRPC, err = grpcCfg.ToServer(ctx, host.GetExtensions(), r.settings.TelemetrySettings); err != nil { return err } if r.nextTraces != nil { ptraceotlp.RegisterGRPCServer(r.serverGRPC, trace.New(r.nextTraces, r.obsrepGRPC)) } if r.nextMetrics != nil { pmetricotlp.RegisterGRPCServer(r.serverGRPC, metrics.New(r.nextMetrics, r.obsrepGRPC)) } if r.nextLogs != nil { plogotlp.RegisterGRPCServer(r.serverGRPC, logs.New(r.nextLogs, r.obsrepGRPC)) } if r.nextProfiles != nil { pprofileotlp.RegisterGRPCServer(r.serverGRPC, profiles.New(r.nextProfiles)) } var gln net.Listener if gln, err = grpcCfg.NetAddr.Listen(ctx); err != nil { return err } r.settings.Logger.Info("Starting GRPC server", zap.String("endpoint", gln.Addr().String())) r.shutdownWG.Add(1) go func() { defer r.shutdownWG.Done() if errGrpc := r.serverGRPC.Serve(gln); errGrpc != nil && !errors.Is(errGrpc, grpc.ErrServerStopped) { componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errGrpc)) } }() return nil } func (r *otlpReceiver) startHTTPServer(ctx context.Context, host component.Host) error { // If HTTP is not enabled, nothing to start. if !r.cfg.HTTP.HasValue() { return nil } httpCfg := r.cfg.HTTP.Get() httpMux := http.NewServeMux() if r.nextTraces != nil { httpTracesReceiver := trace.New(r.nextTraces, r.obsrepHTTP) httpMux.HandleFunc(string(httpCfg.TracesURLPath), func(resp http.ResponseWriter, req *http.Request) { handleTraces(resp, req, httpTracesReceiver) }) } if r.nextMetrics != nil { httpMetricsReceiver := metrics.New(r.nextMetrics, r.obsrepHTTP) httpMux.HandleFunc(string(httpCfg.MetricsURLPath), func(resp http.ResponseWriter, req *http.Request) { handleMetrics(resp, req, httpMetricsReceiver) }) } if r.nextLogs != nil { httpLogsReceiver := logs.New(r.nextLogs, r.obsrepHTTP) httpMux.HandleFunc(string(httpCfg.LogsURLPath), func(resp http.ResponseWriter, req *http.Request) { handleLogs(resp, req, httpLogsReceiver) }) } if r.nextProfiles != nil { httpProfilesReceiver := profiles.New(r.nextProfiles) httpMux.HandleFunc(defaultProfilesURLPath, func(resp http.ResponseWriter, req *http.Request) { handleProfiles(resp, req, httpProfilesReceiver) }) } var err error if r.serverHTTP, err = httpCfg.ServerConfig.ToServer(ctx, host.GetExtensions(), r.settings.TelemetrySettings, httpMux, confighttp.WithErrorHandler(errorHandler)); err != nil { return err } var hln net.Listener if hln, err = httpCfg.ServerConfig.ToListener(ctx); err != nil { return err } r.settings.Logger.Info("Starting HTTP server", zap.String("endpoint", hln.Addr().String())) r.shutdownWG.Add(1) go func() { defer r.shutdownWG.Done() if errHTTP := r.serverHTTP.Serve(hln); errHTTP != nil && !errors.Is(errHTTP, http.ErrServerClosed) { componentstatus.ReportStatus(host, componentstatus.NewFatalErrorEvent(errHTTP)) } }() return nil } // Start runs the trace receiver on the gRPC server. Currently // it also enables the metrics receiver too. func (r *otlpReceiver) Start(ctx context.Context, host component.Host) error { if err := r.startGRPCServer(ctx, host); err != nil { return err } if err := r.startHTTPServer(ctx, host); err != nil { // It's possible that a valid GRPC server configuration was specified, // but an invalid HTTP configuration. If that's the case, the successfully // started GRPC server must be shutdown to ensure no goroutines are leaked. return errors.Join(err, r.Shutdown(ctx)) } return nil } // Shutdown is a method to turn off receiving. func (r *otlpReceiver) Shutdown(ctx context.Context) error { var err error if r.serverHTTP != nil { err = r.serverHTTP.Shutdown(ctx) } if r.serverGRPC != nil { r.serverGRPC.GracefulStop() } r.shutdownWG.Wait() return err } func (r *otlpReceiver) registerTraceConsumer(tc consumer.Traces) { r.nextTraces = tc } func (r *otlpReceiver) registerMetricsConsumer(mc consumer.Metrics) { r.nextMetrics = mc } func (r *otlpReceiver) registerLogsConsumer(lc consumer.Logs) { r.nextLogs = lc } func (r *otlpReceiver) registerProfilesConsumer(tc xconsumer.Profiles) { r.nextProfiles = tc } opentelemetry-collector-0.141.0/receiver/otlpreceiver/otlp_test.go000066400000000000000000001406371511331344600254240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver import ( "bytes" "compress/gzip" "context" "encoding/json" "errors" "fmt" "io" "net" "net/http" "strings" "sync" "testing" "time" "github.com/klauspost/compress/zstd" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" spb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials/insecure" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configgrpc" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/confignet" "go.opentelemetry.io/collector/config/configoptional" "go.opentelemetry.io/collector/config/configtls" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metadata" "go.opentelemetry.io/collector/receiver/receiverhelper" "go.opentelemetry.io/collector/receiver/receivertest" ) const otlpReceiverName = "receiver_test" var otlpReceiverID = component.MustNewIDWithName("otlp", otlpReceiverName) func TestJsonHttp(t *testing.T) { tests := []struct { name string encoding string contentType string err error expectedStatus *spb.Status expectedStatusCode int }{ { name: "JSONUncompressed", encoding: "", contentType: "application/json", }, { name: "JSONUncompressedUTF8", encoding: "", contentType: "application/json; charset=utf-8", }, { name: "JSONUncompressedUppercase", encoding: "", contentType: "APPLICATION/JSON", }, { name: "JSONGzipCompressed", encoding: "gzip", contentType: "application/json", }, { name: "JSONZstdCompressed", encoding: "zstd", contentType: "application/json", }, { name: "Permanent NotGRPCError", encoding: "", contentType: "application/json", err: consumererror.NewPermanent(errors.New("my error")), expectedStatus: &spb.Status{Code: int32(codes.Internal), Message: "Permanent error: my error"}, expectedStatusCode: http.StatusInternalServerError, }, { name: "Retryable NotGRPCError", encoding: "", contentType: "application/json", err: errors.New("my error"), expectedStatus: &spb.Status{Code: int32(codes.Unavailable), Message: "my error"}, expectedStatusCode: http.StatusServiceUnavailable, }, { name: "Permanent GRPCError", encoding: "", contentType: "application/json", err: status.New(codes.Internal, "").Err(), expectedStatus: &spb.Status{Code: int32(codes.Internal), Message: ""}, expectedStatusCode: http.StatusInternalServerError, }, { name: "Retryable GRPCError", encoding: "", contentType: "application/json", err: status.New(codes.Unavailable, "Service Unavailable").Err(), expectedStatus: &spb.Status{Code: int32(codes.Unavailable), Message: "Service Unavailable"}, expectedStatusCode: http.StatusServiceUnavailable, }, } addr := testutil.GetAvailableLocalAddress(t) sink := newErrOrSinkConsumer() recv := newHTTPReceiver(t, componenttest.NewNopTelemetrySettings(), addr, sink) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost()), "Failed to start trace receiver") t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink.Reset() sink.SetConsumeError(tt.err) for _, dr := range generateDataRequests(t) { url := "http://" + addr + dr.path respBytes := doHTTPRequest(t, url, tt.encoding, tt.contentType, dr.jsonBytes, tt.expectedStatusCode) if tt.err == nil { tr := ptraceotlp.NewExportResponse() require.NoError(t, tr.UnmarshalJSON(respBytes), "Unable to unmarshal response to Response") sink.checkData(t, dr.data, 1) } else { errStatus := &spb.Status{} require.NoError(t, json.Unmarshal(respBytes, errStatus)) if s, ok := status.FromError(tt.err); ok { assert.Equal(t, s.Proto().Code, errStatus.Code) assert.Equal(t, s.Proto().Message, errStatus.Message) } else { fmt.Println(errStatus) assert.True(t, proto.Equal(errStatus, tt.expectedStatus)) } sink.checkData(t, dr.data, 0) } } }) } } func TestHandleInvalidRequests(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) sink := newErrOrSinkConsumer() recv := newHTTPReceiver(t, componenttest.NewNopTelemetrySettings(), addr, sink) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost()), "Failed to start trace receiver") t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) tests := []struct { name string uri string method string contentType string expectedStatus int expectedResponseBody string }{ { name: "no content type", uri: defaultTracesURLPath, method: http.MethodPost, contentType: "", expectedStatus: http.StatusUnsupportedMediaType, expectedResponseBody: "415 unsupported media type, supported: [application/json, application/x-protobuf]", }, { name: "invalid content type", uri: defaultTracesURLPath, method: http.MethodPost, contentType: "invalid", expectedStatus: http.StatusUnsupportedMediaType, expectedResponseBody: "415 unsupported media type, supported: [application/json, application/x-protobuf]", }, { name: "invalid request", uri: defaultTracesURLPath, method: http.MethodPost, contentType: "application/json", expectedStatus: http.StatusBadRequest, }, { uri: defaultTracesURLPath, method: http.MethodPatch, contentType: "application/json", expectedStatus: http.StatusMethodNotAllowed, expectedResponseBody: "405 method not allowed, supported: [POST]", }, { uri: defaultTracesURLPath, method: http.MethodGet, contentType: "application/json", expectedStatus: http.StatusMethodNotAllowed, expectedResponseBody: "405 method not allowed, supported: [POST]", }, { name: "no content type", uri: defaultMetricsURLPath, method: http.MethodPost, contentType: "", expectedStatus: http.StatusUnsupportedMediaType, expectedResponseBody: "415 unsupported media type, supported: [application/json, application/x-protobuf]", }, { name: "invalid content type", uri: defaultMetricsURLPath, method: http.MethodPost, contentType: "invalid", expectedStatus: http.StatusUnsupportedMediaType, expectedResponseBody: "415 unsupported media type, supported: [application/json, application/x-protobuf]", }, { name: "invalid request", uri: defaultMetricsURLPath, method: http.MethodPost, contentType: "application/json", expectedStatus: http.StatusBadRequest, }, { uri: defaultMetricsURLPath, method: http.MethodPatch, contentType: "application/json", expectedStatus: http.StatusMethodNotAllowed, expectedResponseBody: "405 method not allowed, supported: [POST]", }, { uri: defaultMetricsURLPath, method: http.MethodGet, contentType: "application/json", expectedStatus: http.StatusMethodNotAllowed, expectedResponseBody: "405 method not allowed, supported: [POST]", }, { name: "no content type", uri: defaultLogsURLPath, method: http.MethodPost, contentType: "", expectedStatus: http.StatusUnsupportedMediaType, expectedResponseBody: "415 unsupported media type, supported: [application/json, application/x-protobuf]", }, { name: "invalid content type", uri: defaultLogsURLPath, method: http.MethodPost, contentType: "invalid", expectedStatus: http.StatusUnsupportedMediaType, expectedResponseBody: "415 unsupported media type, supported: [application/json, application/x-protobuf]", }, { name: "invalid request", uri: defaultLogsURLPath, method: http.MethodPost, contentType: "application/json", expectedStatus: http.StatusBadRequest, }, { uri: defaultLogsURLPath, method: http.MethodPatch, contentType: "application/json", expectedStatus: http.StatusMethodNotAllowed, expectedResponseBody: "405 method not allowed, supported: [POST]", }, { uri: defaultLogsURLPath, method: http.MethodGet, contentType: "application/json", expectedStatus: http.StatusMethodNotAllowed, expectedResponseBody: "405 method not allowed, supported: [POST]", }, } for _, tt := range tests { t.Run(tt.method+" "+tt.uri+" "+tt.name, func(t *testing.T) { url := "http://" + addr + tt.uri req, err := http.NewRequest(tt.method, url, bytes.NewReader([]byte(`1234`))) require.NoError(t, err) req.Header.Set("Content-Type", tt.contentType) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) body, err := io.ReadAll(resp.Body) require.NoError(t, err) if tt.name == "invalid request" { assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) assert.Equal(t, tt.expectedStatus, resp.StatusCode) return } assert.Equal(t, "text/plain", resp.Header.Get("Content-Type")) assert.Equal(t, tt.expectedStatus, resp.StatusCode) assert.Equal(t, tt.expectedResponseBody, string(body)) }) } require.NoError(t, recv.Shutdown(context.Background())) } func TestProtoHttp(t *testing.T) { tests := []struct { name string encoding string err error expectedStatus *spb.Status expectedStatusCode int }{ { name: "ProtoUncompressed", encoding: "", }, { name: "ProtoGzipCompressed", encoding: "gzip", }, { name: "ProtoZstdCompressed", encoding: "zstd", }, { name: "Permanent NotGRPCError", encoding: "", err: consumererror.NewPermanent(errors.New("my error")), expectedStatus: &spb.Status{Code: int32(codes.Internal), Message: "Permanent error: my error"}, expectedStatusCode: http.StatusInternalServerError, }, { name: "Retryable NotGRPCError", encoding: "", err: errors.New("my error"), expectedStatus: &spb.Status{Code: int32(codes.Unavailable), Message: "my error"}, expectedStatusCode: http.StatusServiceUnavailable, }, { name: "Permanent GRPCError", encoding: "", err: status.New(codes.InvalidArgument, "Bad Request").Err(), expectedStatus: &spb.Status{Code: int32(codes.InvalidArgument), Message: "Bad Request"}, expectedStatusCode: http.StatusBadRequest, }, { name: "Retryable GRPCError", encoding: "", err: status.New(codes.Unavailable, "Service Unavailable").Err(), expectedStatus: &spb.Status{Code: int32(codes.Unavailable), Message: "Service Unavailable"}, expectedStatusCode: http.StatusServiceUnavailable, }, } addr := testutil.GetAvailableLocalAddress(t) // Set the buffer count to 1 to make it flush the test span immediately. sink := newErrOrSinkConsumer() recv := newHTTPReceiver(t, componenttest.NewNopTelemetrySettings(), addr, sink) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost()), "Failed to start trace receiver") t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink.Reset() sink.SetConsumeError(tt.err) for _, dr := range generateDataRequests(t) { url := "http://" + addr + dr.path respBytes := doHTTPRequest(t, url, tt.encoding, "application/x-protobuf", dr.protoBytes, tt.expectedStatusCode) if tt.err == nil { tr := ptraceotlp.NewExportResponse() require.NoError(t, tr.UnmarshalProto(respBytes)) sink.checkData(t, dr.data, 1) } else { errStatus := &spb.Status{} require.NoError(t, proto.Unmarshal(respBytes, errStatus)) if s, ok := status.FromError(tt.err); ok { assert.True(t, proto.Equal(errStatus, s.Proto())) } else { assert.True(t, proto.Equal(errStatus, tt.expectedStatus)) } sink.checkData(t, dr.data, 0) } } }) } } func TestOTLPReceiverInvalidContentEncoding(t *testing.T) { tests := []struct { name string content string encoding string reqBodyFunc func() (*bytes.Buffer, error) checkBody func(tb testing.TB, got []byte) status int }{ { name: "JsonGzipUncompressed", content: "application/json", encoding: "gzip", reqBodyFunc: func() (*bytes.Buffer, error) { return bytes.NewBuffer([]byte(`{"key": "value"}`)), nil }, checkBody: func(tb testing.TB, got []byte) { assert.JSONEq(tb, `{"code":3,"message": "gzip: invalid header"}`, string(got)) }, status: 400, }, { name: "ProtoGzipUncompressed", content: "application/x-protobuf", encoding: "gzip", reqBodyFunc: func() (*bytes.Buffer, error) { return bytes.NewBuffer([]byte(`{"key": "value"}`)), nil }, checkBody: func(tb testing.TB, got []byte) { expected, err := proto.Marshal(status.New(codes.InvalidArgument, "gzip: invalid header").Proto()) require.NoError(tb, err) assert.Equal(tb, expected, got) }, status: 400, }, { name: "ProtoZstdUncompressed", content: "application/x-protobuf", encoding: "zstd", reqBodyFunc: func() (*bytes.Buffer, error) { return bytes.NewBuffer([]byte(`{"key": "value"}`)), nil }, checkBody: func(tb testing.TB, got []byte) { expected, err := proto.Marshal(status.New(codes.InvalidArgument, "invalid input: magic number mismatch").Proto()) require.NoError(tb, err) assert.Equal(tb, expected, got) }, status: 400, }, } addr := testutil.GetAvailableLocalAddress(t) // Set the buffer count to 1 to make it flush the test span immediately. recv := newHTTPReceiver(t, componenttest.NewNopTelemetrySettings(), addr, consumertest.NewNop()) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost()), "Failed to start trace receiver") t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) url := fmt.Sprintf("http://%s%s", addr, defaultTracesURLPath) for _, test := range tests { t.Run(test.name, func(t *testing.T) { body, err := test.reqBodyFunc() require.NoError(t, err) req, err := http.NewRequest(http.MethodPost, url, body) require.NoError(t, err) req.Header.Set("Content-Type", test.content) req.Header.Set("Content-Encoding", test.encoding) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) assert.Equal(t, test.status, resp.StatusCode, "Unexpected return status") assert.Equal(t, test.content, resp.Header.Get("Content-Type"), "Unexpected response Content-Type") respBytes, err := io.ReadAll(resp.Body) require.NoError(t, err) require.NoError(t, resp.Body.Close()) test.checkBody(t, respBytes) }) } } func TestOTLPReceiverNoContentType(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) // Set the buffer count to 1 to make it flush the test span immediately. recv := newHTTPReceiver(t, componenttest.NewNopTelemetrySettings(), addr, consumertest.NewNop()) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost()), "Failed to start trace receiver") t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) url := fmt.Sprintf("http://%s%s", addr, defaultTracesURLPath) t.Run("NoContentType", func(t *testing.T) { body := bytes.NewBuffer([]byte(`{"key": "value"}`)) req, err := http.NewRequest(http.MethodPost, url, body) require.NoError(t, err, "Error creating trace POST request: %v", err) // Set invalid encoding to trigger an error req.Header.Set("Content-Encoding", "invalid") resp, err := http.DefaultClient.Do(req) require.NoError(t, err, "Error posting to server: %v", err) // Don't care about the response body, just check the content type defer resp.Body.Close() require.Equal(t, fallbackContentType, resp.Header.Get("Content-Type"), "Unexpected response Content-Type") }) } func TestGRPCNewPortAlreadyUsed(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) ln, err := net.Listen("tcp", addr) require.NoError(t, err, "failed to listen on %q: %v", addr, err) t.Cleanup(func() { assert.NoError(t, ln.Close()) }) r := newGRPCReceiver(t, componenttest.NewNopTelemetrySettings(), addr, consumertest.NewNop()) require.NotNil(t, r) require.Error(t, r.Start(context.Background(), componenttest.NewNopHost())) } func TestHTTPNewPortAlreadyUsed(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) ln, err := net.Listen("tcp", addr) require.NoError(t, err, "failed to listen on %q: %v", addr, err) t.Cleanup(func() { assert.NoError(t, ln.Close()) }) r := newHTTPReceiver(t, componenttest.NewNopTelemetrySettings(), addr, consumertest.NewNop()) require.NotNil(t, r) require.Error(t, r.Start(context.Background(), componenttest.NewNopHost())) } // TestOTLPReceiverGRPCMetricsIngestTest checks that the metrics receiver // is returning the proper response (return and metrics) when the next consumer // in the pipeline reports error. func TestOTLPReceiverGRPCMetricsIngestTest(t *testing.T) { // Get a new available port addr := testutil.GetAvailableLocalAddress(t) // Create a sink sink := &errOrSinkConsumer{MetricsSink: new(consumertest.MetricsSink)} // Create a telemetry instance tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) // Create telemetry settings settings := tt.NewTelemetrySettings() recv := newGRPCReceiver(t, settings, addr, sink) require.NotNil(t, recv) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) defer func() { assert.NoError(t, cc.Close()) }() // Set up the error case sink.SetConsumeError(errors.New("consumer error")) md := testdata.GenerateMetrics(1) _, err = pmetricotlp.NewGRPCClient(cc).Export(context.Background(), pmetricotlp.NewExportRequestFromMetrics(md)) errStatus, ok := status.FromError(err) require.True(t, ok) assert.Equal(t, codes.Unavailable, errStatus.Code()) // Assert receiver metrics including receiver_requests assertReceiverMetrics(t, tt, otlpReceiverID, "grpc", 0, 2) } // TestOTLPReceiverGRPCTracesIngestTest checks that the gRPC trace receiver // is returning the proper response (return and metrics) when the next consumer // in the pipeline reports error. The test changes the responses returned by the // next trace consumer, checks if data was passed down the pipeline and if // proper metrics were recorded. It also uses all endpoints supported by the // trace receiver. func TestOTLPReceiverGRPCTracesIngestTest(t *testing.T) { type ingestionStateTest struct { okToIngest bool permanent bool expectedCode codes.Code } expectedReceivedBatches := 2 expectedIngestionBlockedRPCs := 2 ingestionStates := []ingestionStateTest{ { okToIngest: true, expectedCode: codes.OK, }, { okToIngest: false, expectedCode: codes.Unavailable, }, { okToIngest: false, expectedCode: codes.Internal, permanent: true, }, { okToIngest: true, expectedCode: codes.OK, }, } addr := testutil.GetAvailableLocalAddress(t) td := testdata.GenerateTraces(1) tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) sink := &errOrSinkConsumer{TracesSink: new(consumertest.TracesSink)} recv := newGRPCReceiver(t, tt.NewTelemetrySettings(), addr, sink) require.NotNil(t, recv) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) defer func() { assert.NoError(t, cc.Close()) }() for _, ingestionState := range ingestionStates { if ingestionState.okToIngest { sink.SetConsumeError(nil) } else { if ingestionState.permanent { sink.SetConsumeError(consumererror.NewPermanent(errors.New("consumer error"))) } else { sink.SetConsumeError(errors.New("consumer error")) } } _, err = ptraceotlp.NewGRPCClient(cc).Export(context.Background(), ptraceotlp.NewExportRequestFromTraces(td)) errStatus, ok := status.FromError(err) require.True(t, ok) assert.Equal(t, ingestionState.expectedCode, errStatus.Code()) } require.Len(t, sink.AllTraces(), expectedReceivedBatches) assertReceiverTraces(t, tt, otlpReceiverID, "grpc", int64(expectedReceivedBatches), int64(expectedIngestionBlockedRPCs)) } // TestOTLPReceiverHTTPTracesIngestTest checks that the HTTP trace receiver // is returning the proper response (return and metrics) when the next consumer // in the pipeline reports error. The test changes the responses returned by the // next trace consumer, checks if data was passed down the pipeline and if // proper metrics were recorded. It also uses all endpoints supported by the // trace receiver. func TestOTLPReceiverHTTPTracesIngestTest(t *testing.T) { type ingestionStateTest struct { okToIngest bool err error expectedCode codes.Code expectedStatusCode int } expectedReceivedBatches := 2 expectedIngestionBlockedRPCs := 2 ingestionStates := []ingestionStateTest{ { okToIngest: true, expectedCode: codes.OK, }, { okToIngest: false, err: consumererror.NewPermanent(errors.New("consumer error")), expectedCode: codes.Internal, expectedStatusCode: http.StatusInternalServerError, }, { okToIngest: false, err: errors.New("consumer error"), expectedCode: codes.Unavailable, expectedStatusCode: http.StatusServiceUnavailable, }, { okToIngest: true, expectedCode: codes.OK, }, } addr := testutil.GetAvailableLocalAddress(t) td := testdata.GenerateTraces(1) tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) sink := &errOrSinkConsumer{TracesSink: new(consumertest.TracesSink)} recv := newHTTPReceiver(t, tt.NewTelemetrySettings(), addr, sink) require.NotNil(t, recv) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) for _, ingestionState := range ingestionStates { if ingestionState.okToIngest { sink.SetConsumeError(nil) } else { sink.SetConsumeError(ingestionState.err) } pbMarshaler := ptrace.ProtoMarshaler{} pbBytes, err := pbMarshaler.MarshalTraces(td) require.NoError(t, err) req, err := http.NewRequest(http.MethodPost, "http://"+addr+defaultTracesURLPath, bytes.NewReader(pbBytes)) require.NoError(t, err) req.Header.Set("Content-Type", pbContentType) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) respBytes, err := io.ReadAll(resp.Body) require.NoError(t, err) if ingestionState.expectedCode == codes.OK { require.Equal(t, 200, resp.StatusCode) tr := ptraceotlp.NewExportResponse() require.NoError(t, tr.UnmarshalProto(respBytes)) } else { errStatus := &spb.Status{} require.NoError(t, proto.Unmarshal(respBytes, errStatus)) assert.Equal(t, ingestionState.expectedStatusCode, resp.StatusCode) assert.EqualValues(t, ingestionState.expectedCode, errStatus.Code) } } require.Len(t, sink.AllTraces(), expectedReceivedBatches) assertReceiverTraces(t, tt, otlpReceiverID, "http", int64(expectedReceivedBatches), int64(expectedIngestionBlockedRPCs)) } func TestGRPCInvalidTLSCredentials(t *testing.T) { cfg := &Config{ Protocols: Protocols{ GRPC: configoptional.Some(configgrpc.ServerConfig{ NetAddr: confignet.AddrConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), Transport: confignet.TransportTypeTCP, }, TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CertFile: "willfail", }, }), }), }, } r, err := NewFactory().CreateTraces( context.Background(), receivertest.NewNopSettings(metadata.Type), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NotNil(t, r) assert.EqualError(t, r.Start(context.Background(), componenttest.NewNopHost()), `failed to load TLS config: failed to load TLS cert and key: for auth via TLS, provide both certificate and key, or neither`) } func TestGRPCMaxRecvSize(t *testing.T) { addr := testutil.GetAvailableLocalAddress(t) sink := newErrOrSinkConsumer() cfg := createDefaultConfig().(*Config) cfg.GRPC.GetOrInsertDefault().NetAddr.Endpoint = addr recv := newReceiver(t, componenttest.NewNopTelemetrySettings(), cfg, otlpReceiverID, sink) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) cc, err := grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) td := testdata.GenerateTraces(50000) err = exportTraces(cc, td) require.Error(t, err) assert.NoError(t, cc.Close()) require.NoError(t, recv.Shutdown(context.Background())) cfg.GRPC.Get().MaxRecvMsgSizeMiB = 100 recv = newReceiver(t, componenttest.NewNopTelemetrySettings(), cfg, otlpReceiverID, sink) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) cc, err = grpc.NewClient(addr, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) defer func() { assert.NoError(t, cc.Close()) }() td = testdata.GenerateTraces(50000) require.NoError(t, exportTraces(cc, td)) require.Len(t, sink.AllTraces(), 1) assert.Equal(t, td, sink.AllTraces()[0]) } func TestHTTPInvalidTLSCredentials(t *testing.T) { cfg := &Config{ Protocols: Protocols{ HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: testutil.GetAvailableLocalAddress(t), TLS: configoptional.Some(configtls.ServerConfig{ Config: configtls.Config{ CertFile: "willfail", }, }), }, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }), }, } // TLS is resolved during Start for HTTP. r, err := NewFactory().CreateTraces( context.Background(), receivertest.NewNopSettings(metadata.Type), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NotNil(t, r) assert.EqualError(t, r.Start(context.Background(), componenttest.NewNopHost()), `failed to load TLS config: failed to load TLS cert and key: for auth via TLS, provide both certificate and key, or neither`) } func testHTTPMaxRequestBodySize(t *testing.T, path, contentType string, payload []byte, size, expectedStatusCode int) { addr := testutil.GetAvailableLocalAddress(t) url := "http://" + addr + path cfg := &Config{ Protocols: Protocols{ HTTP: configoptional.Some(HTTPConfig{ ServerConfig: confighttp.ServerConfig{ Endpoint: addr, MaxRequestBodySize: int64(size), }, TracesURLPath: defaultTracesURLPath, MetricsURLPath: defaultMetricsURLPath, LogsURLPath: defaultLogsURLPath, }), }, } recv := newReceiver(t, componenttest.NewNopTelemetrySettings(), cfg, otlpReceiverID, consumertest.NewNop()) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) req := createHTTPRequest(t, url, "", contentType, payload) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) _, err = io.ReadAll(resp.Body) require.NoError(t, err) require.Equal(t, expectedStatusCode, resp.StatusCode) require.NoError(t, recv.Shutdown(context.Background())) } func TestHTTPMaxRequestBodySize(t *testing.T) { dataReqs := generateDataRequests(t) for _, dr := range dataReqs { testHTTPMaxRequestBodySize(t, dr.path, "application/json", dr.jsonBytes, len(dr.jsonBytes), 200) testHTTPMaxRequestBodySize(t, dr.path, "application/json", dr.jsonBytes, len(dr.jsonBytes)-1, 400) testHTTPMaxRequestBodySize(t, dr.path, "application/x-protobuf", dr.protoBytes, len(dr.protoBytes), 200) testHTTPMaxRequestBodySize(t, dr.path, "application/x-protobuf", dr.protoBytes, len(dr.protoBytes)-1, 400) } } func newGRPCReceiver(t *testing.T, settings component.TelemetrySettings, endpoint string, c consumertest.Consumer) component.Component { cfg := createDefaultConfig().(*Config) cfg.GRPC.GetOrInsertDefault().NetAddr.Endpoint = endpoint return newReceiver(t, settings, cfg, otlpReceiverID, c) } func newHTTPReceiver(t *testing.T, settings component.TelemetrySettings, endpoint string, c consumertest.Consumer) component.Component { cfg := createDefaultConfig().(*Config) cfg.HTTP.GetOrInsertDefault().ServerConfig.Endpoint = endpoint return newReceiver(t, settings, cfg, otlpReceiverID, c) } func newReceiver(t *testing.T, settings component.TelemetrySettings, cfg *Config, id component.ID, c consumertest.Consumer) component.Component { set := receivertest.NewNopSettings(metadata.Type) set.TelemetrySettings = settings set.ID = id r, err := newOtlpReceiver(cfg, &set) require.NoError(t, err) r.registerTraceConsumer(c) r.registerMetricsConsumer(c) r.registerLogsConsumer(c) r.registerProfilesConsumer(c) return r } type dataRequest struct { data any path string jsonBytes []byte protoBytes []byte } func generateDataRequests(t *testing.T) []dataRequest { return []dataRequest{generateTracesRequest(t), generateMetricsRequests(t), generateLogsRequest(t), generateProfilesRequest(t)} } func generateTracesRequest(t *testing.T) dataRequest { protoMarshaler := &ptrace.ProtoMarshaler{} jsonMarshaler := &ptrace.JSONMarshaler{} td := testdata.GenerateTraces(2) traceProto, err := protoMarshaler.MarshalTraces(td) require.NoError(t, err) traceJSON, err := jsonMarshaler.MarshalTraces(td) require.NoError(t, err) return dataRequest{data: td, path: defaultTracesURLPath, jsonBytes: traceJSON, protoBytes: traceProto} } func generateMetricsRequests(t *testing.T) dataRequest { protoMarshaler := &pmetric.ProtoMarshaler{} jsonMarshaler := &pmetric.JSONMarshaler{} md := testdata.GenerateMetrics(2) metricProto, err := protoMarshaler.MarshalMetrics(md) require.NoError(t, err) metricJSON, err := jsonMarshaler.MarshalMetrics(md) require.NoError(t, err) return dataRequest{data: md, path: defaultMetricsURLPath, jsonBytes: metricJSON, protoBytes: metricProto} } func generateLogsRequest(t *testing.T) dataRequest { protoMarshaler := &plog.ProtoMarshaler{} jsonMarshaler := &plog.JSONMarshaler{} ld := testdata.GenerateLogs(2) logProto, err := protoMarshaler.MarshalLogs(ld) require.NoError(t, err) logJSON, err := jsonMarshaler.MarshalLogs(ld) require.NoError(t, err) return dataRequest{data: ld, path: defaultLogsURLPath, jsonBytes: logJSON, protoBytes: logProto} } func generateProfilesRequest(t *testing.T) dataRequest { protoMarshaler := &pprofile.ProtoMarshaler{} jsonMarshaler := &pprofile.JSONMarshaler{} md := testdata.GenerateProfiles(2) profileProto, err := protoMarshaler.MarshalProfiles(md) require.NoError(t, err) profileJSON, err := jsonMarshaler.MarshalProfiles(md) require.NoError(t, err) return dataRequest{data: md, path: defaultProfilesURLPath, jsonBytes: profileJSON, protoBytes: profileProto} } func doHTTPRequest( t *testing.T, url string, encoding string, contentType string, data []byte, expectStatusCode int, ) []byte { req := createHTTPRequest(t, url, encoding, contentType, data) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) respBytes, err := io.ReadAll(resp.Body) require.NoError(t, err) require.NoError(t, resp.Body.Close()) // For cases like "application/json; charset=utf-8", the response will be only "application/json" require.True(t, strings.HasPrefix(strings.ToLower(contentType), resp.Header.Get("Content-Type"))) if expectStatusCode == 0 { require.Equal(t, http.StatusOK, resp.StatusCode) } else { require.Equal(t, expectStatusCode, resp.StatusCode) } return respBytes } func createHTTPRequest( t *testing.T, url string, encoding string, contentType string, data []byte, ) *http.Request { var buf *bytes.Buffer switch encoding { case "gzip": buf = compressGzip(t, data) case "zstd": buf = compressZstd(t, data) case "": buf = bytes.NewBuffer(data) default: t.Fatalf("Unsupported compression type %v", encoding) } req, err := http.NewRequest(http.MethodPost, url, buf) require.NoError(t, err) req.Header.Set("Content-Type", contentType) req.Header.Set("Content-Encoding", encoding) return req } func compressGzip(t *testing.T, body []byte) *bytes.Buffer { var buf bytes.Buffer gw := gzip.NewWriter(&buf) defer func() { require.NoError(t, gw.Close()) }() _, err := gw.Write(body) require.NoError(t, err) return &buf } func compressZstd(t *testing.T, body []byte) *bytes.Buffer { var buf bytes.Buffer zw, err := zstd.NewWriter(&buf) require.NoError(t, err) defer func() { require.NoError(t, zw.Close()) }() _, err = zw.Write(body) require.NoError(t, err) return &buf } type senderFunc func(td ptrace.Traces) func TestShutdown(t *testing.T) { endpointGrpc := testutil.GetAvailableLocalAddress(t) endpointHTTP := testutil.GetAvailableLocalAddress(t) nextSink := new(consumertest.TracesSink) // Create OTLP receiver with gRPC and HTTP protocols. factory := NewFactory() cfg := factory.CreateDefaultConfig().(*Config) cfg.GRPC.GetOrInsertDefault().NetAddr.Endpoint = endpointGrpc cfg.HTTP.GetOrInsertDefault().ServerConfig.Endpoint = endpointHTTP set := receivertest.NewNopSettings(metadata.Type) set.ID = otlpReceiverID r, err := NewFactory().CreateTraces( context.Background(), set, cfg, nextSink) require.NoError(t, err) require.NotNil(t, r) require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost())) conn, err := grpc.NewClient(endpointGrpc, grpc.WithTransportCredentials(insecure.NewCredentials())) require.NoError(t, err) t.Cleanup(func() { require.NoError(t, conn.Close()) }) doneSignalGrpc := make(chan bool) doneSignalHTTP := make(chan bool) senderGrpc := func(td ptrace.Traces) { // Ignore error, may be executed after the receiver shutdown. _ = exportTraces(conn, td) } senderHTTP := func(td ptrace.Traces) { // Send request via OTLP/HTTP. marshaler := &ptrace.ProtoMarshaler{} traceBytes, err2 := marshaler.MarshalTraces(td) require.NoError(t, err2) url := "http://" + endpointHTTP + defaultTracesURLPath req := createHTTPRequest(t, url, "", "application/x-protobuf", traceBytes) if resp, errResp := http.DefaultClient.Do(req); errResp == nil { require.NoError(t, resp.Body.Close()) } } // Send traces to the receiver until we signal via done channel, and then // send one more trace after that. go generateTraces(senderGrpc, doneSignalGrpc) go generateTraces(senderHTTP, doneSignalHTTP) // Wait until the receiver outputs anything to the sink. assert.Eventually(t, func() bool { return nextSink.SpanCount() > 0 }, time.Second, 10*time.Millisecond) // Now shutdown the receiver, while continuing sending traces to it. ctx, cancelFn := context.WithTimeout(context.Background(), 10*time.Second) defer cancelFn() require.NoError(t, r.Shutdown(ctx)) // Remember how many spans the sink received. This number should not change after this // point because after Shutdown() returns the component is not allowed to produce // any more data. sinkSpanCountAfterShutdown := nextSink.SpanCount() // Now signal to generateTraces to exit the main generation loop, then send // one more trace and stop. doneSignalGrpc <- true doneSignalHTTP <- true // Wait until all follow up traces are sent. <-doneSignalGrpc <-doneSignalHTTP // The last, additional trace should not be received by sink, so the number of spans in // the sink should not change. assert.Equal(t, sinkSpanCountAfterShutdown, nextSink.SpanCount()) } func generateTraces(senderFn senderFunc, doneSignal chan bool) { // Continuously generate spans until signaled to stop. loop: for { select { case <-doneSignal: break loop default: } senderFn(testdata.GenerateTraces(1)) } // After getting the signal to stop, send one more span and then // finally stop. We should never receive this last span. senderFn(testdata.GenerateTraces(1)) // Indicate that we are done. close(doneSignal) } func exportTraces(cc *grpc.ClientConn, td ptrace.Traces) error { acc := ptraceotlp.NewGRPCClient(cc) req := ptraceotlp.NewExportRequestFromTraces(td) _, err := acc.Export(context.Background(), req) return err } type errOrSinkConsumer struct { consumertest.Consumer *consumertest.TracesSink *consumertest.MetricsSink *consumertest.LogsSink *consumertest.ProfilesSink mu sync.Mutex consumeError error // to be returned by ConsumeTraces, if set } func newErrOrSinkConsumer() *errOrSinkConsumer { return &errOrSinkConsumer{ TracesSink: new(consumertest.TracesSink), MetricsSink: new(consumertest.MetricsSink), LogsSink: new(consumertest.LogsSink), ProfilesSink: new(consumertest.ProfilesSink), } } // SetConsumeError sets an error that will be returned by the Consume function. func (esc *errOrSinkConsumer) SetConsumeError(err error) { esc.mu.Lock() defer esc.mu.Unlock() esc.consumeError = err } func (esc *errOrSinkConsumer) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: false} } // ConsumeTraces stores traces to this sink. func (esc *errOrSinkConsumer) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { esc.mu.Lock() defer esc.mu.Unlock() if esc.consumeError != nil { return esc.consumeError } return esc.TracesSink.ConsumeTraces(ctx, td) } // ConsumeMetrics stores metrics to this sink. func (esc *errOrSinkConsumer) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { esc.mu.Lock() defer esc.mu.Unlock() if esc.consumeError != nil { return esc.consumeError } return esc.MetricsSink.ConsumeMetrics(ctx, md) } // ConsumeLogs stores metrics to this sink. func (esc *errOrSinkConsumer) ConsumeLogs(ctx context.Context, ld plog.Logs) error { esc.mu.Lock() defer esc.mu.Unlock() if esc.consumeError != nil { return esc.consumeError } return esc.LogsSink.ConsumeLogs(ctx, ld) } // ConsumeProfiles stores profiles to this sink. func (esc *errOrSinkConsumer) ConsumeProfiles(ctx context.Context, md pprofile.Profiles) error { esc.mu.Lock() defer esc.mu.Unlock() if esc.consumeError != nil { return esc.consumeError } return esc.ProfilesSink.ConsumeProfiles(ctx, md) } // Reset deletes any stored in the sinks, resets error to nil. func (esc *errOrSinkConsumer) Reset() { esc.mu.Lock() defer esc.mu.Unlock() esc.consumeError = nil esc.TracesSink.Reset() esc.MetricsSink.Reset() esc.LogsSink.Reset() esc.ProfilesSink.Reset() } // Reset deletes any stored in the sinks, resets error to nil. func (esc *errOrSinkConsumer) checkData(t *testing.T, data any, dataLen int) { switch data.(type) { case ptrace.Traces: allTraces := esc.AllTraces() require.Len(t, allTraces, dataLen) if dataLen > 0 { require.Equal(t, allTraces[0], data) } case pmetric.Metrics: allMetrics := esc.AllMetrics() require.Len(t, allMetrics, dataLen) if dataLen > 0 { require.Equal(t, allMetrics[0], data) } case plog.Logs: allLogs := esc.AllLogs() require.Len(t, allLogs, dataLen) if dataLen > 0 { require.Equal(t, allLogs[0], data) } case pprofile.Profiles: allProfiles := esc.AllProfiles() require.Len(t, allProfiles, dataLen) if dataLen > 0 { require.Equal(t, allProfiles[0], data) } } } func assertReceiverTraces(t *testing.T, tt *componenttest.Telemetry, id component.ID, transport string, accepted, rejected int64) { var refused, failed int64 var outcome string gateEnabled := receiverhelper.NewReceiverMetricsGate.IsEnabled() // The errors in the OTLP tests are not downstream, so they should be "failed" when the gate is enabled. if gateEnabled { failed = rejected outcome = "failure" } else { // When the gate is disabled, all errors are "refused". refused = rejected } got, err := tt.GetMetric("otelcol_receiver_failed_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_failed_spans", Description: "The number of spans that failed to be processed by the receiver due to internal errors. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport)), Value: failed, }, }, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) got, err = tt.GetMetric("otelcol_receiver_accepted_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_accepted_spans", Description: "Number of spans successfully pushed into the pipeline. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport)), Value: accepted, }, }, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) got, err = tt.GetMetric("otelcol_receiver_refused_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_refused_spans", Description: "Number of spans that could not be pushed into the pipeline. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport)), Value: refused, }, }, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) // Assert receiver_requests metric if gateEnabled { got, err := tt.GetMetric("otelcol_receiver_requests") require.NoError(t, err) // Calculate expected requests based on accepted and refused counts var expectedRequests []metricdata.DataPoint[int64] if accepted > 0 { expectedRequests = append(expectedRequests, metricdata.DataPoint[int64]{ Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport), attribute.String("outcome", "success")), Value: accepted, }) } if rejected > 0 { expectedRequests = append(expectedRequests, metricdata.DataPoint[int64]{ Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport), attribute.String("outcome", outcome)), Value: rejected, }) } metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_requests", Description: "The number of requests performed.", Unit: "{requests}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: expectedRequests, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } else { _, err := tt.GetMetric("otelcol_receiver_requests") require.Error(t, err) } } func assertReceiverMetrics(t *testing.T, tt *componenttest.Telemetry, id component.ID, transport string, accepted, rejected int64) { var refused, failed int64 var outcome string gateEnabled := receiverhelper.NewReceiverMetricsGate.IsEnabled() // The error used in the metrics test is not downstream. if gateEnabled { failed = rejected outcome = "failure" } else { // When the gate is disabled, all errors are "refused". refused = rejected } got, err := tt.GetMetric("otelcol_receiver_failed_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_failed_metric_points", Description: "The number of metric points that failed to be processed by the receiver due to internal errors. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport)), Value: failed, }, }, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) got, err = tt.GetMetric("otelcol_receiver_accepted_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_accepted_metric_points", Description: "Number of metric points successfully pushed into the pipeline. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport)), Value: accepted, }, }, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) got, err = tt.GetMetric("otelcol_receiver_refused_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_refused_metric_points", Description: "Number of metric points that could not be pushed into the pipeline. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport)), Value: refused, }, }, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) // Assert receiver_requests metric if gateEnabled { got, err := tt.GetMetric("otelcol_receiver_requests") require.NoError(t, err) // Calculate expected requests based on accepted and refused counts var expectedRequests []metricdata.DataPoint[int64] if accepted > 0 { expectedRequests = append(expectedRequests, metricdata.DataPoint[int64]{ Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport), attribute.String("outcome", "success")), Value: accepted, }) } if rejected > 0 { expectedRequests = append(expectedRequests, metricdata.DataPoint[int64]{ Attributes: attribute.NewSet( attribute.String("receiver", id.String()), attribute.String("transport", transport), attribute.String("outcome", outcome)), Value: 1, // One request failed }) } metricdatatest.AssertEqual(t, metricdata.Metrics{ Name: "otelcol_receiver_requests", Description: "The number of requests performed.", Unit: "{requests}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: expectedRequests, }, }, got, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } else { _, err := tt.GetMetric("otelcol_receiver_requests") require.Error(t, err) } } opentelemetry-collector-0.141.0/receiver/otlpreceiver/otlphttp.go000066400000000000000000000170231511331344600252550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver // import "go.opentelemetry.io/collector/receiver/otlpreceiver" import ( "fmt" "io" "mime" "net/http" "strconv" "time" "google.golang.org/grpc/status" "go.opentelemetry.io/collector/internal/statusutil" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/errors" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/logs" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/metrics" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/profiles" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/trace" ) // Pre-computed status with code=Internal to be used in case of a marshaling error. var fallbackMsg = []byte(`{"code": 13, "message": "failed to marshal error message"}`) const fallbackContentType = "application/json" func handleTraces(resp http.ResponseWriter, req *http.Request, tracesReceiver *trace.Receiver) { enc, ok := readContentType(resp, req) if !ok { return } body, ok := readAndCloseBody(resp, req, enc) if !ok { return } otlpReq, err := enc.unmarshalTracesRequest(body) if err != nil { writeError(resp, enc, err, http.StatusBadRequest) return } otlpResp, err := tracesReceiver.Export(req.Context(), otlpReq) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } msg, err := enc.marshalTracesResponse(otlpResp) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } writeResponse(resp, enc.contentType(), http.StatusOK, msg) } func handleMetrics(resp http.ResponseWriter, req *http.Request, metricsReceiver *metrics.Receiver) { enc, ok := readContentType(resp, req) if !ok { return } body, ok := readAndCloseBody(resp, req, enc) if !ok { return } otlpReq, err := enc.unmarshalMetricsRequest(body) if err != nil { writeError(resp, enc, err, http.StatusBadRequest) return } otlpResp, err := metricsReceiver.Export(req.Context(), otlpReq) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } msg, err := enc.marshalMetricsResponse(otlpResp) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } writeResponse(resp, enc.contentType(), http.StatusOK, msg) } func handleLogs(resp http.ResponseWriter, req *http.Request, logsReceiver *logs.Receiver) { enc, ok := readContentType(resp, req) if !ok { return } body, ok := readAndCloseBody(resp, req, enc) if !ok { return } otlpReq, err := enc.unmarshalLogsRequest(body) if err != nil { writeError(resp, enc, err, http.StatusBadRequest) return } otlpResp, err := logsReceiver.Export(req.Context(), otlpReq) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } msg, err := enc.marshalLogsResponse(otlpResp) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } writeResponse(resp, enc.contentType(), http.StatusOK, msg) } func handleProfiles(resp http.ResponseWriter, req *http.Request, profilesReceiver *profiles.Receiver) { enc, ok := readContentType(resp, req) if !ok { return } body, ok := readAndCloseBody(resp, req, enc) if !ok { return } otlpReq, err := enc.unmarshalProfilesRequest(body) if err != nil { writeError(resp, enc, err, http.StatusBadRequest) return } otlpResp, err := profilesReceiver.Export(req.Context(), otlpReq) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } msg, err := enc.marshalProfilesResponse(otlpResp) if err != nil { writeError(resp, enc, err, http.StatusInternalServerError) return } writeResponse(resp, enc.contentType(), http.StatusOK, msg) } func readContentType(resp http.ResponseWriter, req *http.Request) (encoder, bool) { if req.Method != http.MethodPost { handleUnmatchedMethod(resp) return nil, false } switch getMimeTypeFromContentType(req.Header.Get("Content-Type")) { case pbContentType: return pbEncoder, true case jsonContentType: return jsEncoder, true default: handleUnmatchedContentType(resp) return nil, false } } func readAndCloseBody(resp http.ResponseWriter, req *http.Request, enc encoder) ([]byte, bool) { body, err := io.ReadAll(req.Body) if err != nil { writeError(resp, enc, err, http.StatusBadRequest) return nil, false } if err = req.Body.Close(); err != nil { writeError(resp, enc, err, http.StatusBadRequest) return nil, false } return body, true } // writeError encodes the HTTP error inside a rpc.Status message as required by the OTLP protocol. func writeError(w http.ResponseWriter, encoder encoder, err error, statusCode int) { s, ok := status.FromError(err) if ok { statusCode = errors.GetHTTPStatusCodeFromStatus(s) } else { s = statusutil.NewStatusFromMsgAndHTTPCode(err.Error(), statusCode) } writeStatusResponse(w, encoder, statusCode, s) } // errorHandler encodes the HTTP error message inside a rpc.Status message as required // by the OTLP protocol. func errorHandler(w http.ResponseWriter, r *http.Request, errMsg string, statusCode int) { s := statusutil.NewStatusFromMsgAndHTTPCode(errMsg, statusCode) contentType := r.Header.Get("Content-Type") if contentType == "" { contentType = fallbackContentType } switch getMimeTypeFromContentType(contentType) { case pbContentType: writeStatusResponse(w, pbEncoder, statusCode, s) return case jsonContentType: writeStatusResponse(w, jsEncoder, statusCode, s) return } writeResponse(w, fallbackContentType, http.StatusInternalServerError, fallbackMsg) } func writeStatusResponse(w http.ResponseWriter, enc encoder, statusCode int, st *status.Status) { // https://github.com/open-telemetry/opentelemetry-proto/blob/main/docs/specification.md#otlphttp-throttling if statusCode == http.StatusTooManyRequests || statusCode == http.StatusServiceUnavailable { retryInfo := statusutil.GetRetryInfo(st) // Check if server returned throttling information. if retryInfo != nil { // We are throttled. Wait before retrying as requested by the server. // The value of Retry-After field can be either an HTTP-date or a number of // seconds to delay after the response is received. See https://datatracker.ietf.org/doc/html/rfc7231#section-7.1.3 // // Retry-After = HTTP-date / delay-seconds // // Use delay-seconds since is easier to format as well as does not require clock synchronization. w.Header().Set("Retry-After", strconv.FormatInt(int64(retryInfo.GetRetryDelay().AsDuration()/time.Second), 10)) } } msg, err := enc.marshalStatus(st.Proto()) if err != nil { writeResponse(w, fallbackContentType, http.StatusInternalServerError, fallbackMsg) return } writeResponse(w, enc.contentType(), statusCode, msg) } func writeResponse(w http.ResponseWriter, contentType string, statusCode int, msg []byte) { w.Header().Set("Content-Type", contentType) w.WriteHeader(statusCode) // Nothing we can do with the error if we cannot write to the response. _, _ = w.Write(msg) } func getMimeTypeFromContentType(contentType string) string { mediatype, _, err := mime.ParseMediaType(contentType) if err != nil { return "" } return mediatype } func handleUnmatchedMethod(resp http.ResponseWriter) { hst := http.StatusMethodNotAllowed writeResponse(resp, "text/plain", hst, fmt.Appendf(nil, "%v method not allowed, supported: [POST]", hst)) } func handleUnmatchedContentType(resp http.ResponseWriter) { hst := http.StatusUnsupportedMediaType writeResponse(resp, "text/plain", hst, fmt.Appendf(nil, "%v unsupported media type, supported: [%s, %s]", hst, jsonContentType, pbContentType)) } opentelemetry-collector-0.141.0/receiver/otlpreceiver/otlphttp_test.go000066400000000000000000000106221511331344600263120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otlpreceiver import ( "context" "io" "net/http" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/genproto/googleapis/rpc/errdetails" spb "google.golang.org/genproto/googleapis/rpc/status" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/durationpb" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/receiver/otlpreceiver/internal/errors" ) func TestHttpRetryAfter(t *testing.T) { tests := []struct { name string contentType string err error expectedStatusCode int expectedHasRetryAfter bool expectedRetryAfter string }{ { name: "StatusErrorRetryableNoRetryAfter", err: status.New(codes.DeadlineExceeded, "").Err(), expectedStatusCode: http.StatusServiceUnavailable, }, { name: "StatusErrorRetryableWithZeroRetryAfter", err: func() error { st := status.New(codes.ResourceExhausted, "") dt, err := st.WithDetails(&errdetails.RetryInfo{ RetryDelay: durationpb.New(0), }) require.NoError(t, err) return dt.Err() }(), expectedStatusCode: http.StatusTooManyRequests, expectedHasRetryAfter: true, expectedRetryAfter: "0", }, { name: "StatusErrorRetryableRetryAfter", err: func() error { st := status.New(codes.ResourceExhausted, "") dt, err := st.WithDetails(&errdetails.RetryInfo{ RetryDelay: durationpb.New(13 * time.Second), }) require.NoError(t, err) return dt.Err() }(), expectedStatusCode: http.StatusTooManyRequests, expectedHasRetryAfter: true, expectedRetryAfter: "13", }, { name: "StatusErrorNotRetryableRetryAfter", err: func() error { st := status.New(codes.Unknown, "") dt, err := st.WithDetails(&errdetails.RetryInfo{ RetryDelay: durationpb.New(12 * time.Second), }) require.NoError(t, err) return dt.Err() }(), expectedStatusCode: http.StatusInternalServerError, }, { name: "StatusErrorNotRetryableNoRetryAfter", err: status.New(codes.InvalidArgument, "").Err(), expectedStatusCode: http.StatusBadRequest, }, } addr := testutil.GetAvailableLocalAddress(t) // Set the buffer count to 1 to make it flush the test span immediately. sink := newErrOrSinkConsumer() recv := newHTTPReceiver(t, componenttest.NewNopTelemetrySettings(), addr, sink) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost()), "Failed to start trace receiver") t.Cleanup(func() { require.NoError(t, recv.Shutdown(context.Background())) }) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { sink.Reset() sink.SetConsumeError(tt.err) for _, dr := range generateDataRequests(t) { url := "http://" + addr + dr.path req := createHTTPRequest(t, url, "", "application/x-protobuf", dr.protoBytes) resp, err := http.DefaultClient.Do(req) require.NoError(t, err) respBytes, err := io.ReadAll(resp.Body) require.NoError(t, err) require.NoError(t, resp.Body.Close()) // For cases like "application/json; charset=utf-8", the response will be only "application/json" require.True(t, strings.HasPrefix(strings.ToLower("application/x-protobuf"), resp.Header.Get("Content-Type"))) if tt.expectedHasRetryAfter { require.Equal(t, tt.expectedRetryAfter, resp.Header.Get("Retry-After")) } else { require.Empty(t, resp.Header.Get("Retry-After")) } assert.Equal(t, tt.expectedStatusCode, resp.StatusCode) if tt.err == nil { tr := ptraceotlp.NewExportResponse() require.NoError(t, tr.UnmarshalProto(respBytes)) sink.checkData(t, dr.data, 1) } else { errStatus := &spb.Status{} require.NoError(t, proto.Unmarshal(respBytes, errStatus)) // The HTTP receiver transforms errors through GetStatusFromError // We need to get the expected transformed error, not the original expectedErr := errors.GetStatusFromError(tt.err) s, ok := status.FromError(expectedErr) require.True(t, ok) assert.True(t, proto.Equal(errStatus, s.Proto())) } } }) } } opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/000077500000000000000000000000001511331344600246565ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/bad_no_proto_config.yaml000066400000000000000000000000131511331344600315260ustar00rootroot00000000000000protocols: opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/bad_proto_config.yaml000066400000000000000000000000641511331344600310400ustar00rootroot00000000000000protocols: thrift: endpoint: "127.0.0.1:1234" opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/config.yaml000066400000000000000000000040301511331344600270040ustar00rootroot00000000000000protocols: grpc: # The following entry demonstrates how to specify TLS credentials for the server. # Note: These files do not exist. If the receiver is started with this configuration, it will fail. tls: cert_file: test.crt key_file: test.key # The following demonstrates how to set maximum limits on stream, message size and connection idle time. # Note: The test yaml has demonstrated configuration on a grouped by their structure; however, all of the settings can # be mix and matched like adding the maximum connection idle setting in this example. max_recv_msg_size_mib: 32 max_concurrent_streams: 16 read_buffer_size: 1024 write_buffer_size: 1024 # The following entry configures all of the keep alive settings. These settings are used to configure the receiver. keepalive: server_parameters: max_connection_idle: 11s max_connection_age: 12s max_connection_age_grace: 13s time: 30s timeout: 5s enforcement_policy: min_time: 10s permit_without_stream: true http: auth: authenticator: test # The following entry demonstrates how to specify TLS credentials for the server. # Note: These files do not exist. If the receiver is started with this configuration, it will fail. tls: cert_file: test.crt key_file: test.key # The following entry demonstrates how to configure the OTLP receiver to allow Cross-Origin Resource Sharing (CORS). # Both fully qualified domain names and the use of wildcards are supported. cors: allowed_origins: - https://*.test.com # Wildcard subdomain. Allows domains like https://www.test.com and https://foo.test.com but not https://wwwtest.com. - https://test.com # Fully qualified domain name. Allows https://test.com only. max_age: 7200 # The following shows URL paths for endpoints where signals are listened for bt the OTLP receiver traces_url_path: traces metrics_url_path: /v2/metrics logs_url_path: log/ingest opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/default.yaml000066400000000000000000000002611511331344600271650ustar00rootroot00000000000000# The following entry initializes the default OTLP receiver. # The full name of this receiver is `otlp` and can be referenced in pipelines by 'otlp'. protocols: grpc: http: opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/invalid_logs_path.yaml000066400000000000000000000000611511331344600312250ustar00rootroot00000000000000protocols: http: logs_url_path: ":invalid" opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/invalid_metrics_path.yaml000066400000000000000000000000641511331344600317320ustar00rootroot00000000000000protocols: http: metrics_url_path: ":invalid" opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/invalid_profiles_path.yaml000066400000000000000000000000651511331344600321100ustar00rootroot00000000000000protocols: http: profiles_url_path: ":invalid" opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/invalid_traces_path.yaml000066400000000000000000000000631511331344600315440ustar00rootroot00000000000000protocols: http: traces_url_path: ":invalid" opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/only_grpc.yaml000066400000000000000000000001471511331344600275400ustar00rootroot00000000000000# The following entry initializes the default OTLP receiver with only gRPC support. protocols: grpc: opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/only_http.yaml000066400000000000000000000001471511331344600275640ustar00rootroot00000000000000# The following entry initializes the default OTLP receiver with only http support. protocols: http: opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/only_http_empty_map.yaml000066400000000000000000000002231511331344600316320ustar00rootroot00000000000000# The following entry initializes the default OTLP receiver with only http support by setting it explicitly to an empty map. protocols: http: {} opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/only_http_null.yaml000066400000000000000000000002151511331344600306120ustar00rootroot00000000000000# The following entry initializes the default OTLP receiver with only http support by setting it explicitly to null. protocols: http: null opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/typo_default_proto_config.yaml000066400000000000000000000000621511331344600330070ustar00rootroot00000000000000# cspell:ignore htttp protocols: grpc: htttp: opentelemetry-collector-0.141.0/receiver/otlpreceiver/testdata/uds.yaml000066400000000000000000000003401511331344600263320ustar00rootroot00000000000000# The following entry demonstrates how to specify a Unix Domain Socket for the server. protocols: grpc: transport: unix endpoint: /tmp/grpc_otlp.sock http: # transport: unix endpoint: /tmp/http_otlp.sock opentelemetry-collector-0.141.0/receiver/package_test.go000066400000000000000000000003111511331344600233160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receiver import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/receiver.go000066400000000000000000000161161511331344600225020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receiver // import "go.opentelemetry.io/collector/receiver" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver/internal" ) // Traces receiver receives traces. // Its purpose is to translate data from any format to the collector's internal trace format. // Traces receiver feeds a consumer.Traces with data. // // For example, it could be Zipkin data source which translates Zipkin spans into ptrace.Traces. type Traces interface { component.Component } // Metrics receiver receives metrics. // Its purpose is to translate data from any format to the collector's internal metrics format. // Metrics receiver feeds a consumer.Metrics with data. // // For example, it could be Prometheus data source which translates Prometheus metrics into pmetric.Metrics. type Metrics interface { component.Component } // Logs receiver receives logs. // Its purpose is to translate data from any format to the collector's internal logs data format. // Logs receiver feeds a consumer.Logs with data. // // For example, it could be a receiver that reads syslogs and convert them into plog.Logs. type Logs interface { component.Component } // Settings configures receiver creators. type Settings struct { // ID returns the ID of the component that will be created. ID component.ID component.TelemetrySettings // BuildInfo can be used by components for informational purposes. BuildInfo component.BuildInfo // prevent unkeyed literal initialization _ struct{} } // Factory is a factory interface for receivers. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. type Factory interface { component.Factory // CreateTraces creates a Traces based on this config. // If the receiver type does not support traces, // this function returns the error [pipeline.ErrSignalNotSupported]. // Implementers can assume `next` is never nil. CreateTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Traces, error) // TracesStability gets the stability level of the Traces receiver. TracesStability() component.StabilityLevel // CreateMetrics creates a Metrics based on this config. // If the receiver type does not support metrics, // this function returns the error [pipeline.ErrSignalNotSupported]. // Implementers can assume `next` is never nil. CreateMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Metrics, error) // MetricsStability gets the stability level of the Metrics receiver. MetricsStability() component.StabilityLevel // CreateLogs creates a Logs based on this config. // If the receiver type does not support logs, // this function returns the error [pipeline.ErrSignalNotSupported]. // Implementers can assume `next` is never nil. CreateLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Logs, error) // LogsStability gets the stability level of the Logs receiver. LogsStability() component.StabilityLevel unexportedFactoryFunc() } // FactoryOption apply changes to Factory. type FactoryOption interface { // applyOption applies the option. applyOption(o *factory) } // factoryOptionFunc is an FactoryOption created through a function. type factoryOptionFunc func(*factory) func (f factoryOptionFunc) applyOption(o *factory) { f(o) } // CreateTracesFunc is the equivalent of Factory.CreateTraces. type CreateTracesFunc func(context.Context, Settings, component.Config, consumer.Traces) (Traces, error) // CreateMetricsFunc is the equivalent of Factory.CreateMetrics. type CreateMetricsFunc func(context.Context, Settings, component.Config, consumer.Metrics) (Metrics, error) // CreateLogsFunc is the equivalent of Factory.CreateLogs. type CreateLogsFunc func(context.Context, Settings, component.Config, consumer.Logs) (Logs, error) type factory struct { cfgType component.Type component.CreateDefaultConfigFunc createTracesFunc CreateTracesFunc tracesStabilityLevel component.StabilityLevel createMetricsFunc CreateMetricsFunc metricsStabilityLevel component.StabilityLevel createLogsFunc CreateLogsFunc logsStabilityLevel component.StabilityLevel } func (f *factory) Type() component.Type { return f.cfgType } func (f *factory) unexportedFactoryFunc() {} func (f *factory) TracesStability() component.StabilityLevel { return f.tracesStabilityLevel } func (f *factory) MetricsStability() component.StabilityLevel { return f.metricsStabilityLevel } func (f *factory) LogsStability() component.StabilityLevel { return f.logsStabilityLevel } func (f *factory) CreateTraces(ctx context.Context, set Settings, cfg component.Config, next consumer.Traces) (Traces, error) { if f.createTracesFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createTracesFunc(ctx, set, cfg, next) } func (f *factory) CreateMetrics(ctx context.Context, set Settings, cfg component.Config, next consumer.Metrics) (Metrics, error) { if f.createMetricsFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createMetricsFunc(ctx, set, cfg, next) } func (f *factory) CreateLogs(ctx context.Context, set Settings, cfg component.Config, next consumer.Logs) (Logs, error) { if f.createLogsFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createLogsFunc(ctx, set, cfg, next) } // WithTraces overrides the default "error not supported" implementation for Factory.CreateTraces and the default "undefined" stability level. func WithTraces(createTraces CreateTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.tracesStabilityLevel = sl o.createTracesFunc = createTraces }) } // WithMetrics overrides the default "error not supported" implementation for Factory.CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.metricsStabilityLevel = sl o.createMetricsFunc = createMetrics }) } // WithLogs overrides the default "error not supported" implementation for Factory.CreateLogs and the default "undefined" stability level. func WithLogs(createLogs CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.logsStabilityLevel = sl o.createLogsFunc = createLogs }) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { f := &factory{ cfgType: cfgType, CreateDefaultConfigFunc: createDefaultConfig, } for _, opt := range options { opt.applyOption(f) } return f } opentelemetry-collector-0.141.0/receiver/receiver_test.go000066400000000000000000000064411511331344600235410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receiver import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver/internal" ) var ( testType = component.MustNewType("test") testID = component.NewID(testType) ) func TestNewFactory(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) _, err := f.CreateTraces(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) _, err = f.CreateMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) _, err = f.CreateLogs(context.Background(), Settings{ID: testID}, &defaultCfg, consumertest.NewNop()) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) } func TestNewFactoryWithOptions(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }, WithTraces(createTraces, component.StabilityLevelDeprecated), WithMetrics(createMetrics, component.StabilityLevelAlpha), WithLogs(createLogs, component.StabilityLevelStable)) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) wrongID := component.MustNewID("wrong") wrongIDErrStr := internal.ErrIDMismatch(wrongID, testType).Error() assert.Equal(t, component.StabilityLevelDeprecated, f.TracesStability()) _, err := f.CreateTraces(context.Background(), Settings{ID: testID}, &defaultCfg, nil) require.NoError(t, err) _, err = f.CreateTraces(context.Background(), Settings{ID: wrongID}, &defaultCfg, nil) require.EqualError(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelAlpha, f.MetricsStability()) _, err = f.CreateMetrics(context.Background(), Settings{ID: testID}, &defaultCfg, nil) require.NoError(t, err) _, err = f.CreateMetrics(context.Background(), Settings{ID: wrongID}, &defaultCfg, nil) require.EqualError(t, err, wrongIDErrStr) assert.Equal(t, component.StabilityLevelStable, f.LogsStability()) _, err = f.CreateLogs(context.Background(), Settings{ID: testID}, &defaultCfg, nil) require.NoError(t, err) _, err = f.CreateLogs(context.Background(), Settings{ID: wrongID}, &defaultCfg, nil) require.EqualError(t, err, wrongIDErrStr) } var nopInstance = &nopReceiver{ Consumer: consumertest.NewNop(), } // nopReceiver stores consumed traces and metrics for testing purposes. type nopReceiver struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createTraces(context.Context, Settings, component.Config, consumer.Traces) (Traces, error) { return nopInstance, nil } func createMetrics(context.Context, Settings, component.Config, consumer.Metrics) (Metrics, error) { return nopInstance, nil } func createLogs(context.Context, Settings, component.Config, consumer.Logs) (Logs, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/receiver/receiverhelper/000077500000000000000000000000001511331344600233465ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/receiverhelper/Makefile000066400000000000000000000000361511331344600250050ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/receiver/receiverhelper/documentation.md000066400000000000000000000060631511331344600265460ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # receiverhelper ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_receiver_accepted_log_records Number of log records successfully pushed into the pipeline. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Alpha | ### otelcol_receiver_accepted_metric_points Number of metric points successfully pushed into the pipeline. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_receiver_accepted_spans Number of spans successfully pushed into the pipeline. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Alpha | ### otelcol_receiver_failed_log_records The number of log records that failed to be processed by the receiver due to internal errors. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Alpha | ### otelcol_receiver_failed_metric_points The number of metric points that failed to be processed by the receiver due to internal errors. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_receiver_failed_spans The number of spans that failed to be processed by the receiver due to internal errors. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Alpha | ### otelcol_receiver_refused_log_records Number of log records that could not be pushed into the pipeline. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {records} | Sum | Int | true | Alpha | ### otelcol_receiver_refused_metric_points Number of metric points that could not be pushed into the pipeline. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_receiver_refused_spans Number of spans that could not be pushed into the pipeline. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {spans} | Sum | Int | true | Alpha | ### otelcol_receiver_requests The number of requests performed. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {requests} | Sum | Int | true | Alpha | #### Attributes | Name | Description | Values | | ---- | ----------- | ------ | | outcome | The outcome of receiver requests | Str: ``success``, ``refused``, ``failure`` | opentelemetry-collector-0.141.0/receiver/receiverhelper/featuregates.go000066400000000000000000000015561511331344600263630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receiverhelper // import "go.opentelemetry.io/collector/receiver/receiverhelper" import "go.opentelemetry.io/collector/featuregate" // NewReceiverMetricsGate is the feature gate that controls whether to distinguish downstream errors from internal errors in pipeline telemetry. var NewReceiverMetricsGate = featuregate.GlobalRegistry().MustRegister( "receiverhelper.newReceiverMetrics", featuregate.StageAlpha, featuregate.WithRegisterFromVersion("v0.138.0"), featuregate.WithRegisterDescription("Controls whether receivers emit new metrics and span attributes to distinguish downstream errors from internal errors. This is a breaking change for the semantics of the otelcol_receiver_refused_metric_points, otelcol_receiver_refused_log_records and otelcol_receiver_refused_spans."), ) opentelemetry-collector-0.141.0/receiver/receiverhelper/generated_package_test.go000066400000000000000000000002551511331344600303470ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package receiverhelper import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/receiverhelper/go.mod000066400000000000000000000052751511331344600244650ustar00rootroot00000000000000module go.opentelemetry.io/collector/receiver/receiverhelper go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/consumer v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/receiver => ../ replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/receiver/receiverhelper/go.sum000066400000000000000000000157461511331344600245160ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/000077500000000000000000000000001511331344600251625ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/metadata/000077500000000000000000000000001511331344600267425ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/metadata/generated_telemetry.go000066400000000000000000000116371511331344600333310ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/receiver/receiverhelper") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/receiver/receiverhelper") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration ReceiverAcceptedLogRecords metric.Int64Counter ReceiverAcceptedMetricPoints metric.Int64Counter ReceiverAcceptedSpans metric.Int64Counter ReceiverFailedLogRecords metric.Int64Counter ReceiverFailedMetricPoints metric.Int64Counter ReceiverFailedSpans metric.Int64Counter ReceiverRefusedLogRecords metric.Int64Counter ReceiverRefusedMetricPoints metric.Int64Counter ReceiverRefusedSpans metric.Int64Counter ReceiverRequests metric.Int64Counter } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.ReceiverAcceptedLogRecords, err = builder.meter.Int64Counter( "otelcol_receiver_accepted_log_records", metric.WithDescription("Number of log records successfully pushed into the pipeline. [Alpha]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ReceiverAcceptedMetricPoints, err = builder.meter.Int64Counter( "otelcol_receiver_accepted_metric_points", metric.WithDescription("Number of metric points successfully pushed into the pipeline. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ReceiverAcceptedSpans, err = builder.meter.Int64Counter( "otelcol_receiver_accepted_spans", metric.WithDescription("Number of spans successfully pushed into the pipeline. [Alpha]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) builder.ReceiverFailedLogRecords, err = builder.meter.Int64Counter( "otelcol_receiver_failed_log_records", metric.WithDescription("The number of log records that failed to be processed by the receiver due to internal errors. [Alpha]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ReceiverFailedMetricPoints, err = builder.meter.Int64Counter( "otelcol_receiver_failed_metric_points", metric.WithDescription("The number of metric points that failed to be processed by the receiver due to internal errors. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ReceiverFailedSpans, err = builder.meter.Int64Counter( "otelcol_receiver_failed_spans", metric.WithDescription("The number of spans that failed to be processed by the receiver due to internal errors. [Alpha]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) builder.ReceiverRefusedLogRecords, err = builder.meter.Int64Counter( "otelcol_receiver_refused_log_records", metric.WithDescription("Number of log records that could not be pushed into the pipeline. [Alpha]"), metric.WithUnit("{records}"), ) errs = errors.Join(errs, err) builder.ReceiverRefusedMetricPoints, err = builder.meter.Int64Counter( "otelcol_receiver_refused_metric_points", metric.WithDescription("Number of metric points that could not be pushed into the pipeline. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ReceiverRefusedSpans, err = builder.meter.Int64Counter( "otelcol_receiver_refused_spans", metric.WithDescription("Number of spans that could not be pushed into the pipeline. [Alpha]"), metric.WithUnit("{spans}"), ) errs = errors.Join(errs, err) builder.ReceiverRequests, err = builder.meter.Int64Counter( "otelcol_receiver_requests", metric.WithDescription("The number of requests performed. [Alpha]"), metric.WithUnit("{requests}"), ) errs = errors.Join(errs, err) return &builder, errs } generated_telemetry_test.go000066400000000000000000000035011511331344600343000ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/metadata// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/receiver/receiverhelper", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/receiver/receiverhelper", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/metadatatest/000077500000000000000000000000001511331344600276425ustar00rootroot00000000000000generated_telemetrytest.go000066400000000000000000000147171511331344600350540ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" ) func AssertEqualReceiverAcceptedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_accepted_log_records", Description: "Number of log records successfully pushed into the pipeline. [Alpha]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_accepted_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverAcceptedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_accepted_metric_points", Description: "Number of metric points successfully pushed into the pipeline. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_accepted_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverAcceptedSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_accepted_spans", Description: "Number of spans successfully pushed into the pipeline. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_accepted_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverFailedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_failed_log_records", Description: "The number of log records that failed to be processed by the receiver due to internal errors. [Alpha]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_failed_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverFailedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_failed_metric_points", Description: "The number of metric points that failed to be processed by the receiver due to internal errors. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_failed_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverFailedSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_failed_spans", Description: "The number of spans that failed to be processed by the receiver due to internal errors. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_failed_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverRefusedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_refused_log_records", Description: "Number of log records that could not be pushed into the pipeline. [Alpha]", Unit: "{records}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_refused_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverRefusedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_refused_metric_points", Description: "Number of metric points that could not be pushed into the pipeline. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_refused_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverRefusedSpans(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_refused_spans", Description: "Number of spans that could not be pushed into the pipeline. [Alpha]", Unit: "{spans}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_refused_spans") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverRequests(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_receiver_requests", Description: "The number of requests performed. [Alpha]", Unit: "{requests}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_receiver_requests") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } generated_telemetrytest_test.go000066400000000000000000000047241511331344600361100ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/receiver/receiverhelper/internal/metadata" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() tb.ReceiverAcceptedLogRecords.Add(context.Background(), 1) tb.ReceiverAcceptedMetricPoints.Add(context.Background(), 1) tb.ReceiverAcceptedSpans.Add(context.Background(), 1) tb.ReceiverFailedLogRecords.Add(context.Background(), 1) tb.ReceiverFailedMetricPoints.Add(context.Background(), 1) tb.ReceiverFailedSpans.Add(context.Background(), 1) tb.ReceiverRefusedLogRecords.Add(context.Background(), 1) tb.ReceiverRefusedMetricPoints.Add(context.Background(), 1) tb.ReceiverRefusedSpans.Add(context.Background(), 1) tb.ReceiverRequests.Add(context.Background(), 1) AssertEqualReceiverAcceptedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverAcceptedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverAcceptedSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverFailedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverFailedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverFailedSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverRefusedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverRefusedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverRefusedSpans(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverRequests(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/receiver/receiverhelper/internal/obsmetrics.go000066400000000000000000000036431511331344600276710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package internal // import "go.opentelemetry.io/collector/receiver/receiverhelper/internal" const ( // SpanNameSep is duplicate between receiver and exporter. SpanNameSep = "/" // ReceiverKey used to identify receivers in metrics and traces. ReceiverKey = "receiver" // TransportKey used to identify the transport used to received the data. TransportKey = "transport" // FormatKey used to identify the format of the data received. FormatKey = "format" // AcceptedSpansKey used to identify spans accepted by the Collector. AcceptedSpansKey = "accepted_spans" // RefusedSpansKey used to identify spans refused (ie.: not ingested) by the Collector. RefusedSpansKey = "refused_spans" // FailedSpansKey used to identify spans failed to be processed by the Collector. FailedSpansKey = "failed_spans" // AcceptedMetricPointsKey used to identify metric points accepted by the Collector. AcceptedMetricPointsKey = "accepted_metric_points" // RefusedMetricPointsKey used to identify metric points refused (ie.: not ingested) by the // Collector. RefusedMetricPointsKey = "refused_metric_points" // FailedMetricPointKey used to identify metric points failed to be processed by the Collector. FailedMetricPointsKey = "failed_metric_points" // AcceptedLogRecordsKey used to identify log records accepted by the Collector. AcceptedLogRecordsKey = "accepted_log_records" // RefusedLogRecordsKey used to identify log records refused (ie.: not ingested) by the // Collector. RefusedLogRecordsKey = "refused_log_records" // FailedLogRecordsKey used to identify log records failed to be processed by the Collector. FailedLogRecordsKey = "failed_log_records" ReceiveTraceDataOperationSuffix = SpanNameSep + "TraceDataReceived" ReceiverMetricsOperationSuffix = SpanNameSep + "MetricsReceived" ReceiverLogsOperationSuffix = SpanNameSep + "LogsReceived" ) opentelemetry-collector-0.141.0/receiver/receiverhelper/metadata.yaml000066400000000000000000000056521511331344600260220ustar00rootroot00000000000000type: receiverhelper github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg stability: beta: [metrics, traces, logs] telemetry: metrics: receiver_accepted_log_records: enabled: true stability: level: alpha description: Number of log records successfully pushed into the pipeline. unit: "{records}" sum: value_type: int monotonic: true receiver_accepted_metric_points: stability: level: alpha enabled: true description: Number of metric points successfully pushed into the pipeline. unit: "{datapoints}" sum: value_type: int monotonic: true receiver_accepted_spans: enabled: true stability: level: alpha description: Number of spans successfully pushed into the pipeline. unit: "{spans}" sum: value_type: int monotonic: true receiver_failed_log_records: enabled: true stability: level: alpha description: The number of log records that failed to be processed by the receiver due to internal errors. unit: "{records}" sum: value_type: int monotonic: true receiver_failed_metric_points: enabled: true stability: level: alpha description: The number of metric points that failed to be processed by the receiver due to internal errors. unit: "{datapoints}" sum: value_type: int monotonic: true receiver_failed_spans: enabled: true stability: level: alpha description: The number of spans that failed to be processed by the receiver due to internal errors. unit: "{spans}" sum: value_type: int monotonic: true receiver_refused_log_records: enabled: true stability: level: alpha description: Number of log records that could not be pushed into the pipeline. unit: "{records}" sum: value_type: int monotonic: true receiver_refused_metric_points: enabled: true stability: level: alpha description: Number of metric points that could not be pushed into the pipeline. unit: "{datapoints}" sum: value_type: int monotonic: true receiver_refused_spans: enabled: true stability: level: alpha description: Number of spans that could not be pushed into the pipeline. unit: "{spans}" sum: value_type: int monotonic: true receiver_requests: enabled: true stability: level: alpha description: The number of requests performed. unit: "{requests}" sum: value_type: int monotonic: true attributes: - outcome attributes: outcome: description: The outcome of receiver requests type: string enum: - success - refused - failure opentelemetry-collector-0.141.0/receiver/receiverhelper/obsreport.go000066400000000000000000000207671511331344600257300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package receiverhelper // import "go.opentelemetry.io/collector/receiver/receiverhelper" import ( "context" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receiverhelper/internal" "go.opentelemetry.io/collector/receiver/receiverhelper/internal/metadata" ) // ObsReport is a helper to add observability to a receiver. type ObsReport struct { spanNamePrefix string transport string longLivedCtx bool tracer trace.Tracer otelAttrs metric.MeasurementOption telemetryBuilder *metadata.TelemetryBuilder } // ObsReportSettings are settings for creating an ObsReport. type ObsReportSettings struct { ReceiverID component.ID Transport string // LongLivedCtx when true indicates that the context passed in the call // outlives the individual receive operation. // Typically the long lived context is associated to a connection, // eg.: a gRPC stream, for which many batches of data are received in individual // operations without a corresponding new context per operation. LongLivedCtx bool ReceiverCreateSettings receiver.Settings // prevent unkeyed literal initialization _ struct{} } // NewObsReport creates a new ObsReport. func NewObsReport(cfg ObsReportSettings) (*ObsReport, error) { return newReceiver(cfg) } func newReceiver(cfg ObsReportSettings) (*ObsReport, error) { telemetryBuilder, err := metadata.NewTelemetryBuilder(cfg.ReceiverCreateSettings.TelemetrySettings) if err != nil { return nil, err } return &ObsReport{ spanNamePrefix: internal.ReceiverKey + internal.SpanNameSep + cfg.ReceiverID.String(), transport: cfg.Transport, longLivedCtx: cfg.LongLivedCtx, tracer: cfg.ReceiverCreateSettings.TracerProvider.Tracer(cfg.ReceiverID.String()), otelAttrs: metric.WithAttributeSet(attribute.NewSet( attribute.String(internal.ReceiverKey, cfg.ReceiverID.String()), attribute.String(internal.TransportKey, cfg.Transport), )), telemetryBuilder: telemetryBuilder, }, nil } // StartTracesOp is called when a request is received from a client. // The returned context should be used in other calls to the obsreport functions // dealing with the same receive operation. func (rec *ObsReport) StartTracesOp(operationCtx context.Context) context.Context { return rec.startOp(operationCtx, internal.ReceiveTraceDataOperationSuffix) } // EndTracesOp completes the receive operation that was started with // StartTracesOp. func (rec *ObsReport) EndTracesOp( receiverCtx context.Context, format string, numReceivedSpans int, err error, ) { rec.endOp(receiverCtx, format, numReceivedSpans, err, pipeline.SignalTraces) } // StartLogsOp is called when a request is received from a client. // The returned context should be used in other calls to the obsreport functions // dealing with the same receive operation. func (rec *ObsReport) StartLogsOp(operationCtx context.Context) context.Context { return rec.startOp(operationCtx, internal.ReceiverLogsOperationSuffix) } // EndLogsOp completes the receive operation that was started with // StartLogsOp. func (rec *ObsReport) EndLogsOp( receiverCtx context.Context, format string, numReceivedLogRecords int, err error, ) { rec.endOp(receiverCtx, format, numReceivedLogRecords, err, pipeline.SignalLogs) } // StartMetricsOp is called when a request is received from a client. // The returned context should be used in other calls to the obsreport functions // dealing with the same receive operation. func (rec *ObsReport) StartMetricsOp(operationCtx context.Context) context.Context { return rec.startOp(operationCtx, internal.ReceiverMetricsOperationSuffix) } // EndMetricsOp completes the receive operation that was started with // StartMetricsOp. func (rec *ObsReport) EndMetricsOp( receiverCtx context.Context, format string, numReceivedPoints int, err error, ) { rec.endOp(receiverCtx, format, numReceivedPoints, err, pipeline.SignalMetrics) } // startOp creates the span used to trace the operation. Returning // the updated context with the created span. func (rec *ObsReport) startOp(receiverCtx context.Context, operationSuffix string) context.Context { var ctx context.Context var span trace.Span spanName := rec.spanNamePrefix + operationSuffix if !rec.longLivedCtx { ctx, span = rec.tracer.Start(receiverCtx, spanName) } else { // Since the receiverCtx is long lived do not use it to start the span. // This way this trace ends when the EndTracesOp is called. // Here is safe to ignore the returned context since it is not used below. _, span = rec.tracer.Start(context.Background(), spanName, trace.WithLinks(trace.Link{ SpanContext: trace.SpanContextFromContext(receiverCtx), })) ctx = trace.ContextWithSpan(receiverCtx, span) } if rec.transport != "" { span.SetAttributes(attribute.String(internal.TransportKey, rec.transport)) } return ctx } // endOp records the observability signals at the end of an operation. func (rec *ObsReport) endOp( receiverCtx context.Context, format string, numReceivedItems int, err error, signal pipeline.Signal, ) { numAccepted := numReceivedItems numRefused := 0 numFailedErrors := 0 if err != nil { numAccepted = 0 // If gate is enabled, we distinguish between refused and failed. if NewReceiverMetricsGate.IsEnabled() { if consumererror.IsDownstream(err) { numRefused = numReceivedItems } else { numFailedErrors = numReceivedItems } } else { // When the gate is disabled, all errors are considered "refused". numRefused = numReceivedItems } } span := trace.SpanFromContext(receiverCtx) rec.recordMetrics(receiverCtx, signal, numAccepted, numRefused, numFailedErrors) // The new otelcol_receiver_requests metric is only emitted when the feature gate is enabled. if NewReceiverMetricsGate.IsEnabled() { var outcome string switch { case err == nil: outcome = "success" case consumererror.IsDownstream(err): outcome = "refused" default: outcome = "failure" } rec.telemetryBuilder.ReceiverRequests.Add(receiverCtx, 1, rec.otelAttrs, metric.WithAttributeSet(attribute.NewSet(attribute.String("outcome", outcome)))) } // end span according to errors if span.IsRecording() { var acceptedItemsKey, refusedItemsKey, failedItemsKey string switch signal { case pipeline.SignalTraces: acceptedItemsKey = internal.AcceptedSpansKey refusedItemsKey = internal.RefusedSpansKey failedItemsKey = internal.FailedSpansKey case pipeline.SignalMetrics: acceptedItemsKey = internal.AcceptedMetricPointsKey refusedItemsKey = internal.RefusedMetricPointsKey failedItemsKey = internal.FailedMetricPointsKey case pipeline.SignalLogs: acceptedItemsKey = internal.AcceptedLogRecordsKey refusedItemsKey = internal.RefusedLogRecordsKey failedItemsKey = internal.FailedLogRecordsKey } span.SetAttributes( attribute.String(internal.FormatKey, format), attribute.Int64(acceptedItemsKey, int64(numAccepted)), attribute.Int64(refusedItemsKey, int64(numRefused)), attribute.Int64(failedItemsKey, int64(numFailedErrors)), ) if err != nil { span.SetStatus(codes.Error, err.Error()) } } span.End() } func (rec *ObsReport) recordMetrics(receiverCtx context.Context, signal pipeline.Signal, numAccepted, numRefused, numFailedErrors int) { var acceptedMeasure, refusedMeasure, failedMeasure metric.Int64Counter switch signal { case pipeline.SignalTraces: acceptedMeasure = rec.telemetryBuilder.ReceiverAcceptedSpans refusedMeasure = rec.telemetryBuilder.ReceiverRefusedSpans failedMeasure = rec.telemetryBuilder.ReceiverFailedSpans case pipeline.SignalMetrics: acceptedMeasure = rec.telemetryBuilder.ReceiverAcceptedMetricPoints refusedMeasure = rec.telemetryBuilder.ReceiverRefusedMetricPoints failedMeasure = rec.telemetryBuilder.ReceiverFailedMetricPoints case pipeline.SignalLogs: acceptedMeasure = rec.telemetryBuilder.ReceiverAcceptedLogRecords refusedMeasure = rec.telemetryBuilder.ReceiverRefusedLogRecords failedMeasure = rec.telemetryBuilder.ReceiverFailedLogRecords } acceptedMeasure.Add(receiverCtx, int64(numAccepted), rec.otelAttrs) refusedMeasure.Add(receiverCtx, int64(numRefused), rec.otelAttrs) failedMeasure.Add(receiverCtx, int64(numFailedErrors), rec.otelAttrs) } opentelemetry-collector-0.141.0/receiver/receiverhelper/obsreport_test.go000066400000000000000000000624131511331344600267610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receiverhelper import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receiverhelper/internal" "go.opentelemetry.io/collector/receiver/receiverhelper/internal/metadatatest" ) const ( transport = "fakeTransport" format = "fakeFormat" ) var ( receiverID = component.MustNewID("fakeReceiver") errFake = errors.New("errFake") ) type testParams struct { items int err error } func TestReceiveTraceDataOp(t *testing.T) { originalState := NewReceiverMetricsGate.IsEnabled() t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), originalState)) }) for _, tc := range []struct { name string enabled bool }{{"gate_enabled", true}, {"gate_disabled", false}} { t.Run(tc.name, func(t *testing.T) { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), tc.enabled)) testTelemetry(t, func(t *testing.T, tt *componenttest.Telemetry) { parentCtx, parentSpan := tt.NewTelemetrySettings().TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() params := []testParams{ {items: 13, err: consumererror.NewDownstream(errFake)}, {items: 42, err: nil}, {items: 7, err: errors.New("non-downstream error")}, // Regular error to test numFailedErrors path } for i, param := range params { rec, err := newReceiver(ObsReportSettings{ ReceiverID: receiverID, Transport: transport, ReceiverCreateSettings: receiver.Settings{ID: receiverID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, }) require.NoError(t, err) ctx := rec.StartTracesOp(parentCtx) assert.NotNil(t, ctx) rec.EndTracesOp(ctx, format, params[i].items, param.err) } spans := tt.SpanRecorder.Ended() require.Len(t, spans, len(params)) var acceptedSpans, refusedSpans, failedSpans int for i, span := range spans { assert.Equal(t, "receiver/"+receiverID.String()+"/TraceDataReceived", span.Name()) err := params[i].err if err == nil { acceptedSpans += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedSpansKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedSpansKey, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedSpansKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Unset, span.Status().Code) } else { isDownstream := consumererror.IsDownstream(err) if !tc.enabled || (tc.enabled && isDownstream) { refusedSpans += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedSpansKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedSpansKey, Value: attribute.Int64Value(0)}) } else { failedSpans += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedSpansKey, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedSpansKey, Value: attribute.Int64Value(int64(params[i].items))}) } require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedSpansKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, err.Error(), span.Status().Description) } } metadatatest.AssertEqualReceiverAcceptedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(acceptedSpans), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverRefusedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(refusedSpans), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverFailedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(failedSpans), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) // Assert otelcol_receiver_requests metric with outcome attribute if tc.enabled { outcomes := make(map[string]int64) for _, param := range params { var outcome string switch { case param.err == nil: outcome = "success" case consumererror.IsDownstream(param.err): outcome = "refused" default: outcome = "failure" } outcomes[outcome]++ } var expectedRequests []metricdata.DataPoint[int64] for outcome, count := range outcomes { expectedRequests = append(expectedRequests, metricdata.DataPoint[int64]{ Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport), attribute.String("outcome", outcome)), Value: count, }) } metadatatest.AssertEqualReceiverRequests(t, tt, expectedRequests, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } }) }) } } func TestReceiveLogsOp(t *testing.T) { originalState := NewReceiverMetricsGate.IsEnabled() t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), originalState)) }) for _, tc := range []struct { name string enabled bool }{{"gate_enabled", true}, {"gate_disabled", false}} { t.Run(tc.name, func(t *testing.T) { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), tc.enabled)) testTelemetry(t, func(t *testing.T, tt *componenttest.Telemetry) { parentCtx, parentSpan := tt.NewTelemetrySettings().TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() params := []testParams{ {items: 13, err: consumererror.NewDownstream(errFake)}, {items: 42, err: nil}, {items: 7, err: errors.New("non-downstream error")}, } for i, param := range params { rec, err := newReceiver(ObsReportSettings{ ReceiverID: receiverID, Transport: transport, ReceiverCreateSettings: receiver.Settings{ID: receiverID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, }) require.NoError(t, err) ctx := rec.StartLogsOp(parentCtx) assert.NotNil(t, ctx) rec.EndLogsOp(ctx, format, params[i].items, param.err) } spans := tt.SpanRecorder.Ended() require.Len(t, spans, len(params)) var acceptedLogRecords, refusedLogRecords, failedLogRecords int for i, span := range spans { assert.Equal(t, "receiver/"+receiverID.String()+"/LogsReceived", span.Name()) err := params[i].err if err == nil { acceptedLogRecords += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedLogRecordsKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedLogRecordsKey, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedLogRecordsKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Unset, span.Status().Code) } else { isDownstream := consumererror.IsDownstream(err) if !tc.enabled || (tc.enabled && isDownstream) { refusedLogRecords += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedLogRecordsKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedLogRecordsKey, Value: attribute.Int64Value(0)}) } else { failedLogRecords += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedLogRecordsKey, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedLogRecordsKey, Value: attribute.Int64Value(int64(params[i].items))}) } require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedLogRecordsKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, err.Error(), span.Status().Description) } } metadatatest.AssertEqualReceiverAcceptedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(acceptedLogRecords), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverRefusedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(refusedLogRecords), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverFailedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(failedLogRecords), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) // Assert otelcol_receiver_requests metric with outcome attribute if tc.enabled { outcomes := make(map[string]int64) for _, param := range params { var outcome string switch { case param.err == nil: outcome = "success" case consumererror.IsDownstream(param.err): outcome = "refused" default: outcome = "failure" } outcomes[outcome]++ } var expectedRequests []metricdata.DataPoint[int64] for outcome, count := range outcomes { expectedRequests = append(expectedRequests, metricdata.DataPoint[int64]{ Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport), attribute.String("outcome", outcome)), Value: count, }) } metadatatest.AssertEqualReceiverRequests(t, tt, expectedRequests, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } }) }) } } func TestReceiveMetricsOp(t *testing.T) { originalState := NewReceiverMetricsGate.IsEnabled() t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), originalState)) }) for _, tc := range []struct { name string enabled bool }{{"gate_enabled", true}, {"gate_disabled", false}} { t.Run(tc.name, func(t *testing.T) { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), tc.enabled)) testTelemetry(t, func(t *testing.T, tt *componenttest.Telemetry) { parentCtx, parentSpan := tt.NewTelemetrySettings().TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() params := []testParams{ {items: 13, err: consumererror.NewDownstream(errFake)}, {items: 42, err: nil}, {items: 7, err: errors.New("non-downstream error")}, } for i, param := range params { rec, err := newReceiver(ObsReportSettings{ ReceiverID: receiverID, Transport: transport, ReceiverCreateSettings: receiver.Settings{ID: receiverID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, }) require.NoError(t, err) ctx := rec.StartMetricsOp(parentCtx) assert.NotNil(t, ctx) rec.EndMetricsOp(ctx, format, params[i].items, param.err) } spans := tt.SpanRecorder.Ended() require.Len(t, spans, len(params)) var acceptedMetricPoints, refusedMetricPoints, failedMetricPoints int for i, span := range spans { assert.Equal(t, "receiver/"+receiverID.String()+"/MetricsReceived", span.Name()) err := params[i].err if err == nil { acceptedMetricPoints += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedMetricPointsKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedMetricPointsKey, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedMetricPointsKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Unset, span.Status().Code) } else { isDownstream := consumererror.IsDownstream(err) if !tc.enabled || (tc.enabled && isDownstream) { refusedMetricPoints += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedMetricPointsKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedMetricPointsKey, Value: attribute.Int64Value(0)}) } else { failedMetricPoints += params[i].items require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedMetricPointsKey, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedMetricPointsKey, Value: attribute.Int64Value(int64(params[i].items))}) } require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedMetricPointsKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, err.Error(), span.Status().Description) } } metadatatest.AssertEqualReceiverAcceptedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(acceptedMetricPoints), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverRefusedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(refusedMetricPoints), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverFailedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(failedMetricPoints), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) // Assert otelcol_receiver_requests metric with outcome attribute if tc.enabled { outcomes := make(map[string]int64) for _, param := range params { var outcome string switch { case param.err == nil: outcome = "success" case consumererror.IsDownstream(param.err): outcome = "refused" default: outcome = "failure" } outcomes[outcome]++ } var expectedRequests []metricdata.DataPoint[int64] for outcome, count := range outcomes { expectedRequests = append(expectedRequests, metricdata.DataPoint[int64]{ Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport), attribute.String("outcome", outcome)), Value: count, }) } metadatatest.AssertEqualReceiverRequests(t, tt, expectedRequests, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } }) }) } } func TestReceiveWithLongLivedCtx(t *testing.T) { originalState := NewReceiverMetricsGate.IsEnabled() t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), originalState)) }) for _, tc := range []struct { name string enabled bool }{{"gate_enabled", true}, {"gate_disabled", false}} { t.Run(tc.name, func(t *testing.T) { require.NoError(t, featuregate.GlobalRegistry().Set(NewReceiverMetricsGate.ID(), tc.enabled)) tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) longLivedCtx, parentSpan := tt.NewTelemetrySettings().TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() params := []testParams{ {items: 17, err: nil}, {items: 23, err: consumererror.NewDownstream(errFake)}, } for i := range params { // Use a new context on each operation to simulate distinct operations // under the same long lived context. rec, rerr := NewObsReport(ObsReportSettings{ ReceiverID: receiverID, Transport: transport, LongLivedCtx: true, ReceiverCreateSettings: receiver.Settings{ID: receiverID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, }) require.NoError(t, rerr) ctx := rec.StartTracesOp(longLivedCtx) assert.NotNil(t, ctx) rec.EndTracesOp(ctx, format, params[i].items, params[i].err) } spans := tt.SpanRecorder.Ended() require.Len(t, spans, len(params)) for i, span := range spans { assert.False(t, span.Parent().IsValid()) require.Len(t, span.Links(), 1) link := span.Links()[0] assert.Equal(t, parentSpan.SpanContext().TraceID(), link.SpanContext.TraceID()) assert.Equal(t, parentSpan.SpanContext().SpanID(), link.SpanContext.SpanID()) assert.Equal(t, "receiver/"+receiverID.String()+"/TraceDataReceived", span.Name()) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.TransportKey, Value: attribute.StringValue(transport)}) switch { case params[i].err == nil: require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedSpansKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedSpansKey, Value: attribute.Int64Value(0)}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedSpansKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Unset, span.Status().Code) case consumererror.IsDownstream(params[i].err): require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.AcceptedSpansKey, Value: attribute.Int64Value(0)}) // For downstream errors require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.RefusedSpansKey, Value: attribute.Int64Value(int64(params[i].items))}) require.Contains(t, span.Attributes(), attribute.KeyValue{Key: internal.FailedSpansKey, Value: attribute.Int64Value(0)}) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) default: t.Fatalf("unexpected error: %v", params[i].err) } } }) } } func TestCheckReceiverTracesViews(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) rec, err := NewObsReport(ObsReportSettings{ ReceiverID: receiverID, Transport: transport, ReceiverCreateSettings: receiver.Settings{ID: receiverID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, }) require.NoError(t, err) ctx := rec.StartTracesOp(context.Background()) require.NotNil(t, ctx) rec.EndTracesOp(ctx, format, 7, nil) metadatatest.AssertEqualReceiverAcceptedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(7), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverRefusedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(0), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverFailedSpans(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(0), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestCheckReceiverMetricsViews(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) rec, err := NewObsReport(ObsReportSettings{ ReceiverID: receiverID, Transport: transport, ReceiverCreateSettings: receiver.Settings{ID: receiverID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, }) require.NoError(t, err) ctx := rec.StartMetricsOp(context.Background()) require.NotNil(t, ctx) rec.EndMetricsOp(ctx, format, 7, nil) metadatatest.AssertEqualReceiverAcceptedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(7), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverRefusedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(0), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverFailedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(0), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestCheckReceiverLogsViews(t *testing.T) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) rec, err := NewObsReport(ObsReportSettings{ ReceiverID: receiverID, Transport: transport, ReceiverCreateSettings: receiver.Settings{ID: receiverID, TelemetrySettings: tt.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo()}, }) require.NoError(t, err) ctx := rec.StartLogsOp(context.Background()) require.NotNil(t, ctx) rec.EndLogsOp(ctx, format, 7, nil) metadatatest.AssertEqualReceiverAcceptedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(7), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverRefusedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(0), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualReceiverFailedLogRecords(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(internal.ReceiverKey, receiverID.String()), attribute.String(internal.TransportKey, transport)), Value: int64(0), }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func testTelemetry(t *testing.T, testFunc func(t *testing.T, tt *componenttest.Telemetry)) { tt := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tt.Shutdown(context.Background())) }) testFunc(t, tt) } opentelemetry-collector-0.141.0/receiver/receivertest/000077500000000000000000000000001511331344600230465ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/receivertest/Makefile000066400000000000000000000000361511331344600245050ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/receiver/receivertest/contract_checker.go000066400000000000000000000447471511331344600267160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receivertest // import "go.opentelemetry.io/collector/receiver/receivertest" import ( "context" "errors" "fmt" "maps" "math/rand/v2" "sync" "sync/atomic" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" ) // UniqueIDAttrName is the attribute name that is used in log records/spans/datapoints as the unique identifier. const UniqueIDAttrName = "test_id" // UniqueIDAttrVal is the value type of the UniqueIDAttrName. type UniqueIDAttrVal string type Generator interface { // Start the generator and prepare to generate. Will be followed by calls to Generate(). // Start() may be called again after Stop() is called to begin a new test scenario. Start() // Stop generating. There will be no more calls to Generate() until Start() is called again. Stop() // Generate must generate and send at least one data element (span, log record or metric data point) // to the receiver and return a copy of generated element ids. // The generated data must contain uniquely identifiable elements, each with a // different value of attribute named UniqueIDAttrName. // CreateOneLogWithID() can be used a helper to create such logs. // May be called concurrently from multiple goroutines. Generate() []UniqueIDAttrVal } type CheckConsumeContractParams struct { T *testing.T // Factory that allows to create a receiver. Factory receiver.Factory Signal pipeline.Signal // Config of the receiver to use. Config component.Config // Generator that can send data to the receiver. Generator Generator // GenerateCount specifies the number of times to call the generator.Generate() // for each test scenario. GenerateCount int // prevent unkeyed literal initialization _ struct{} } // CheckConsumeContract checks the contract between the receiver and its next consumer. For the contract // description see ../doc.go. The checker will detect violations of contract on different scenarios: on success, // on permanent and non-permanent errors and mix of error types. func CheckConsumeContract(params CheckConsumeContractParams) { // Different scenarios to test for. // The decision function defines the testing scenario (i.e. to test for // success case or for error case or a mix of both). See for example randomErrorsConsumeDecision. scenarios := []struct { name string decisionFunc func(ids idSet) error }{ { name: "always_succeed", // Always succeed. We expect all data to be delivered as is. decisionFunc: func(idSet) error { return nil }, }, { name: "random_non_permanent_error", decisionFunc: randomNonPermanentErrorConsumeDecision, }, { name: "random_permanent_error", decisionFunc: randomPermanentErrorConsumeDecision, }, { name: "random_error", decisionFunc: randomErrorsConsumeDecision, }, } for _, scenario := range scenarios { params.T.Run( scenario.name, func(*testing.T) { checkConsumeContractScenario(params, scenario.decisionFunc) }, ) } } func checkConsumeContractScenario(params CheckConsumeContractParams, decisionFunc func(ids idSet) error) { consumer := &mockConsumer{t: params.T, consumeDecisionFunc: decisionFunc, acceptedIDs: make(idSet), droppedIDs: make(idSet)} ctx := context.Background() // Create and start the receiver. var receiver component.Component var err error switch params.Signal { case pipeline.SignalLogs: receiver, err = params.Factory.CreateLogs(ctx, NewNopSettings(params.Factory.Type()), params.Config, consumer) case pipeline.SignalTraces: receiver, err = params.Factory.CreateTraces(ctx, NewNopSettings(params.Factory.Type()), params.Config, consumer) case pipeline.SignalMetrics: receiver, err = params.Factory.CreateMetrics(ctx, NewNopSettings(params.Factory.Type()), params.Config, consumer) default: require.FailNow(params.T, "must specify a valid DataType to test for") } require.NoError(params.T, err) err = receiver.Start(ctx, componenttest.NewNopHost()) require.NoError(params.T, err) // Begin generating data to the receiver. generatedIDs := make(idSet) var generatedIndex int64 var mux sync.Mutex var wg sync.WaitGroup const concurrency = 4 params.Generator.Start() defer params.Generator.Stop() // Create concurrent goroutines that use the generator. // The total number of generator calls will be equal to params.GenerateCount. for range concurrency { wg.Add(1) go func() { defer wg.Done() for atomic.AddInt64(&generatedIndex, 1) <= int64(params.GenerateCount) { ids := params.Generator.Generate() require.NotEmpty(params.T, ids) mux.Lock() duplicates := generatedIDs.mergeSlice(ids) mux.Unlock() // Check that the generator works correctly. There may not be any duplicates in the // generated data set. require.Empty(params.T, duplicates) } }() } // Wait until all generator goroutines are done. wg.Wait() // Wait until all data is seen by the consumer. assert.Eventually(params.T, func() bool { // Calculate the union of accepted and dropped data. acceptedAndDropped, duplicates := consumer.acceptedAndDropped() if len(duplicates) != 0 { assert.Failf(params.T, "found duplicate elements in received and dropped data", "keys=%v", duplicates) } // Compare accepted+dropped with generated. Once they are equal it means all data is seen by the consumer. missingInOther, onlyInOther := generatedIDs.compare(acceptedAndDropped) return len(missingInOther) == 0 && len(onlyInOther) == 0 }, 5*time.Second, 10*time.Millisecond) // Do some final checks. Need the union of accepted and dropped data again. acceptedAndDropped, duplicates := consumer.acceptedAndDropped() if len(duplicates) != 0 { assert.Failf(params.T, "found duplicate elements in accepted and dropped data", "keys=%v", duplicates) } // Make sure generated and accepted+dropped are exactly the same. missingInOther, onlyInOther := generatedIDs.compare(acceptedAndDropped) if len(missingInOther) != 0 { assert.Failf(params.T, "found elements sent that were not delivered", "keys=%v", missingInOther) } if len(onlyInOther) != 0 { assert.Failf(params.T, "found elements in accepted and dropped data that was never sent", "keys=%v", onlyInOther) } err = receiver.Shutdown(ctx) require.NoError(params.T, err) // Print some stats to help debug test failures. fmt.Printf( "Sent %d, accepted=%d, expected dropped=%d, non-permanent errors retried=%d\n", len(generatedIDs), len(consumer.acceptedIDs), len(consumer.droppedIDs), consumer.nonPermanentFailures, ) } // idSet is a set of unique ids of data elements used in the test (logs, spans or metric data points). type idSet map[UniqueIDAttrVal]bool // compare to another set and calculate the differences from this set. func (ds idSet) compare(other idSet) (missingInOther, onlyInOther []UniqueIDAttrVal) { for k := range ds { if _, ok := other[k]; !ok { missingInOther = append(missingInOther, k) } } for k := range other { if _, ok := ds[k]; !ok { onlyInOther = append(onlyInOther, k) } } return missingInOther, onlyInOther } // merge another set into this one and return a list of duplicate ids. func (ds idSet) merge(other idSet) (duplicates []UniqueIDAttrVal) { for k, v := range other { if _, ok := ds[k]; ok { duplicates = append(duplicates, k) } else { ds[k] = v } } return duplicates } // mergeSlice merges another set into this one and return a list of duplicate ids. func (ds idSet) mergeSlice(other []UniqueIDAttrVal) (duplicates []UniqueIDAttrVal) { for _, id := range other { if _, ok := ds[id]; ok { duplicates = append(duplicates, id) } else { ds[id] = true } } return duplicates } // union computes the union of this and another sets. A new set if created to return the result. // Also returns a list of any duplicate ids found. func (ds idSet) union(other idSet) (union idSet, duplicates []UniqueIDAttrVal) { union = map[UniqueIDAttrVal]bool{} maps.Copy(union, ds) for k, v := range other { if _, ok := union[k]; ok { duplicates = append(duplicates, k) } else { union[k] = v } } return union, duplicates } // A function that returns a value indicating what the receiver's next consumer decides // to do as a result of ConsumeLogs/Trace/Metrics call. // The result of the decision function becomes the return value of ConsumeLogs/Trace/Metrics. // Supplying different decision functions allows to test different scenarios of the contract // between the receiver and it next consumer. type consumeDecisionFunc func(ids idSet) error var ( errNonPermanent = errors.New("non permanent error") errPermanent = errors.New("permanent error") ) // randomNonPermanentErrorConsumeDecision is a decision function that succeeds approximately // half of the time and fails with a non-permanent error the rest of the time. func randomNonPermanentErrorConsumeDecision(idSet) error { if rand.Float32() < 0.5 { return errNonPermanent } return nil } // randomPermanentErrorConsumeDecision is a decision function that succeeds approximately // half of the time and fails with a permanent error the rest of the time. func randomPermanentErrorConsumeDecision(idSet) error { if rand.Float32() < 0.5 { return consumererror.NewPermanent(errPermanent) } return nil } // randomErrorsConsumeDecision is a decision function that succeeds approximately // a third of the time, fails with a permanent error the third of the time and fails with // a non-permanent error the rest of the time. func randomErrorsConsumeDecision(idSet) error { r := rand.Float64() third := 1.0 / 3.0 if r < third { return consumererror.NewPermanent(errPermanent) } if r < 2*third { return errNonPermanent } return nil } // mockConsumer accepts or drops the data from the receiver based on the decision made by // consumeDecisionFunc and remembers the accepted and dropped data sets for later checks. // mockConsumer implements all 3 consume functions: ConsumeLogs/ConsumeTraces/ConsumeMetrics // and can be used for testing any of the 3 signals. type mockConsumer struct { t *testing.T consumeDecisionFunc consumeDecisionFunc mux sync.Mutex acceptedIDs idSet droppedIDs idSet nonPermanentFailures int } func (m *mockConsumer) Capabilities() consumer.Capabilities { return consumer.Capabilities{} } func (m *mockConsumer) ConsumeTraces(_ context.Context, data ptrace.Traces) error { ids, err := idSetFromTraces(data) require.NoError(m.t, err) return m.consume(ids) } // idSetFromTraces computes an idSet from given ptrace.Traces. The idSet will contain ids of all spans. func idSetFromTraces(data ptrace.Traces) (idSet, error) { ds := map[UniqueIDAttrVal]bool{} rss := data.ResourceSpans() for i := 0; i < rss.Len(); i++ { ils := rss.At(i).ScopeSpans() for j := 0; j < ils.Len(); j++ { ss := ils.At(j).Spans() for k := 0; k < ss.Len(); k++ { elem := ss.At(k) key, exists := elem.Attributes().Get(UniqueIDAttrName) if !exists { return ds, fmt.Errorf("invalid data element, attribute %q is missing", UniqueIDAttrName) } if key.Type() != pcommon.ValueTypeStr { return ds, fmt.Errorf("invalid data element, attribute %q is wrong type %v", UniqueIDAttrName, key.Type()) } ds[UniqueIDAttrVal(key.Str())] = true } } } return ds, nil } func (m *mockConsumer) ConsumeLogs(_ context.Context, data plog.Logs) error { ids, err := idSetFromLogs(data) require.NoError(m.t, err) return m.consume(ids) } // idSetFromLogs computes an idSet from given plog.Logs. The idSet will contain ids of all log records. func idSetFromLogs(data plog.Logs) (idSet, error) { ds := map[UniqueIDAttrVal]bool{} rss := data.ResourceLogs() for i := 0; i < rss.Len(); i++ { ils := rss.At(i).ScopeLogs() for j := 0; j < ils.Len(); j++ { ss := ils.At(j).LogRecords() for k := 0; k < ss.Len(); k++ { elem := ss.At(k) key, exists := elem.Attributes().Get(UniqueIDAttrName) if !exists { return ds, fmt.Errorf("invalid data element, attribute %q is missing", UniqueIDAttrName) } if key.Type() != pcommon.ValueTypeStr { return ds, fmt.Errorf("invalid data element, attribute %q is wrong type %v", UniqueIDAttrName, key.Type()) } ds[UniqueIDAttrVal(key.Str())] = true } } } return ds, nil } func (m *mockConsumer) ConsumeMetrics(_ context.Context, data pmetric.Metrics) error { ids, err := idSetFromMetrics(data) require.NoError(m.t, err) return m.consume(ids) } // idSetFromMetrics computes an idSet from given pmetric.Metrics. The idSet will contain ids of all metric data points. func idSetFromMetrics(data pmetric.Metrics) (idSet, error) { ds := map[UniqueIDAttrVal]bool{} rss := data.ResourceMetrics() for i := 0; i < rss.Len(); i++ { ils := rss.At(i).ScopeMetrics() for j := 0; j < ils.Len(); j++ { ss := ils.At(j).Metrics() for k := 0; k < ss.Len(); k++ { elem := ss.At(k) switch elem.Type() { case pmetric.MetricTypeGauge: for l := 0; l < elem.Gauge().DataPoints().Len(); l++ { dp := elem.Gauge().DataPoints().At(l) if err := idSetFromDataPoint(ds, dp.Attributes()); err != nil { return ds, err } } case pmetric.MetricTypeSum: for l := 0; l < elem.Sum().DataPoints().Len(); l++ { dp := elem.Sum().DataPoints().At(l) if err := idSetFromDataPoint(ds, dp.Attributes()); err != nil { return ds, err } } case pmetric.MetricTypeSummary: for l := 0; l < elem.Summary().DataPoints().Len(); l++ { dp := elem.Summary().DataPoints().At(l) if err := idSetFromDataPoint(ds, dp.Attributes()); err != nil { return ds, err } } case pmetric.MetricTypeHistogram: for l := 0; l < elem.Histogram().DataPoints().Len(); l++ { dp := elem.Histogram().DataPoints().At(l) if err := idSetFromDataPoint(ds, dp.Attributes()); err != nil { return ds, err } } case pmetric.MetricTypeExponentialHistogram: for l := 0; l < elem.ExponentialHistogram().DataPoints().Len(); l++ { dp := elem.ExponentialHistogram().DataPoints().At(l) if err := idSetFromDataPoint(ds, dp.Attributes()); err != nil { return ds, err } } } } } } return ds, nil } func idSetFromDataPoint(ds map[UniqueIDAttrVal]bool, attributes pcommon.Map) error { key, exists := attributes.Get(UniqueIDAttrName) if !exists { return fmt.Errorf("invalid data element, attribute %q is missing", UniqueIDAttrName) } if key.Type() != pcommon.ValueTypeStr { return fmt.Errorf("invalid data element, attribute %q is wrong type %v", UniqueIDAttrName, key.Type()) } ds[UniqueIDAttrVal(key.Str())] = true return nil } // consume the elements with the specified ids, regardless of the element data type. func (m *mockConsumer) consume(ids idSet) error { m.mux.Lock() defer m.mux.Unlock() // Consult with user-defined decision function to decide what to do with the data. if err := m.consumeDecisionFunc(ids); err != nil { // The decision is to return an error to the receiver. if consumererror.IsPermanent(err) { // It is a permanent error, which means we need to drop the data. // Remember the ids of dropped elements. duplicates := m.droppedIDs.merge(ids) require.Empty(m.t, duplicates, "elements that were dropped previously were sent again") } else { // It is a non-permanent error. Don't add it to the drop list. Remember the number of // failures to print at the end of the test. m.nonPermanentFailures++ } // Return the error to the receiver. return err } // The decision is a success. Remember the ids of the data in the accepted list. duplicates := m.acceptedIDs.merge(ids) require.Empty(m.t, duplicates, "elements that were accepted previously were sent again") return nil } // Calculate union of accepted and dropped ids. // Returns the union and the list of duplicates between the two sets (if any) func (m *mockConsumer) acceptedAndDropped() (acceptedAndDropped idSet, duplicates []UniqueIDAttrVal) { m.mux.Lock() defer m.mux.Unlock() return m.acceptedIDs.union(m.droppedIDs) } func CreateOneLogWithID(id UniqueIDAttrVal) plog.Logs { data := plog.NewLogs() data.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Attributes().PutStr( UniqueIDAttrName, string(id), ) return data } func CreateGaugeMetricWithID(id UniqueIDAttrVal) pmetric.Metrics { data := pmetric.NewMetrics() gauge := data.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() gauge.AppendEmpty().SetEmptyGauge().DataPoints().AppendEmpty().Attributes().PutStr( UniqueIDAttrName, string(id), ) return data } func CreateSumMetricWithID(id UniqueIDAttrVal) pmetric.Metrics { data := pmetric.NewMetrics() sum := data.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() sum.AppendEmpty().SetEmptySum().DataPoints().AppendEmpty().Attributes().PutStr( UniqueIDAttrName, string(id), ) return data } func CreateSummaryMetricWithID(id UniqueIDAttrVal) pmetric.Metrics { data := pmetric.NewMetrics() summary := data.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() summary.AppendEmpty().SetEmptySummary().DataPoints().AppendEmpty().Attributes().PutStr( UniqueIDAttrName, string(id), ) return data } func CreateHistogramMetricWithID(id UniqueIDAttrVal) pmetric.Metrics { data := pmetric.NewMetrics() histogram := data.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() histogram.AppendEmpty().SetEmptyHistogram().DataPoints().AppendEmpty().Attributes().PutStr( UniqueIDAttrName, string(id), ) return data } func CreateExponentialHistogramMetricWithID(id UniqueIDAttrVal) pmetric.Metrics { data := pmetric.NewMetrics() exponentialHistogram := data.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics() exponentialHistogram.AppendEmpty().SetEmptyExponentialHistogram().DataPoints().AppendEmpty().Attributes().PutStr( UniqueIDAttrName, string(id), ) return data } func CreateOneSpanWithID(id UniqueIDAttrVal) ptrace.Traces { data := ptrace.NewTraces() data.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty().Attributes().PutStr( UniqueIDAttrName, string(id), ) return data } opentelemetry-collector-0.141.0/receiver/receivertest/contract_checker_test.go000066400000000000000000000260731511331344600277450ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receivertest import ( "context" "strconv" "sync/atomic" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" ) // This file is an example that demonstrates how to use the CheckConsumeContract() function. // We declare a trivial example receiver, a data generator and then use them in TestConsumeContract(). type exampleReceiver struct { nextLogsConsumer consumer.Logs nextTracesConsumer consumer.Traces nextMetricsConsumer consumer.Metrics } func (s *exampleReceiver) Start(context.Context, component.Host) error { return nil } func (s *exampleReceiver) Shutdown(context.Context) error { return nil } func (s *exampleReceiver) ReceiveLogs(data plog.Logs) { // This very simple implementation demonstrates how a single items receiving should happen. for { err := s.nextLogsConsumer.ConsumeLogs(context.Background(), data) if err != nil { // The next consumer returned an error. if !consumererror.IsPermanent(err) { // It is not a permanent error, so we must retry sending it again. In network-based // receivers instead we can ask our sender to re-retry the same data again later. // We may also pause here a bit if we don't want to hammer the next consumer. continue } } // If we are hear either the ConsumeLogs returned success or it returned a permanent error. // In either case we don't need to retry the same data, we are done. return } } func (s *exampleReceiver) ReceiveMetrics(data pmetric.Metrics) { // This very simple implementation demonstrates how a single items receiving should happen. for { err := s.nextMetricsConsumer.ConsumeMetrics(context.Background(), data) if err != nil { // The next consumer returned an error. if !consumererror.IsPermanent(err) { // It is not a permanent error, so we must retry sending it again. In network-based // receivers instead we can ask our sender to re-retry the same data again later. // We may also pause here a bit if we don't want to hammer the next consumer. continue } } // If we are hear either the ConsumeLogs returned success or it returned a permanent error. // In either case we don't need to retry the same data, we are done. return } } func (s *exampleReceiver) ReceiveTraces(data ptrace.Traces) { // This very simple implementation demonstrates how a single items receiving should happen. for { err := s.nextTracesConsumer.ConsumeTraces(context.Background(), data) if err != nil { // The next consumer returned an error. if !consumererror.IsPermanent(err) { // It is not a permanent error, so we must retry sending it again. In network-based // receivers instead we can ask our sender to re-retry the same data again later. // We may also pause here a bit if we don't want to hammer the next consumer. continue } } // If we are hear either the ConsumeLogs returned success or it returned a permanent error. // In either case we don't need to retry the same data, we are done. return } } // A config for exampleReceiver. type exampleReceiverConfig struct { generator Generator } // A generator that can send data to exampleReceiver. type exampleLogGenerator struct { t *testing.T receiver *exampleReceiver sequenceNum int64 } func (g *exampleLogGenerator) Start() { g.sequenceNum = 0 } func (g *exampleLogGenerator) Stop() {} func (g *exampleLogGenerator) Generate() []UniqueIDAttrVal { // Make sure the id is atomically incremented. Generate() may be called concurrently. id := UniqueIDAttrVal(strconv.FormatInt(atomic.AddInt64(&g.sequenceNum, 1), 10)) data := CreateOneLogWithID(id) // Send the generated data to the receiver. g.receiver.ReceiveLogs(data) // And return the ids for bookkeeping by the test. return []UniqueIDAttrVal{id} } // A generator that can send data to exampleReceiver. type exampleTraceGenerator struct { t *testing.T receiver *exampleReceiver sequenceNum int64 } func (g *exampleTraceGenerator) Start() { g.sequenceNum = 0 } func (g *exampleTraceGenerator) Stop() {} func (g *exampleTraceGenerator) Generate() []UniqueIDAttrVal { // Make sure the id is atomically incremented. Generate() may be called concurrently. id := UniqueIDAttrVal(strconv.FormatInt(atomic.AddInt64(&g.sequenceNum, 1), 10)) data := CreateOneSpanWithID(id) // Send the generated data to the receiver. g.receiver.ReceiveTraces(data) // And return the ids for bookkeeping by the test. return []UniqueIDAttrVal{id} } // A generator that can send data to exampleReceiver. type exampleMetricGenerator struct { t *testing.T receiver *exampleReceiver sequenceNum int64 } func (g *exampleMetricGenerator) Start() { g.sequenceNum = 0 } func (g *exampleMetricGenerator) Stop() {} func (g *exampleMetricGenerator) Generate() []UniqueIDAttrVal { // Make sure the id is atomically incremented. Generate() may be called concurrently. next := atomic.AddInt64(&g.sequenceNum, 1) id := UniqueIDAttrVal(strconv.FormatInt(next, 10)) var data pmetric.Metrics switch next % 5 { case 0: data = CreateGaugeMetricWithID(id) case 1: data = CreateSumMetricWithID(id) case 2: data = CreateSummaryMetricWithID(id) case 3: data = CreateHistogramMetricWithID(id) case 4: data = CreateExponentialHistogramMetricWithID(id) } // Send the generated data to the receiver. g.receiver.ReceiveMetrics(data) // And return the ids for bookkeeping by the test. return []UniqueIDAttrVal{id} } func newExampleFactory() receiver.Factory { return receiver.NewFactory( component.MustNewType("example_receiver"), func() component.Config { return &exampleReceiverConfig{} }, receiver.WithLogs(createLog, component.StabilityLevelBeta), receiver.WithMetrics(createMetric, component.StabilityLevelBeta), receiver.WithTraces(createTrace, component.StabilityLevelBeta), ) } func createTrace(_ context.Context, _ receiver.Settings, cfg component.Config, consumer consumer.Traces) (receiver.Traces, error) { rcv := &exampleReceiver{nextTracesConsumer: consumer} cfg.(*exampleReceiverConfig).generator.(*exampleTraceGenerator).receiver = rcv return rcv, nil } func createMetric(_ context.Context, _ receiver.Settings, cfg component.Config, consumer consumer.Metrics) (receiver.Metrics, error) { rcv := &exampleReceiver{nextMetricsConsumer: consumer} cfg.(*exampleReceiverConfig).generator.(*exampleMetricGenerator).receiver = rcv return rcv, nil } func createLog( _ context.Context, _ receiver.Settings, cfg component.Config, consumer consumer.Logs, ) (receiver.Logs, error) { rcv := &exampleReceiver{nextLogsConsumer: consumer} cfg.(*exampleReceiverConfig).generator.(*exampleLogGenerator).receiver = rcv return rcv, nil } // TestConsumeContract is an example of testing of the receiver for the contract between the // receiver and next consumer. func TestConsumeContract(t *testing.T) { // Number of log records to send per scenario. const logsPerTest = 100 generator := &exampleLogGenerator{t: t} cfg := &exampleReceiverConfig{generator: generator} params := CheckConsumeContractParams{ T: t, Factory: newExampleFactory(), Signal: pipeline.SignalLogs, Config: cfg, Generator: generator, GenerateCount: logsPerTest, } // Run the contract checker. This will trigger test failures if any problems are found. CheckConsumeContract(params) } // TestConsumeMetricsContract is an example of testing of the receiver for the contract between the // receiver and next consumer. func TestConsumeMetricsContract(t *testing.T) { // Number of metric data points to send per scenario. const metricsPerTest = 100 generator := &exampleMetricGenerator{t: t} cfg := &exampleReceiverConfig{generator: generator} params := CheckConsumeContractParams{ T: t, Factory: newExampleFactory(), Signal: pipeline.SignalMetrics, Config: cfg, Generator: generator, GenerateCount: metricsPerTest, } // Run the contract checker. This will trigger test failures if any problems are found. CheckConsumeContract(params) } // TestConsumeTracesContract is an example of testing of the receiver for the contract between the // receiver and next consumer. func TestConsumeTracesContract(t *testing.T) { // Number of trace spans to send per scenario. const spansPerTest = 100 generator := &exampleTraceGenerator{t: t} cfg := &exampleReceiverConfig{generator: generator} params := CheckConsumeContractParams{ T: t, Factory: newExampleFactory(), Signal: pipeline.SignalTraces, Config: cfg, Generator: generator, GenerateCount: spansPerTest, } // Run the contract checker. This will trigger test failures if any problems are found. CheckConsumeContract(params) } func TestIDSetFromDataPoint(t *testing.T) { require.Error(t, idSetFromDataPoint(map[UniqueIDAttrVal]bool{}, pcommon.NewMap())) m := pcommon.NewMap() m.PutStr("foo", "bar") require.Error(t, idSetFromDataPoint(map[UniqueIDAttrVal]bool{}, m)) m.PutInt(UniqueIDAttrName, 64) require.Error(t, idSetFromDataPoint(map[UniqueIDAttrVal]bool{}, m)) m.PutStr(UniqueIDAttrName, "myid") result := map[UniqueIDAttrVal]bool{} require.NoError(t, idSetFromDataPoint(result, m)) require.True(t, result["myid"]) } func TestBadMetricPoint(t *testing.T) { for _, test := range []struct { name string metrics pmetric.Metrics }{ { name: "gauge", metrics: func() pmetric.Metrics { m := pmetric.NewMetrics() m.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyGauge().DataPoints().AppendEmpty() return m }(), }, { name: "sum", metrics: func() pmetric.Metrics { m := pmetric.NewMetrics() m.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints().AppendEmpty() return m }(), }, { name: "summary", metrics: func() pmetric.Metrics { m := pmetric.NewMetrics() m.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySummary().DataPoints().AppendEmpty() return m }(), }, { name: "histogram", metrics: func() pmetric.Metrics { m := pmetric.NewMetrics() m.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyHistogram().DataPoints().AppendEmpty() return m }(), }, { name: "exponential histogram", metrics: func() pmetric.Metrics { m := pmetric.NewMetrics() m.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyExponentialHistogram().DataPoints().AppendEmpty() return m }(), }, } { t.Run(test.name, func(t *testing.T) { _, err := idSetFromMetrics(test.metrics) require.Error(t, err) }) } } opentelemetry-collector-0.141.0/receiver/receivertest/go.mod000066400000000000000000000057211511331344600241610ustar00rootroot00000000000000module go.opentelemetry.io/collector/receiver/receivertest go 1.24.0 require ( github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/receiver => ../ replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/receiver/xreceiver => ../xreceiver replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/receiver/receivertest/go.sum000066400000000000000000000157461511331344600242160ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/receiver/receivertest/nop_receiver.go000066400000000000000000000042431511331344600260600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receivertest // import "go.opentelemetry.io/collector/receiver/receivertest" import ( "context" "github.com/google/uuid" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/xreceiver" ) var NopType = component.MustNewType("nop") // NewNopSettings returns a new nop settings for Create*Receiver functions with the given type. func NewNopSettings(typ component.Type) receiver.Settings { return receiver.Settings{ ID: component.NewIDWithName(typ, uuid.NewString()), TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } // NewNopFactory returns a receiver.Factory that constructs nop receivers supporting all data types. func NewNopFactory() receiver.Factory { return xreceiver.NewFactory( NopType, func() component.Config { return &nopConfig{} }, xreceiver.WithTraces(createTraces, component.StabilityLevelStable), xreceiver.WithMetrics(createMetrics, component.StabilityLevelStable), xreceiver.WithLogs(createLogs, component.StabilityLevelStable), xreceiver.WithProfiles(createProfiles, component.StabilityLevelAlpha), ) } type nopConfig struct{} func createTraces(context.Context, receiver.Settings, component.Config, consumer.Traces) (receiver.Traces, error) { return nopInstance, nil } func createMetrics(context.Context, receiver.Settings, component.Config, consumer.Metrics) (receiver.Metrics, error) { return nopInstance, nil } func createLogs(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { return nopInstance, nil } func createProfiles(context.Context, receiver.Settings, component.Config, xconsumer.Profiles) (xreceiver.Profiles, error) { return nopInstance, nil } var nopInstance = &nopReceiver{} // nopReceiver acts as a receiver for testing purposes. type nopReceiver struct { component.StartFunc component.ShutdownFunc } opentelemetry-collector-0.141.0/receiver/receivertest/nop_receiver_test.go000066400000000000000000000033121511331344600271130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receivertest import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/receiver/xreceiver" ) func TestNewNopFactory(t *testing.T) { factory := NewNopFactory() require.NotNil(t, factory) assert.Equal(t, "nop", factory.Type().String()) cfg := factory.CreateDefaultConfig() assert.Equal(t, &nopConfig{}, cfg) traces, err := factory.CreateTraces(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, traces.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, traces.Shutdown(context.Background())) metrics, err := factory.CreateMetrics(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, metrics.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, metrics.Shutdown(context.Background())) logs, err := factory.CreateLogs(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, logs.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, logs.Shutdown(context.Background())) profiles, err := factory.(xreceiver.Factory).CreateProfiles(context.Background(), NewNopSettings(NopType), cfg, consumertest.NewNop()) require.NoError(t, err) assert.NoError(t, profiles.Start(context.Background(), componenttest.NewNopHost())) assert.NoError(t, profiles.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/receiver/receivertest/package_test.go000066400000000000000000000003151511331344600260260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package receivertest import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/receiver/xreceiver/000077500000000000000000000000001511331344600223365ustar00rootroot00000000000000opentelemetry-collector-0.141.0/receiver/xreceiver/Makefile000066400000000000000000000000361511331344600237750ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/receiver/xreceiver/go.mod000066400000000000000000000040311511331344600234420ustar00rootroot00000000000000module go.opentelemetry.io/collector/receiver/xreceiver go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/receiver v1.47.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/collector/consumer v1.47.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/receiver => ../ replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/receiver/xreceiver/go.sum000066400000000000000000000124431511331344600234750ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/receiver/xreceiver/metadata.yaml000066400000000000000000000003001511331344600247730ustar00rootroot00000000000000type: xreceiver github_project: open-telemetry/opentelemetry-collector status: class: pkg codeowners: active: - mx-psi - dmathieu stability: development: [profiles] opentelemetry-collector-0.141.0/receiver/xreceiver/profiles.go000066400000000000000000000105171511331344600245140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xreceiver // import "go.opentelemetry.io/collector/receiver/xreceiver" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/internal" ) // Profiles receiver receives profiles. // Its purpose is to translate data from any format to the collector's internal profile format. // Profiles receiver feeds a xconsumer.Profiles with data. // // For example, it could be a pprof data source which translates pprof profiles into pprofile.Profiles. type Profiles interface { component.Component } // Factory is a factory interface for receivers. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. type Factory interface { receiver.Factory // CreateProfiles creates a Profiles based on this config. // If the receiver type does not support tracing or if the config is not valid // an error will be returned instead. `next` is never nil. CreateProfiles(ctx context.Context, set receiver.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) // ProfilesStability gets the stability level of the Profiles receiver. ProfilesStability() component.StabilityLevel } // CreateProfilesFunc is the equivalent of Factory.CreateProfiles. type CreateProfilesFunc func(context.Context, receiver.Settings, component.Config, xconsumer.Profiles) (Profiles, error) // FactoryOption apply changes to Factory. type FactoryOption interface { // applyOption applies the option. applyOption(o *factoryOpts) } // factoryOptionFunc is a FactoryOption created through a function. type factoryOptionFunc func(*factoryOpts) func (f factoryOptionFunc) applyOption(o *factoryOpts) { f(o) } type factory struct { receiver.Factory createProfilesFunc CreateProfilesFunc profilesStabilityLevel component.StabilityLevel } func (f *factory) ProfilesStability() component.StabilityLevel { return f.profilesStabilityLevel } func (f *factory) CreateProfiles(ctx context.Context, set receiver.Settings, cfg component.Config, next xconsumer.Profiles) (Profiles, error) { if f.createProfilesFunc == nil { return nil, pipeline.ErrSignalNotSupported } if set.ID.Type() != f.Type() { return nil, internal.ErrIDMismatch(set.ID, f.Type()) } return f.createProfilesFunc(ctx, set, cfg, next) } type factoryOpts struct { opts []receiver.FactoryOption *factory } // WithTraces overrides the default "error not supported" implementation for Factory.CreateTraces and the default "undefined" stability level. func WithTraces(createTraces receiver.CreateTracesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, receiver.WithTraces(createTraces, sl)) }) } // WithMetrics overrides the default "error not supported" implementation for Factory.CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics receiver.CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, receiver.WithMetrics(createMetrics, sl)) }) } // WithLogs overrides the default "error not supported" implementation for Factory.CreateLogs and the default "undefined" stability level. func WithLogs(createLogs receiver.CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, receiver.WithLogs(createLogs, sl)) }) } // WithProfiles overrides the default "error not supported" implementation for Factory.CreateProfiles and the default "undefined" stability level. func WithProfiles(createProfiles CreateProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesStabilityLevel = sl o.createProfilesFunc = createProfiles }) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { opts := factoryOpts{factory: &factory{}} for _, opt := range options { opt.applyOption(&opts) } opts.Factory = receiver.NewFactory(cfgType, createDefaultConfig, opts.opts...) return opts.factory } opentelemetry-collector-0.141.0/receiver/xreceiver/receiver_test.go000066400000000000000000000032711511331344600255330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xreceiver import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/internal" ) var testID = component.MustNewID("test") func TestNewFactoryWithProfiles(t *testing.T) { testType := component.MustNewType("test") defaultCfg := struct{}{} factory := NewFactory( testType, func() component.Config { return &defaultCfg }, WithProfiles(createProfiles, component.StabilityLevelAlpha), ) assert.Equal(t, testType, factory.Type()) assert.EqualValues(t, &defaultCfg, factory.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelAlpha, factory.ProfilesStability()) _, err := factory.CreateProfiles(context.Background(), receiver.Settings{ID: testID}, &defaultCfg, nil) require.NoError(t, err) wrongID := component.MustNewID("wrong") wrongIDErrStr := internal.ErrIDMismatch(wrongID, testType).Error() _, err = factory.CreateProfiles(context.Background(), receiver.Settings{ID: wrongID}, &defaultCfg, nil) assert.EqualError(t, err, wrongIDErrStr) } var nopInstance = &nopReceiver{ Consumer: consumertest.NewNop(), } // nopReceiver stores consumed traces and metrics for testing purposes. type nopReceiver struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createProfiles(context.Context, receiver.Settings, component.Config, xconsumer.Profiles) (Profiles, error) { return nopInstance, nil } opentelemetry-collector-0.141.0/renovate.json000066400000000000000000000057001511331344600212560ustar00rootroot00000000000000{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "labels": [ "renovatebot", "dependencies" ], "constraints": { "go": "1.24" }, "extends": [ "config:recommended", "helpers:pinGitHubActionDigests" ], "schedule": [ "on tuesday" ], "packageRules": [ { "matchManagers": [ "gomod" ], "matchUpdateTypes": [ "pin", "pinDigest", "digest", "lockFileMaintenance", "rollback", "bump", "replacement" ], "enabled": false }, { "matchManagers": [ "gomod" ], "matchUpdateTypes": [ "major" ], "prBodyNotes": [ ":warning: MAJOR VERSION UPDATE :warning: - please manually update this package" ], "labels": [ "dependency-major-update" ] }, { "matchManagers": [ "dockerfile" ], "groupName": "dockerfile deps" }, { "matchManagers": [ "docker-compose" ], "groupName": "docker-compose deps" }, { "matchManagers": [ "github-actions" ], "groupName": "github-actions deps" }, { "matchManagers": [ "gomod" ], "matchSourceUrls": [ "https://github.com/open-telemetry/opentelemetry-go-contrib" ], "groupName": "All opentelemetry-go-contrib packages" }, { "matchManagers": [ "gomod" ], "groupName": "All go.opentelemetry.io/contrib packages", "matchSourceUrls": [ "https://go.opentelemetry.io/otel{/,}**" ], "allowedVersions": "!/v0.59.*/" }, { "matchManagers": [ "gomod" ], "groupName": "All google.golang.org packages", "matchSourceUrls": [ "https://google.golang.org{/,}**" ] }, { "matchManagers": [ "gomod" ], "groupName": "All golang.org/x packages", "matchPackageNames": [ "golang.org/x{/,}**" ] }, { "matchManagers": [ "gomod" ], "groupName": "All github.com/knadh/koanf packages", "matchPackageNames": [ "github.com/knadh/koanf{/,}**" ] }, { "matchManagers": [ "gomod" ], "groupName": "All go.opentelemetry.io/collector packages", "matchPackageNames": [ "go.opentelemetry.io/collector{/,}**" ] }, { "matchManagers": [ "gomod" ], "groupName": "All go.opentelemetry.io/build-tools packages", "matchPackageNames": [ "go.opentelemetry.io/build-tools{/,}**" ] }, { "matchManagers": [ "gomod" ], "matchDepTypes": [ "toolchain" ], "enabled": false } ], "ignoreDeps": [ "github.com/mattn/go-ieproxy" ], "prConcurrentLimit": 200, "suppressNotifications": [ "prEditedNotification" ], "postUpdateOptions": [ "gomodTidy", ] } opentelemetry-collector-0.141.0/reports/000077500000000000000000000000001511331344600202345ustar00rootroot00000000000000opentelemetry-collector-0.141.0/reports/distributions/000077500000000000000000000000001511331344600231365ustar00rootroot00000000000000opentelemetry-collector-0.141.0/reports/distributions/contrib.yaml000066400000000000000000000006471511331344600254710ustar00rootroot00000000000000name: contrib url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-contrib maintainers: [] components: connector: - forward exporter: - debug - nop - otlp - otlphttp extension: - zpages pkg: - service processor: - batch - memory_limiter receiver: - nop - otlp opentelemetry-collector-0.141.0/reports/distributions/core.yaml000066400000000000000000000006341511331344600247550ustar00rootroot00000000000000name: core url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol maintainers: [] components: connector: - forward exporter: - debug - nop - otlp - otlphttp extension: - zpages pkg: - service processor: - batch - memory_limiter receiver: - nop - otlp opentelemetry-collector-0.141.0/reports/distributions/k8s.yaml000066400000000000000000000005661511331344600245360ustar00rootroot00000000000000name: k8s url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-k8s maintainers: [] components: connector: - forward exporter: - debug - nop - otlp - otlphttp extension: - zpages processor: - batch - memory_limiter receiver: - otlp opentelemetry-collector-0.141.0/reports/distributions/otlp.yaml000066400000000000000000000003411511331344600247760ustar00rootroot00000000000000name: otlp url: https://github.com/open-telemetry/opentelemetry-collector-releases/tree/main/distributions/otelcol-otlp maintainers: [] components: exporter: - otlp - otlphttp receiver: - otlp opentelemetry-collector-0.141.0/scraper/000077500000000000000000000000001511331344600201755ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/Makefile000066400000000000000000000000331511331344600216310ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/scraper/README.md000066400000000000000000000020141511331344600214510ustar00rootroot00000000000000# General Information A scraper defines how to connect and scrape telemetry data from an external source. | Status | | | ------------- |-----------| | Stability | [development]: metrics, logs | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Apkg%2F%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Apkg%2F) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Apkg%2F%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Apkg%2F) | [development]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#development opentelemetry-collector-0.141.0/scraper/doc.go000066400000000000000000000004421511331344600212710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package scraper allows to define pull based receivers that can be configured using the scraperreceiver. package scraper // import "go.opentelemetry.io/collector/scraper" opentelemetry-collector-0.141.0/scraper/factory.go000066400000000000000000000102601511331344600221720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraper // import "go.opentelemetry.io/collector/scraper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pipeline" ) // Settings configures scraper creators. type Settings struct { // ID returns the ID of the component that will be created. ID component.ID component.TelemetrySettings // BuildInfo can be used by components for informational purposes. BuildInfo component.BuildInfo // prevent unkeyed literal initialization _ struct{} } // Factory is factory interface for scrapers. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. type Factory interface { component.Factory // CreateLogs creates a Logs scraper based on this config. // If the scraper type does not support logs, // this function returns the error [pipeline.ErrSignalNotSupported]. CreateLogs(ctx context.Context, set Settings, cfg component.Config) (Logs, error) // CreateMetrics creates a Metrics scraper based on this config. // If the scraper type does not support metrics, // this function returns the error [pipeline.ErrSignalNotSupported]. CreateMetrics(ctx context.Context, set Settings, cfg component.Config) (Metrics, error) // LogsStability gets the stability level of the Logs scraper. LogsStability() component.StabilityLevel // MetricsStability gets the stability level of the Metrics scraper. MetricsStability() component.StabilityLevel unexportedFactoryFunc() } // FactoryOption apply changes to Options. type FactoryOption interface { // applyOption applies the option. applyOption(o *factory) } var _ FactoryOption = (*factoryOptionFunc)(nil) // factoryOptionFunc is a FactoryOption created through a function. type factoryOptionFunc func(*factory) func (f factoryOptionFunc) applyOption(o *factory) { f(o) } type factory struct { cfgType component.Type component.CreateDefaultConfigFunc createLogsFunc CreateLogsFunc createMetricsFunc CreateMetricsFunc logsStabilityLevel component.StabilityLevel metricsStabilityLevel component.StabilityLevel } func (f *factory) Type() component.Type { return f.cfgType } func (f *factory) unexportedFactoryFunc() {} func (f *factory) LogsStability() component.StabilityLevel { return f.logsStabilityLevel } func (f *factory) MetricsStability() component.StabilityLevel { return f.metricsStabilityLevel } func (f *factory) CreateLogs(ctx context.Context, set Settings, cfg component.Config) (Logs, error) { if f.createLogsFunc == nil { return nil, pipeline.ErrSignalNotSupported } return f.createLogsFunc(ctx, set, cfg) } func (f *factory) CreateMetrics(ctx context.Context, set Settings, cfg component.Config) (Metrics, error) { if f.createMetricsFunc == nil { return nil, pipeline.ErrSignalNotSupported } return f.createMetricsFunc(ctx, set, cfg) } // CreateLogsFunc is the equivalent of Factory.CreateLogs(). type CreateLogsFunc func(context.Context, Settings, component.Config) (Logs, error) // CreateMetricsFunc is the equivalent of Factory.CreateMetrics(). type CreateMetricsFunc func(context.Context, Settings, component.Config) (Metrics, error) // WithLogs overrides the default "error not supported" implementation for CreateLogs and the default "undefined" stability level. func WithLogs(createLogs CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.logsStabilityLevel = sl o.createLogsFunc = createLogs }) } // WithMetrics overrides the default "error not supported" implementation for CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factory) { o.metricsStabilityLevel = sl o.createMetricsFunc = createMetrics }) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { f := &factory{ cfgType: cfgType, CreateDefaultConfigFunc: createDefaultConfig, } for _, opt := range options { opt.applyOption(f) } return f } opentelemetry-collector-0.141.0/scraper/factory_test.go000066400000000000000000000040311511331344600232300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraper import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pipeline" ) var testType = component.MustNewType("test") func nopSettings() Settings { return Settings{ ID: component.NewID(testType), TelemetrySettings: componenttest.NewNopTelemetrySettings(), } } func TestNewFactory(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) _, err := f.CreateLogs(context.Background(), nopSettings(), &defaultCfg) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) _, err = f.CreateMetrics(context.Background(), nopSettings(), &defaultCfg) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) } func TestNewFactoryWithOptions(t *testing.T) { testType := component.MustNewType("test") defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }, WithLogs(createLogs, component.StabilityLevelAlpha), WithMetrics(createMetrics, component.StabilityLevelAlpha)) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelAlpha, f.LogsStability()) _, err := f.CreateLogs(context.Background(), Settings{}, &defaultCfg) require.NoError(t, err) assert.Equal(t, component.StabilityLevelAlpha, f.MetricsStability()) _, err = f.CreateMetrics(context.Background(), Settings{}, &defaultCfg) require.NoError(t, err) } func createLogs(context.Context, Settings, component.Config) (Logs, error) { return NewLogs(newTestScrapeLogsFunc(nil)) } func createMetrics(context.Context, Settings, component.Config) (Metrics, error) { return NewMetrics(newTestScrapeMetricsFunc(nil)) } opentelemetry-collector-0.141.0/scraper/generated_package_test.go000066400000000000000000000002461511331344600251760ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package scraper import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/scraper/go.mod000066400000000000000000000033651511331344600213120ustar00rootroot00000000000000module go.opentelemetry.io/collector/scraper go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pipeline => ../pipeline replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/component/componenttest => ../component/componenttest replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/scraper/go.sum000066400000000000000000000140451511331344600213340ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/scraper/logs.go000066400000000000000000000017641511331344600215000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraper // import "go.opentelemetry.io/collector/scraper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/plog" ) // Logs is the base interface for logs scrapers. type Logs interface { component.Component // ScrapeLogs is the base interface to indicate that how should logs be scraped. ScrapeLogs(context.Context) (plog.Logs, error) } // ScrapeLogsFunc is a helper function that is similar to Logs.ScrapeLogs. type ScrapeLogsFunc ScrapeFunc[plog.Logs] func (sf ScrapeLogsFunc) ScrapeLogs(ctx context.Context) (plog.Logs, error) { return sf(ctx) } type logs struct { baseScraper ScrapeLogsFunc } // NewLogs creates a new Logs scraper. func NewLogs(scrape ScrapeLogsFunc, options ...Option) (Logs, error) { if scrape == nil { return nil, errNilFunc } bs := &logs{ baseScraper: newBaseScraper(options), ScrapeLogsFunc: scrape, } return bs, nil } opentelemetry-collector-0.141.0/scraper/logs_test.go000066400000000000000000000041051511331344600225270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraper import ( "context" "errors" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/plog" ) func TestNewLogs(t *testing.T) { mp, err := NewLogs(newTestScrapeLogsFunc(nil)) require.NoError(t, err) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) md, err := mp.ScrapeLogs(context.Background()) require.NoError(t, err) assert.Equal(t, plog.NewLogs(), md) require.NoError(t, mp.Shutdown(context.Background())) } func TestNewLogs_WithOptions(t *testing.T) { want := errors.New("my_error") mp, err := NewLogs(newTestScrapeLogsFunc(nil), WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want })) require.NoError(t, err) assert.Equal(t, want, mp.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, mp.Shutdown(context.Background())) } func TestNewLogs_NilRequiredFields(t *testing.T) { _, err := NewLogs(nil) require.Error(t, err) } func TestNewLogs_ProcessLogsError(t *testing.T) { want := errors.New("my_error") mp, err := NewLogs(newTestScrapeLogsFunc(want)) require.NoError(t, err) _, err = mp.ScrapeLogs(context.Background()) require.ErrorIs(t, err, want) } func TestLogsConcurrency(t *testing.T) { mp, err := NewLogs(newTestScrapeLogsFunc(nil)) require.NoError(t, err) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) var wg sync.WaitGroup for range 10 { wg.Add(1) go func() { defer wg.Done() for range 10000 { _, errScrape := mp.ScrapeLogs(context.Background()) assert.NoError(t, errScrape) } }() } wg.Wait() require.NoError(t, mp.Shutdown(context.Background())) } func newTestScrapeLogsFunc(retError error) ScrapeLogsFunc { return func(_ context.Context) (plog.Logs, error) { return plog.NewLogs(), retError } } opentelemetry-collector-0.141.0/scraper/metadata.yaml000066400000000000000000000002471511331344600226440ustar00rootroot00000000000000type: scraper github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg stability: development: [metrics, logs] opentelemetry-collector-0.141.0/scraper/metrics.go000066400000000000000000000017631511331344600222010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraper // import "go.opentelemetry.io/collector/scraper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pmetric" ) // Metrics is the base interface for metrics scrapers. type Metrics interface { component.Component ScrapeMetrics(context.Context) (pmetric.Metrics, error) } // ScrapeMetricsFunc is a helper function that is similar to Metrics.ScrapeMetrics. type ScrapeMetricsFunc ScrapeFunc[pmetric.Metrics] func (sf ScrapeMetricsFunc) ScrapeMetrics(ctx context.Context) (pmetric.Metrics, error) { return sf(ctx) } type metrics struct { baseScraper ScrapeMetricsFunc } // NewMetrics creates a new Metrics scraper. func NewMetrics(scrape ScrapeMetricsFunc, options ...Option) (Metrics, error) { if scrape == nil { return nil, errNilFunc } bs := &metrics{ baseScraper: newBaseScraper(options), ScrapeMetricsFunc: scrape, } return bs, nil } opentelemetry-collector-0.141.0/scraper/metrics_test.go000066400000000000000000000046251511331344600232400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraper import ( "context" "errors" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/pmetric" ) func TestNewMetrics(t *testing.T) { mp, err := NewMetrics(newTestScrapeMetricsFunc(nil)) require.NoError(t, err) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) md, err := mp.ScrapeMetrics(context.Background()) require.NoError(t, err) assert.Equal(t, pmetric.NewMetrics(), md) require.NoError(t, mp.Shutdown(context.Background())) } func TestNewMetrics_WithOptions(t *testing.T) { want := errors.New("my_error") mp, err := NewMetrics(newTestScrapeMetricsFunc(nil), WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want })) require.NoError(t, err) assert.Equal(t, want, mp.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, mp.Shutdown(context.Background())) } func TestNewMetrics_NilRequiredFields(t *testing.T) { _, err := NewMetrics(nil) require.Error(t, err) } func TestNewMetrics_ProcessMetricsError(t *testing.T) { want := errors.New("my_error") mp, err := NewMetrics(newTestScrapeMetricsFunc(want)) require.NoError(t, err) _, err = mp.ScrapeMetrics(context.Background()) require.ErrorIs(t, err, want) } func TestMetricsConcurrency(t *testing.T) { incomingMetrics := pmetric.NewMetrics() dps := incomingMetrics.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptySum().DataPoints() // Add 2 data points to the incoming dps.AppendEmpty() dps.AppendEmpty() mp, err := NewMetrics(newTestScrapeMetricsFunc(nil)) require.NoError(t, err) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) var wg sync.WaitGroup for range 10 { wg.Add(1) go func() { defer wg.Done() for range 10000 { _, errScrape := mp.ScrapeMetrics(context.Background()) assert.NoError(t, errScrape) } }() } wg.Wait() require.NoError(t, mp.Shutdown(context.Background())) } func newTestScrapeMetricsFunc(retError error) ScrapeMetricsFunc { return func(_ context.Context) (pmetric.Metrics, error) { return pmetric.NewMetrics(), retError } } opentelemetry-collector-0.141.0/scraper/scraper.go000066400000000000000000000024301511331344600221620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraper // import "go.opentelemetry.io/collector/scraper" import ( "context" "errors" "go.opentelemetry.io/collector/component" ) var errNilFunc = errors.New("nil scrape func") // ScrapeFunc scrapes data. type ScrapeFunc[T any] func(context.Context) (T, error) // Option apply changes to internal options. type Option interface { apply(*baseScraper) } type scraperOptionFunc func(*baseScraper) func (of scraperOptionFunc) apply(e *baseScraper) { of(e) } // WithStart sets the function that will be called on startup. func WithStart(start component.StartFunc) Option { return scraperOptionFunc(func(o *baseScraper) { o.StartFunc = start }) } // WithShutdown sets the function that will be called on shutdown. func WithShutdown(shutdown component.ShutdownFunc) Option { return scraperOptionFunc(func(o *baseScraper) { o.ShutdownFunc = shutdown }) } type baseScraper struct { component.StartFunc component.ShutdownFunc } // newBaseScraper returns the internal settings starting from the default and applying all options. func newBaseScraper(options []Option) baseScraper { // Start from the default options: bs := baseScraper{} for _, op := range options { op.apply(&bs) } return bs } opentelemetry-collector-0.141.0/scraper/scrapererror/000077500000000000000000000000001511331344600227065ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/scrapererror/doc.go000066400000000000000000000003451511331344600240040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package scrapererror provides custom error types for scrapers. package scrapererror // import "go.opentelemetry.io/collector/scraper/scrapererror" opentelemetry-collector-0.141.0/scraper/scrapererror/package_test.go000066400000000000000000000003151511331344600256660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scrapererror import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/scraper/scrapererror/partialscrapeerror.go000066400000000000000000000014731511331344600271460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scrapererror // import "go.opentelemetry.io/collector/scraper/scrapererror" import "errors" // PartialScrapeError is an error to represent // that a subset of data were failed to be scraped. type PartialScrapeError struct { error Failed int } // NewPartialScrapeError creates PartialScrapeError for failed data. // Use this error type only when a subset of data was failed to be scraped. func NewPartialScrapeError(err error, failed int) PartialScrapeError { return PartialScrapeError{ error: err, Failed: failed, } } // IsPartialScrapeError checks if an error was wrapped with PartialScrapeError. func IsPartialScrapeError(err error) bool { var partialScrapeErr PartialScrapeError return errors.As(err, &partialScrapeErr) } opentelemetry-collector-0.141.0/scraper/scrapererror/partialscrapeerror_test.go000066400000000000000000000012161511331344600302000ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scrapererror import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestPartialScrapeError(t *testing.T) { failed := 2 err := errors.New("some error") partialErr := NewPartialScrapeError(err, failed) require.EqualError(t, err, partialErr.Error()) assert.Equal(t, failed, partialErr.Failed) } func TestIsPartialScrapeError(t *testing.T) { err := errors.New("testError") require.False(t, IsPartialScrapeError(err)) err = NewPartialScrapeError(err, 2) require.True(t, IsPartialScrapeError(err)) } opentelemetry-collector-0.141.0/scraper/scrapererror/scrapeerror.go000066400000000000000000000022321511331344600255630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scrapererror // import "go.opentelemetry.io/collector/scraper/scrapererror" import ( "go.uber.org/multierr" ) // ScrapeErrors contains multiple PartialScrapeErrors and can also contain generic errors. type ScrapeErrors struct { errs []error failedScrapeCount int } // AddPartial adds a PartialScrapeError with the provided failed count and error. func (s *ScrapeErrors) AddPartial(failed int, err error) { s.errs = append(s.errs, NewPartialScrapeError(err, failed)) s.failedScrapeCount += failed } // Add adds a regular error. func (s *ScrapeErrors) Add(err error) { s.errs = append(s.errs, err) } // Combine converts a slice of errors into one error. // It will return a PartialScrapeError if at least one error in the slice is a PartialScrapeError. func (s *ScrapeErrors) Combine() error { partialScrapeErr := false for _, err := range s.errs { if IsPartialScrapeError(err) { partialScrapeErr = true } } combined := multierr.Combine(s.errs...) if !partialScrapeErr { return combined } return NewPartialScrapeError(combined, s.failedScrapeCount) } opentelemetry-collector-0.141.0/scraper/scrapererror/scrapeerror_test.go000066400000000000000000000054361511331344600266330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scrapererror import ( "errors" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestScrapeErrorsAddPartial(t *testing.T) { err1 := errors.New("err 1") err2 := errors.New("err 2") expected := []error{ PartialScrapeError{error: err1, Failed: 1}, PartialScrapeError{error: err2, Failed: 10}, } var errs ScrapeErrors errs.AddPartial(1, err1) errs.AddPartial(10, err2) assert.Equal(t, expected, errs.errs) } func TestScrapeErrorsAdd(t *testing.T) { err1 := errors.New("err a") err2 := errors.New("err b") expected := []error{err1, err2} var errs ScrapeErrors errs.Add(err1) errs.Add(err2) assert.Equal(t, expected, errs.errs) } func TestScrapeErrorsCombine(t *testing.T) { testCases := []struct { errs func() ScrapeErrors expectedErr string expectedFailedCount int expectNil bool expectedScrape bool }{ { errs: func() ScrapeErrors { var errs ScrapeErrors return errs }, expectNil: true, }, { errs: func() ScrapeErrors { var errs ScrapeErrors errs.AddPartial(10, errors.New("bad scrapes")) errs.AddPartial(1, fmt.Errorf("err: %w", errors.New("bad scrape"))) return errs }, expectedErr: "bad scrapes; err: bad scrape", expectedFailedCount: 11, expectedScrape: true, }, { errs: func() ScrapeErrors { var errs ScrapeErrors errs.Add(errors.New("bad regular")) errs.Add(fmt.Errorf("err: %w", errors.New("bad reg"))) return errs }, expectedErr: "bad regular; err: bad reg", }, { errs: func() ScrapeErrors { var errs ScrapeErrors errs.AddPartial(2, errors.New("bad two scrapes")) errs.AddPartial(10, fmt.Errorf("%d scrapes failed: %w", 10, errors.New("bad things happened"))) errs.Add(errors.New("bad event")) errs.Add(fmt.Errorf("event: %w", errors.New("something happened"))) return errs }, expectedErr: "bad two scrapes; 10 scrapes failed: bad things happened; bad event; event: something happened", expectedFailedCount: 12, expectedScrape: true, }, } for _, tt := range testCases { scrapeErrs := tt.errs() if tt.expectNil { require.NoError(t, scrapeErrs.Combine()) continue } require.EqualError(t, scrapeErrs.Combine(), tt.expectedErr) if tt.expectedScrape { var partialScrapeErr PartialScrapeError if !errors.As(scrapeErrs.Combine(), &partialScrapeErr) { t.Errorf("%+v.Combine() = %q. Want: PartialScrapeError", scrapeErrs, scrapeErrs.Combine()) } else if tt.expectedFailedCount != partialScrapeErr.Failed { t.Errorf("%+v.Combine().Failed. Got %d Failed count. Want: %d", scrapeErrs, partialScrapeErr.Failed, tt.expectedFailedCount) } } } } opentelemetry-collector-0.141.0/scraper/scraperhelper/000077500000000000000000000000001511331344600230345ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/scraperhelper/Makefile000066400000000000000000000000361511331344600244730ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/scraper/scraperhelper/README.md000066400000000000000000000020531511331344600243130ustar00rootroot00000000000000# General Information A scraper defines how to connect and scrape telemetry data from an external source. | Status | | | ------------- |-----------| | Stability | [beta]: metrics, logs | | Issues | [![Open issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aopen%20label%3Apkg%2Fscraperhelper%20&label=open&color=orange&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aopen+is%3Aissue+label%3Apkg%2Fscraperhelper) [![Closed issues](https://img.shields.io/github/issues-search/open-telemetry/opentelemetry-collector?query=is%3Aissue%20is%3Aclosed%20label%3Apkg%2Fscraperhelper%20&label=closed&color=blue&logo=opentelemetry)](https://github.com/open-telemetry/opentelemetry-collector/issues?q=is%3Aclosed+is%3Aissue+label%3Apkg%2Fscraperhelper) | [beta]: https://github.com/open-telemetry/opentelemetry-collector/blob/main/docs/component-stability.md#beta opentelemetry-collector-0.141.0/scraper/scraperhelper/config.go000066400000000000000000000033201511331344600246260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper // import "go.opentelemetry.io/collector/scraper/scraperhelper" import ( "errors" "fmt" "time" "go.uber.org/multierr" ) var errNonPositiveInterval = errors.New("requires positive value") // ControllerConfig defines common settings for a scraper controller // configuration. Scraper controller receivers can embed this struct, instead // of receiver.Settings, and extend it with more fields if needed. type ControllerConfig struct { // CollectionInterval sets how frequently the scraper // should be called and used as the context timeout // to ensure that scrapers don't exceed the interval. CollectionInterval time.Duration `mapstructure:"collection_interval"` // InitialDelay sets the initial start delay for the scraper, // any non positive value is assumed to be immediately. InitialDelay time.Duration `mapstructure:"initial_delay"` // Timeout is an optional value used to set scraper's context deadline. Timeout time.Duration `mapstructure:"timeout"` // prevent unkeyed literal initialization _ struct{} } // NewDefaultControllerConfig returns default scraper controller // settings with a collection interval of one minute. func NewDefaultControllerConfig() ControllerConfig { return ControllerConfig{ CollectionInterval: time.Minute, InitialDelay: time.Second, Timeout: 0, } } func (set *ControllerConfig) Validate() (errs error) { if set.CollectionInterval <= 0 { errs = multierr.Append(errs, fmt.Errorf(`"collection_interval": %w`, errNonPositiveInterval)) } if set.Timeout < 0 { errs = multierr.Append(errs, fmt.Errorf(`"timeout": %w`, errNonPositiveInterval)) } return errs } opentelemetry-collector-0.141.0/scraper/scraperhelper/config_test.go000066400000000000000000000020001511331344600256570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper import ( "testing" "time" "github.com/stretchr/testify/assert" ) func TestScrapeControllerSettings(t *testing.T) { t.Parallel() for _, tc := range []struct { name string set ControllerConfig errVal string }{ { name: "default configuration", set: NewDefaultControllerConfig(), errVal: "", }, { name: "zero value configuration", set: ControllerConfig{}, errVal: `"collection_interval": requires positive value`, }, { name: "invalid timeout", set: ControllerConfig{ CollectionInterval: time.Minute, Timeout: -1 * time.Minute, }, errVal: `"timeout": requires positive value`, }, } { t.Run(tc.name, func(t *testing.T) { t.Parallel() err := tc.set.Validate() if tc.errVal == "" { assert.NoError(t, err, "Must not error") return } assert.EqualError(t, err, tc.errVal, "Must match the expected error") }) } } opentelemetry-collector-0.141.0/scraper/scraperhelper/controller.go000066400000000000000000000205161511331344600255520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper // import "go.opentelemetry.io/collector/scraper/scraperhelper" import ( "context" "sync" "time" "go.uber.org/multierr" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receiverhelper" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapererror" ) // ControllerOption apply changes to internal options. type ControllerOption interface { apply(*controllerOptions) } type optionFunc func(*controllerOptions) func (of optionFunc) apply(e *controllerOptions) { of(e) } // AddScraper configures the scraper.Metrics to be called with the specified options, // and at the specified collection interval. // // Observability information will be reported, and the scraped metrics // will be passed to the next consumer. func AddScraper(t component.Type, sc scraper.Metrics) ControllerOption { f := scraper.NewFactory(t, nil, scraper.WithMetrics(func(context.Context, scraper.Settings, component.Config) (scraper.Metrics, error) { return sc, nil }, component.StabilityLevelAlpha)) return AddFactoryWithConfig(f, nil) } // AddFactoryWithConfig configures the scraper.Factory and associated config that // will be used to create a new scraper. The created scraper will be called with // the specified options, and at the specified collection interval. // // Observability information will be reported, and the scraped metrics // will be passed to the next consumer. func AddFactoryWithConfig(f scraper.Factory, cfg component.Config) ControllerOption { return optionFunc(func(o *controllerOptions) { o.factoriesWithConfig = append(o.factoriesWithConfig, factoryWithConfig{f: f, cfg: cfg}) }) } // WithTickerChannel allows you to override the scraper controller's ticker // channel to specify when scrape is called. This is only expected to be // used by tests. func WithTickerChannel(tickerCh <-chan time.Time) ControllerOption { return optionFunc(func(o *controllerOptions) { o.tickerCh = tickerCh }) } type factoryWithConfig struct { f scraper.Factory cfg component.Config } type controllerOptions struct { tickerCh <-chan time.Time factoriesWithConfig []factoryWithConfig } type controller[T component.Component] struct { collectionInterval time.Duration initialDelay time.Duration timeout time.Duration scrapers []T scrapeFunc func(*controller[T]) tickerCh <-chan time.Time done chan struct{} wg sync.WaitGroup obsrecv *receiverhelper.ObsReport } func newController[T component.Component]( cfg *ControllerConfig, rSet receiver.Settings, scrapers []T, scrapeFunc func(*controller[T]), tickerCh <-chan time.Time, ) (*controller[T], error) { obsrecv, err := receiverhelper.NewObsReport(receiverhelper.ObsReportSettings{ ReceiverID: rSet.ID, Transport: "", ReceiverCreateSettings: rSet, }) if err != nil { return nil, err } cs := &controller[T]{ collectionInterval: cfg.CollectionInterval, initialDelay: cfg.InitialDelay, timeout: cfg.Timeout, scrapers: scrapers, scrapeFunc: scrapeFunc, done: make(chan struct{}), tickerCh: tickerCh, obsrecv: obsrecv, } return cs, nil } // Start the receiver, invoked during service start. func (sc *controller[T]) Start(ctx context.Context, host component.Host) error { for _, scrp := range sc.scrapers { if err := scrp.Start(ctx, host); err != nil { return err } } sc.startScraping() return nil } // Shutdown the receiver, invoked during service shutdown. func (sc *controller[T]) Shutdown(ctx context.Context) error { // Signal the goroutine to stop. close(sc.done) sc.wg.Wait() var errs error for _, scrp := range sc.scrapers { errs = multierr.Append(errs, scrp.Shutdown(ctx)) } return errs } // startScraping initiates a ticker that calls Scrape based on the configured // collection interval. func (sc *controller[T]) startScraping() { sc.wg.Add(1) go func() { defer sc.wg.Done() if sc.initialDelay > 0 { select { case <-time.After(sc.initialDelay): case <-sc.done: return } } if sc.tickerCh == nil { ticker := time.NewTicker(sc.collectionInterval) defer ticker.Stop() sc.tickerCh = ticker.C } // Call scrape method during initialization to ensure // that scrapers start from when the component starts // instead of waiting for the full duration to start. sc.scrapeFunc(sc) for { select { case <-sc.tickerCh: sc.scrapeFunc(sc) case <-sc.done: return } } }() } // NewLogsController creates a receiver.Logs with the configured options, that can control multiple scraper.Logs. func NewLogsController(cfg *ControllerConfig, rSet receiver.Settings, nextConsumer consumer.Logs, options ...ControllerOption, ) (receiver.Logs, error) { co := getOptions(options) scrapers := make([]scraper.Logs, 0, len(co.factoriesWithConfig)) for _, fwc := range co.factoriesWithConfig { set := getSettings(fwc.f.Type(), rSet) s, err := fwc.f.CreateLogs(context.Background(), set, fwc.cfg) if err != nil { return nil, err } s, err = wrapObsLogs(s, rSet.ID, set.ID, set.TelemetrySettings) if err != nil { return nil, err } scrapers = append(scrapers, s) } return newController[scraper.Logs]( cfg, rSet, scrapers, func(c *controller[scraper.Logs]) { scrapeLogs(c, nextConsumer) }, co.tickerCh) } // NewMetricsController creates a receiver.Metrics with the configured options, that can control multiple scraper.Metrics. func NewMetricsController(cfg *ControllerConfig, rSet receiver.Settings, nextConsumer consumer.Metrics, options ...ControllerOption, ) (receiver.Metrics, error) { co := getOptions(options) scrapers := make([]scraper.Metrics, 0, len(co.factoriesWithConfig)) for _, fwc := range co.factoriesWithConfig { set := getSettings(fwc.f.Type(), rSet) s, err := fwc.f.CreateMetrics(context.Background(), set, fwc.cfg) if err != nil { return nil, err } s, err = wrapObsMetrics(s, rSet.ID, set.ID, set.TelemetrySettings) if err != nil { return nil, err } scrapers = append(scrapers, s) } return newController[scraper.Metrics]( cfg, rSet, scrapers, func(c *controller[scraper.Metrics]) { scrapeMetrics(c, nextConsumer) }, co.tickerCh) } func scrapeLogs(c *controller[scraper.Logs], nextConsumer consumer.Logs) { ctx, done := withScrapeContext(c.timeout) defer done() logs := plog.NewLogs() for i := range c.scrapers { md, err := c.scrapers[i].ScrapeLogs(ctx) if err != nil && !scrapererror.IsPartialScrapeError(err) { continue } md.ResourceLogs().MoveAndAppendTo(logs.ResourceLogs()) } logRecordCount := logs.LogRecordCount() ctx = c.obsrecv.StartMetricsOp(ctx) err := nextConsumer.ConsumeLogs(ctx, logs) c.obsrecv.EndMetricsOp(ctx, "", logRecordCount, err) } func scrapeMetrics(c *controller[scraper.Metrics], nextConsumer consumer.Metrics) { ctx, done := withScrapeContext(c.timeout) defer done() metrics := pmetric.NewMetrics() for i := range c.scrapers { md, err := c.scrapers[i].ScrapeMetrics(ctx) if err != nil && !scrapererror.IsPartialScrapeError(err) { continue } md.ResourceMetrics().MoveAndAppendTo(metrics.ResourceMetrics()) } dataPointCount := metrics.DataPointCount() ctx = c.obsrecv.StartMetricsOp(ctx) err := nextConsumer.ConsumeMetrics(ctx, metrics) c.obsrecv.EndMetricsOp(ctx, "", dataPointCount, err) } func getOptions(options []ControllerOption) controllerOptions { co := controllerOptions{} for _, op := range options { op.apply(&co) } return co } func getSettings(sType component.Type, rSet receiver.Settings) scraper.Settings { return scraper.Settings{ ID: component.NewID(sType), TelemetrySettings: rSet.TelemetrySettings, BuildInfo: rSet.BuildInfo, } } // withScrapeContext will return a context that has no deadline if timeout is 0 // which implies no explicit timeout had occurred, otherwise, a context // with a deadline of the provided timeout is returned. func withScrapeContext(timeout time.Duration) (context.Context, context.CancelFunc) { if timeout == 0 { return context.WithCancel(context.Background()) } return context.WithTimeout(context.Background(), timeout) } opentelemetry-collector-0.141.0/scraper/scraperhelper/controller_test.go000066400000000000000000000564441511331344600266220ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper import ( "context" "errors" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" sdktrace "go.opentelemetry.io/otel/sdk/trace" "go.uber.org/multierr" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapererror" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadatatest" ) type testInitialize struct { ch chan bool err error } func (ts *testInitialize) start(context.Context, component.Host) error { ts.ch <- true return ts.err } type testClose struct { ch chan bool err error } func (ts *testClose) shutdown(context.Context) error { ts.ch <- true return ts.err } type testScrape struct { ch chan int timesScrapeCalled int err error } func (ts *testScrape) scrapeLogs(context.Context) (plog.Logs, error) { ts.timesScrapeCalled++ ts.ch <- ts.timesScrapeCalled if ts.err != nil { return plog.Logs{}, ts.err } md := plog.NewLogs() md.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty().Body().SetStr("") return md, nil } func (ts *testScrape) scrapeMetrics(context.Context) (pmetric.Metrics, error) { ts.timesScrapeCalled++ ts.ch <- ts.timesScrapeCalled if ts.err != nil { return pmetric.Metrics{}, ts.err } md := pmetric.NewMetrics() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyGauge().DataPoints().AppendEmpty() return md, nil } func newTestNoDelaySettings() *ControllerConfig { return &ControllerConfig{ CollectionInterval: time.Second, InitialDelay: 0, } } type scraperTestCase struct { name string scrapers int scraperControllerSettings *ControllerConfig scrapeErr error expectScraped bool initialize bool close bool initializeErr error closeErr error } func TestLogsScrapeController(t *testing.T) { testCases := []scraperTestCase{ { name: "NoScrapers", }, { name: "AddLogsScrapersWithCollectionInterval", scrapers: 2, expectScraped: true, }, { name: "AddLogsScrapers_ScrapeError", scrapers: 2, scrapeErr: errors.New("err1"), }, { name: "AddLogsScrapersWithInitializeAndClose", scrapers: 2, initialize: true, expectScraped: true, close: true, }, { name: "AddLogsScrapersWithInitializeAndCloseErrors", scrapers: 2, initialize: true, close: true, initializeErr: errors.New("err1"), closeErr: errors.New("err2"), }, } for _, test := range testCases { t.Run(test.name, func(t *testing.T) { receiverID := component.MustNewID("receiver") tel := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) set := tel.NewTelemetrySettings() _, parentSpan := set.TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() initializeChs := make([]chan bool, test.scrapers) scrapeLogsChs := make([]chan int, test.scrapers) closeChs := make([]chan bool, test.scrapers) options := configureLogOptions(t, test, initializeChs, scrapeLogsChs, closeChs) tickerCh := make(chan time.Time) options = append(options, WithTickerChannel(tickerCh)) sink := new(consumertest.LogsSink) cfg := newTestNoDelaySettings() if test.scraperControllerSettings != nil { cfg = test.scraperControllerSettings } mr, err := NewLogsController(cfg, receiver.Settings{ID: receiverID, TelemetrySettings: set, BuildInfo: component.NewDefaultBuildInfo()}, sink, options...) require.NoError(t, err) err = mr.Start(context.Background(), componenttest.NewNopHost()) expectedStartErr := getExpectedStartErr(test) if expectedStartErr != nil { assert.Equal(t, expectedStartErr, err) } else if test.initialize { assertChannelsCalled(t, initializeChs, "start was not called") } const iterations = 5 if test.expectScraped || test.scrapeErr != nil { // validate that scrape is called at least N times for each configured scraper for _, ch := range scrapeLogsChs { <-ch } // Consume the initial scrapes on start for range iterations { tickerCh <- time.Now() for _, ch := range scrapeLogsChs { <-ch } } // wait until all calls to scrape have completed if test.scrapeErr == nil { require.Eventually(t, func() bool { return sink.LogRecordCount() == (1+iterations)*(test.scrapers) }, time.Second, time.Millisecond) } if test.expectScraped { assert.GreaterOrEqual(t, sink.LogRecordCount(), iterations) } spans := tel.SpanRecorder.Ended() assertReceiverSpan(t, spans) assertScraperSpan(t, test.scrapeErr, spans, "scraper/scraper/ScrapeLogs") assertLogsScraperObsMetrics(t, tel, receiverID, component.MustNewID("scraper"), test.scrapeErr, sink) } err = mr.Shutdown(context.Background()) expectedShutdownErr := getExpectedShutdownErr(test) if expectedShutdownErr != nil { assert.EqualError(t, err, expectedShutdownErr.Error()) } else if test.close { assertChannelsCalled(t, closeChs, "shutdown was not called") } }) } } func TestMetricsScrapeController(t *testing.T) { testCases := []scraperTestCase{ { name: "NoScrapers", }, { name: "AddMetricsScrapersWithCollectionInterval", scrapers: 2, expectScraped: true, }, { name: "AddMetricsScrapers_ScrapeError", scrapers: 2, scrapeErr: errors.New("err1"), }, { name: "AddMetricsScrapersWithInitializeAndClose", scrapers: 2, initialize: true, expectScraped: true, close: true, }, { name: "AddMetricsScrapersWithInitializeAndCloseErrors", scrapers: 2, initialize: true, close: true, initializeErr: errors.New("err1"), closeErr: errors.New("err2"), }, } for _, test := range testCases { t.Run(test.name, func(t *testing.T) { receiverID := component.MustNewID("receiver") tel := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) set := tel.NewTelemetrySettings() _, parentSpan := set.TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() initializeChs := make([]chan bool, test.scrapers) scrapeMetricsChs := make([]chan int, test.scrapers) closeChs := make([]chan bool, test.scrapers) options := configureMetricOptions(t, test, initializeChs, scrapeMetricsChs, closeChs) tickerCh := make(chan time.Time) options = append(options, WithTickerChannel(tickerCh)) sink := new(consumertest.MetricsSink) cfg := newTestNoDelaySettings() if test.scraperControllerSettings != nil { cfg = test.scraperControllerSettings } mr, err := NewMetricsController(cfg, receiver.Settings{ID: receiverID, TelemetrySettings: set, BuildInfo: component.NewDefaultBuildInfo()}, sink, options...) require.NoError(t, err) err = mr.Start(context.Background(), componenttest.NewNopHost()) expectedStartErr := getExpectedStartErr(test) if expectedStartErr != nil { assert.Equal(t, expectedStartErr, err) } else if test.initialize { assertChannelsCalled(t, initializeChs, "start was not called") } const iterations = 5 if test.expectScraped || test.scrapeErr != nil { // validate that scrape is called at least N times for each configured scraper for _, ch := range scrapeMetricsChs { <-ch } // Consume the initial scrapes on start for range iterations { tickerCh <- time.Now() for _, ch := range scrapeMetricsChs { <-ch } } // wait until all calls to scrape have completed if test.scrapeErr == nil { require.Eventually(t, func() bool { return sink.DataPointCount() == (1+iterations)*(test.scrapers) }, time.Second, time.Millisecond) } if test.expectScraped { assert.GreaterOrEqual(t, sink.DataPointCount(), iterations) } spans := tel.SpanRecorder.Ended() assertReceiverSpan(t, spans) assertScraperSpan(t, test.scrapeErr, spans, "scraper/scraper/ScrapeMetrics") assertMetricsScraperObsMetrics(t, tel, receiverID, component.MustNewID("scraper"), test.scrapeErr, sink) } err = mr.Shutdown(context.Background()) expectedShutdownErr := getExpectedShutdownErr(test) if expectedShutdownErr != nil { assert.EqualError(t, err, expectedShutdownErr.Error()) } else if test.close { assertChannelsCalled(t, closeChs, "shutdown was not called") } }) } } func configureLogOptions(t *testing.T, test scraperTestCase, initializeChs []chan bool, scrapeLogsChs []chan int, closeChs []chan bool) []ControllerOption { var logsOptions []ControllerOption for i := 0; i < test.scrapers; i++ { var scraperOptions []scraper.Option if test.initialize { initializeChs[i] = make(chan bool, 1) ti := &testInitialize{ch: initializeChs[i], err: test.initializeErr} scraperOptions = append(scraperOptions, scraper.WithStart(ti.start)) } if test.close { closeChs[i] = make(chan bool, 1) tc := &testClose{ch: closeChs[i], err: test.closeErr} scraperOptions = append(scraperOptions, scraper.WithShutdown(tc.shutdown)) } scrapeLogsChs[i] = make(chan int) ts := &testScrape{ch: scrapeLogsChs[i], err: test.scrapeErr} scp, err := scraper.NewLogs(ts.scrapeLogs, scraperOptions...) require.NoError(t, err) logsOptions = append(logsOptions, addLogsScraper(component.MustNewType("scraper"), scp)) } return logsOptions } func configureMetricOptions(t *testing.T, test scraperTestCase, initializeChs []chan bool, scrapeMetricsChs []chan int, closeChs []chan bool) []ControllerOption { var metricOptions []ControllerOption for i := 0; i < test.scrapers; i++ { var scraperOptions []scraper.Option if test.initialize { initializeChs[i] = make(chan bool, 1) ti := &testInitialize{ch: initializeChs[i], err: test.initializeErr} scraperOptions = append(scraperOptions, scraper.WithStart(ti.start)) } if test.close { closeChs[i] = make(chan bool, 1) tc := &testClose{ch: closeChs[i], err: test.closeErr} scraperOptions = append(scraperOptions, scraper.WithShutdown(tc.shutdown)) } scrapeMetricsChs[i] = make(chan int) ts := &testScrape{ch: scrapeMetricsChs[i], err: test.scrapeErr} scp, err := scraper.NewMetrics(ts.scrapeMetrics, scraperOptions...) require.NoError(t, err) metricOptions = append(metricOptions, AddScraper(component.MustNewType("scraper"), scp)) } return metricOptions } func getExpectedStartErr(test scraperTestCase) error { return test.initializeErr } func getExpectedShutdownErr(test scraperTestCase) error { var errs error if test.closeErr != nil { for i := 0; i < test.scrapers; i++ { errs = multierr.Append(errs, test.closeErr) } } return errs } func assertChannelsCalled(t *testing.T, chs []chan bool, message string) { for _, ic := range chs { assertChannelCalled(t, ic, message) } } func assertChannelCalled(t *testing.T, ch chan bool, message string) { select { case <-ch: default: assert.Fail(t, message) } } func assertReceiverSpan(t *testing.T, spans []sdktrace.ReadOnlySpan) { receiverSpan := false for _, span := range spans { if span.Name() == "receiver/receiver/MetricsReceived" { receiverSpan = true break } } assert.True(t, receiverSpan) } func assertScraperSpan(t *testing.T, expectedErr error, spans []sdktrace.ReadOnlySpan, expectedSpanName string) { expectedStatusCode := codes.Unset expectedStatusMessage := "" if expectedErr != nil { expectedStatusCode = codes.Error expectedStatusMessage = expectedErr.Error() } scraperSpan := false for _, span := range spans { if span.Name() == expectedSpanName { scraperSpan = true assert.Equal(t, expectedStatusCode, span.Status().Code) assert.Equal(t, expectedStatusMessage, span.Status().Description) break } } assert.True(t, scraperSpan) } func assertLogsScraperObsMetrics(t *testing.T, tel *componenttest.Telemetry, receiver, scraper component.ID, expectedErr error, sink *consumertest.LogsSink) { logRecordCounts := 0 for _, md := range sink.AllLogs() { logRecordCounts += md.LogRecordCount() } expectedScraped := int64(sink.LogRecordCount()) expectedErrored := int64(0) if expectedErr != nil { var partialError scrapererror.PartialScrapeError if errors.As(expectedErr, &partialError) { expectedErrored = int64(partialError.Failed) } else { expectedScraped = int64(0) expectedErrored = int64(sink.LogRecordCount()) } } metadatatest.AssertEqualScraperScrapedLogRecords(t, tel, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: expectedScraped, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualScraperErroredLogRecords(t, tel, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: expectedErrored, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func assertMetricsScraperObsMetrics(t *testing.T, tel *componenttest.Telemetry, receiver, scraper component.ID, expectedErr error, sink *consumertest.MetricsSink) { dataPointCounts := 0 for _, md := range sink.AllMetrics() { dataPointCounts += md.DataPointCount() } expectedScraped := int64(sink.DataPointCount()) expectedErrored := int64(0) if expectedErr != nil { var partialError scrapererror.PartialScrapeError if errors.As(expectedErr, &partialError) { expectedErrored = int64(partialError.Failed) } else { expectedScraped = int64(0) expectedErrored = int64(sink.DataPointCount()) } } metadatatest.AssertEqualScraperScrapedMetricPoints(t, tel, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: expectedScraped, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualScraperErroredMetricPoints(t, tel, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: expectedErrored, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } func TestSingleLogsScraperPerInterval(t *testing.T) { scrapeCh := make(chan int, 10) ts := &testScrape{ch: scrapeCh} cfg := newTestNoDelaySettings() tickerCh := make(chan time.Time) scp, err := scraper.NewLogs(ts.scrapeLogs) require.NoError(t, err) recv, err := NewLogsController( cfg, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.LogsSink), addLogsScraper(component.MustNewType("scraper"), scp), WithTickerChannel(tickerCh), ) require.NoError(t, err) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) defer func() { require.NoError(t, recv.Shutdown(context.Background())) }() tickerCh <- time.Now() assert.Eventually( t, func() bool { return <-scrapeCh == 2 }, 300*time.Millisecond, 100*time.Millisecond, "Make sure the scraper channel is called twice", ) select { case <-scrapeCh: assert.Fail(t, "Scrape was called more than twice") case <-time.After(100 * time.Millisecond): return } } func TestSingleMetricsScraperPerInterval(t *testing.T) { scrapeCh := make(chan int, 10) ts := &testScrape{ch: scrapeCh} cfg := newTestNoDelaySettings() tickerCh := make(chan time.Time) scp, err := scraper.NewMetrics(ts.scrapeMetrics) require.NoError(t, err) recv, err := NewMetricsController( cfg, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.MetricsSink), AddScraper(component.MustNewType("scraper"), scp), WithTickerChannel(tickerCh), ) require.NoError(t, err) require.NoError(t, recv.Start(context.Background(), componenttest.NewNopHost())) defer func() { require.NoError(t, recv.Shutdown(context.Background())) }() tickerCh <- time.Now() assert.Eventually( t, func() bool { return <-scrapeCh == 2 }, 300*time.Millisecond, 100*time.Millisecond, "Make sure the scraper channel is called twice", ) select { case <-scrapeCh: assert.Fail(t, "Scrape was called more than twice") case <-time.After(100 * time.Millisecond): return } } func TestLogsScraperControllerStartsOnInit(t *testing.T) { t.Parallel() ts := &testScrape{ ch: make(chan int, 1), } scp, err := scraper.NewLogs(ts.scrapeLogs) require.NoError(t, err, "Must not error when creating scraper") r, err := NewLogsController( &ControllerConfig{ CollectionInterval: time.Hour, InitialDelay: 0, }, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.LogsSink), addLogsScraper(component.MustNewType("scraper"), scp), ) require.NoError(t, err, "Must not error when creating scrape controller") assert.NoError(t, r.Start(context.Background(), componenttest.NewNopHost()), "Must not error on start") <-time.After(500 * time.Nanosecond) require.NoError(t, r.Shutdown(context.Background()), "Must not have errored on shutdown") assert.Equal(t, 1, ts.timesScrapeCalled, "Must have been called as soon as the controller started") } func TestMetricsScraperControllerStartsOnInit(t *testing.T) { t.Parallel() ts := &testScrape{ ch: make(chan int, 1), } scp, err := scraper.NewMetrics(ts.scrapeMetrics) require.NoError(t, err, "Must not error when creating scraper") r, err := NewMetricsController( &ControllerConfig{ CollectionInterval: time.Hour, InitialDelay: 0, }, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.MetricsSink), AddScraper(component.MustNewType("scraper"), scp), ) require.NoError(t, err, "Must not error when creating scrape controller") assert.NoError(t, r.Start(context.Background(), componenttest.NewNopHost()), "Must not error on start") <-time.After(500 * time.Nanosecond) require.NoError(t, r.Shutdown(context.Background()), "Must not have errored on shutdown") assert.Equal(t, 1, ts.timesScrapeCalled, "Must have been called as soon as the controller started") } func TestLogsScraperControllerInitialDelay(t *testing.T) { if testing.Short() { t.Skip("This requires real time to pass, skipping") return } t.Parallel() var ( elapsed = make(chan time.Time, 1) cfg = ControllerConfig{ CollectionInterval: time.Second, InitialDelay: 300 * time.Millisecond, } ) scp, err := scraper.NewLogs(func(context.Context) (plog.Logs, error) { elapsed <- time.Now() return plog.NewLogs(), nil }) require.NoError(t, err, "Must not error when creating scraper") r, err := NewLogsController( &cfg, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.LogsSink), addLogsScraper(component.MustNewType("scraper"), scp), ) require.NoError(t, err, "Must not error when creating receiver") t0 := time.Now() require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost()), "Must not error when starting") t1 := <-elapsed assert.GreaterOrEqual(t, t1.Sub(t0), 300*time.Millisecond, "Must have had 300ms pass as defined by initial delay") assert.NoError(t, r.Shutdown(context.Background()), "Must not error closing down") } func TestMetricsScraperControllerInitialDelay(t *testing.T) { if testing.Short() { t.Skip("This requires real time to pass, skipping") return } t.Parallel() var ( elapsed = make(chan time.Time, 1) cfg = ControllerConfig{ CollectionInterval: time.Second, InitialDelay: 300 * time.Millisecond, } ) scp, err := scraper.NewMetrics(func(context.Context) (pmetric.Metrics, error) { elapsed <- time.Now() return pmetric.NewMetrics(), nil }) require.NoError(t, err, "Must not error when creating scraper") r, err := NewMetricsController( &cfg, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.MetricsSink), AddScraper(component.MustNewType("scraper"), scp), ) require.NoError(t, err, "Must not error when creating receiver") t0 := time.Now() require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost()), "Must not error when starting") t1 := <-elapsed assert.GreaterOrEqual(t, t1.Sub(t0), 300*time.Millisecond, "Must have had 300ms pass as defined by initial delay") assert.NoError(t, r.Shutdown(context.Background()), "Must not error closing down") } func TestLogsScraperShutdownBeforeScrapeCanStart(t *testing.T) { cfg := ControllerConfig{ CollectionInterval: time.Second, InitialDelay: 5 * time.Second, } scp, err := scraper.NewLogs(func(context.Context) (plog.Logs, error) { // make the scraper wait for long enough it would disrupt a shutdown. time.Sleep(30 * time.Second) return plog.NewLogs(), nil }) require.NoError(t, err, "Must not error when creating scraper") r, err := NewLogsController( &cfg, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.LogsSink), addLogsScraper(component.MustNewType("scraper"), scp), ) require.NoError(t, err, "Must not error when creating receiver") require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost())) shutdown := make(chan struct{}, 1) go func() { assert.NoError(t, r.Shutdown(context.Background())) close(shutdown) }() timer := time.NewTicker(10 * time.Second) select { case <-timer.C: require.Fail(t, "shutdown should not wait for scraping") case <-shutdown: } } func TestMetricsScraperShutdownBeforeScrapeCanStart(t *testing.T) { cfg := ControllerConfig{ CollectionInterval: time.Second, InitialDelay: 5 * time.Second, } scp, err := scraper.NewMetrics(func(context.Context) (pmetric.Metrics, error) { // make the scraper wait for long enough it would disrupt a shutdown. time.Sleep(30 * time.Second) return pmetric.NewMetrics(), nil }) require.NoError(t, err, "Must not error when creating scraper") r, err := NewMetricsController( &cfg, receivertest.NewNopSettings(receivertest.NopType), new(consumertest.MetricsSink), AddScraper(component.MustNewType("scraper"), scp), ) require.NoError(t, err, "Must not error when creating receiver") require.NoError(t, r.Start(context.Background(), componenttest.NewNopHost())) shutdown := make(chan struct{}, 1) go func() { assert.NoError(t, r.Shutdown(context.Background())) close(shutdown) }() timer := time.NewTicker(10 * time.Second) select { case <-timer.C: require.Fail(t, "shutdown should not wait for scraping") case <-shutdown: } } func addLogsScraper(t component.Type, sc scraper.Logs) ControllerOption { f := scraper.NewFactory(t, nil, scraper.WithLogs(func(context.Context, scraper.Settings, component.Config) (scraper.Logs, error) { return sc, nil }, component.StabilityLevelAlpha)) return AddFactoryWithConfig(f, nil) } opentelemetry-collector-0.141.0/scraper/scraperhelper/doc.go000066400000000000000000000004051511331344600241270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package scraperhelper provides utilities for scrapers. package scraperhelper // import "go.opentelemetry.io/collector/scraper/scraperhelper" opentelemetry-collector-0.141.0/scraper/scraperhelper/documentation.md000066400000000000000000000023001511331344600262220ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # scraperhelper ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol_scraper_errored_log_records Number of log records that were unable to be scraped. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_scraper_errored_metric_points Number of metric points that were unable to be scraped. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_scraper_scraped_log_records Number of log records successfully scraped. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | ### otelcol_scraper_scraped_metric_points Number of metric points successfully scraped. [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {datapoints} | Sum | Int | true | Alpha | opentelemetry-collector-0.141.0/scraper/scraperhelper/generated_package_test.go000066400000000000000000000002541511331344600300340ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package scraperhelper import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/scraper/scraperhelper/go.mod000066400000000000000000000066331511331344600241520ustar00rootroot00000000000000module go.opentelemetry.io/collector/scraper/scraperhelper go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/receiverhelper v0.141.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.opentelemetry.io/collector/scraper v0.141.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.1 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/consumer/consumererror v0.141.0 // indirect go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata/pprofile v0.141.0 // indirect go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 // indirect golang.org/x/sys v0.37.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/scraper => ../ replace go.opentelemetry.io/collector/receiver => ../../receiver replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror replace go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest replace go.opentelemetry.io/collector/receiver/receiverhelper => ../../receiver/receiverhelper replace go.opentelemetry.io/collector/consumer => ../../consumer replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver replace go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/scraper/scraperhelper/go.sum000066400000000000000000000157461511331344600242040ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo= golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/scraper/scraperhelper/internal/000077500000000000000000000000001511331344600246505ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/scraperhelper/internal/metadata/000077500000000000000000000000001511331344600264305ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/scraperhelper/internal/metadata/generated_telemetry.go000066400000000000000000000056431511331344600330170ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/scraper/scraperhelper") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/scraper/scraperhelper") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration ScraperErroredLogRecords metric.Int64Counter ScraperErroredMetricPoints metric.Int64Counter ScraperScrapedLogRecords metric.Int64Counter ScraperScrapedMetricPoints metric.Int64Counter } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.ScraperErroredLogRecords, err = builder.meter.Int64Counter( "otelcol_scraper_errored_log_records", metric.WithDescription("Number of log records that were unable to be scraped. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ScraperErroredMetricPoints, err = builder.meter.Int64Counter( "otelcol_scraper_errored_metric_points", metric.WithDescription("Number of metric points that were unable to be scraped. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ScraperScrapedLogRecords, err = builder.meter.Int64Counter( "otelcol_scraper_scraped_log_records", metric.WithDescription("Number of log records successfully scraped. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) builder.ScraperScrapedMetricPoints, err = builder.meter.Int64Counter( "otelcol_scraper_scraped_metric_points", metric.WithDescription("Number of metric points successfully scraped. [Alpha]"), metric.WithUnit("{datapoints}"), ) errs = errors.Join(errs, err) return &builder, errs } opentelemetry-collector-0.141.0/scraper/scraperhelper/internal/metadata/generated_telemetry_test.go000066400000000000000000000034751511331344600340570ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/scraper/scraperhelper", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/scraper/scraperhelper", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/scraper/scraperhelper/internal/metadatatest/000077500000000000000000000000001511331344600273305ustar00rootroot00000000000000generated_telemetrytest.go000066400000000000000000000053421511331344600345340ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/scraperhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" ) func AssertEqualScraperErroredLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_scraper_errored_log_records", Description: "Number of log records that were unable to be scraped. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_scraper_errored_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualScraperErroredMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_scraper_errored_metric_points", Description: "Number of metric points that were unable to be scraped. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_scraper_errored_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualScraperScrapedLogRecords(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_scraper_scraped_log_records", Description: "Number of log records successfully scraped. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_scraper_scraped_log_records") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualScraperScrapedMetricPoints(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_scraper_scraped_metric_points", Description: "Number of metric points successfully scraped. [Alpha]", Unit: "{datapoints}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_scraper_scraped_metric_points") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } generated_telemetrytest_test.go000066400000000000000000000026021511331344600355670ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/scraperhelper/internal/metadatatest// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadata" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() tb.ScraperErroredLogRecords.Add(context.Background(), 1) tb.ScraperErroredMetricPoints.Add(context.Background(), 1) tb.ScraperScrapedLogRecords.Add(context.Background(), 1) tb.ScraperScrapedMetricPoints.Add(context.Background(), 1) AssertEqualScraperErroredLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualScraperErroredMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualScraperScrapedLogRecords(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualScraperScrapedMetricPoints(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/scraper/scraperhelper/metadata.yaml000066400000000000000000000022341511331344600255010ustar00rootroot00000000000000type: scraperhelper github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg stability: beta: [metrics, logs] telemetry: metrics: scraper_errored_log_records: enabled: true stability: level: alpha description: Number of log records that were unable to be scraped. unit: "{datapoints}" sum: value_type: int monotonic: true scraper_errored_metric_points: enabled: true stability: level: alpha description: Number of metric points that were unable to be scraped. unit: "{datapoints}" sum: value_type: int monotonic: true scraper_scraped_log_records: enabled: true stability: level: alpha description: Number of log records successfully scraped. unit: "{datapoints}" sum: value_type: int monotonic: true scraper_scraped_metric_points: enabled: true stability: level: alpha description: Number of metric points successfully scraped. unit: "{datapoints}" sum: value_type: int monotonic: true opentelemetry-collector-0.141.0/scraper/scraperhelper/obs_logs.go000066400000000000000000000051011511331344600251670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper // import "go.opentelemetry.io/collector/scraper/scraperhelper" import ( "context" "errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapererror" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadata" ) const ( // scrapedLogRecordsKey used to identify log records scraped by the // Collector. scrapedLogRecordsKey = "scraped_log_records" // erroredLogRecordsKey used to identify log records errored (i.e. // unable to be scraped) by the Collector. erroredLogRecordsKey = "errored_log_records" ) func wrapObsLogs(sc scraper.Logs, receiverID, scraperID component.ID, set component.TelemetrySettings) (scraper.Logs, error) { telemetryBuilder, errBuilder := metadata.NewTelemetryBuilder(set) if errBuilder != nil { return nil, errBuilder } tracer := metadata.Tracer(set) spanName := scraperKey + spanNameSep + scraperID.String() + spanNameSep + "ScrapeLogs" otelAttrs := metric.WithAttributeSet(attribute.NewSet( attribute.String(receiverKey, receiverID.String()), attribute.String(scraperKey, scraperID.String()), )) scraperFuncs := func(ctx context.Context) (plog.Logs, error) { ctx, span := tracer.Start(ctx, spanName) defer span.End() md, err := sc.ScrapeLogs(ctx) numScrapedLogs := 0 numErroredLogs := 0 if err != nil { set.Logger.Error("Error scraping logs", zap.Error(err)) var partialErr scrapererror.PartialScrapeError if errors.As(err, &partialErr) { numErroredLogs = partialErr.Failed numScrapedLogs = md.LogRecordCount() } } else { numScrapedLogs = md.LogRecordCount() } telemetryBuilder.ScraperScrapedLogRecords.Add(ctx, int64(numScrapedLogs), otelAttrs) telemetryBuilder.ScraperErroredLogRecords.Add(ctx, int64(numErroredLogs), otelAttrs) // end span according to errors if span.IsRecording() { span.SetAttributes( attribute.String(formatKey, pipeline.SignalMetrics.String()), attribute.Int64(scrapedLogRecordsKey, int64(numScrapedLogs)), attribute.Int64(erroredLogRecordsKey, int64(numErroredLogs)), ) if err != nil { span.SetStatus(codes.Error, err.Error()) } } return md, err } return scraper.NewLogs(scraperFuncs, scraper.WithStart(sc.Start), scraper.WithShutdown(sc.Shutdown)) } opentelemetry-collector-0.141.0/scraper/scraperhelper/obs_logs_test.go000066400000000000000000000106131511331344600262320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadatatest" ) func TestScrapeLogsDataOp(t *testing.T) { tel := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) set := tel.NewTelemetrySettings() parentCtx, parentSpan := set.TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() params := []testParams{ {items: 23, err: partialErrFake}, {items: 29, err: errFake}, {items: 15, err: nil}, } for i := range params { sm, err := scraper.NewLogs(func(context.Context) (plog.Logs, error) { return testdata.GenerateLogs(params[i].items), params[i].err }) require.NoError(t, err) sf, err := wrapObsLogs(sm, receiverID, scraperID, set) require.NoError(t, err) _, err = sf.ScrapeLogs(parentCtx) require.ErrorIs(t, err, params[i].err) } spans := tel.SpanRecorder.Ended() require.Len(t, spans, len(params)) var scrapedLogRecords, erroredLogRecords int for i, span := range spans { assert.Equal(t, "scraper/"+scraperID.String()+"/ScrapeLogs", span.Name()) switch { case params[i].err == nil: scrapedLogRecords += params[i].items require.Contains(t, span.Attributes(), attribute.Int64(scrapedLogRecordsKey, int64(params[i].items))) require.Contains(t, span.Attributes(), attribute.Int64(erroredLogRecordsKey, 0)) assert.Equal(t, codes.Unset, span.Status().Code) case errors.Is(params[i].err, errFake): // Since we get an error, we cannot record any metrics because we don't know if the returned plog.Logs is valid instance. require.Contains(t, span.Attributes(), attribute.Int64(scrapedLogRecordsKey, 0)) require.Contains(t, span.Attributes(), attribute.Int64(erroredLogRecordsKey, 0)) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) case errors.Is(params[i].err, partialErrFake): scrapedLogRecords += params[i].items erroredLogRecords += 2 require.Contains(t, span.Attributes(), attribute.Int64(scrapedLogRecordsKey, int64(params[i].items))) require.Contains(t, span.Attributes(), attribute.Int64(erroredLogRecordsKey, 2)) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) default: t.Fatalf("unexpected err param: %v", params[i].err) } } checkScraperLogs(t, tel, receiverID, scraperID, int64(scrapedLogRecords), int64(erroredLogRecords)) } func TestCheckScraperLogs(t *testing.T) { tel := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) sm, err := scraper.NewLogs(func(context.Context) (plog.Logs, error) { return testdata.GenerateLogs(7), nil }) require.NoError(t, err) sf, err := wrapObsLogs(sm, receiverID, scraperID, tel.NewTelemetrySettings()) require.NoError(t, err) _, err = sf.ScrapeLogs(context.Background()) require.NoError(t, err) checkScraperLogs(t, tel, receiverID, scraperID, 7, 0) } func checkScraperLogs(t *testing.T, tel *componenttest.Telemetry, receiver, scraper component.ID, scrapedLogRecords, erroredLogRecords int64) { metadatatest.AssertEqualScraperScrapedLogRecords(t, tel, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: scrapedLogRecords, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualScraperErroredLogRecords(t, tel, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: erroredLogRecords, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } opentelemetry-collector-0.141.0/scraper/scraperhelper/obs_metrics.go000066400000000000000000000056521511331344600257040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper // import "go.opentelemetry.io/collector/scraper/scraperhelper" import ( "context" "errors" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/metric" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapererror" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadata" ) const ( // scraperKey used to identify scrapers in metrics and traces. scraperKey = "scraper" // scrapedMetricPointsKey used to identify metric points scraped by the // Collector. scrapedMetricPointsKey = "scraped_metric_points" // erroredMetricPointsKey used to identify metric points errored (i.e. // unable to be scraped) by the Collector. erroredMetricPointsKey = "errored_metric_points" spanNameSep = "/" // receiverKey used to identify receivers in metrics and traces. receiverKey = "receiver" // FormatKey used to identify the format of the data received. formatKey = "format" ) func wrapObsMetrics(sc scraper.Metrics, receiverID, scraperID component.ID, set component.TelemetrySettings) (scraper.Metrics, error) { telemetryBuilder, errBuilder := metadata.NewTelemetryBuilder(set) if errBuilder != nil { return nil, errBuilder } tracer := metadata.Tracer(set) spanName := scraperKey + spanNameSep + scraperID.String() + spanNameSep + "ScrapeMetrics" otelAttrs := metric.WithAttributeSet(attribute.NewSet( attribute.String(receiverKey, receiverID.String()), attribute.String(scraperKey, scraperID.String()), )) scraperFuncs := func(ctx context.Context) (pmetric.Metrics, error) { ctx, span := tracer.Start(ctx, spanName) defer span.End() md, err := sc.ScrapeMetrics(ctx) numScrapedMetrics := 0 numErroredMetrics := 0 if err != nil { set.Logger.Error("Error scraping metrics", zap.Error(err)) var partialErr scrapererror.PartialScrapeError if errors.As(err, &partialErr) { numErroredMetrics = partialErr.Failed numScrapedMetrics = md.MetricCount() } } else { numScrapedMetrics = md.MetricCount() } telemetryBuilder.ScraperScrapedMetricPoints.Add(ctx, int64(numScrapedMetrics), otelAttrs) telemetryBuilder.ScraperErroredMetricPoints.Add(ctx, int64(numErroredMetrics), otelAttrs) // end span according to errors if span.IsRecording() { span.SetAttributes( attribute.String(formatKey, pipeline.SignalMetrics.String()), attribute.Int64(scrapedMetricPointsKey, int64(numScrapedMetrics)), attribute.Int64(erroredMetricPointsKey, int64(numErroredMetrics)), ) if err != nil { span.SetStatus(codes.Error, err.Error()) } } return md, err } return scraper.NewMetrics(scraperFuncs, scraper.WithStart(sc.Start), scraper.WithShutdown(sc.Shutdown)) } opentelemetry-collector-0.141.0/scraper/scraperhelper/obs_metrics_test.go000066400000000000000000000114531511331344600267370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scraperhelper import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/scraper" "go.opentelemetry.io/collector/scraper/scrapererror" "go.opentelemetry.io/collector/scraper/scraperhelper/internal/metadatatest" ) var ( receiverID = component.MustNewID("fakeReceiver") scraperID = component.MustNewID("fakeScraper") errFake = errors.New("errFake") partialErrFake = scrapererror.NewPartialScrapeError(errFake, 2) ) type testParams struct { items int err error } func TestScrapeMetricsDataOp(t *testing.T) { tel := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) set := tel.NewTelemetrySettings() parentCtx, parentSpan := set.TracerProvider.Tracer("test").Start(context.Background(), t.Name()) defer parentSpan.End() params := []testParams{ {items: 23, err: partialErrFake}, {items: 29, err: errFake}, {items: 15, err: nil}, } for i := range params { sm, err := scraper.NewMetrics(func(context.Context) (pmetric.Metrics, error) { return testdata.GenerateMetrics(params[i].items), params[i].err }) require.NoError(t, err) sf, err := wrapObsMetrics(sm, receiverID, scraperID, set) require.NoError(t, err) _, err = sf.ScrapeMetrics(parentCtx) require.ErrorIs(t, err, params[i].err) } spans := tel.SpanRecorder.Ended() require.Len(t, spans, len(params)) var scrapedMetricPoints, erroredMetricPoints int for i, span := range spans { assert.Equal(t, "scraper/"+scraperID.String()+"/ScrapeMetrics", span.Name()) switch { case params[i].err == nil: scrapedMetricPoints += params[i].items require.Contains(t, span.Attributes(), attribute.Int64(scrapedMetricPointsKey, int64(params[i].items))) require.Contains(t, span.Attributes(), attribute.Int64(erroredMetricPointsKey, 0)) assert.Equal(t, codes.Unset, span.Status().Code) case errors.Is(params[i].err, errFake): // Since we get an error, we cannot record any metrics because we don't know if the returned pmetric.Metrics is valid instance. require.Contains(t, span.Attributes(), attribute.Int64(scrapedMetricPointsKey, 0)) require.Contains(t, span.Attributes(), attribute.Int64(erroredMetricPointsKey, 0)) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) case errors.Is(params[i].err, partialErrFake): scrapedMetricPoints += params[i].items erroredMetricPoints += 2 require.Contains(t, span.Attributes(), attribute.Int64(scrapedMetricPointsKey, int64(params[i].items))) require.Contains(t, span.Attributes(), attribute.Int64(erroredMetricPointsKey, 2)) assert.Equal(t, codes.Error, span.Status().Code) assert.Equal(t, params[i].err.Error(), span.Status().Description) default: t.Fatalf("unexpected err param: %v", params[i].err) } } checkScraperMetrics(t, tel, receiverID, scraperID, int64(scrapedMetricPoints), int64(erroredMetricPoints)) } func TestCheckScraperMetrics(t *testing.T) { tel := componenttest.NewTelemetry() t.Cleanup(func() { require.NoError(t, tel.Shutdown(context.Background())) }) sm, err := scraper.NewMetrics(func(context.Context) (pmetric.Metrics, error) { return testdata.GenerateMetrics(7), nil }) require.NoError(t, err) sf, err := wrapObsMetrics(sm, receiverID, scraperID, tel.NewTelemetrySettings()) require.NoError(t, err) _, err = sf.ScrapeMetrics(context.Background()) require.NoError(t, err) checkScraperMetrics(t, tel, receiverID, scraperID, 7, 0) } func checkScraperMetrics(t *testing.T, tt *componenttest.Telemetry, receiver, scraper component.ID, scrapedMetricPoints, erroredMetricPoints int64) { metadatatest.AssertEqualScraperScrapedMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: scrapedMetricPoints, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) metadatatest.AssertEqualScraperErroredMetricPoints(t, tt, []metricdata.DataPoint[int64]{ { Attributes: attribute.NewSet( attribute.String(receiverKey, receiver.String()), attribute.String(scraperKey, scraper.String())), Value: erroredMetricPoints, }, }, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreExemplars()) } opentelemetry-collector-0.141.0/scraper/scrapertest/000077500000000000000000000000001511331344600225345ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/scrapertest/Makefile000066400000000000000000000000361511331344600241730ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/scraper/scrapertest/go.mod000066400000000000000000000033131511331344600236420ustar00rootroot00000000000000module go.opentelemetry.io/collector/scraper/scrapertest go 1.24.0 require ( github.com/google/uuid v1.6.0 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/scraper v0.141.0 ) require ( github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/collector/pipeline v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect ) replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/scraper => ../ replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/scraper/scrapertest/go.sum000066400000000000000000000123671511331344600237000ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/scraper/scrapertest/settings.go000066400000000000000000000013371511331344600247270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package scrapertest // import "go.opentelemetry.io/collector/scraper/scrapertest" import ( "github.com/google/uuid" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/scraper" ) var NopType = component.MustNewType("nop") // NewNopSettings returns a new nop scraper.Settings with the given type. func NewNopSettings(typ component.Type) scraper.Settings { return scraper.Settings{ ID: component.NewIDWithName(typ, uuid.NewString()), TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } opentelemetry-collector-0.141.0/scraper/xscraper/000077500000000000000000000000001511331344600220245ustar00rootroot00000000000000opentelemetry-collector-0.141.0/scraper/xscraper/Makefile000066400000000000000000000000361511331344600234630ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/scraper/xscraper/doc.go000066400000000000000000000004551511331344600231240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml // Package xscraper allows to define pull based receivers that can be configured using the scraperreceiver. package xscraper // import "go.opentelemetry.io/collector/scraper/xscraper" opentelemetry-collector-0.141.0/scraper/xscraper/factory.go000066400000000000000000000063241511331344600240270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xscraper // import "go.opentelemetry.io/collector/scraper/xscraper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/scraper" ) type Factory interface { scraper.Factory // CreateProfiles creates a Profiles scraper based on this config. // If the scraper type does not support profiles, // this function returns the error [pipeline.ErrSignalNotSupported]. CreateProfiles(ctx context.Context, set scraper.Settings, cfg component.Config) (Profiles, error) // ProfilesStability gets the stability level of the Profiles scraper. ProfilesStability() component.StabilityLevel } // FactoryOption apply changes to Options. type FactoryOption interface { // applyOption applies the option. applyOption(o *factoryOpts) } type factoryOpts struct { opts []scraper.FactoryOption *factory } var _ FactoryOption = (*factoryOptionFunc)(nil) // factoryOptionFunc is a FactoryOption created through a function. type factoryOptionFunc func(*factoryOpts) func (f factoryOptionFunc) applyOption(o *factoryOpts) { f(o) } type factory struct { scraper.Factory createProfilesFunc CreateProfilesFunc profilesStabilityLevel component.StabilityLevel } func (f *factory) ProfilesStability() component.StabilityLevel { return f.profilesStabilityLevel } func (f *factory) CreateProfiles(ctx context.Context, set scraper.Settings, cfg component.Config) (Profiles, error) { if f.createProfilesFunc == nil { return nil, pipeline.ErrSignalNotSupported } return f.createProfilesFunc(ctx, set, cfg) } // WithLogs overrides the default "error not supported" implementation for CreateLogs and the default "undefined" stability level. func WithLogs(createLogs scraper.CreateLogsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, scraper.WithLogs(createLogs, sl)) }) } // WithMetrics overrides the default "error not supported" implementation for CreateMetrics and the default "undefined" stability level. func WithMetrics(createMetrics scraper.CreateMetricsFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.opts = append(o.opts, scraper.WithMetrics(createMetrics, sl)) }) } // CreateProfilesFunc is the equivalent of Factory.CreateProfiles(). type CreateProfilesFunc func(context.Context, scraper.Settings, component.Config) (Profiles, error) // WithProfiles overrides the default "error not supported" implementation for CreateProfiles and the default "undefined" stability level. func WithProfiles(createProfiles CreateProfilesFunc, sl component.StabilityLevel) FactoryOption { return factoryOptionFunc(func(o *factoryOpts) { o.profilesStabilityLevel = sl o.createProfilesFunc = createProfiles }) } // NewFactory returns a Factory. func NewFactory(cfgType component.Type, createDefaultConfig component.CreateDefaultConfigFunc, options ...FactoryOption) Factory { opts := factoryOpts{factory: &factory{}} for _, opt := range options { opt.applyOption(&opts) } opts.Factory = scraper.NewFactory(cfgType, createDefaultConfig, opts.opts...) return opts.factory } opentelemetry-collector-0.141.0/scraper/xscraper/factory_test.go000066400000000000000000000055231511331344600250660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xscraper import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/scraper" ) var testType = component.MustNewType("test") func nopSettings() scraper.Settings { return scraper.Settings{ ID: component.NewID(testType), TelemetrySettings: componenttest.NewNopTelemetrySettings(), } } func TestNewFactory(t *testing.T) { defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) _, err := f.CreateProfiles(context.Background(), nopSettings(), &defaultCfg) require.ErrorIs(t, err, pipeline.ErrSignalNotSupported) } func TestNewFactoryWithOptions(t *testing.T) { testType := component.MustNewType("test") defaultCfg := struct{}{} f := NewFactory( testType, func() component.Config { return &defaultCfg }, WithLogs(createLogs, component.StabilityLevelAlpha), WithMetrics(createMetrics, component.StabilityLevelAlpha), WithProfiles(createProfiles, component.StabilityLevelDevelopment)) assert.Equal(t, testType, f.Type()) assert.EqualValues(t, &defaultCfg, f.CreateDefaultConfig()) assert.Equal(t, component.StabilityLevelDevelopment, f.ProfilesStability()) _, err := f.CreateProfiles(context.Background(), scraper.Settings{}, &defaultCfg) require.NoError(t, err) assert.Equal(t, component.StabilityLevelAlpha, f.LogsStability()) _, err = f.CreateLogs(context.Background(), scraper.Settings{}, &defaultCfg) require.NoError(t, err) assert.Equal(t, component.StabilityLevelAlpha, f.MetricsStability()) _, err = f.CreateMetrics(context.Background(), scraper.Settings{}, &defaultCfg) require.NoError(t, err) } func createProfiles(context.Context, scraper.Settings, component.Config) (Profiles, error) { return NewProfiles(newTestScrapeProfilesFunc(nil)) } func createLogs(context.Context, scraper.Settings, component.Config) (scraper.Logs, error) { return scraper.NewLogs(newTestScrapeLogsFunc(nil)) } func createMetrics(context.Context, scraper.Settings, component.Config) (scraper.Metrics, error) { return scraper.NewMetrics(newTestScrapeMetricsFunc(nil)) } func newTestScrapeLogsFunc(retError error) scraper.ScrapeLogsFunc { return func(_ context.Context) (plog.Logs, error) { return plog.NewLogs(), retError } } func newTestScrapeMetricsFunc(retError error) scraper.ScrapeMetricsFunc { return func(_ context.Context) (pmetric.Metrics, error) { return pmetric.NewMetrics(), retError } } opentelemetry-collector-0.141.0/scraper/xscraper/generated_package_test.go000066400000000000000000000002471511331344600270260ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package xscraper import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/scraper/xscraper/go.mod000066400000000000000000000040211511331344600231270ustar00rootroot00000000000000module go.opentelemetry.io/collector/scraper/xscraper go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/scraper v0.141.0 go.uber.org/goleak v1.3.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/pmezard/go-difflib v1.0.0 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect golang.org/x/sys v0.37.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/pipeline => ../../pipeline replace go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile replace go.opentelemetry.io/collector/component => ../../component replace go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest replace go.opentelemetry.io/collector/scraper => ../../scraper replace go.opentelemetry.io/collector/featuregate => ../../featuregate replace go.opentelemetry.io/collector/pdata => ../../pdata replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/scraper/xscraper/go.sum000066400000000000000000000140451511331344600231630ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/scraper/xscraper/metadata.yaml000066400000000000000000000003011511331344600244620ustar00rootroot00000000000000type: xscraper github_project: open-telemetry/opentelemetry-collector status: class: pkg codeowners: active: - dmathieu - florianl stability: development: [profiles] opentelemetry-collector-0.141.0/scraper/xscraper/profiles.go000066400000000000000000000021671511331344600242040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xscraper // import "go.opentelemetry.io/collector/scraper/xscraper" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/scraper" ) // Profiles is the base interface for profiles scrapers. type Profiles interface { component.Component // ScrapeProfiles is the base interface to indicate that how should profiles be scraped. ScrapeProfiles(context.Context) (pprofile.Profiles, error) } // ScrapeProfilesFunc is a helper function. type ScrapeProfilesFunc scraper.ScrapeFunc[pprofile.Profiles] func (sf ScrapeProfilesFunc) ScrapeProfiles(ctx context.Context) (pprofile.Profiles, error) { return sf(ctx) } type profiles struct { baseScraper ScrapeProfilesFunc } // NewProfiles creates a new Profiles scraper. func NewProfiles(scrape ScrapeProfilesFunc, options ...Option) (Profiles, error) { if scrape == nil { return nil, errNilFunc } bs := &profiles{ baseScraper: newBaseScraper(options), ScrapeProfilesFunc: scrape, } return bs, nil } opentelemetry-collector-0.141.0/scraper/xscraper/profiles_test.go000066400000000000000000000042621511331344600252410ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xscraper import ( "context" "errors" "sync" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/pprofile" ) func TestNewProfiles(t *testing.T) { mp, err := NewProfiles(newTestScrapeProfilesFunc(nil)) require.NoError(t, err) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) md, err := mp.ScrapeProfiles(context.Background()) require.NoError(t, err) assert.Equal(t, pprofile.NewProfiles(), md) require.NoError(t, mp.Shutdown(context.Background())) } func TestNewProfiles_WithOptions(t *testing.T) { want := errors.New("my_error") mp, err := NewProfiles(newTestScrapeProfilesFunc(nil), WithStart(func(context.Context, component.Host) error { return want }), WithShutdown(func(context.Context) error { return want })) require.NoError(t, err) assert.Equal(t, want, mp.Start(context.Background(), componenttest.NewNopHost())) assert.Equal(t, want, mp.Shutdown(context.Background())) } func TestNewProfiles_NilRequiredFields(t *testing.T) { _, err := NewProfiles(nil) require.Error(t, err) } func TestNewProfiles_ProcessProfilesError(t *testing.T) { want := errors.New("my_error") mp, err := NewProfiles(newTestScrapeProfilesFunc(want)) require.NoError(t, err) _, err = mp.ScrapeProfiles(context.Background()) require.ErrorIs(t, err, want) } func TestProfilesConcurrency(t *testing.T) { mp, err := NewProfiles(newTestScrapeProfilesFunc(nil)) require.NoError(t, err) require.NoError(t, mp.Start(context.Background(), componenttest.NewNopHost())) var wg sync.WaitGroup for range 10 { wg.Add(1) go func() { defer wg.Done() for range 10000 { _, errScrape := mp.ScrapeProfiles(context.Background()) assert.NoError(t, errScrape) } }() } wg.Wait() require.NoError(t, mp.Shutdown(context.Background())) } func newTestScrapeProfilesFunc(retError error) ScrapeProfilesFunc { return func(_ context.Context) (pprofile.Profiles, error) { return pprofile.NewProfiles(), retError } } opentelemetry-collector-0.141.0/scraper/xscraper/scraper.go000066400000000000000000000024421511331344600240140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package xscraper // import "go.opentelemetry.io/collector/scraper/xscraper" import ( "context" "errors" "go.opentelemetry.io/collector/component" ) var errNilFunc = errors.New("nil scrape func") // ScrapeFunc scrapes data. type ScrapeFunc[T any] func(context.Context) (T, error) // Option apply changes to internal options. type Option interface { apply(*baseScraper) } type scraperOptionFunc func(*baseScraper) func (of scraperOptionFunc) apply(e *baseScraper) { of(e) } // WithStart sets the function that will be called on startup. func WithStart(start component.StartFunc) Option { return scraperOptionFunc(func(o *baseScraper) { o.StartFunc = start }) } // WithShutdown sets the function that will be called on shutdown. func WithShutdown(shutdown component.ShutdownFunc) Option { return scraperOptionFunc(func(o *baseScraper) { o.ShutdownFunc = shutdown }) } type baseScraper struct { component.StartFunc component.ShutdownFunc } // newBaseScraper returns the internal settings starting from the default and applying all options. func newBaseScraper(options []Option) baseScraper { // Start from the default options: bs := baseScraper{} for _, op := range options { op.apply(&bs) } return bs } opentelemetry-collector-0.141.0/service/000077500000000000000000000000001511331344600201765ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/Makefile000066400000000000000000000000331511331344600216320ustar00rootroot00000000000000include ../Makefile.Common opentelemetry-collector-0.141.0/service/README.md000066400000000000000000000122221511331344600214540ustar00rootroot00000000000000# OpenTelemetry Collector Service ## How to provide configuration? The `--config` flag accepts either a file path or values in the form of a config URI `":"`. Currently, the OpenTelemetry Collector supports the following providers `scheme`: - [file](../confmap/provider/fileprovider/provider.go) - Reads configuration from a file. E.g. `file:path/to/config.yaml`. - [env](../confmap/provider/envprovider/provider.go) - Reads configuration from an environment variable. E.g. `env:MY_CONFIG_IN_AN_ENVVAR`. - [yaml](../confmap/provider/yamlprovider/provider.go) - Reads configuration from yaml bytes. E.g. `yaml:exporters::debug::verbosity: detailed`. - [http](../confmap/provider/httpprovider/provider.go) - Reads configuration from a HTTP URI. E.g. `http://www.example.com` For more technical details about how configuration is resolved you can read the [configuration resolving design](../confmap/README.md#configuration-resolving). ### Single Config Source 1. Simple local file: `./otelcorecol --config=examples/local/otel-config.yaml` 2. Simple local file using the new URI format: `./otelcorecol --config=file:examples/local/otel-config.yaml` 3. Config provided via an environment variable: `./otelcorecol --config=env:MY_CONFIG_IN_AN_ENVVAR` ### Multiple Config Sources 1. Merge a `otel-config.yaml` file with the content of an environment variable `MY_OTHER_CONFIG` and use the merged result as the config: `./otelcorecol --config=file:examples/local/otel-config.yaml --config=env:MY_OTHER_CONFIG` 2. Merge a `config.yaml` file with the content of a yaml bytes configuration (overwrites the `exporters::debug::verbosity` config) and use the content as the config: `./otelcorecol --config=file:examples/local/otel-config.yaml --config="yaml:exporters::debug::verbosity: normal"` ### Embedding other configuration providers One configuration provider can also make references to other config providers, like the following: ```yaml receivers: otlp: protocols: grpc: exporters: ${file:otlp-exporter.yaml} service: extensions: [ ] pipelines: traces: receivers: [ otlp ] processors: [ ] exporters: [ otlp ] ``` ## How to override config properties? The `--set` flag allows to set arbitrary config property. The `--set` values are merged into the final configuration after all the sources specified by the `--config` are resolved and merged. ### The Format and Limitations of `--set` #### Simple property The `--set` option takes always one key/value pair, and it is used like this: `--set key=value`. The YAML equivalent of that is: ```yaml key: value ``` #### Complex nested keys Use dot (`.`) in the pair's name as key separator to reference nested map values. For example, `--set outer.inner=value` is translated into this: ```yaml outer: inner: value ``` #### Multiple values To set multiple values specify multiple --set flags, so `--set a=b --set c=d` becomes: ```yaml a: b c: d ``` #### Array values Arrays can be expressed by enclosing values in `[]`. For example, `--set "key=[a, b, c]"` translates to: ```yaml key: - a - b - c ``` #### Map values Maps can be expressed by enclosing values in `{}`. For example, `"--set "key={a: c}"` translates to: ```yaml key: a: c ``` #### Limitations 1. Does not support setting a key that contains a dot `.`. 2. Does not support setting a key that contains a equal sign `=`. 3. The configuration key separator inside the value part of the property is "::". For example `--set "name={a::b: c}"` is equivalent with `--set name.a.b=c`. ## How to check components available in a distribution Use the sub command build-info. Below is an example: ```bash ./otelcorecol components ``` Sample output: ```yaml buildinfo: command: otelcorecol description: Local OpenTelemetry Collector binary, testing only. version: 0.62.1-dev receivers: - otlp processors: - memory_limiter exporters: - otlp - otlphttp - debug extensions: - zpages ``` ## How to validate configuration file and return all errors without running collector ```bash ./otelcorecol validate --config=file:examples/local/otel-config.yaml ``` ## How to examine the final configuration after resolving, parsing and validating? Use `print-config` in the default mode (`--mode=redacted`) and `--feature-gates=otelcol.printInitialConfig`: ```bash ./otelcorecol print-config --config=file:examples/local/otel-config.yaml ``` Note that by default the configuration will only print when it is valid, and that sensitive information will be redacted. To print a potentially invalid configuration, use `--validate=false`. ## How to examine the final configuration including sensitive fields? Use `print-config` with `--mode=unredacted` and `--feature-gates=otelcol.printInitialConfig`: ```bash ./otelcorecol print-config --mode=unredacted --config=file:examples/local/otel-config.yaml ``` ## How to print the final configuration in JSON format? Use `print-config` with `--format=json` and `--feature-gates=otelcol.printInitialConfig`. Note that JSON format is considered unstable. ```bash ./otelcorecol print-config --format=json --config=file:examples/local/otel-config.yaml ``` opentelemetry-collector-0.141.0/service/config.go000066400000000000000000000015111511331344600217700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package service // import "go.opentelemetry.io/collector/service" import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/pipelines" ) // Config defines the configurable components of the Service. type Config struct { // Telemetry is the configuration for collector's own telemetry. Telemetry component.Config `mapstructure:"telemetry"` // Extensions are the ordered list of extensions configured for the service. Extensions extensions.Config `mapstructure:"extensions,omitempty"` // Pipelines are the set of data pipelines configured for the service. Pipelines pipelines.Config `mapstructure:"pipelines"` // prevent unkeyed literal initialization _ struct{} } opentelemetry-collector-0.141.0/service/config_test.go000066400000000000000000000051301511331344600230300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package service import ( "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/pipelines" ) func TestConfigValidate(t *testing.T) { testCases := []struct { name string // test case name (also file name containing config yaml) cfgFn func() *Config expected error }{ { name: "valid", cfgFn: generateConfig, expected: nil, }, { name: "valid-telemetry-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Telemetry = fakeTelemetryConfig{Invalid: false} return cfg }, expected: nil, }, { name: "duplicate-processor-reference", cfgFn: func() *Config { cfg := generateConfig() pipe := cfg.Pipelines[pipeline.NewID(pipeline.SignalTraces)] pipe.Processors = append(pipe.Processors, pipe.Processors...) return cfg }, expected: errors.New(`references processor "nop" multiple times`), }, { name: "invalid-telemetry-config", cfgFn: func() *Config { cfg := generateConfig() cfg.Telemetry = fakeTelemetryConfig{Invalid: true} return cfg }, expected: errors.New("telemetry: invalid config"), }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn() err := xconfmap.Validate(cfg) if tt.expected != nil { assert.ErrorContains(t, err, tt.expected.Error()) } else { assert.NoError(t, err) } }) } } func TestConfmapMarshalConfig(t *testing.T) { conf := confmap.New() require.NoError(t, conf.Marshal(Config{ Telemetry: fakeTelemetryConfig{}, })) assert.Equal(t, map[string]any{ "pipelines": map[string]any(nil), "telemetry": map[string]any{"invalid": false}, }, conf.ToStringMap()) } func generateConfig() *Config { return &Config{ Extensions: extensions.Config{component.MustNewID("nop")}, Pipelines: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, } } type fakeTelemetryConfig struct { Invalid bool `mapstructure:"invalid"` } func (cfg fakeTelemetryConfig) Validate() error { if cfg.Invalid { return errors.New("invalid config") } return nil } opentelemetry-collector-0.141.0/service/documentation.md000066400000000000000000000061661511331344600234020ustar00rootroot00000000000000[comment]: <> (Code generated by mdatagen. DO NOT EDIT.) # service ## Internal Telemetry The following telemetry is emitted by this component. ### otelcol.connector.consumed.items Number of items passed to the connector. [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {item} | Sum | Int | true | Development | ### otelcol.connector.produced.items Number of items emitted from the connector. [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {item} | Sum | Int | true | Development | ### otelcol.exporter.consumed.items Number of items passed to the exporter. [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {item} | Sum | Int | true | Development | ### otelcol_process_cpu_seconds Total CPU user and system time in seconds [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | s | Sum | Double | true | Alpha | ### otelcol_process_memory_rss Total physical memory (resident set size) [Alpha] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | By | Gauge | Int | Alpha | ### otelcol_process_runtime_heap_alloc_bytes Bytes of allocated heap objects (see 'go doc runtime.MemStats.HeapAlloc') [Alpha] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | By | Gauge | Int | Alpha | ### otelcol_process_runtime_total_alloc_bytes Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | By | Sum | Int | true | Alpha | ### otelcol_process_runtime_total_sys_memory_bytes Total bytes of memory obtained from the OS (see 'go doc runtime.MemStats.Sys') [Alpha] | Unit | Metric Type | Value Type | Stability | | ---- | ----------- | ---------- | --------- | | By | Gauge | Int | Alpha | ### otelcol_process_uptime Uptime of the process [Alpha] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | s | Sum | Double | true | Alpha | ### otelcol.processor.consumed.items Number of items passed to the processor. [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {item} | Sum | Int | true | Development | ### otelcol.processor.produced.items Number of items emitted from the processor. [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {item} | Sum | Int | true | Development | ### otelcol.receiver.produced.items Number of items emitted from the receiver. [Development] | Unit | Metric Type | Value Type | Monotonic | Stability | | ---- | ----------- | ---------- | --------- | --------- | | {item} | Sum | Int | true | Development | opentelemetry-collector-0.141.0/service/extensions/000077500000000000000000000000001511331344600223755ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/extensions/config.go000066400000000000000000000004751511331344600241770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensions // import "go.opentelemetry.io/collector/service/extensions" import "go.opentelemetry.io/collector/component" // Config represents the ordered list of extensions configured for the service. type Config []component.ID opentelemetry-collector-0.141.0/service/extensions/extensions.go000066400000000000000000000157531511331344600251360ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensions // import "go.opentelemetry.io/collector/service/extensions" import ( "context" "fmt" "net/http" "sort" "go.uber.org/multierr" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensioncapabilities" "go.opentelemetry.io/collector/service/internal/attribute" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/componentattribute" "go.opentelemetry.io/collector/service/internal/status" "go.opentelemetry.io/collector/service/internal/zpages" ) const zExtensionName = "zextensionname" // Extensions is a map of extensions created from extension configs. type Extensions struct { telemetry component.TelemetrySettings extMap map[component.ID]extension.Extension instanceIDs map[component.ID]*componentstatus.InstanceID extensionIDs []component.ID // start order (and reverse stop order) reporter status.Reporter } // Start starts all extensions. func (bes *Extensions) Start(ctx context.Context, host component.Host) error { bes.telemetry.Logger.Info("Starting extensions...") for _, extID := range bes.extensionIDs { extLogger := componentattribute.LoggerWithAttributes(bes.telemetry.Logger, attribute.Extension(extID).Set().ToSlice()) extLogger.Info("Extension is starting...") instanceID := bes.instanceIDs[extID] ext := bes.extMap[extID] bes.reporter.ReportStatus( instanceID, componentstatus.NewEvent(componentstatus.StatusStarting), ) if err := ext.Start(ctx, host); err != nil { bes.reporter.ReportStatus( instanceID, componentstatus.NewPermanentErrorEvent(err), ) // We log with zap.AddStacktrace(zap.DPanicLevel) to avoid adding the stack trace to the error log extLogger.WithOptions(zap.AddStacktrace(zap.DPanicLevel)).Error("Failed to start extension", zap.Error(err)) return err } bes.reporter.ReportOKIfStarting(instanceID) extLogger.Info("Extension started.") } return nil } // Shutdown stops all extensions. func (bes *Extensions) Shutdown(ctx context.Context) error { bes.telemetry.Logger.Info("Stopping extensions...") var errs error for i := len(bes.extensionIDs) - 1; i >= 0; i-- { extID := bes.extensionIDs[i] instanceID := bes.instanceIDs[extID] ext := bes.extMap[extID] bes.reporter.ReportStatus( instanceID, componentstatus.NewEvent(componentstatus.StatusStopping), ) if err := ext.Shutdown(ctx); err != nil { bes.reporter.ReportStatus( instanceID, componentstatus.NewPermanentErrorEvent(err), ) errs = multierr.Append(errs, err) continue } bes.reporter.ReportStatus( instanceID, componentstatus.NewEvent(componentstatus.StatusStopped), ) } return errs } func (bes *Extensions) NotifyPipelineReady() error { for _, extID := range bes.extensionIDs { ext := bes.extMap[extID] if pw, ok := ext.(extensioncapabilities.PipelineWatcher); ok { if err := pw.Ready(); err != nil { return fmt.Errorf("failed to notify extension %q: %w", extID, err) } } } return nil } func (bes *Extensions) NotifyPipelineNotReady() error { var errs error for _, extID := range bes.extensionIDs { ext := bes.extMap[extID] if pw, ok := ext.(extensioncapabilities.PipelineWatcher); ok { errs = multierr.Append(errs, pw.NotReady()) } } return errs } func (bes *Extensions) NotifyConfig(ctx context.Context, conf *confmap.Conf) error { var errs error for _, extID := range bes.extensionIDs { ext := bes.extMap[extID] if cw, ok := ext.(extensioncapabilities.ConfigWatcher); ok { clonedConf := confmap.NewFromStringMap(conf.ToStringMap()) errs = multierr.Append(errs, cw.NotifyConfig(ctx, clonedConf)) } } return errs } func (bes *Extensions) NotifyComponentStatusChange(source *componentstatus.InstanceID, event *componentstatus.Event) { for _, extID := range bes.extensionIDs { ext := bes.extMap[extID] if sw, ok := ext.(componentstatus.Watcher); ok { sw.ComponentStatusChanged(source, event) } } } func (bes *Extensions) GetExtensions() map[component.ID]component.Component { result := make(map[component.ID]component.Component, len(bes.extMap)) for extID, v := range bes.extMap { result[extID] = v } return result } func (bes *Extensions) HandleZPages(w http.ResponseWriter, r *http.Request) { extensionName := r.URL.Query().Get(zExtensionName) w.Header().Set("Content-Type", "text/html; charset=utf-8") zpages.WriteHTMLPageHeader(w, zpages.HeaderData{Title: "Extensions"}) data := zpages.SummaryExtensionsTableData{} data.Rows = make([]zpages.SummaryExtensionsTableRowData, 0, len(bes.extMap)) for _, id := range bes.extensionIDs { row := zpages.SummaryExtensionsTableRowData{FullName: id.String()} data.Rows = append(data.Rows, row) } sort.Slice(data.Rows, func(i, j int) bool { return data.Rows[i].FullName < data.Rows[j].FullName }) zpages.WriteHTMLExtensionsSummaryTable(w, data) if extensionName != "" { zpages.WriteHTMLComponentHeader(w, zpages.ComponentHeaderData{ Name: extensionName, }) // TODO: Add config + status info. } zpages.WriteHTMLPageFooter(w) } // Settings holds configuration for building Extensions. type Settings struct { Telemetry component.TelemetrySettings BuildInfo component.BuildInfo // Extensions builder for extensions. Extensions builders.Extension } type Option interface { apply(*Extensions) } type optionFunc func(*Extensions) func (of optionFunc) apply(e *Extensions) { of(e) } func WithReporter(reporter status.Reporter) Option { return optionFunc(func(e *Extensions) { e.reporter = reporter }) } // New creates a new Extensions from Config. func New(ctx context.Context, set Settings, cfg Config, options ...Option) (*Extensions, error) { exts := &Extensions{ telemetry: set.Telemetry, extMap: make(map[component.ID]extension.Extension), instanceIDs: make(map[component.ID]*componentstatus.InstanceID), extensionIDs: make([]component.ID, 0, len(cfg)), reporter: status.NewNopStatusReporter(), } for _, opt := range options { opt.apply(exts) } for _, extID := range cfg { instanceID := componentstatus.NewInstanceID(extID, component.KindExtension) extSet := extension.Settings{ ID: extID, TelemetrySettings: componentattribute.TelemetrySettingsWithAttributes(set.Telemetry, *attribute.Extension(extID).Set()), BuildInfo: set.BuildInfo, } ext, err := set.Extensions.Create(ctx, extSet) if err != nil { return nil, fmt.Errorf("failed to create extension %q: %w", extID, err) } // Check if the factory really created the extension. if ext == nil { return nil, fmt.Errorf("factory for %q produced a nil extension", extID) } exts.extMap[extID] = ext exts.instanceIDs[extID] = instanceID } order, err := computeOrder(exts) if err != nil { return nil, err } exts.extensionIDs = order return exts, nil } opentelemetry-collector-0.141.0/service/extensions/extensions_test.go000066400000000000000000000375731511331344600262010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensions import ( "context" "errors" "slices" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensioncapabilities" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/status" ) func TestBuildExtensions(t *testing.T) { nopExtensionFactory := extensiontest.NewNopFactory() nopExtensionConfig := nopExtensionFactory.CreateDefaultConfig() errExtensionFactory := newCreateErrorExtensionFactory() errExtensionConfig := errExtensionFactory.CreateDefaultConfig() badExtensionFactory := newBadExtensionFactory() badExtensionCfg := badExtensionFactory.CreateDefaultConfig() tests := []struct { name string factories map[component.Type]extension.Factory extensionsConfigs map[component.ID]component.Config config Config wantErrMsg string }{ { name: "extension_not_configured", config: Config{ component.MustNewID("myextension"), }, wantErrMsg: "failed to create extension \"myextension\": extension \"myextension\" is not configured", }, { name: "missing_extension_factory", extensionsConfigs: map[component.ID]component.Config{ component.MustNewID("unknown"): nopExtensionConfig, }, config: Config{ component.MustNewID("unknown"), }, wantErrMsg: "failed to create extension \"unknown\": extension factory not available for: \"unknown\"", }, { name: "error_on_create_extension", factories: map[component.Type]extension.Factory{ errExtensionFactory.Type(): errExtensionFactory, }, extensionsConfigs: map[component.ID]component.Config{ component.NewID(errExtensionFactory.Type()): errExtensionConfig, }, config: Config{ component.NewID(errExtensionFactory.Type()), }, wantErrMsg: "failed to create extension \"err\": cannot create \"err\" extension type", }, { name: "bad_factory", factories: map[component.Type]extension.Factory{ badExtensionFactory.Type(): badExtensionFactory, }, extensionsConfigs: map[component.ID]component.Config{ component.NewID(badExtensionFactory.Type()): badExtensionCfg, }, config: Config{ component.NewID(badExtensionFactory.Type()), }, wantErrMsg: "factory for \"bf\" produced a nil extension", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { _, err := New(context.Background(), Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), Extensions: builders.NewExtension(tt.extensionsConfigs, tt.factories), }, tt.config) require.Error(t, err) assert.EqualError(t, err, tt.wantErrMsg) }) } } type testOrderExt struct { name string deps []string } type testOrderCase struct { testName string extensions []testOrderExt order []string err string } func TestOrdering(t *testing.T) { tests := []testOrderCase{ { testName: "no_deps", extensions: []testOrderExt{{name: ""}, {name: "foo"}, {name: "bar"}}, order: nil, // no predictable order }, { testName: "deps", extensions: []testOrderExt{ {name: "foo", deps: []string{"bar"}}, // foo -> bar {name: "baz", deps: []string{"foo"}}, // baz -> foo {name: "bar"}, }, // baz -> foo -> bar order: []string{"recording/bar", "recording/foo", "recording/baz"}, }, { testName: "deps_double", extensions: []testOrderExt{ {name: "foo", deps: []string{"bar"}}, // foo -> bar {name: "baz", deps: []string{"foo", "bar"}}, // baz -> {foo, bar} {name: "bar"}, }, // baz -> foo -> bar order: []string{"recording/bar", "recording/foo", "recording/baz"}, }, { testName: "unknown_dep", extensions: []testOrderExt{ {name: "foo", deps: []string{"BAZ"}}, {name: "bar"}, }, err: "unable to find extension", }, { testName: "circular", extensions: []testOrderExt{ {name: "foo", deps: []string{"bar"}}, {name: "bar", deps: []string{"foo"}}, }, err: "unable to order extensions", }, } for _, testCase := range tests { t.Run(testCase.testName, testCase.testOrdering) } } func (tc testOrderCase) testOrdering(t *testing.T) { var startOrder []string var shutdownOrder []string recordingExtensionFactory := newRecordingExtensionFactory(func(set extension.Settings, _ component.Host) error { startOrder = append(startOrder, set.ID.String()) return nil }, func(set extension.Settings) error { shutdownOrder = append(shutdownOrder, set.ID.String()) return nil }) extCfgs := make(map[component.ID]component.Config) extIDs := make([]component.ID, len(tc.extensions)) for i, ext := range tc.extensions { extID := component.NewIDWithName(recordingExtensionFactory.Type(), ext.name) extIDs[i] = extID extCfgs[extID] = recordingExtensionConfig{dependencies: ext.deps} } exts, err := New(context.Background(), Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), Extensions: builders.NewExtension( extCfgs, map[component.Type]extension.Factory{ recordingExtensionFactory.Type(): recordingExtensionFactory, }), }, Config(extIDs)) if tc.err != "" { require.ErrorContains(t, err, tc.err) return } require.NoError(t, err) err = exts.Start(context.Background(), componenttest.NewNopHost()) require.NoError(t, err) err = exts.Shutdown(context.Background()) require.NoError(t, err) if len(tc.order) > 0 { require.Equal(t, tc.order, startOrder) slices.Reverse(shutdownOrder) require.Equal(t, tc.order, shutdownOrder) } } func TestNotifyConfig(t *testing.T) { notificationError := errors.New("Error processing config") nopExtensionFactory := extensiontest.NewNopFactory() nopExtensionConfig := nopExtensionFactory.CreateDefaultConfig() n1ExtensionFactory := newConfigWatcherExtensionFactory(component.MustNewType("notifiable1"), func() error { return nil }) n1ExtensionConfig := n1ExtensionFactory.CreateDefaultConfig() n2ExtensionFactory := newConfigWatcherExtensionFactory(component.MustNewType("notifiable2"), func() error { return nil }) n2ExtensionConfig := n1ExtensionFactory.CreateDefaultConfig() nErrExtensionFactory := newConfigWatcherExtensionFactory(component.MustNewType("notifiableErr"), func() error { return notificationError }) nErrExtensionConfig := nErrExtensionFactory.CreateDefaultConfig() tests := []struct { name string factories map[component.Type]extension.Factory extensionsConfigs map[component.ID]component.Config serviceExtensions []component.ID wantErrMsg string want error }{ { name: "No notifiable extensions", factories: map[component.Type]extension.Factory{ component.MustNewType("nop"): nopExtensionFactory, }, extensionsConfigs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExtensionConfig, }, serviceExtensions: []component.ID{ component.MustNewID("nop"), }, }, { name: "One notifiable extension", factories: map[component.Type]extension.Factory{ component.MustNewType("notifiable1"): n1ExtensionFactory, }, extensionsConfigs: map[component.ID]component.Config{ component.MustNewID("notifiable1"): n1ExtensionConfig, }, serviceExtensions: []component.ID{ component.MustNewID("notifiable1"), }, }, { name: "Multiple notifiable extensions", factories: map[component.Type]extension.Factory{ component.MustNewType("notifiable1"): n1ExtensionFactory, component.MustNewType("notifiable2"): n2ExtensionFactory, }, extensionsConfigs: map[component.ID]component.Config{ component.MustNewID("notifiable1"): n1ExtensionConfig, component.MustNewID("notifiable2"): n2ExtensionConfig, }, serviceExtensions: []component.ID{ component.MustNewID("notifiable1"), component.MustNewID("notifiable2"), }, }, { name: "Errors in extension notification", factories: map[component.Type]extension.Factory{ component.MustNewType("notifiableErr"): nErrExtensionFactory, }, extensionsConfigs: map[component.ID]component.Config{ component.MustNewID("notifiableErr"): nErrExtensionConfig, }, serviceExtensions: []component.ID{ component.MustNewID("notifiableErr"), }, want: notificationError, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { extensions, err := New(context.Background(), Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), Extensions: builders.NewExtension(tt.extensionsConfigs, tt.factories), }, tt.serviceExtensions) require.NoError(t, err) errs := extensions.NotifyConfig(context.Background(), confmap.NewFromStringMap(map[string]any{})) assert.Equal(t, tt.want, errs) }) } } type configWatcherExtension struct { fn func() error } func (comp *configWatcherExtension) Start(context.Context, component.Host) error { return comp.fn() } func (comp *configWatcherExtension) Shutdown(context.Context) error { return comp.fn() } func (comp *configWatcherExtension) NotifyConfig(context.Context, *confmap.Conf) error { return comp.fn() } func newConfigWatcherExtension(fn func() error) *configWatcherExtension { comp := &configWatcherExtension{ fn: fn, } return comp } func newConfigWatcherExtensionFactory(name component.Type, fn func() error) extension.Factory { return extension.NewFactory( name, func() component.Config { return &struct{}{} }, func(context.Context, extension.Settings, component.Config) (extension.Extension, error) { return newConfigWatcherExtension(fn), nil }, component.StabilityLevelDevelopment, ) } func newBadExtensionFactory() extension.Factory { return extension.NewFactory( component.MustNewType("bf"), func() component.Config { return &struct{}{} }, func(context.Context, extension.Settings, component.Config) (extension.Extension, error) { return nil, nil }, component.StabilityLevelDevelopment, ) } func newCreateErrorExtensionFactory() extension.Factory { return extension.NewFactory( component.MustNewType("err"), func() component.Config { return &struct{}{} }, func(context.Context, extension.Settings, component.Config) (extension.Extension, error) { return nil, errors.New("cannot create \"err\" extension type") }, component.StabilityLevelDevelopment, ) } func TestStatusReportedOnStartupShutdown(t *testing.T) { // compare two slices of status events ignoring timestamp assertEqualStatuses := func(t *testing.T, evts1, evts2 []*componentstatus.Event) { assert.Len(t, evts2, len(evts1)) for i := range evts1 { ev1 := evts1[i] ev2 := evts2[i] assert.Equal(t, ev1.Status(), ev2.Status()) assert.Equal(t, ev1.Err(), ev2.Err()) } } for _, tt := range []struct { name string expectedStatuses []*componentstatus.Event startErr error shutdownErr error }{ { name: "successful startup/shutdown", expectedStatuses: []*componentstatus.Event{ componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, startErr: nil, shutdownErr: nil, }, { name: "start error", expectedStatuses: []*componentstatus.Event{ componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewPermanentErrorEvent(assert.AnError), }, startErr: assert.AnError, shutdownErr: nil, }, { name: "shutdown error", expectedStatuses: []*componentstatus.Event{ componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewPermanentErrorEvent(assert.AnError), }, startErr: nil, shutdownErr: assert.AnError, }, } { t.Run(tt.name, func(t *testing.T) { statusType := component.MustNewType("statustest") compID := component.NewID(statusType) factory := newStatusTestExtensionFactory(statusType, tt.startErr, tt.shutdownErr) config := factory.CreateDefaultConfig() extensionsConfigs := map[component.ID]component.Config{ compID: config, } factories := map[component.Type]extension.Factory{ statusType: factory, } var actualStatuses []*componentstatus.Event rep := status.NewReporter(func(_ *componentstatus.InstanceID, ev *componentstatus.Event) { actualStatuses = append(actualStatuses, ev) }, func(err error) { require.NoError(t, err) }) extensions, err := New( context.Background(), Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), Extensions: builders.NewExtension(extensionsConfigs, factories), }, []component.ID{compID}, WithReporter(rep), ) require.NoError(t, err) assert.Equal(t, tt.startErr, extensions.Start(context.Background(), componenttest.NewNopHost())) if tt.startErr == nil { assert.Equal(t, tt.shutdownErr, extensions.Shutdown(context.Background())) } assertEqualStatuses(t, tt.expectedStatuses, actualStatuses) }) } } type statusTestExtension struct { startErr error shutdownErr error } func (ext *statusTestExtension) Start(context.Context, component.Host) error { return ext.startErr } func (ext *statusTestExtension) Shutdown(context.Context) error { return ext.shutdownErr } func newStatusTestExtension(startErr, shutdownErr error) *statusTestExtension { return &statusTestExtension{ startErr: startErr, shutdownErr: shutdownErr, } } func newStatusTestExtensionFactory(name component.Type, startErr, shutdownErr error) extension.Factory { return extension.NewFactory( name, func() component.Config { return &struct{}{} }, func(context.Context, extension.Settings, component.Config) (extension.Extension, error) { return newStatusTestExtension(startErr, shutdownErr), nil }, component.StabilityLevelDevelopment, ) } func newRecordingExtensionFactory(startCallback func(set extension.Settings, host component.Host) error, shutdownCallback func(set extension.Settings) error) extension.Factory { return extension.NewFactory( component.MustNewType("recording"), func() component.Config { return &recordingExtensionConfig{} }, func(_ context.Context, set extension.Settings, cfg component.Config) (extension.Extension, error) { return &recordingExtension{ config: cfg.(recordingExtensionConfig), createSettings: set, startCallback: startCallback, shutdownCallback: shutdownCallback, }, nil }, component.StabilityLevelDevelopment, ) } type recordingExtensionConfig struct { dependencies []string // names of dependencies of the same extension type } type recordingExtension struct { config recordingExtensionConfig startCallback func(set extension.Settings, host component.Host) error shutdownCallback func(set extension.Settings) error createSettings extension.Settings } var _ extensioncapabilities.Dependent = (*recordingExtension)(nil) func (ext *recordingExtension) Dependencies() []component.ID { if len(ext.config.dependencies) == 0 { return nil } deps := make([]component.ID, len(ext.config.dependencies)) for i, dep := range ext.config.dependencies { deps[i] = component.MustNewIDWithName("recording", dep) } return deps } func (ext *recordingExtension) Start(_ context.Context, host component.Host) error { return ext.startCallback(ext.createSettings, host) } func (ext *recordingExtension) Shutdown(context.Context) error { return ext.shutdownCallback(ext.createSettings) } opentelemetry-collector-0.141.0/service/extensions/graph.go000066400000000000000000000035301511331344600240260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensions // import "go.opentelemetry.io/collector/service/extensions" import ( "errors" "fmt" "strings" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension/extensioncapabilities" ) type node struct { nodeID int64 extID component.ID } func (n node) ID() int64 { return n.nodeID } func computeOrder(exts *Extensions) ([]component.ID, error) { graph := simple.NewDirectedGraph() nodes := make(map[component.ID]*node) for extID := range exts.extMap { n := &node{ nodeID: int64(len(nodes) + 1), extID: extID, } graph.AddNode(n) nodes[extID] = n } for extID, ext := range exts.extMap { n := nodes[extID] if dep, ok := ext.(extensioncapabilities.Dependent); ok { for _, depID := range dep.Dependencies() { d, ok := nodes[depID] if !ok { return nil, fmt.Errorf("unable to find extension %s on which extension %s depends", depID, extID) } graph.SetEdge(graph.NewEdge(d, n)) } } } orderedNodes, err := topo.Sort(graph) if err != nil { return nil, cycleErr(err, topo.DirectedCyclesIn(graph)) } order := make([]component.ID, len(orderedNodes)) for i, n := range orderedNodes { order[i] = n.(*node).extID } return order, nil } func cycleErr(err error, cycles [][]graph.Node) error { var topoErr topo.Unorderable if !errors.As(err, &topoErr) || len(cycles) == 0 || len(cycles[0]) == 0 { return err } cycle := cycles[0] var names []string for _, n := range cycle { node := n.(*node) names = append(names, node.extID.String()) } cycleStr := "[" + strings.Join(names, " -> ") + "]" return fmt.Errorf("unable to order extensions by dependencies, cycle found %s: %w", cycleStr, err) } opentelemetry-collector-0.141.0/service/extensions/graph_test.go000066400000000000000000000012141511331344600250620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensions // import "go.opentelemetry.io/collector/service/extensions" import ( "errors" "testing" "github.com/stretchr/testify/assert" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/topo" ) func TestCycleErr(t *testing.T) { err := errors.New("foo") assert.Equal(t, err, cycleErr(err, nil), "cycleErr should return the error unchanged when it's unrecognized") var topoErr topo.Unorderable = [][]graph.Node{{}} assert.Equal(t, topoErr, cycleErr(topoErr, nil), "cycleErr should return topo.Unorderable error unchanged when no cycles are found") } opentelemetry-collector-0.141.0/service/extensions/package_test.go000066400000000000000000000003131511331344600253530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package extensions import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/generated_package_test.go000066400000000000000000000002461511331344600251770ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package service import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/go.mod000066400000000000000000000302031511331344600213020ustar00rootroot00000000000000module go.opentelemetry.io/collector/service go 1.24.0 require ( github.com/google/uuid v1.6.0 github.com/prometheus/client_model v0.6.2 github.com/prometheus/common v0.67.1 github.com/shirou/gopsutil/v4 v4.25.10 github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/component/componentstatus v0.141.0 go.opentelemetry.io/collector/component/componenttest v0.141.0 go.opentelemetry.io/collector/config/confighttp v0.141.0 go.opentelemetry.io/collector/config/configtelemetry v0.141.0 go.opentelemetry.io/collector/confmap v1.47.0 go.opentelemetry.io/collector/confmap/xconfmap v0.141.0 go.opentelemetry.io/collector/connector v0.141.0 go.opentelemetry.io/collector/connector/connectortest v0.141.0 go.opentelemetry.io/collector/connector/xconnector v0.141.0 go.opentelemetry.io/collector/consumer v1.47.0 go.opentelemetry.io/collector/consumer/consumererror v0.141.0 go.opentelemetry.io/collector/consumer/consumertest v0.141.0 go.opentelemetry.io/collector/consumer/xconsumer v0.141.0 go.opentelemetry.io/collector/exporter v1.47.0 go.opentelemetry.io/collector/exporter/exportertest v0.141.0 go.opentelemetry.io/collector/exporter/xexporter v0.141.0 go.opentelemetry.io/collector/extension v1.47.0 go.opentelemetry.io/collector/extension/extensioncapabilities v0.141.0 go.opentelemetry.io/collector/extension/extensiontest v0.141.0 go.opentelemetry.io/collector/extension/zpagesextension v0.141.0 go.opentelemetry.io/collector/featuregate v1.47.0 go.opentelemetry.io/collector/internal/fanoutconsumer v0.141.0 go.opentelemetry.io/collector/internal/telemetry v0.141.0 go.opentelemetry.io/collector/internal/testutil v0.141.0 go.opentelemetry.io/collector/otelcol v0.141.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/pdata/pprofile v0.141.0 go.opentelemetry.io/collector/pdata/testdata v0.141.0 go.opentelemetry.io/collector/pdata/xpdata v0.141.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/pipeline/xpipeline v0.141.0 go.opentelemetry.io/collector/processor v1.47.0 go.opentelemetry.io/collector/processor/processortest v0.141.0 go.opentelemetry.io/collector/processor/xprocessor v0.141.0 go.opentelemetry.io/collector/receiver v1.47.0 go.opentelemetry.io/collector/receiver/receivertest v0.141.0 go.opentelemetry.io/collector/receiver/xreceiver v0.141.0 go.opentelemetry.io/collector/service/hostcapabilities v0.141.0 go.opentelemetry.io/collector/service/telemetry/telemetrytest v0.141.0 go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 go.opentelemetry.io/contrib/otelconf v0.18.0 go.opentelemetry.io/contrib/propagators/b3 v1.38.0 go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel/log v0.14.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/sdk v1.38.0 go.opentelemetry.io/otel/sdk/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/goleak v1.3.0 go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.1 gonum.org/v1/gonum v0.16.0 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/ebitengine/purego v0.9.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d // indirect github.com/fsnotify/fsnotify v1.9.0 // 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-viper/mapstructure/v2 v2.4.0 // indirect github.com/gobwas/glob v0.2.3 // indirect github.com/golang/snappy v1.0.0 // indirect github.com/google/go-tpm v0.9.7 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.18.1 // 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.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/reflectwalk v1.0.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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect github.com/rs/cors v1.11.1 // indirect github.com/spf13/cobra v1.10.1 // indirect github.com/spf13/pflag v1.0.9 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/client v1.47.0 // indirect go.opentelemetry.io/collector/config/configauth v1.47.0 // indirect go.opentelemetry.io/collector/config/configcompression v1.47.0 // indirect go.opentelemetry.io/collector/config/configmiddleware v1.47.0 // indirect go.opentelemetry.io/collector/config/configopaque v1.47.0 // indirect go.opentelemetry.io/collector/config/configoptional v1.47.0 // indirect go.opentelemetry.io/collector/config/configtls v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionauth v1.47.0 // indirect go.opentelemetry.io/collector/extension/extensionmiddleware v0.141.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 // indirect go.opentelemetry.io/contrib/zpages v0.63.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/connector => ../connector replace go.opentelemetry.io/collector/connector/connectortest => ../connector/connectortest replace go.opentelemetry.io/collector/component => ../component replace go.opentelemetry.io/collector/component/componenttest => ../component/componenttest replace go.opentelemetry.io/collector/internal/telemetry => ../internal/telemetry/ replace go.opentelemetry.io/collector/component/componentstatus => ../component/componentstatus replace go.opentelemetry.io/collector/pdata => ../pdata replace go.opentelemetry.io/collector/pdata/testdata => ../pdata/testdata replace go.opentelemetry.io/collector/extension/zpagesextension => ../extension/zpagesextension replace go.opentelemetry.io/collector/extension => ../extension replace go.opentelemetry.io/collector/exporter => ../exporter replace go.opentelemetry.io/collector/confmap => ../confmap replace go.opentelemetry.io/collector/confmap/xconfmap => ../confmap/xconfmap replace go.opentelemetry.io/collector/config/configtelemetry => ../config/configtelemetry replace go.opentelemetry.io/collector/pipeline => ../pipeline replace go.opentelemetry.io/collector/processor => ../processor replace go.opentelemetry.io/collector/processor/processortest => ../processor/processortest replace go.opentelemetry.io/collector/consumer => ../consumer replace go.opentelemetry.io/collector/service/hostcapabilities => ./hostcapabilities replace go.opentelemetry.io/collector/service/telemetry/telemetrytest => ./telemetry/telemetrytest replace go.opentelemetry.io/collector/receiver => ../receiver replace go.opentelemetry.io/collector/featuregate => ../featuregate replace go.opentelemetry.io/collector/config/configretry => ../config/configretry replace go.opentelemetry.io/collector/extension/extensionauth => ../extension/extensionauth replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../extension/extensioncapabilities replace go.opentelemetry.io/collector/config/configopaque => ../config/configopaque replace go.opentelemetry.io/collector/config/confighttp => ../config/confighttp replace go.opentelemetry.io/collector/config/configauth => ../config/configauth replace go.opentelemetry.io/collector/config/configtls => ../config/configtls replace go.opentelemetry.io/collector/config/configcompression => ../config/configcompression replace go.opentelemetry.io/collector/pdata/pprofile => ../pdata/pprofile replace go.opentelemetry.io/collector/consumer/xconsumer => ../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumertest => ../consumer/consumertest replace go.opentelemetry.io/collector/client => ../client replace go.opentelemetry.io/collector/receiver/xreceiver => ../receiver/xreceiver replace go.opentelemetry.io/collector/receiver/receivertest => ../receiver/receivertest replace go.opentelemetry.io/collector/processor/xprocessor => ../processor/xprocessor replace go.opentelemetry.io/collector/exporter/xexporter => ../exporter/xexporter replace go.opentelemetry.io/collector/pipeline/xpipeline => ../pipeline/xpipeline replace go.opentelemetry.io/collector/exporter/exportertest => ../exporter/exportertest replace go.opentelemetry.io/collector/consumer/consumererror => ../consumer/consumererror replace go.opentelemetry.io/collector/connector/xconnector => ../connector/xconnector replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../internal/fanoutconsumer replace go.opentelemetry.io/collector/extension/extensiontest => ../extension/extensiontest replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/extension/xextension => ../extension/xextension replace go.opentelemetry.io/collector/otelcol => ../otelcol replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../confmap/provider/fileprovider replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../extension/extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/pdata/xpdata => ../pdata/xpdata replace go.opentelemetry.io/collector/exporter/exporterhelper => ../exporter/exporterhelper replace go.opentelemetry.io/collector/config/configoptional => ../config/configoptional replace go.opentelemetry.io/collector/internal/testutil => ../internal/testutil opentelemetry-collector-0.141.0/service/go.sum000066400000000000000000000504311511331344600213340ustar00rootroot00000000000000github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/ebitengine/purego v0.9.0 h1:mh0zpKBIXDceC63hpvPuGLiJ8ZAa3DfrFTudmfi8A4k= github.com/ebitengine/purego v0.9.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d h1:EdO/NMMuCZfxhdzTZLuKAciQSnI2DV+Ppg8+vAYrnqA= github.com/foxboron/go-tpm-keyfiles v0.0.0-20250903184740-5d135037bd4d/go.mod h1:uAyTlAUxchYuiFjTHmuIEJ4nGSm7iOPaGcAyA81fJ80= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006 h1:50sW4r0PcvlpG4PV8tYh2RVCapszJgaOLRCS2subvV4= github.com/foxboron/swtpm_test v0.0.0-20230726224112-46aaafdf7006/go.mod h1:eIXCMsMYCaqq9m1KSSxXwQG11krpuNPGP3k0uaWrbas= github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/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-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs= github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= 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/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.7 h1:u89J4tUUeDTlH8xxC3CTW7OHZjbjKoHdQ9W7gCUhtxA= github.com/google/go-tpm v0.9.7/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= github.com/google/go-tpm-tools v0.4.4 h1:oiQfAIkc6xTy9Fl5NKTeTJkBTlXdHsxAofmQyxBKY98= github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo= 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.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM= github.com/knadh/koanf/v2 v2.3.0/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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/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/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rs/cors v1.11.1 h1:eU3gRzXLRK57F5rKMGMZURNdIG4EoAmX8k94r9wXWHA= github.com/rs/cors v1.11.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil/v4 v4.25.10 h1:at8lk/5T1OgtuCp+AwrDofFRjnvosn0nkN2OLQ6g8tA= github.com/shirou/gopsutil/v4 v4.25.10/go.mod h1:+kSwyC8DRUD9XXEHCAFjK+0nuArFJM0lva+StQAcskM= github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s= github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0= github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY= github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 h1:aBKdhLVieqvwWe9A79UHI/0vgp2t/s2euY8X59pGRlw= go.opentelemetry.io/contrib/bridges/otelzap v0.13.0/go.mod h1:SYqtxLQE7iINgh6WFuVi2AI70148B8EI35DSk0Wr8m4= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0 h1:RbKq8BG0FI8OiXhBfcRtqqHcZcka+gU3cskNuf05R18= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.63.0/go.mod h1:h06DGIukJOevXaj/xrNjhi/2098RZzcLTbc0jDAUbsg= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/contrib/propagators/b3 v1.38.0 h1:uHsCCOSKl0kLrV2dLkFK+8Ywk9iKa/fptkytc6aFFEo= go.opentelemetry.io/contrib/propagators/b3 v1.38.0/go.mod h1:wMRSZJZcY8ya9mApLLhwIMjqmApy2o/Ml+62lhvxyHU= go.opentelemetry.io/contrib/zpages v0.63.0 h1:TppOKuZGbqXMgsfjqq3i09N5Vbo1JLtLImUqiTPGnX4= go.opentelemetry.io/contrib/zpages v0.63.0/go.mod h1:5F8uugz75ay/MMhRRhxAXY33FuaI8dl7jTxefrIy5qk= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= 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= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/service/hostcapabilities/000077500000000000000000000000001511331344600235255ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/hostcapabilities/Makefile000066400000000000000000000000361511331344600251640ustar00rootroot00000000000000include ../../Makefile.Common opentelemetry-collector-0.141.0/service/hostcapabilities/go.mod000066400000000000000000000122371511331344600246400ustar00rootroot00000000000000module go.opentelemetry.io/collector/service/hostcapabilities go 1.24.0 require ( go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/pipeline v1.47.0 go.opentelemetry.io/collector/service v0.141.0 ) require ( github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/collector/pdata v1.47.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/metric v1.38.0 // indirect go.opentelemetry.io/otel/trace v1.38.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect ) replace ( go.opentelemetry.io/collector/client => ../../client go.opentelemetry.io/collector/component => ../../component go.opentelemetry.io/collector/component/componentstatus => ../../component/componentstatus go.opentelemetry.io/collector/component/componenttest => ../../component/componenttest go.opentelemetry.io/collector/config/configauth => ../../config/configauth go.opentelemetry.io/collector/config/configcompression => ../../config/configcompression go.opentelemetry.io/collector/config/confighttp => ../../config/confighttp go.opentelemetry.io/collector/config/configopaque => ../../config/configopaque go.opentelemetry.io/collector/config/configretry => ../../config/configretry go.opentelemetry.io/collector/config/configtelemetry => ../../config/configtelemetry go.opentelemetry.io/collector/config/configtls => ../../config/configtls go.opentelemetry.io/collector/confmap => ../../confmap go.opentelemetry.io/collector/confmap/xconfmap => ../../confmap/xconfmap go.opentelemetry.io/collector/connector => ../../connector go.opentelemetry.io/collector/connector/connectortest => ../../connector/connectortest go.opentelemetry.io/collector/connector/xconnector => ../../connector/xconnector go.opentelemetry.io/collector/consumer => ../../consumer go.opentelemetry.io/collector/consumer/consumererror => ../../consumer/consumererror go.opentelemetry.io/collector/consumer/consumertest => ../../consumer/consumertest go.opentelemetry.io/collector/consumer/xconsumer => ../../consumer/xconsumer go.opentelemetry.io/collector/exporter => ../../exporter go.opentelemetry.io/collector/exporter/exportertest => ../../exporter/exportertest go.opentelemetry.io/collector/exporter/xexporter => ../../exporter/xexporter go.opentelemetry.io/collector/extension => ../../extension go.opentelemetry.io/collector/extension/extensionauth => ../../extension/extensionauth go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../extension/extensionauth/extensionauthtest go.opentelemetry.io/collector/extension/extensioncapabilities => ../../extension/extensioncapabilities go.opentelemetry.io/collector/extension/extensiontest => ../../extension/extensiontest go.opentelemetry.io/collector/extension/xextension => ../../extension/xextension go.opentelemetry.io/collector/extension/zpagesextension => ../../extension/zpagesextension go.opentelemetry.io/collector/featuregate => ../../featuregate go.opentelemetry.io/collector/internal/fanoutconsumer => ../../internal/fanoutconsumer go.opentelemetry.io/collector/internal/telemetry => ../../internal/telemetry go.opentelemetry.io/collector/pdata => ../../pdata go.opentelemetry.io/collector/pdata/pprofile => ../../pdata/pprofile go.opentelemetry.io/collector/pdata/testdata => ../../pdata/testdata go.opentelemetry.io/collector/pipeline => ../../pipeline go.opentelemetry.io/collector/pipeline/xpipeline => ../../pipeline/xpipeline go.opentelemetry.io/collector/processor => ../../processor go.opentelemetry.io/collector/processor/processortest => ../../processor/processortest go.opentelemetry.io/collector/processor/xprocessor => ../../processor/xprocessor go.opentelemetry.io/collector/receiver => ../../receiver go.opentelemetry.io/collector/receiver/receivertest => ../../receiver/receivertest go.opentelemetry.io/collector/receiver/xreceiver => ../../receiver/xreceiver go.opentelemetry.io/collector/service => .. ) replace go.opentelemetry.io/collector/otelcol => ../../otelcol replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../confmap/provider/fileprovider replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/config/configmiddleware => ../../config/configmiddleware replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../extension/extensionmiddleware replace go.opentelemetry.io/collector/pdata/xpdata => ../../pdata/xpdata replace go.opentelemetry.io/collector/exporter/exporterhelper => ../../exporter/exporterhelper replace go.opentelemetry.io/collector/config/configoptional => ../../config/configoptional replace go.opentelemetry.io/collector/service/telemetry/telemetrytest => ../telemetry/telemetrytest replace go.opentelemetry.io/collector/internal/testutil => ../../internal/testutil opentelemetry-collector-0.141.0/service/hostcapabilities/go.sum000066400000000000000000000107651511331344600246710ustar00rootroot00000000000000github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.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/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/service/hostcapabilities/interfaces.go000066400000000000000000000027441511331344600262060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package hostcapabilities provides interfaces that can be implemented by the host // to provide additional capabilities. package hostcapabilities // import "go.opentelemetry.io/collector/service/hostcapabilities" import ( "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/internal/moduleinfo" ) // ModuleInfo is an interface that may be implemented by the host to provide // information about modules that were used to build the host. type ModuleInfo interface { // GetModuleInfos returns the module information for the host // i.e. Receivers, Processors, Exporters, Extensions, and Connectors GetModuleInfos() moduleinfo.ModuleInfos } // ExposeExporters is an interface that may be implemented by the host to provide // access to the exporters that were used to build the host. // // Deprecated: [v0.121.0] Will be removed in Service 1.0. // See: https://github.com/open-telemetry/opentelemetry-collector/issues/7370 for service 1.0 type ExposeExporters interface { GetExporters() map[pipeline.Signal]map[component.ID]component.Component } // ComponentFactory is an interface that may be implemented by the host to // provide a component's factory type ComponentFactory interface { // GetFactory returns the component factory for the given // component type GetFactory(kind component.Kind, componentType component.Type) component.Factory } opentelemetry-collector-0.141.0/service/internal/000077500000000000000000000000001511331344600220125ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/attribute/000077500000000000000000000000001511331344600240155ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/attribute/attribute.go000066400000000000000000000062751511331344600263610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package attribute // import "go.opentelemetry.io/collector/service/internal/attribute" import ( "hash/fnv" "strings" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pipeline" ) const ( capabiltiesKind = "capabilities" fanoutKind = "fanout" ) type Attributes struct { set attribute.Set id int64 } func newAttributes(attrs ...attribute.KeyValue) Attributes { h := fnv.New64a() for _, kv := range attrs { h.Write([]byte("(" + string(kv.Key) + "|" + kv.Value.AsString() + ")")) } return Attributes{ set: attribute.NewSet(attrs...), // The graph identifies nodes by an int64 ID, but fnv gives us a uint64. // It is safe to cast because the meaning of the number is irrelevant. // We only care that each node has a unique 64 bit ID, which is unaltered by this cast. id: int64(h.Sum64()), // #nosec G115 } } func (a Attributes) Set() *attribute.Set { return &a.set } func (a Attributes) ID() int64 { return a.id } func Receiver(pipelineType pipeline.Signal, id component.ID) Attributes { return newAttributes( attribute.String(telemetry.ComponentKindKey, strings.ToLower(component.KindReceiver.String())), attribute.String(telemetry.SignalKey, pipelineType.String()), attribute.String(telemetry.ComponentIDKey, id.String()), ) } func Processor(pipelineID pipeline.ID, id component.ID) Attributes { return newAttributes( attribute.String(telemetry.ComponentKindKey, strings.ToLower(component.KindProcessor.String())), attribute.String(telemetry.SignalKey, pipelineID.Signal().String()), attribute.String(telemetry.PipelineIDKey, pipelineID.String()), attribute.String(telemetry.ComponentIDKey, id.String()), ) } func Exporter(pipelineType pipeline.Signal, id component.ID) Attributes { return newAttributes( attribute.String(telemetry.ComponentKindKey, strings.ToLower(component.KindExporter.String())), attribute.String(telemetry.SignalKey, pipelineType.String()), attribute.String(telemetry.ComponentIDKey, id.String()), ) } func Connector(exprPipelineType, rcvrPipelineType pipeline.Signal, id component.ID) Attributes { return newAttributes( attribute.String(telemetry.ComponentKindKey, strings.ToLower(component.KindConnector.String())), attribute.String(telemetry.SignalKey, exprPipelineType.String()), attribute.String(telemetry.SignalOutputKey, rcvrPipelineType.String()), attribute.String(telemetry.ComponentIDKey, id.String()), ) } func Extension(id component.ID) Attributes { return newAttributes( attribute.String(telemetry.ComponentKindKey, strings.ToLower(component.KindExtension.String())), attribute.String(telemetry.ComponentIDKey, id.String()), ) } func Capabilities(pipelineID pipeline.ID) Attributes { return newAttributes( attribute.String(telemetry.ComponentKindKey, capabiltiesKind), attribute.String(telemetry.PipelineIDKey, pipelineID.String()), ) } func Fanout(pipelineID pipeline.ID) Attributes { return newAttributes( attribute.String(telemetry.ComponentKindKey, fanoutKind), attribute.String(telemetry.PipelineIDKey, pipelineID.String()), ) } opentelemetry-collector-0.141.0/service/internal/attribute/attribute_test.go000066400000000000000000000123221511331344600274060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package attribute_test import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/service/internal/attribute" ) var ( signals = []pipeline.Signal{ pipeline.SignalTraces, pipeline.SignalMetrics, pipeline.SignalLogs, xpipeline.SignalProfiles, } cIDs = []component.ID{ component.MustNewID("foo"), component.MustNewID("foo2"), component.MustNewID("bar"), } pIDs = []pipeline.ID{ pipeline.NewID(pipeline.SignalTraces), pipeline.NewIDWithName(pipeline.SignalTraces, "2"), pipeline.NewID(pipeline.SignalMetrics), pipeline.NewIDWithName(pipeline.SignalMetrics, "2"), pipeline.NewID(pipeline.SignalLogs), pipeline.NewIDWithName(pipeline.SignalLogs, "2"), pipeline.NewID(xpipeline.SignalProfiles), pipeline.NewIDWithName(xpipeline.SignalProfiles, "2"), } ) func TestReceiver(t *testing.T) { for _, sig := range signals { for _, id := range cIDs { r := attribute.Receiver(sig, id) componentKind, ok := r.Set().Value(telemetry.ComponentKindKey) require.True(t, ok) require.Equal(t, "receiver", componentKind.AsString()) signal, ok := r.Set().Value(telemetry.SignalKey) require.True(t, ok) require.Equal(t, sig.String(), signal.AsString()) componentID, ok := r.Set().Value(telemetry.ComponentIDKey) require.True(t, ok) require.Equal(t, id.String(), componentID.AsString()) } } } func TestProcessor(t *testing.T) { for _, pID := range pIDs { for _, id := range cIDs { p := attribute.Processor(pID, id) componentKind, ok := p.Set().Value(telemetry.ComponentKindKey) require.True(t, ok) require.Equal(t, "processor", componentKind.AsString()) pipelineID, ok := p.Set().Value(telemetry.PipelineIDKey) require.True(t, ok) require.Equal(t, pID.String(), pipelineID.AsString()) componentID, ok := p.Set().Value(telemetry.ComponentIDKey) require.True(t, ok) require.Equal(t, id.String(), componentID.AsString()) } } } func TestExporter(t *testing.T) { for _, sig := range signals { for _, id := range cIDs { e := attribute.Exporter(sig, id) componentKind, ok := e.Set().Value(telemetry.ComponentKindKey) require.True(t, ok) require.Equal(t, "exporter", componentKind.AsString()) signal, ok := e.Set().Value(telemetry.SignalKey) require.True(t, ok) require.Equal(t, sig.String(), signal.AsString()) componentID, ok := e.Set().Value(telemetry.ComponentIDKey) require.True(t, ok) require.Equal(t, id.String(), componentID.AsString()) } } } func TestConnector(t *testing.T) { for _, exprSig := range signals { for _, rcvrSig := range signals { for _, id := range cIDs { c := attribute.Connector(exprSig, rcvrSig, id) componentKind, ok := c.Set().Value(telemetry.ComponentKindKey) require.True(t, ok) require.Equal(t, "connector", componentKind.AsString()) signal, ok := c.Set().Value(telemetry.SignalKey) require.True(t, ok) require.Equal(t, exprSig.String(), signal.AsString()) signalOutput, ok := c.Set().Value(telemetry.SignalOutputKey) require.True(t, ok) require.Equal(t, rcvrSig.String(), signalOutput.AsString()) componentID, ok := c.Set().Value(telemetry.ComponentIDKey) require.True(t, ok) require.Equal(t, id.String(), componentID.AsString()) } } } } func TestExtension(t *testing.T) { e := attribute.Extension(component.MustNewID("foo")) componentKind, ok := e.Set().Value(telemetry.ComponentKindKey) require.True(t, ok) require.Equal(t, "extension", componentKind.AsString()) } func TestSetEquality(t *testing.T) { // The sets are created independently but should be exactly equivalent. // We will ensure that corresponding elements are equal and that // non-corresponding elements are not equal. setI, setJ := createExampleSets(), createExampleSets() for i, ei := range setI { for j, ej := range setJ { if i == j { require.Equal(t, ei.ID(), ej.ID()) si, sj := ei.Set(), ej.Set() require.True(t, si.Equals(sj)) } else { require.NotEqual(t, ei.ID(), ej.ID()) si, sj := ei.Set(), ej.Set() require.False(t, si.Equals(sj)) } } } } func createExampleSets() []attribute.Attributes { sets := []attribute.Attributes{} // Receiver examples. for _, sig := range signals { for _, id := range cIDs { sets = append(sets, attribute.Receiver(sig, id)) } } // Processor examples. for _, pID := range pIDs { for _, cID := range cIDs { sets = append(sets, attribute.Processor(pID, cID)) } } // Exporter examples. for _, sig := range signals { for _, id := range cIDs { sets = append(sets, attribute.Exporter(sig, id)) } } // Connector examples. for _, exprSig := range signals { for _, rcvrSig := range signals { for _, id := range cIDs { sets = append(sets, attribute.Connector(exprSig, rcvrSig, id)) } } } // Capabilities examples. for _, pID := range pIDs { sets = append(sets, attribute.Capabilities(pID)) } // Fanout examples. for _, pID := range pIDs { sets = append(sets, attribute.Fanout(pID)) } return sets } opentelemetry-collector-0.141.0/service/internal/builders/000077500000000000000000000000001511331344600236235ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/builders/builders.go000066400000000000000000000014031511331344600257610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders // import "go.opentelemetry.io/collector/service/internal/builders" import ( "errors" "go.uber.org/zap" "go.opentelemetry.io/collector/component" ) var ( errNilNextConsumer = errors.New("nil next Consumer") NopType = component.MustNewType("nop") ) // logStabilityLevel logs the stability level of a component. The log level is set to info for // undefined, unmaintained, deprecated and development. The log level is set to debug // for alpha, beta and stable. func logStabilityLevel(logger *zap.Logger, sl component.StabilityLevel) { if sl >= component.StabilityLevelAlpha { logger.Debug(sl.LogMessage()) } else { logger.Info(sl.LogMessage()) } } opentelemetry-collector-0.141.0/service/internal/builders/builders_test/000077500000000000000000000000001511331344600264735ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/builders/builders_test/connector_test.go000066400000000000000000000617131511331344600320630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders import ( "context" "fmt" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/service/internal/builders" ) func TestConnectorBuilder(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]connector.Factory{ connector.NewFactory(component.MustNewType("err"), nil), xconnector.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xconnector.WithTracesToTraces(createConnectorTracesToTraces, component.StabilityLevelDevelopment), xconnector.WithTracesToMetrics(createConnectorTracesToMetrics, component.StabilityLevelDevelopment), xconnector.WithTracesToLogs(createConnectorTracesToLogs, component.StabilityLevelDevelopment), xconnector.WithTracesToProfiles(createConnectorTracesToProfiles, component.StabilityLevelDevelopment), xconnector.WithMetricsToTraces(createConnectorMetricsToTraces, component.StabilityLevelAlpha), xconnector.WithMetricsToMetrics(createConnectorMetricsToMetrics, component.StabilityLevelAlpha), xconnector.WithMetricsToLogs(createConnectorMetricsToLogs, component.StabilityLevelAlpha), xconnector.WithMetricsToProfiles(createConnectorMetricsToProfiles, component.StabilityLevelAlpha), xconnector.WithLogsToTraces(createConnectorLogsToTraces, component.StabilityLevelDeprecated), xconnector.WithLogsToMetrics(createConnectorLogsToMetrics, component.StabilityLevelDeprecated), xconnector.WithLogsToLogs(createConnectorLogsToLogs, component.StabilityLevelDeprecated), xconnector.WithLogsToProfiles(createConnectorLogsToProfiles, component.StabilityLevelDeprecated), xconnector.WithProfilesToTraces(createxconnectorToTraces, component.StabilityLevelDevelopment), xconnector.WithProfilesToMetrics(createxconnectorToMetrics, component.StabilityLevelDevelopment), xconnector.WithProfilesToLogs(createxconnectorToLogs, component.StabilityLevelDevelopment), xconnector.WithProfilesToProfiles(createxconnectorToProfiles, component.StabilityLevelDevelopment), ), }...) require.NoError(t, err) testCases := []struct { name string id component.ID err func(pipeline.Signal, pipeline.Signal) string nextTraces consumer.Traces nextLogs consumer.Logs nextMetrics consumer.Metrics nextProfiles xconsumer.Profiles }{ { name: "unknown", id: component.MustNewID("unknown"), err: func(pipeline.Signal, pipeline.Signal) string { return "connector factory not available for: \"unknown\"" }, nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "err", id: component.MustNewID("err"), err: func(expType, rcvType pipeline.Signal) string { return fmt.Sprintf("connector \"err\" cannot connect from %s to %s: telemetry type is not supported", expType, rcvType) }, nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "all", id: component.MustNewID("all"), err: func(pipeline.Signal, pipeline.Signal) string { return "" }, nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "all/named", id: component.MustNewIDWithName("all", "named"), err: func(pipeline.Signal, pipeline.Signal) string { return "" }, nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "no next consumer", id: component.MustNewID("unknown"), err: func(_, _ pipeline.Signal) string { return "nil next Consumer" }, nextTraces: nil, nextLogs: nil, nextMetrics: nil, nextProfiles: nil, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfgs := map[component.ID]component.Config{tt.id: defaultCfg} b := builders.NewConnector(cfgs, factories) t2t, err := b.CreateTracesToTraces(context.Background(), createConnectorSettings(tt.id), tt.nextTraces) if expectedErr := tt.err(pipeline.SignalTraces, pipeline.SignalTraces); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, t2t) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, t2t) } t2m, err := b.CreateTracesToMetrics(context.Background(), createConnectorSettings(tt.id), tt.nextMetrics) if expectedErr := tt.err(pipeline.SignalTraces, pipeline.SignalMetrics); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, t2m) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, t2m) } t2l, err := b.CreateTracesToLogs(context.Background(), createConnectorSettings(tt.id), tt.nextLogs) if expectedErr := tt.err(pipeline.SignalTraces, pipeline.SignalLogs); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, t2l) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, t2l) } t2p, err := b.CreateTracesToProfiles(context.Background(), createConnectorSettings(tt.id), tt.nextProfiles) if expectedErr := tt.err(pipeline.SignalTraces, xpipeline.SignalProfiles); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, t2p) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, t2p) } m2t, err := b.CreateMetricsToTraces(context.Background(), createConnectorSettings(tt.id), tt.nextTraces) if expectedErr := tt.err(pipeline.SignalMetrics, pipeline.SignalTraces); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, m2t) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, m2t) } m2m, err := b.CreateMetricsToMetrics(context.Background(), createConnectorSettings(tt.id), tt.nextMetrics) if expectedErr := tt.err(pipeline.SignalMetrics, pipeline.SignalMetrics); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, m2m) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, m2m) } m2l, err := b.CreateMetricsToLogs(context.Background(), createConnectorSettings(tt.id), tt.nextLogs) if expectedErr := tt.err(pipeline.SignalMetrics, pipeline.SignalLogs); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, m2l) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, m2l) } m2p, err := b.CreateMetricsToProfiles(context.Background(), createConnectorSettings(tt.id), tt.nextProfiles) if expectedErr := tt.err(pipeline.SignalMetrics, xpipeline.SignalProfiles); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, m2p) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, m2p) } l2t, err := b.CreateLogsToTraces(context.Background(), createConnectorSettings(tt.id), tt.nextTraces) if expectedErr := tt.err(pipeline.SignalLogs, pipeline.SignalTraces); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, l2t) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, l2t) } l2m, err := b.CreateLogsToMetrics(context.Background(), createConnectorSettings(tt.id), tt.nextMetrics) if expectedErr := tt.err(pipeline.SignalLogs, pipeline.SignalMetrics); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, l2m) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, l2m) } l2l, err := b.CreateLogsToLogs(context.Background(), createConnectorSettings(tt.id), tt.nextLogs) if expectedErr := tt.err(pipeline.SignalLogs, pipeline.SignalLogs); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, l2l) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, l2l) } l2p, err := b.CreateLogsToProfiles(context.Background(), createConnectorSettings(tt.id), tt.nextProfiles) if expectedErr := tt.err(pipeline.SignalLogs, xpipeline.SignalProfiles); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, l2p) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, l2p) } p2t, err := b.CreateProfilesToTraces(context.Background(), createConnectorSettings(tt.id), tt.nextTraces) if expectedErr := tt.err(xpipeline.SignalProfiles, pipeline.SignalTraces); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, p2t) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, p2t) } p2m, err := b.CreateProfilesToMetrics(context.Background(), createConnectorSettings(tt.id), tt.nextMetrics) if expectedErr := tt.err(xpipeline.SignalProfiles, pipeline.SignalMetrics); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, p2m) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, p2m) } p2l, err := b.CreateProfilesToLogs(context.Background(), createConnectorSettings(tt.id), tt.nextLogs) if expectedErr := tt.err(xpipeline.SignalProfiles, pipeline.SignalLogs); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, p2l) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, p2l) } p2p, err := b.CreateProfilesToProfiles(context.Background(), createConnectorSettings(tt.id), tt.nextProfiles) if expectedErr := tt.err(xpipeline.SignalProfiles, xpipeline.SignalProfiles); expectedErr != "" { assert.EqualError(t, err, expectedErr) assert.Nil(t, p2p) } else { assert.NoError(t, err) assert.Equal(t, nopConnectorInstance, p2p) } }) } } func TestConnectorBuilderMissingConfig(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]connector.Factory{ xconnector.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xconnector.WithTracesToTraces(createConnectorTracesToTraces, component.StabilityLevelDevelopment), xconnector.WithTracesToMetrics(createConnectorTracesToMetrics, component.StabilityLevelDevelopment), xconnector.WithTracesToLogs(createConnectorTracesToLogs, component.StabilityLevelDevelopment), xconnector.WithTracesToProfiles(createConnectorTracesToProfiles, component.StabilityLevelDevelopment), xconnector.WithMetricsToTraces(createConnectorMetricsToTraces, component.StabilityLevelAlpha), xconnector.WithMetricsToMetrics(createConnectorMetricsToMetrics, component.StabilityLevelAlpha), xconnector.WithMetricsToLogs(createConnectorMetricsToLogs, component.StabilityLevelAlpha), xconnector.WithMetricsToProfiles(createConnectorMetricsToProfiles, component.StabilityLevelAlpha), xconnector.WithLogsToTraces(createConnectorLogsToTraces, component.StabilityLevelDeprecated), xconnector.WithLogsToMetrics(createConnectorLogsToMetrics, component.StabilityLevelDeprecated), xconnector.WithLogsToLogs(createConnectorLogsToLogs, component.StabilityLevelDeprecated), xconnector.WithLogsToProfiles(createConnectorLogsToProfiles, component.StabilityLevelDeprecated), xconnector.WithProfilesToTraces(createxconnectorToTraces, component.StabilityLevelDevelopment), xconnector.WithProfilesToMetrics(createxconnectorToMetrics, component.StabilityLevelDevelopment), xconnector.WithProfilesToLogs(createxconnectorToLogs, component.StabilityLevelDevelopment), xconnector.WithProfilesToProfiles(createxconnectorToProfiles, component.StabilityLevelDevelopment), ), }...) require.NoError(t, err) bErr := builders.NewConnector(map[component.ID]component.Config{}, factories) missingID := component.MustNewIDWithName("all", "missing") t2t, err := bErr.CreateTracesToTraces(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, t2t) t2m, err := bErr.CreateTracesToMetrics(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, t2m) t2l, err := bErr.CreateTracesToLogs(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, t2l) t2p, err := bErr.CreateTracesToProfiles(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, t2p) m2t, err := bErr.CreateMetricsToTraces(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, m2t) m2m, err := bErr.CreateMetricsToMetrics(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, m2m) m2l, err := bErr.CreateMetricsToLogs(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, m2l) m2p, err := bErr.CreateMetricsToProfiles(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, m2p) l2t, err := bErr.CreateLogsToTraces(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, l2t) l2m, err := bErr.CreateLogsToMetrics(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, l2m) l2l, err := bErr.CreateLogsToLogs(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, l2l) l2p, err := bErr.CreateLogsToProfiles(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, l2p) p2t, err := bErr.CreateProfilesToTraces(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, p2t) p2m, err := bErr.CreateProfilesToMetrics(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, p2m) p2l, err := bErr.CreateProfilesToLogs(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, p2l) p2p, err := bErr.CreateProfilesToProfiles(context.Background(), createConnectorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "connector \"all/missing\" is not configured") assert.Nil(t, p2p) } func TestConnectorBuilderGetters(t *testing.T) { factories, err := otelcol.MakeFactoryMap([]connector.Factory{connector.NewFactory(component.MustNewType("foo"), nil)}...) require.NoError(t, err) cfgs := map[component.ID]component.Config{component.MustNewID("foo"): struct{}{}} b := builders.NewConnector(cfgs, factories) assert.True(t, b.IsConfigured(component.MustNewID("foo"))) assert.False(t, b.IsConfigured(component.MustNewID("bar"))) assert.NotNil(t, b.Factory(component.MustNewID("foo").Type())) assert.Nil(t, b.Factory(component.MustNewID("bar").Type())) } func TestNewNopConnectorConfigsAndFactories(t *testing.T) { configs, factories := builders.NewNopConnectorConfigsAndFactories() builder := builders.NewConnector(configs, factories) require.NotNil(t, builder) factory := connectortest.NewNopFactory() cfg := factory.CreateDefaultConfig() set := connectortest.NewNopSettings(factory.Type()) set.ID = component.NewIDWithName(builders.NopType, "conn") tracesToTraces, err := factory.CreateTracesToTraces(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bTracesToTraces, err := builder.CreateTracesToTraces(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, tracesToTraces, bTracesToTraces) tracesToMetrics, err := factory.CreateTracesToMetrics(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bTracesToMetrics, err := builder.CreateTracesToMetrics(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, tracesToMetrics, bTracesToMetrics) tracesToLogs, err := factory.CreateTracesToLogs(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bTracesToLogs, err := builder.CreateTracesToLogs(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, tracesToLogs, bTracesToLogs) tracesToProfiles, err := factory.(xconnector.Factory).CreateTracesToProfiles(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bTracesToProfiles, err := builder.CreateTracesToProfiles(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, tracesToProfiles, bTracesToProfiles) metricsToTraces, err := factory.CreateMetricsToTraces(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bMetricsToTraces, err := builder.CreateMetricsToTraces(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, metricsToTraces, bMetricsToTraces) metricsToMetrics, err := factory.CreateMetricsToMetrics(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bMetricsToMetrics, err := builder.CreateMetricsToMetrics(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, metricsToMetrics, bMetricsToMetrics) metricsToLogs, err := factory.CreateMetricsToLogs(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bMetricsToLogs, err := builder.CreateMetricsToLogs(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, metricsToLogs, bMetricsToLogs) metricsToProfiles, err := factory.(xconnector.Factory).CreateMetricsToProfiles(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bMetricsToProfiles, err := builder.CreateMetricsToProfiles(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, metricsToProfiles, bMetricsToProfiles) logsToTraces, err := factory.CreateLogsToTraces(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bLogsToTraces, err := builder.CreateLogsToTraces(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, logsToTraces, bLogsToTraces) logsToMetrics, err := factory.CreateLogsToMetrics(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bLogsToMetrics, err := builder.CreateLogsToMetrics(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, logsToMetrics, bLogsToMetrics) logsToLogs, err := factory.CreateLogsToLogs(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bLogsToLogs, err := builder.CreateLogsToLogs(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, logsToLogs, bLogsToLogs) logsToProfiles, err := factory.(xconnector.Factory).CreateLogsToProfiles(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bLogsToProfiles, err := builder.CreateLogsToProfiles(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, logsToProfiles, bLogsToProfiles) profilesToTraces, err := factory.(xconnector.Factory).CreateProfilesToTraces(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bProfilesToTraces, err := builder.CreateProfilesToTraces(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, profilesToTraces, bProfilesToTraces) profilesToMetrics, err := factory.(xconnector.Factory).CreateProfilesToMetrics(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bProfilesToMetrics, err := builder.CreateProfilesToMetrics(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, profilesToMetrics, bProfilesToMetrics) profilesToLogs, err := factory.(xconnector.Factory).CreateProfilesToLogs(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bProfilesToLogs, err := builder.CreateProfilesToLogs(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, profilesToLogs, bProfilesToLogs) profilesToProfiles, err := factory.(xconnector.Factory).CreateProfilesToProfiles(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bProfilesToProfiles, err := builder.CreateProfilesToProfiles(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, profilesToProfiles, bProfilesToProfiles) } var nopConnectorInstance = &nopConnector{ Consumer: consumertest.NewNop(), } // nopConnector stores consumed traces and metrics for testing purposes. type nopConnector struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createConnectorTracesToTraces(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Traces, error) { return nopConnectorInstance, nil } func createConnectorTracesToMetrics(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Traces, error) { return nopConnectorInstance, nil } func createConnectorTracesToLogs(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Traces, error) { return nopConnectorInstance, nil } func createConnectorTracesToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Traces, error) { return nopConnectorInstance, nil } func createConnectorMetricsToTraces(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Metrics, error) { return nopConnectorInstance, nil } func createConnectorMetricsToMetrics(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Metrics, error) { return nopConnectorInstance, nil } func createConnectorMetricsToLogs(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Metrics, error) { return nopConnectorInstance, nil } func createConnectorMetricsToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Metrics, error) { return nopConnectorInstance, nil } func createConnectorLogsToTraces(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Logs, error) { return nopConnectorInstance, nil } func createConnectorLogsToMetrics(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Logs, error) { return nopConnectorInstance, nil } func createConnectorLogsToLogs(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Logs, error) { return nopConnectorInstance, nil } func createConnectorLogsToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Logs, error) { return nopConnectorInstance, nil } func createxconnectorToTraces(context.Context, connector.Settings, component.Config, consumer.Traces) (xconnector.Profiles, error) { return nopConnectorInstance, nil } func createxconnectorToMetrics(context.Context, connector.Settings, component.Config, consumer.Metrics) (xconnector.Profiles, error) { return nopConnectorInstance, nil } func createxconnectorToLogs(context.Context, connector.Settings, component.Config, consumer.Logs) (xconnector.Profiles, error) { return nopConnectorInstance, nil } func createxconnectorToProfiles(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (xconnector.Profiles, error) { return nopConnectorInstance, nil } func createConnectorSettings(id component.ID) connector.Settings { return connector.Settings{ ID: id, TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } opentelemetry-collector-0.141.0/service/internal/builders/builders_test/exporter_test.go000066400000000000000000000161061511331344600317350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders import ( "context" "testing" "github.com/stretchr/testify/assert" "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/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/service/internal/builders" ) func TestExporterBuilder(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]exporter.Factory{ exporter.NewFactory(component.MustNewType("err"), nil), xexporter.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xexporter.WithTraces(createExporterTraces, component.StabilityLevelDevelopment), xexporter.WithMetrics(createExporterMetrics, component.StabilityLevelAlpha), xexporter.WithLogs(createExporterLogs, component.StabilityLevelDeprecated), xexporter.WithProfiles(createxexporter, component.StabilityLevelDevelopment), ), }...) require.NoError(t, err) testCases := []struct { name string id component.ID err string }{ { name: "unknown", id: component.MustNewID("unknown"), err: "exporter factory not available for: \"unknown\"", }, { name: "err", id: component.MustNewID("err"), err: "telemetry type is not supported", }, { name: "all", id: component.MustNewID("all"), }, { name: "all/named", id: component.MustNewIDWithName("all", "named"), }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfgs := map[component.ID]component.Config{tt.id: defaultCfg} b := builders.NewExporter(cfgs, factories) te, err := b.CreateTraces(context.Background(), createExporterSettings(tt.id)) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, te) } else { require.NoError(t, err) assert.Equal(t, nopExporterInstance, te) } me, err := b.CreateMetrics(context.Background(), createExporterSettings(tt.id)) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, me) } else { require.NoError(t, err) assert.Equal(t, nopExporterInstance, me) } le, err := b.CreateLogs(context.Background(), createExporterSettings(tt.id)) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, le) } else { require.NoError(t, err) assert.Equal(t, nopExporterInstance, le) } pe, err := b.CreateProfiles(context.Background(), createExporterSettings(tt.id)) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, pe) } else { require.NoError(t, err) assert.Equal(t, nopExporterInstance, pe) } }) } } func TestExporterBuilderMissingConfig(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]exporter.Factory{ xexporter.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xexporter.WithTraces(createExporterTraces, component.StabilityLevelDevelopment), xexporter.WithMetrics(createExporterMetrics, component.StabilityLevelAlpha), xexporter.WithLogs(createExporterLogs, component.StabilityLevelDeprecated), xexporter.WithProfiles(createxexporter, component.StabilityLevelDevelopment), ), }...) require.NoError(t, err) bErr := builders.NewExporter(map[component.ID]component.Config{}, factories) missingID := component.MustNewIDWithName("all", "missing") te, err := bErr.CreateTraces(context.Background(), createExporterSettings(missingID)) require.EqualError(t, err, "exporter \"all/missing\" is not configured") assert.Nil(t, te) me, err := bErr.CreateMetrics(context.Background(), createExporterSettings(missingID)) require.EqualError(t, err, "exporter \"all/missing\" is not configured") assert.Nil(t, me) le, err := bErr.CreateLogs(context.Background(), createExporterSettings(missingID)) require.EqualError(t, err, "exporter \"all/missing\" is not configured") assert.Nil(t, le) pe, err := bErr.CreateProfiles(context.Background(), createExporterSettings(missingID)) require.EqualError(t, err, "exporter \"all/missing\" is not configured") assert.Nil(t, pe) } func TestExporterBuilderFactory(t *testing.T) { factories, err := otelcol.MakeFactoryMap([]exporter.Factory{exporter.NewFactory(component.MustNewType("foo"), nil)}...) require.NoError(t, err) cfgs := map[component.ID]component.Config{component.MustNewID("foo"): struct{}{}} b := builders.NewExporter(cfgs, factories) assert.NotNil(t, b.Factory(component.MustNewID("foo").Type())) assert.Nil(t, b.Factory(component.MustNewID("bar").Type())) } func TestNewNopExporterConfigsAndFactories(t *testing.T) { configs, factories := builders.NewNopExporterConfigsAndFactories() builder := builders.NewExporter(configs, factories) require.NotNil(t, builder) factory := exportertest.NewNopFactory() cfg := factory.CreateDefaultConfig() set := exportertest.NewNopSettings(factory.Type()) set.ID = component.NewID(builders.NopType) traces, err := factory.CreateTraces(context.Background(), set, cfg) require.NoError(t, err) bTraces, err := builder.CreateTraces(context.Background(), set) require.NoError(t, err) assert.IsType(t, traces, bTraces) metrics, err := factory.CreateMetrics(context.Background(), set, cfg) require.NoError(t, err) bMetrics, err := builder.CreateMetrics(context.Background(), set) require.NoError(t, err) assert.IsType(t, metrics, bMetrics) logs, err := factory.CreateLogs(context.Background(), set, cfg) require.NoError(t, err) bLogs, err := builder.CreateLogs(context.Background(), set) require.NoError(t, err) assert.IsType(t, logs, bLogs) profiles, err := factory.(xexporter.Factory).CreateProfiles(context.Background(), set, cfg) require.NoError(t, err) bProfiles, err := builder.CreateProfiles(context.Background(), set) require.NoError(t, err) assert.IsType(t, profiles, bProfiles) } var nopExporterInstance = &nopExporter{ Consumer: consumertest.NewNop(), } // nopExporter stores consumed traces, metrics, logs and profiles for testing purposes. type nopExporter struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createExporterTraces(context.Context, exporter.Settings, component.Config) (exporter.Traces, error) { return nopExporterInstance, nil } func createExporterMetrics(context.Context, exporter.Settings, component.Config) (exporter.Metrics, error) { return nopExporterInstance, nil } func createExporterLogs(context.Context, exporter.Settings, component.Config) (exporter.Logs, error) { return nopExporterInstance, nil } func createxexporter(context.Context, exporter.Settings, component.Config) (xexporter.Profiles, error) { return nopExporterInstance, nil } func createExporterSettings(id component.ID) exporter.Settings { return exporter.Settings{ ID: id, TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } opentelemetry-collector-0.141.0/service/internal/builders/builders_test/extension_test.go000066400000000000000000000064431511331344600321040ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensiontest" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/service/internal/builders" ) func TestExtensionBuilder(t *testing.T) { testType := component.MustNewType("test") defaultCfg := struct{}{} testID := component.NewID(testType) unknownID := component.MustNewID("unknown") factories, err := otelcol.MakeFactoryMap([]extension.Factory{ extension.NewFactory( testType, func() component.Config { return &defaultCfg }, func(_ context.Context, settings extension.Settings, _ component.Config) (extension.Extension, error) { return nopExtension{Settings: settings}, nil }, component.StabilityLevelDevelopment), }...) require.NoError(t, err) cfgs := map[component.ID]component.Config{testID: defaultCfg, unknownID: defaultCfg} b := builders.NewExtension(cfgs, factories) e, err := b.Create(context.Background(), createExtensionSettings(testID)) require.NoError(t, err) assert.NotNil(t, e) // Check that the extension has access to the resource attributes. nop, ok := e.(nopExtension) assert.True(t, ok) assert.Equal(t, 0, nop.Settings.Resource.Attributes().Len()) missingType, err := b.Create(context.Background(), createExtensionSettings(unknownID)) require.EqualError(t, err, "extension factory not available for: \"unknown\"") assert.Nil(t, missingType) missingCfg, err := b.Create(context.Background(), createExtensionSettings(component.NewIDWithName(testType, "foo"))) require.EqualError(t, err, "extension \"test/foo\" is not configured") assert.Nil(t, missingCfg) } func TestExtensionBuilderFactory(t *testing.T) { factories, err := otelcol.MakeFactoryMap([]extension.Factory{extension.NewFactory(component.MustNewType("foo"), nil, nil, component.StabilityLevelDevelopment)}...) require.NoError(t, err) cfgs := map[component.ID]component.Config{component.MustNewID("foo"): struct{}{}} b := builders.NewExtension(cfgs, factories) assert.NotNil(t, b.Factory(component.MustNewID("foo").Type())) assert.Nil(t, b.Factory(component.MustNewID("bar").Type())) } func TestNewNopExtensionConfigsAndFactories(t *testing.T) { configs, factories := builders.NewNopExtensionConfigsAndFactories() builder := builders.NewExtension(configs, factories) require.NotNil(t, builder) factory := extensiontest.NewNopFactory() cfg := factory.CreateDefaultConfig() set := extensiontest.NewNopSettings(factory.Type()) set.ID = component.NewID(builders.NopType) ext, err := factory.Create(context.Background(), set, cfg) require.NoError(t, err) bExt, err := builder.Create(context.Background(), set) require.NoError(t, err) assert.IsType(t, ext, bExt) } type nopExtension struct { component.StartFunc component.ShutdownFunc extension.Settings } func createExtensionSettings(id component.ID) extension.Settings { return extension.Settings{ ID: id, TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } opentelemetry-collector-0.141.0/service/internal/builders/builders_test/processor_test.go000066400000000000000000000213021511331344600320760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/processor/xprocessor" "go.opentelemetry.io/collector/service/internal/builders" ) func TestProcessorBuilder(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]processor.Factory{ processor.NewFactory(component.MustNewType("err"), nil), xprocessor.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xprocessor.WithTraces(createProcessorTraces, component.StabilityLevelDevelopment), xprocessor.WithMetrics(createProcessorMetrics, component.StabilityLevelAlpha), xprocessor.WithLogs(createProcessorLogs, component.StabilityLevelDeprecated), xprocessor.WithProfiles(createxprocessor, component.StabilityLevelDevelopment), ), }...) require.NoError(t, err) testCases := []struct { name string id component.ID err string nextTraces consumer.Traces nextLogs consumer.Logs nextMetrics consumer.Metrics nextProfiles xconsumer.Profiles }{ { name: "unknown", id: component.MustNewID("unknown"), err: "processor factory not available for: \"unknown\"", nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "err", id: component.MustNewID("err"), err: "telemetry type is not supported", nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "all", id: component.MustNewID("all"), nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "all/named", id: component.MustNewIDWithName("all", "named"), nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "no next consumer", id: component.MustNewID("unknown"), err: "nil next Consumer", nextTraces: nil, nextLogs: nil, nextMetrics: nil, nextProfiles: nil, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfgs := map[component.ID]component.Config{tt.id: defaultCfg} b := builders.NewProcessor(cfgs, factories) te, err := b.CreateTraces(context.Background(), createProcessorSettings(tt.id), tt.nextTraces) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, te) } else { require.NoError(t, err) assert.Equal(t, nopProcessorInstance, te) } me, err := b.CreateMetrics(context.Background(), createProcessorSettings(tt.id), tt.nextMetrics) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, me) } else { require.NoError(t, err) assert.Equal(t, nopProcessorInstance, me) } le, err := b.CreateLogs(context.Background(), createProcessorSettings(tt.id), tt.nextLogs) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, le) } else { require.NoError(t, err) assert.Equal(t, nopProcessorInstance, le) } pe, err := b.CreateProfiles(context.Background(), createProcessorSettings(tt.id), tt.nextProfiles) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, pe) } else { require.NoError(t, err) assert.Equal(t, nopProcessorInstance, pe) } }) } } func TestProcessorBuilderMissingConfig(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]processor.Factory{ xprocessor.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xprocessor.WithTraces(createProcessorTraces, component.StabilityLevelDevelopment), xprocessor.WithMetrics(createProcessorMetrics, component.StabilityLevelAlpha), xprocessor.WithLogs(createProcessorLogs, component.StabilityLevelDeprecated), xprocessor.WithProfiles(createxprocessor, component.StabilityLevelDevelopment), ), }...) require.NoError(t, err) bErr := builders.NewProcessor(map[component.ID]component.Config{}, factories) missingID := component.MustNewIDWithName("all", "missing") te, err := bErr.CreateTraces(context.Background(), createProcessorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "processor \"all/missing\" is not configured") assert.Nil(t, te) me, err := bErr.CreateMetrics(context.Background(), createProcessorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "processor \"all/missing\" is not configured") assert.Nil(t, me) le, err := bErr.CreateLogs(context.Background(), createProcessorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "processor \"all/missing\" is not configured") assert.Nil(t, le) pe, err := bErr.CreateProfiles(context.Background(), createProcessorSettings(missingID), consumertest.NewNop()) require.EqualError(t, err, "processor \"all/missing\" is not configured") assert.Nil(t, pe) } func TestProcessorBuilderFactory(t *testing.T) { factories, err := otelcol.MakeFactoryMap([]processor.Factory{processor.NewFactory(component.MustNewType("foo"), nil)}...) require.NoError(t, err) cfgs := map[component.ID]component.Config{component.MustNewID("foo"): struct{}{}} b := builders.NewProcessor(cfgs, factories) assert.NotNil(t, b.Factory(component.MustNewID("foo").Type())) assert.Nil(t, b.Factory(component.MustNewID("bar").Type())) } func TestNewNopProcessorBuilder(t *testing.T) { configs, factories := builders.NewNopProcessorConfigsAndFactories() builder := builders.NewProcessor(configs, factories) require.NotNil(t, builder) factory := processortest.NewNopFactory() cfg := factory.CreateDefaultConfig() set := processortest.NewNopSettings(factory.Type()) set.ID = component.NewID(builders.NopType) traces, err := factory.CreateTraces(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bTraces, err := builder.CreateTraces(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, traces, bTraces) metrics, err := factory.CreateMetrics(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bMetrics, err := builder.CreateMetrics(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, metrics, bMetrics) logs, err := factory.CreateLogs(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bLogs, err := builder.CreateLogs(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, logs, bLogs) profiles, err := factory.(xprocessor.Factory).CreateProfiles(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bProfiles, err := builder.CreateProfiles(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, profiles, bProfiles) } var nopProcessorInstance = &nopProcessor{ Consumer: consumertest.NewNop(), } // nopProcessor stores consumed traces, metrics, logs and profiles for testing purposes. type nopProcessor struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createProcessorTraces(context.Context, processor.Settings, component.Config, consumer.Traces) (processor.Traces, error) { return nopProcessorInstance, nil } func createProcessorMetrics(context.Context, processor.Settings, component.Config, consumer.Metrics) (processor.Metrics, error) { return nopProcessorInstance, nil } func createProcessorLogs(context.Context, processor.Settings, component.Config, consumer.Logs) (processor.Logs, error) { return nopProcessorInstance, nil } func createxprocessor(context.Context, processor.Settings, component.Config, xconsumer.Profiles) (xprocessor.Profiles, error) { return nopProcessorInstance, nil } func createProcessorSettings(id component.ID) processor.Settings { return processor.Settings{ ID: id, TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } opentelemetry-collector-0.141.0/service/internal/builders/builders_test/receiver_test.go000066400000000000000000000207711511331344600316740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/otelcol" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/receiver/xreceiver" "go.opentelemetry.io/collector/service/internal/builders" ) func TestReceiverBuilder(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]receiver.Factory{ receiver.NewFactory(component.MustNewType("err"), nil), xreceiver.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xreceiver.WithTraces(createReceiverTraces, component.StabilityLevelDevelopment), xreceiver.WithMetrics(createReceiverMetrics, component.StabilityLevelAlpha), xreceiver.WithLogs(createReceiverLogs, component.StabilityLevelDeprecated), xreceiver.WithProfiles(createReceiverProfiles, component.StabilityLevelAlpha), ), }...) require.NoError(t, err) testCases := []struct { name string id component.ID err string nextTraces consumer.Traces nextLogs consumer.Logs nextMetrics consumer.Metrics nextProfiles xconsumer.Profiles }{ { name: "unknown", id: component.MustNewID("unknown"), err: "receiver factory not available for: \"unknown\"", nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "err", id: component.MustNewID("err"), err: "telemetry type is not supported", nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "all", id: component.MustNewID("all"), nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "all/named", id: component.MustNewIDWithName("all", "named"), nextTraces: consumertest.NewNop(), nextLogs: consumertest.NewNop(), nextMetrics: consumertest.NewNop(), nextProfiles: consumertest.NewNop(), }, { name: "no next consumer", id: component.MustNewID("unknown"), err: "nil next Consumer", nextTraces: nil, nextLogs: nil, nextMetrics: nil, nextProfiles: nil, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfgs := map[component.ID]component.Config{tt.id: defaultCfg} b := builders.NewReceiver(cfgs, factories) te, err := b.CreateTraces(context.Background(), settings(tt.id), tt.nextTraces) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, te) } else { require.NoError(t, err) assert.Equal(t, nopReceiverInstance, te) } me, err := b.CreateMetrics(context.Background(), settings(tt.id), tt.nextMetrics) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, me) } else { require.NoError(t, err) assert.Equal(t, nopReceiverInstance, me) } le, err := b.CreateLogs(context.Background(), settings(tt.id), tt.nextLogs) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, le) } else { require.NoError(t, err) assert.Equal(t, nopReceiverInstance, le) } pe, err := b.CreateProfiles(context.Background(), settings(tt.id), tt.nextProfiles) if tt.err != "" { require.EqualError(t, err, tt.err) assert.Nil(t, pe) } else { require.NoError(t, err) assert.Equal(t, nopReceiverInstance, pe) } }) } } func TestReceiverBuilderMissingConfig(t *testing.T) { defaultCfg := struct{}{} factories, err := otelcol.MakeFactoryMap([]receiver.Factory{ xreceiver.NewFactory( component.MustNewType("all"), func() component.Config { return &defaultCfg }, xreceiver.WithTraces(createReceiverTraces, component.StabilityLevelDevelopment), xreceiver.WithMetrics(createReceiverMetrics, component.StabilityLevelAlpha), xreceiver.WithLogs(createReceiverLogs, component.StabilityLevelDeprecated), xreceiver.WithProfiles(createReceiverProfiles, component.StabilityLevelAlpha), ), }...) require.NoError(t, err) bErr := builders.NewReceiver(map[component.ID]component.Config{}, factories) missingID := component.MustNewIDWithName("all", "missing") te, err := bErr.CreateTraces(context.Background(), settings(missingID), consumertest.NewNop()) require.EqualError(t, err, "receiver \"all/missing\" is not configured") assert.Nil(t, te) me, err := bErr.CreateMetrics(context.Background(), settings(missingID), consumertest.NewNop()) require.EqualError(t, err, "receiver \"all/missing\" is not configured") assert.Nil(t, me) le, err := bErr.CreateLogs(context.Background(), settings(missingID), consumertest.NewNop()) require.EqualError(t, err, "receiver \"all/missing\" is not configured") assert.Nil(t, le) pe, err := bErr.CreateProfiles(context.Background(), settings(missingID), consumertest.NewNop()) require.EqualError(t, err, "receiver \"all/missing\" is not configured") assert.Nil(t, pe) } func TestReceiverBuilderFactory(t *testing.T) { factories, err := otelcol.MakeFactoryMap([]receiver.Factory{receiver.NewFactory(component.MustNewType("foo"), nil)}...) require.NoError(t, err) cfgs := map[component.ID]component.Config{component.MustNewID("foo"): struct{}{}} b := builders.NewReceiver(cfgs, factories) assert.NotNil(t, b.Factory(component.MustNewID("foo").Type())) assert.Nil(t, b.Factory(component.MustNewID("bar").Type())) } func TestNewNopReceiverConfigsAndFactories(t *testing.T) { configs, factories := builders.NewNopReceiverConfigsAndFactories() builder := builders.NewReceiver(configs, factories) require.NotNil(t, builder) factory := receivertest.NewNopFactory() cfg := factory.CreateDefaultConfig() set := receivertest.NewNopSettings(factory.Type()) set.ID = component.NewID(builders.NopType) traces, err := factory.CreateTraces(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bTraces, err := builder.CreateTraces(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, traces, bTraces) metrics, err := factory.CreateMetrics(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bMetrics, err := builder.CreateMetrics(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, metrics, bMetrics) logs, err := factory.CreateLogs(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bLogs, err := builder.CreateLogs(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, logs, bLogs) profiles, err := factory.(xreceiver.Factory).CreateProfiles(context.Background(), set, cfg, consumertest.NewNop()) require.NoError(t, err) bProfiles, err := builder.CreateProfiles(context.Background(), set, consumertest.NewNop()) require.NoError(t, err) assert.IsType(t, profiles, bProfiles) } func settings(id component.ID) receiver.Settings { return receiver.Settings{ ID: id, TelemetrySettings: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), } } var nopReceiverInstance = &nopReceiver{ Consumer: consumertest.NewNop(), } // nopReceiver stores consumed traces and metrics for testing purposes. type nopReceiver struct { component.StartFunc component.ShutdownFunc consumertest.Consumer } func createReceiverTraces(context.Context, receiver.Settings, component.Config, consumer.Traces) (receiver.Traces, error) { return nopReceiverInstance, nil } func createReceiverMetrics(context.Context, receiver.Settings, component.Config, consumer.Metrics) (receiver.Metrics, error) { return nopReceiverInstance, nil } func createReceiverLogs(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { return nopReceiverInstance, nil } func createReceiverProfiles(context.Context, receiver.Settings, component.Config, xconsumer.Profiles) (xreceiver.Profiles, error) { return nopReceiverInstance, nil } opentelemetry-collector-0.141.0/service/internal/builders/connector.go000066400000000000000000000334061511331344600261520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders // import "go.opentelemetry.io/collector/service/internal/builders" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" ) func errDataTypes(id component.ID, from, to pipeline.Signal) error { return fmt.Errorf("connector %q cannot connect from %s to %s: %w", id, from, to, pipeline.ErrSignalNotSupported) } // ConnectorBuilder is a helper struct that given a set of Configs and Factories helps with creating connectors. type ConnectorBuilder struct { cfgs map[component.ID]component.Config factories map[component.Type]connector.Factory } // NewConnector creates a new ConnectorBuilder to help with creating components form a set of configs and factories. func NewConnector(cfgs map[component.ID]component.Config, factories map[component.Type]connector.Factory) *ConnectorBuilder { return &ConnectorBuilder{cfgs: cfgs, factories: factories} } // CreateTracesToTraces creates a Traces connector based on the settings and config. func (b *ConnectorBuilder) CreateTracesToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (connector.Traces, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.TracesToTracesStability()) return f.CreateTracesToTraces(ctx, set, cfg, next) } // CreateTracesToMetrics creates a Traces connector based on the settings and config. func (b *ConnectorBuilder) CreateTracesToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (connector.Traces, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.TracesToMetricsStability()) return f.CreateTracesToMetrics(ctx, set, cfg, next) } // CreateTracesToLogs creates a Traces connector based on the settings and config. func (b *ConnectorBuilder) CreateTracesToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (connector.Traces, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.TracesToLogsStability()) return f.CreateTracesToLogs(ctx, set, cfg, next) } // CreateTracesToProfiles creates a Traces connector based on the settings and config. func (b *ConnectorBuilder) CreateTracesToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (connector.Traces, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } connFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } f, ok := connFact.(xconnector.Factory) if !ok { return nil, errDataTypes(set.ID, pipeline.SignalTraces, xpipeline.SignalProfiles) } logStabilityLevel(set.Logger, f.TracesToProfilesStability()) return f.CreateTracesToProfiles(ctx, set, cfg, next) } // CreateMetricsToTraces creates a Metrics connector based on the settings and config. func (b *ConnectorBuilder) CreateMetricsToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (connector.Metrics, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.MetricsToTracesStability()) return f.CreateMetricsToTraces(ctx, set, cfg, next) } // CreateMetricsToMetrics creates a Metrics connector based on the settings and config. func (b *ConnectorBuilder) CreateMetricsToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (connector.Metrics, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.MetricsToMetricsStability()) return f.CreateMetricsToMetrics(ctx, set, cfg, next) } // CreateMetricsToLogs creates a Metrics connector based on the settings and config. func (b *ConnectorBuilder) CreateMetricsToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (connector.Metrics, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.MetricsToLogsStability()) return f.CreateMetricsToLogs(ctx, set, cfg, next) } // CreateMetricsToProfiles creates a Metrics connector based on the settings and config. func (b *ConnectorBuilder) CreateMetricsToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (connector.Metrics, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } connFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } f, ok := connFact.(xconnector.Factory) if !ok { return nil, errDataTypes(set.ID, pipeline.SignalMetrics, xpipeline.SignalProfiles) } logStabilityLevel(set.Logger, f.MetricsToProfilesStability()) return f.CreateMetricsToProfiles(ctx, set, cfg, next) } // CreateLogsToTraces creates a Logs connector based on the settings and config. func (b *ConnectorBuilder) CreateLogsToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (connector.Logs, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.LogsToTracesStability()) return f.CreateLogsToTraces(ctx, set, cfg, next) } // CreateLogsToMetrics creates a Logs connector based on the settings and config. func (b *ConnectorBuilder) CreateLogsToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (connector.Logs, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.LogsToMetricsStability()) return f.CreateLogsToMetrics(ctx, set, cfg, next) } // CreateLogsToLogs creates a Logs connector based on the settings and config. func (b *ConnectorBuilder) CreateLogsToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (connector.Logs, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.LogsToLogsStability()) return f.CreateLogsToLogs(ctx, set, cfg, next) } // CreateLogsToProfiles creates a Logs connector based on the settings and config. func (b *ConnectorBuilder) CreateLogsToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (connector.Logs, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } connFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } f, ok := connFact.(xconnector.Factory) if !ok { return nil, errDataTypes(set.ID, pipeline.SignalLogs, xpipeline.SignalProfiles) } logStabilityLevel(set.Logger, f.LogsToProfilesStability()) return f.CreateLogsToProfiles(ctx, set, cfg, next) } // CreateProfilesToTraces creates a Profiles connector based on the settings and config. func (b *ConnectorBuilder) CreateProfilesToTraces(ctx context.Context, set connector.Settings, next consumer.Traces) (xconnector.Profiles, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } connFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } f, ok := connFact.(xconnector.Factory) if !ok { return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalTraces) } logStabilityLevel(set.Logger, f.ProfilesToTracesStability()) return f.CreateProfilesToTraces(ctx, set, cfg, next) } // CreateProfilesToMetrics creates a Profiles connector based on the settings and config. func (b *ConnectorBuilder) CreateProfilesToMetrics(ctx context.Context, set connector.Settings, next consumer.Metrics) (xconnector.Profiles, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } connFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } f, ok := connFact.(xconnector.Factory) if !ok { return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalMetrics) } logStabilityLevel(set.Logger, f.ProfilesToMetricsStability()) return f.CreateProfilesToMetrics(ctx, set, cfg, next) } // CreateProfilesToLogs creates a Profiles connector based on the settings and config. func (b *ConnectorBuilder) CreateProfilesToLogs(ctx context.Context, set connector.Settings, next consumer.Logs) (xconnector.Profiles, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } connFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } f, ok := connFact.(xconnector.Factory) if !ok { return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, pipeline.SignalLogs) } logStabilityLevel(set.Logger, f.ProfilesToLogsStability()) return f.CreateProfilesToLogs(ctx, set, cfg, next) } // CreateProfilesToProfiles creates a Profiles connector based on the settings and config. func (b *ConnectorBuilder) CreateProfilesToProfiles(ctx context.Context, set connector.Settings, next xconsumer.Profiles) (xconnector.Profiles, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("connector %q is not configured", set.ID) } connFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("connector factory not available for: %q", set.ID) } f, ok := connFact.(xconnector.Factory) if !ok { return nil, errDataTypes(set.ID, xpipeline.SignalProfiles, xpipeline.SignalProfiles) } logStabilityLevel(set.Logger, f.ProfilesToProfilesStability()) return f.CreateProfilesToProfiles(ctx, set, cfg, next) } func (b *ConnectorBuilder) IsConfigured(componentID component.ID) bool { _, ok := b.cfgs[componentID] return ok } func (b *ConnectorBuilder) Factory(componentType component.Type) component.Factory { return b.factories[componentType] } // NewNopConnectorConfigsAndFactories returns a configuration and factories that allows building a new nop connector. func NewNopConnectorConfigsAndFactories() (map[component.ID]component.Config, map[component.Type]connector.Factory) { nopFactory := connectortest.NewNopFactory() // Use a different ID than receivertest and exportertest to avoid ambiguous // configuration scenarios. Ambiguous IDs are detected in the 'otelcol' package, // but lower level packages such as 'service' assume that IDs are disambiguated. connID := component.NewIDWithName(NopType, "conn") configs := map[component.ID]component.Config{ connID: nopFactory.CreateDefaultConfig(), } factories := map[component.Type]connector.Factory{ NopType: nopFactory, } return configs, factories } opentelemetry-collector-0.141.0/service/internal/builders/exporter.go000066400000000000000000000074551511331344600260350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders // import "go.opentelemetry.io/collector/service/internal/builders" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/pipeline" ) // ExporterBuilder is a helper struct that given a set of Configs and Factories helps with creating exporters. type ExporterBuilder struct { cfgs map[component.ID]component.Config factories map[component.Type]exporter.Factory } // NewExporter creates a new ExporterBuilder to help with creating components form a set of configs and factories. func NewExporter(cfgs map[component.ID]component.Config, factories map[component.Type]exporter.Factory) *ExporterBuilder { return &ExporterBuilder{cfgs: cfgs, factories: factories} } // CreateTraces creates a Traces exporter based on the settings and config. func (b *ExporterBuilder) CreateTraces(ctx context.Context, set exporter.Settings) (exporter.Traces, error) { cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("exporter %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("exporter factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.TracesStability()) return f.CreateTraces(ctx, set, cfg) } // CreateMetrics creates a Metrics exporter based on the settings and config. func (b *ExporterBuilder) CreateMetrics(ctx context.Context, set exporter.Settings) (exporter.Metrics, error) { cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("exporter %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("exporter factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.MetricsStability()) return f.CreateMetrics(ctx, set, cfg) } // CreateLogs creates a Logs exporter based on the settings and config. func (b *ExporterBuilder) CreateLogs(ctx context.Context, set exporter.Settings) (exporter.Logs, error) { cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("exporter %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("exporter factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.LogsStability()) return f.CreateLogs(ctx, set, cfg) } // CreateProfiles creates a Profiles exporter based on the settings and config. func (b *ExporterBuilder) CreateProfiles(ctx context.Context, set exporter.Settings) (xexporter.Profiles, error) { cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("exporter %q is not configured", set.ID) } expFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("exporter factory not available for: %q", set.ID) } f, ok := expFact.(xexporter.Factory) if !ok { return nil, pipeline.ErrSignalNotSupported } logStabilityLevel(set.Logger, f.ProfilesStability()) return f.CreateProfiles(ctx, set, cfg) } func (b *ExporterBuilder) Factory(componentType component.Type) component.Factory { return b.factories[componentType] } // NewNopExporterConfigsAndFactories returns a configuration and factories that allows building a new nop exporter. func NewNopExporterConfigsAndFactories() (map[component.ID]component.Config, map[component.Type]exporter.Factory) { nopFactory := exportertest.NewNopFactory() configs := map[component.ID]component.Config{ component.NewID(NopType): nopFactory.CreateDefaultConfig(), } factories := map[component.Type]exporter.Factory{ NopType: nopFactory, } return configs, factories } opentelemetry-collector-0.141.0/service/internal/builders/extension.go000066400000000000000000000045431511331344600261740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders // import "go.opentelemetry.io/collector/service/internal/builders" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/extensiontest" ) // Extension is an interface that allows using implementations of the builder // from different packages. type Extension interface { Create(context.Context, extension.Settings) (extension.Extension, error) Factory(component.Type) component.Factory } // ExtensionBuilder is a helper struct that given a set of Configs and Factories helps with creating extensions. type ExtensionBuilder struct { cfgs map[component.ID]component.Config factories map[component.Type]extension.Factory } // NewExtension creates a new ExtensionBuilder to help with creating // components form a set of configs and factories. func NewExtension(cfgs map[component.ID]component.Config, factories map[component.Type]extension.Factory) *ExtensionBuilder { return &ExtensionBuilder{cfgs: cfgs, factories: factories} } // Create creates an extension based on the settings and configs available. func (b *ExtensionBuilder) Create(ctx context.Context, set extension.Settings) (extension.Extension, error) { cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("extension %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("extension factory not available for: %q", set.ID) } sl := f.Stability() if sl >= component.StabilityLevelAlpha { set.Logger.Debug(sl.LogMessage()) } else { set.Logger.Info(sl.LogMessage()) } return f.Create(ctx, set, cfg) } func (b *ExtensionBuilder) Factory(componentType component.Type) component.Factory { return b.factories[componentType] } // NewNopExtensionConfigsAndFactories returns a configuration and factories that allows building a new nop processor. func NewNopExtensionConfigsAndFactories() (map[component.ID]component.Config, map[component.Type]extension.Factory) { nopFactory := extensiontest.NewNopFactory() configs := map[component.ID]component.Config{ component.NewID(NopType): nopFactory.CreateDefaultConfig(), } factories := map[component.Type]extension.Factory{ NopType: nopFactory, } return configs, factories } opentelemetry-collector-0.141.0/service/internal/builders/processor.go000066400000000000000000000104221511331344600261700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders // import "go.opentelemetry.io/collector/service/internal/builders" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/processor/xprocessor" ) // ProcessorBuilder processor is a helper struct that given a set of Configs // and Factories helps with creating processors. type ProcessorBuilder struct { cfgs map[component.ID]component.Config factories map[component.Type]processor.Factory } // NewProcessor creates a new ProcessorBuilder to help with creating components form a set of configs and factories. func NewProcessor(cfgs map[component.ID]component.Config, factories map[component.Type]processor.Factory) *ProcessorBuilder { return &ProcessorBuilder{cfgs: cfgs, factories: factories} } // CreateTraces creates a Traces processor based on the settings and config. func (b *ProcessorBuilder) CreateTraces(ctx context.Context, set processor.Settings, next consumer.Traces) (processor.Traces, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("processor %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("processor factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.TracesStability()) return f.CreateTraces(ctx, set, cfg, next) } // CreateMetrics creates a Metrics processor based on the settings and config. func (b *ProcessorBuilder) CreateMetrics(ctx context.Context, set processor.Settings, next consumer.Metrics) (processor.Metrics, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("processor %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("processor factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.MetricsStability()) return f.CreateMetrics(ctx, set, cfg, next) } // CreateLogs creates a Logs processor based on the settings and config. func (b *ProcessorBuilder) CreateLogs(ctx context.Context, set processor.Settings, next consumer.Logs) (processor.Logs, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("processor %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("processor factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.LogsStability()) return f.CreateLogs(ctx, set, cfg, next) } // CreateProfiles creates a Profiles processor based on the settings and config. func (b *ProcessorBuilder) CreateProfiles(ctx context.Context, set processor.Settings, next xconsumer.Profiles) (xprocessor.Profiles, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("processor %q is not configured", set.ID) } procFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("processor factory not available for: %q", set.ID) } f, ok := procFact.(xprocessor.Factory) if !ok { return nil, pipeline.ErrSignalNotSupported } logStabilityLevel(set.Logger, f.ProfilesStability()) return f.CreateProfiles(ctx, set, cfg, next) } func (b *ProcessorBuilder) Factory(componentType component.Type) component.Factory { return b.factories[componentType] } // NewNopProcessorConfigsAndFactories returns a configuration and factories that allows building a new nop processor. func NewNopProcessorConfigsAndFactories() (map[component.ID]component.Config, map[component.Type]processor.Factory) { nopFactory := processortest.NewNopFactory() configs := map[component.ID]component.Config{ component.NewID(NopType): nopFactory.CreateDefaultConfig(), } factories := map[component.Type]processor.Factory{ NopType: nopFactory, } return configs, factories } opentelemetry-collector-0.141.0/service/internal/builders/receiver.go000066400000000000000000000103461511331344600257620ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package builders // import "go.opentelemetry.io/collector/service/internal/builders" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/receiver/xreceiver" ) // ReceiverBuilder receiver is a helper struct that given a set of Configs and // Factories helps with creating receivers. type ReceiverBuilder struct { cfgs map[component.ID]component.Config factories map[component.Type]receiver.Factory } // NewReceiver creates a new ReceiverBuilder to help with creating // components form a set of configs and factories. func NewReceiver(cfgs map[component.ID]component.Config, factories map[component.Type]receiver.Factory) *ReceiverBuilder { return &ReceiverBuilder{cfgs: cfgs, factories: factories} } // CreateTraces creates a Traces receiver based on the settings and config. func (b *ReceiverBuilder) CreateTraces(ctx context.Context, set receiver.Settings, next consumer.Traces) (receiver.Traces, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("receiver %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("receiver factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.TracesStability()) return f.CreateTraces(ctx, set, cfg, next) } // CreateMetrics creates a Metrics receiver based on the settings and config. func (b *ReceiverBuilder) CreateMetrics(ctx context.Context, set receiver.Settings, next consumer.Metrics) (receiver.Metrics, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("receiver %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("receiver factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.MetricsStability()) return f.CreateMetrics(ctx, set, cfg, next) } // CreateLogs creates a Logs receiver based on the settings and config. func (b *ReceiverBuilder) CreateLogs(ctx context.Context, set receiver.Settings, next consumer.Logs) (receiver.Logs, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("receiver %q is not configured", set.ID) } f, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("receiver factory not available for: %q", set.ID) } logStabilityLevel(set.Logger, f.LogsStability()) return f.CreateLogs(ctx, set, cfg, next) } // CreateProfiles creates a Profiles receiver based on the settings and config. func (b *ReceiverBuilder) CreateProfiles(ctx context.Context, set receiver.Settings, next xconsumer.Profiles) (xreceiver.Profiles, error) { if next == nil { return nil, errNilNextConsumer } cfg, existsCfg := b.cfgs[set.ID] if !existsCfg { return nil, fmt.Errorf("receiver %q is not configured", set.ID) } recvFact, existsFactory := b.factories[set.ID.Type()] if !existsFactory { return nil, fmt.Errorf("receiver factory not available for: %q", set.ID) } f, ok := recvFact.(xreceiver.Factory) if !ok { return nil, pipeline.ErrSignalNotSupported } logStabilityLevel(set.Logger, f.ProfilesStability()) return f.CreateProfiles(ctx, set, cfg, next) } func (b *ReceiverBuilder) Factory(componentType component.Type) component.Factory { return b.factories[componentType] } // NewNopReceiverConfigsAndFactories returns a configuration and factories that allows building a new nop receiver. func NewNopReceiverConfigsAndFactories() (map[component.ID]component.Config, map[component.Type]receiver.Factory) { nopFactory := receivertest.NewNopFactory() configs := map[component.ID]component.Config{ component.NewID(NopType): nopFactory.CreateDefaultConfig(), } factories := map[component.Type]receiver.Factory{ NopType: nopFactory, } return configs, factories } opentelemetry-collector-0.141.0/service/internal/capabilityconsumer/000077500000000000000000000000001511331344600257075ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/capabilityconsumer/capabilities.go000066400000000000000000000033311511331344600306670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package capabilityconsumer // import "go.opentelemetry.io/collector/service/internal/capabilityconsumer" import ( "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" ) func NewLogs(logs consumer.Logs, capabilities consumer.Capabilities) consumer.Logs { if logs.Capabilities() == capabilities { return logs } return capLogs{Logs: logs, cap: capabilities} } type capLogs struct { consumer.Logs cap consumer.Capabilities } func (mts capLogs) Capabilities() consumer.Capabilities { return mts.cap } func NewMetrics(metrics consumer.Metrics, capabilities consumer.Capabilities) consumer.Metrics { if metrics.Capabilities() == capabilities { return metrics } return capMetrics{Metrics: metrics, cap: capabilities} } type capMetrics struct { consumer.Metrics cap consumer.Capabilities } func (mts capMetrics) Capabilities() consumer.Capabilities { return mts.cap } func NewTraces(traces consumer.Traces, capabilities consumer.Capabilities) consumer.Traces { if traces.Capabilities() == capabilities { return traces } return capTraces{Traces: traces, cap: capabilities} } type capTraces struct { consumer.Traces cap consumer.Capabilities } func (mts capTraces) Capabilities() consumer.Capabilities { return mts.cap } func NewProfiles(profiles xconsumer.Profiles, capabilities consumer.Capabilities) xconsumer.Profiles { if profiles.Capabilities() == capabilities { return profiles } return capProfiles{Profiles: profiles, cap: capabilities} } type capProfiles struct { xconsumer.Profiles cap consumer.Capabilities } func (mts capProfiles) Capabilities() consumer.Capabilities { return mts.cap } opentelemetry-collector-0.141.0/service/internal/capabilityconsumer/capabilities_test.go000066400000000000000000000052611511331344600317320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package capabilityconsumer import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/testdata" ) func TestLogs(t *testing.T) { sink := &consumertest.LogsSink{} require.Equal(t, consumer.Capabilities{MutatesData: false}, sink.Capabilities()) same := NewLogs(sink, consumer.Capabilities{MutatesData: false}) assert.Same(t, sink, same) wrap := NewLogs(sink, consumer.Capabilities{MutatesData: true}) assert.Equal(t, consumer.Capabilities{MutatesData: true}, wrap.Capabilities()) require.NoError(t, wrap.ConsumeLogs(context.Background(), testdata.GenerateLogs(1))) assert.Len(t, sink.AllLogs(), 1) assert.Equal(t, testdata.GenerateLogs(1), sink.AllLogs()[0]) } func TestMetrics(t *testing.T) { sink := &consumertest.MetricsSink{} require.Equal(t, consumer.Capabilities{MutatesData: false}, sink.Capabilities()) same := NewMetrics(sink, consumer.Capabilities{MutatesData: false}) assert.Same(t, sink, same) wrap := NewMetrics(sink, consumer.Capabilities{MutatesData: true}) assert.Equal(t, consumer.Capabilities{MutatesData: true}, wrap.Capabilities()) require.NoError(t, wrap.ConsumeMetrics(context.Background(), testdata.GenerateMetrics(1))) assert.Len(t, sink.AllMetrics(), 1) assert.Equal(t, testdata.GenerateMetrics(1), sink.AllMetrics()[0]) } func TestTraces(t *testing.T) { sink := &consumertest.TracesSink{} require.Equal(t, consumer.Capabilities{MutatesData: false}, sink.Capabilities()) same := NewTraces(sink, consumer.Capabilities{MutatesData: false}) assert.Same(t, sink, same) wrap := NewTraces(sink, consumer.Capabilities{MutatesData: true}) assert.Equal(t, consumer.Capabilities{MutatesData: true}, wrap.Capabilities()) require.NoError(t, wrap.ConsumeTraces(context.Background(), testdata.GenerateTraces(1))) assert.Len(t, sink.AllTraces(), 1) assert.Equal(t, testdata.GenerateTraces(1), sink.AllTraces()[0]) } func TestProfiles(t *testing.T) { sink := &consumertest.ProfilesSink{} require.Equal(t, consumer.Capabilities{MutatesData: false}, sink.Capabilities()) same := NewProfiles(sink, consumer.Capabilities{MutatesData: false}) assert.Same(t, sink, same) wrap := NewProfiles(sink, consumer.Capabilities{MutatesData: true}) assert.Equal(t, consumer.Capabilities{MutatesData: true}, wrap.Capabilities()) require.NoError(t, wrap.ConsumeProfiles(context.Background(), testdata.GenerateProfiles(1))) assert.Len(t, sink.AllProfiles(), 1) assert.Equal(t, testdata.GenerateProfiles(1), sink.AllProfiles()[0]) } opentelemetry-collector-0.141.0/service/internal/capabilityconsumer/package_test.go000066400000000000000000000003231511331344600306660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package capabilityconsumer import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/internal/componentattribute/000077500000000000000000000000001511331344600257405ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/componentattribute/logger_zap.go000066400000000000000000000043221511331344600304210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentattribute // import "go.opentelemetry.io/collector/service/internal/componentattribute" import ( "slices" "go.opentelemetry.io/otel/attribute" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/internal/telemetry" ) // This wrapper around zapcore.Field tells the Zap -> OTel bridge that the field // should be turned into an instrumentation scope instead of a set of log record attributes. type scopeAttributesField struct { fields []zapcore.Field attrs []attribute.KeyValue } var _ zapcore.ObjectMarshaler = scopeAttributesField{} func (saf scopeAttributesField) MarshalLogObject(enc zapcore.ObjectEncoder) error { for _, field := range saf.fields { field.AddTo(enc) } return nil } func makeScopeField(attrs []attribute.KeyValue) zap.Field { return zap.Inline(scopeAttributesField{ fields: telemetry.ToZapFields(attrs), attrs: attrs, }) } func ExtractLogScopeAttributes(field zap.Field) ([]attribute.KeyValue, bool) { if field.Type != zapcore.InlineMarshalerType { return nil, false } saf, ok := field.Interface.(scopeAttributesField) if !ok { return nil, false } return saf.attrs, true } type coreWithAttributes struct { zapcore.Core sourceCore zapcore.Core attrs []attribute.KeyValue withFields []zap.Field } var _ zapcore.Core = coreWithAttributes{} func (cwa coreWithAttributes) With(fields []zapcore.Field) zapcore.Core { cwa.withFields = append(cwa.withFields, fields...) cwa.Core = cwa.Core.With(fields) return cwa } func LoggerWithAttributes(logger *zap.Logger, attrs []attribute.KeyValue) *zap.Logger { return logger.WithOptions(zap.WrapCore(func(c zapcore.Core) zapcore.Core { return coreWithAttributes{ Core: c.With([]zap.Field{makeScopeField(attrs)}), sourceCore: c, attrs: attrs, } })) } func (cwa coreWithAttributes) DropInjectedAttributes(droppedAttrs ...string) zapcore.Core { cwa.attrs = slices.DeleteFunc(slices.Clone(cwa.attrs), func(kv attribute.KeyValue) bool { return slices.Contains(droppedAttrs, string(kv.Key)) }) cwa.Core = cwa.sourceCore.With(append([]zap.Field{makeScopeField(cwa.attrs)}, cwa.withFields...)) return cwa } opentelemetry-collector-0.141.0/service/internal/componentattribute/meter_provider.go000066400000000000000000000022701511331344600313160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentattribute // import "go.opentelemetry.io/collector/service/internal/componentattribute" import ( "slices" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) type meterProviderWithAttributes struct { metric.MeterProvider attrs []attribute.KeyValue } func (mpwa meterProviderWithAttributes) Meter(name string, opts ...metric.MeterOption) metric.Meter { conf := metric.NewMeterConfig(opts...) attrSet := conf.InstrumentationAttributes() // prepend our attributes so they can be overwritten newAttrs := append(slices.Clone(mpwa.attrs), attrSet.ToSlice()...) // append our attribute set option to overwrite the old one opts = append(opts, metric.WithInstrumentationAttributes(newAttrs...)) return mpwa.MeterProvider.Meter(name, opts...) } func (mpwa meterProviderWithAttributes) DropInjectedAttributes(droppedAttrs ...string) metric.MeterProvider { return meterProviderWithAttributes{ MeterProvider: mpwa.MeterProvider, attrs: slices.DeleteFunc(slices.Clone(mpwa.attrs), func(kv attribute.KeyValue) bool { return slices.Contains(droppedAttrs, string(kv.Key)) }), } } opentelemetry-collector-0.141.0/service/internal/componentattribute/telemetry.go000066400000000000000000000015011511331344600302760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentattribute // import "go.opentelemetry.io/collector/service/internal/componentattribute" import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/internal/telemetry" ) func TelemetrySettingsWithAttributes(ts component.TelemetrySettings, attrSet attribute.Set) component.TelemetrySettings { attrs := attrSet.ToSlice() ts.Logger = LoggerWithAttributes(ts.Logger, attrs) ts.TracerProvider = tracerProviderWithAttributes{ TracerProvider: ts.TracerProvider, attrs: attrs, } if telemetry.NewPipelineTelemetryGate.IsEnabled() { ts.MeterProvider = meterProviderWithAttributes{ MeterProvider: ts.MeterProvider, attrs: attrs, } } return ts } opentelemetry-collector-0.141.0/service/internal/componentattribute/telemetry_test.go000066400000000000000000000144651511331344600313520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentattribute_test import ( "context" "encoding/json" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" metricSdk "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" traceSdk "go.opentelemetry.io/otel/sdk/trace" "go.opentelemetry.io/otel/sdk/trace/tracetest" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/service/internal/componentattribute" ) func findScopeAttributesField(context []zap.Field) ([]attribute.KeyValue, bool) { for _, field := range context { scope, ok := componentattribute.ExtractLogScopeAttributes(field) if ok { return scope, true } } return nil, false } func attributeSetJSON(t *testing.T, set attribute.Set) string { scopeBuf, err := json.Marshal(set.MarshalLog()) require.NoError(t, err) return string(scopeBuf) } func getLogScopeAndFields(t *testing.T, logObs *observer.ObservedLogs) (string, string) { logs := logObs.TakeAll() require.Len(t, logs, 1) log := logs[0] require.Equal(t, "test", log.Message) scope, ok := findScopeAttributesField(log.Context) require.True(t, ok, "Failed to find ScopeAttributesField field") scopeStr := attributeSetJSON(t, attribute.NewSet(scope...)) enc := zapcore.NewJSONEncoder(zapcore.EncoderConfig{}) fieldsBuf, err := enc.EncodeEntry(log.Entry, log.Context) require.NoError(t, err) fieldsStr := strings.TrimSuffix(fieldsBuf.String(), "\n") return scopeStr, fieldsStr } func getSpanScope(t *testing.T, spanObs *tracetest.InMemoryExporter) string { spans := spanObs.GetSpans().Snapshots() spanObs.Reset() require.Len(t, spans, 1) span := spans[0] require.Equal(t, "test", span.Name()) return attributeSetJSON(t, span.InstrumentationScope().Attributes) } func getMetricScope(t *testing.T, metricObs *metricSdk.ManualReader) string { rm := metricdata.ResourceMetrics{} err := metricObs.Collect(t.Context(), &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) return attributeSetJSON(t, rm.ScopeMetrics[0].Scope.Attributes) } type TestResults struct { LogScope string LogFields string SpanScope string MetricScope string } func getScopes(t *testing.T, tswa component.TelemetrySettings, logObs *observer.ObservedLogs, spanObs *tracetest.InMemoryExporter, metricObs *metricSdk.ManualReader) TestResults { // Create new tracer, meter, and metric instrument tracer := tswa.TracerProvider.Tracer("test", trace.WithInstrumentationAttributes(attribute.String("after", "val"))) meter := tswa.MeterProvider.Meter("test", metric.WithInstrumentationAttributes(attribute.String("after", "val"))) gauge, err := meter.Int64Gauge("test") require.NoError(t, err) // Emit a log, a span, and a metric point tswa.Logger.Info("test", zap.String("manual", "val")) logScope, logFields := getLogScopeAndFields(t, logObs) _, span := tracer.Start(t.Context(), "test") span.End() gauge.Record(t.Context(), 1) // Check resulting scope attributes return TestResults{ LogScope: logScope, LogFields: logFields, SpanScope: getSpanScope(t, spanObs), MetricScope: getMetricScope(t, metricObs), } } type tracerProviderWrapper struct { trace.TracerProvider } func testTelemetryWithAttributes(t *testing.T, useTraceSdk bool) { prevState := telemetry.NewPipelineTelemetryGate.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), true)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), prevState)) }() // Setup mock TelemetrySettings core, logObs := observer.New(zap.DebugLevel) logger := zap.New(core) logger = logger.With(zap.String("before", "val")) spanObs := tracetest.NewInMemoryExporter() var tracerProvider trace.TracerProvider = traceSdk.NewTracerProvider(traceSdk.WithSpanProcessor(traceSdk.NewSimpleSpanProcessor(spanObs))) if !useTraceSdk { tracerProvider = tracerProviderWrapper{TracerProvider: tracerProvider} } // Use delta temporality so points from the first step are no longer exported in the second step metricObs := metricSdk.NewManualReader(metricSdk.WithTemporalitySelector(func(metricSdk.InstrumentKind) metricdata.Temporality { return metricdata.DeltaTemporality })) meterProvider := metricSdk.NewMeterProvider(metricSdk.WithReader(metricObs)) ts := component.TelemetrySettings{ Logger: logger, TracerProvider: tracerProvider, MeterProvider: meterProvider, } // Inject attributes tswa := componentattribute.TelemetrySettingsWithAttributes(ts, attribute.NewSet( attribute.String("injected1", "val"), attribute.String("injected2", "val"), )) // Check that SDK-only methods are accessible through Unwrap wrapped, ok := tswa.TracerProvider.(interface { Unwrap() trace.TracerProvider }) if assert.True(t, ok) { _, ok := wrapped.Unwrap().(interface { ForceFlush(ctx context.Context) error }) assert.Equal(t, useTraceSdk, ok) } // Add extra log attribute tswa.Logger = tswa.Logger.With(zap.String("after", "val")) assert.Equal(t, TestResults{ LogScope: `{"injected1":"val","injected2":"val"}`, LogFields: `{"before":"val","injected1":"val","injected2":"val","after":"val","manual":"val"}`, SpanScope: `{"after":"val","injected1":"val","injected2":"val"}`, MetricScope: `{"after":"val","injected1":"val","injected2":"val"}`, }, getScopes(t, tswa, logObs, spanObs, metricObs)) // Drop one injected attribute tswa = telemetry.DropInjectedAttributes(tswa, "injected1") // Check scopes again assert.Equal(t, TestResults{ LogScope: `{"injected2":"val"}`, LogFields: `{"before":"val","injected2":"val","after":"val","manual":"val"}`, SpanScope: `{"after":"val","injected2":"val"}`, MetricScope: `{"after":"val","injected2":"val"}`, }, getScopes(t, tswa, logObs, spanObs, metricObs)) } func TestTelemetryWithAttributes(t *testing.T) { t.Run("sdk", func(t *testing.T) { testTelemetryWithAttributes(t, true) }) t.Run("generic", func(t *testing.T) { testTelemetryWithAttributes(t, false) }) } opentelemetry-collector-0.141.0/service/internal/componentattribute/tracer_provider.go000066400000000000000000000024661511331344600314710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package componentattribute // import "go.opentelemetry.io/collector/service/internal/componentattribute" import ( "slices" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" ) type tracerProviderWithAttributes struct { trace.TracerProvider attrs []attribute.KeyValue } func (tpwa tracerProviderWithAttributes) Tracer(name string, options ...trace.TracerOption) trace.Tracer { conf := trace.NewTracerConfig(options...) attrSet := conf.InstrumentationAttributes() // prepend our attributes so they can be overwritten newAttrs := append(slices.Clone(tpwa.attrs), attrSet.ToSlice()...) // append our attribute set option to overwrite the old one options = append(options, trace.WithInstrumentationAttributes(newAttrs...)) return tpwa.TracerProvider.Tracer(name, options...) } func (tpwa tracerProviderWithAttributes) Unwrap() trace.TracerProvider { return tpwa.TracerProvider } func (tpwa tracerProviderWithAttributes) DropInjectedAttributes(droppedAttrs ...string) trace.TracerProvider { return tracerProviderWithAttributes{ TracerProvider: tpwa.TracerProvider, attrs: slices.DeleteFunc(slices.Clone(tpwa.attrs), func(kv attribute.KeyValue) bool { return slices.Contains(droppedAttrs, string(kv.Key)) }), } } opentelemetry-collector-0.141.0/service/internal/graph/000077500000000000000000000000001511331344600231135ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/graph/capabilities.go000066400000000000000000000022571511331344600261010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/internal/attribute" ) var _ consumerNode = (*capabilitiesNode)(nil) // Every pipeline has a "virtual" capabilities node immediately after the receiver(s). // There are two purposes for this node: // 1. Present aggregated capabilities to receivers, such as whether the pipeline mutates data. // 2. Present a consistent "first consumer" for each pipeline. // The nodeID is derived from "pipeline ID". type capabilitiesNode struct { attribute.Attributes pipelineID pipeline.ID baseConsumer consumer.ConsumeTracesFunc consumer.ConsumeMetricsFunc consumer.ConsumeLogsFunc xconsumer.ConsumeProfilesFunc } func newCapabilitiesNode(pipelineID pipeline.ID) *capabilitiesNode { return &capabilitiesNode{ Attributes: attribute.Capabilities(pipelineID), pipelineID: pipelineID, } } func (n *capabilitiesNode) getConsumer() baseConsumer { return n } opentelemetry-collector-0.141.0/service/internal/graph/connector.go000066400000000000000000000303231511331344600254350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "context" otelattr "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/service/internal/attribute" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/capabilityconsumer" "go.opentelemetry.io/collector/service/internal/componentattribute" "go.opentelemetry.io/collector/service/internal/metadata" "go.opentelemetry.io/collector/service/internal/obsconsumer" "go.opentelemetry.io/collector/service/internal/refconsumer" ) const pipelineIDAttrKey = "otelcol.pipeline.id" var _ consumerNode = (*connectorNode)(nil) type connectorNode struct { attribute.Attributes componentID component.ID exprPipelineType pipeline.Signal rcvrPipelineType pipeline.Signal component.Component consumer baseConsumer } func newConnectorNode(exprPipelineType, rcvrPipelineType pipeline.Signal, connID component.ID) *connectorNode { return &connectorNode{ Attributes: attribute.Connector(exprPipelineType, rcvrPipelineType, connID), componentID: connID, exprPipelineType: exprPipelineType, rcvrPipelineType: rcvrPipelineType, } } func (n *connectorNode) getConsumer() baseConsumer { return n.consumer } func (n *connectorNode) buildComponent( ctx context.Context, tel component.TelemetrySettings, info component.BuildInfo, builder *builders.ConnectorBuilder, nexts []baseConsumer, ) error { set := connector.Settings{ ID: n.componentID, TelemetrySettings: componentattribute.TelemetrySettingsWithAttributes(tel, *n.Set()), BuildInfo: info, } switch n.rcvrPipelineType { case pipeline.SignalTraces: return n.buildTraces(ctx, set, builder, nexts) case pipeline.SignalMetrics: return n.buildMetrics(ctx, set, builder, nexts) case pipeline.SignalLogs: return n.buildLogs(ctx, set, builder, nexts) case xpipeline.SignalProfiles: return n.buildProfiles(ctx, set, builder, nexts) } return nil } func (n *connectorNode) buildTraces( ctx context.Context, set connector.Settings, builder *builders.ConnectorBuilder, nexts []baseConsumer, ) error { tb, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return err } producedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorProducedItems, SizeCounter: tb.ConnectorProducedSize, Logger: set.Logger, } consumedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorConsumedItems, SizeCounter: tb.ConnectorConsumedSize, Logger: set.Logger, } consumers := make(map[pipeline.ID]consumer.Traces, len(nexts)) for _, next := range nexts { consumers[next.(*capabilitiesNode).pipelineID] = obsconsumer.NewTraces( next.(consumer.Traces), producedSettings, obsconsumer.WithStaticDataPointAttribute( otelattr.String( pipelineIDAttrKey, next.(*capabilitiesNode).pipelineID.String(), ), ), ) } next := connector.NewTracesRouter(consumers) switch n.exprPipelineType { case pipeline.SignalTraces: n.Component, err = builder.CreateTracesToTraces(ctx, set, next) if err != nil { return err } // Connectors which might pass along data must inherit capabilities of all nexts n.consumer = obsconsumer.NewTraces( capabilityconsumer.NewTraces( n.Component.(consumer.Traces), aggregateCap(n.Component.(consumer.Traces), nexts), ), consumedSettings, ) n.consumer = refconsumer.NewTraces(n.consumer.(consumer.Traces)) case pipeline.SignalMetrics: n.Component, err = builder.CreateMetricsToTraces(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewMetrics(n.Component.(consumer.Metrics), consumedSettings) n.consumer = refconsumer.NewMetrics(n.consumer.(consumer.Metrics)) case pipeline.SignalLogs: n.Component, err = builder.CreateLogsToTraces(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewLogs(n.Component.(consumer.Logs), consumedSettings) n.consumer = refconsumer.NewLogs(n.consumer.(consumer.Logs)) case xpipeline.SignalProfiles: n.Component, err = builder.CreateProfilesToTraces(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewProfiles(n.Component.(xconsumer.Profiles), consumedSettings) n.consumer = refconsumer.NewProfiles(n.consumer.(xconsumer.Profiles)) } return nil } func (n *connectorNode) buildMetrics( ctx context.Context, set connector.Settings, builder *builders.ConnectorBuilder, nexts []baseConsumer, ) error { tb, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return err } producedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorProducedItems, SizeCounter: tb.ConnectorProducedSize, Logger: set.Logger, } consumedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorConsumedItems, SizeCounter: tb.ConnectorConsumedSize, Logger: set.Logger, } consumers := make(map[pipeline.ID]consumer.Metrics, len(nexts)) for _, next := range nexts { consumers[next.(*capabilitiesNode).pipelineID] = obsconsumer.NewMetrics( next.(consumer.Metrics), producedSettings, obsconsumer.WithStaticDataPointAttribute( otelattr.String( pipelineIDAttrKey, next.(*capabilitiesNode).pipelineID.String(), ), ), ) } next := connector.NewMetricsRouter(consumers) switch n.exprPipelineType { case pipeline.SignalMetrics: n.Component, err = builder.CreateMetricsToMetrics(ctx, set, next) if err != nil { return err } // Connectors which might pass along data must inherit capabilities of all nexts n.consumer = obsconsumer.NewMetrics( capabilityconsumer.NewMetrics( n.Component.(consumer.Metrics), aggregateCap(n.Component.(consumer.Metrics), nexts), ), consumedSettings, ) n.consumer = refconsumer.NewMetrics(n.consumer.(consumer.Metrics)) case pipeline.SignalTraces: n.Component, err = builder.CreateTracesToMetrics(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewTraces(n.Component.(consumer.Traces), consumedSettings) n.consumer = refconsumer.NewTraces(n.consumer.(consumer.Traces)) case pipeline.SignalLogs: n.Component, err = builder.CreateLogsToMetrics(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewLogs(n.Component.(consumer.Logs), consumedSettings) n.consumer = refconsumer.NewLogs(n.consumer.(consumer.Logs)) case xpipeline.SignalProfiles: n.Component, err = builder.CreateProfilesToMetrics(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewProfiles(n.Component.(xconsumer.Profiles), consumedSettings) n.consumer = refconsumer.NewProfiles(n.consumer.(xconsumer.Profiles)) } return nil } func (n *connectorNode) buildLogs( ctx context.Context, set connector.Settings, builder *builders.ConnectorBuilder, nexts []baseConsumer, ) error { tb, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return err } producedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorProducedItems, SizeCounter: tb.ConnectorProducedSize, Logger: set.Logger, } consumedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorConsumedItems, SizeCounter: tb.ConnectorConsumedSize, Logger: set.Logger, } consumers := make(map[pipeline.ID]consumer.Logs, len(nexts)) for _, next := range nexts { consumers[next.(*capabilitiesNode).pipelineID] = obsconsumer.NewLogs( next.(consumer.Logs), producedSettings, obsconsumer.WithStaticDataPointAttribute( otelattr.String( pipelineIDAttrKey, next.(*capabilitiesNode).pipelineID.String(), ), ), ) } next := connector.NewLogsRouter(consumers) switch n.exprPipelineType { case pipeline.SignalLogs: n.Component, err = builder.CreateLogsToLogs(ctx, set, next) if err != nil { return err } // Connectors which might pass along data must inherit capabilities of all nexts n.consumer = obsconsumer.NewLogs( capabilityconsumer.NewLogs( n.Component.(consumer.Logs), aggregateCap(n.Component.(consumer.Logs), nexts), ), consumedSettings, ) n.consumer = refconsumer.NewLogs(n.consumer.(consumer.Logs)) case pipeline.SignalTraces: n.Component, err = builder.CreateTracesToLogs(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewTraces(n.Component.(consumer.Traces), consumedSettings) n.consumer = refconsumer.NewTraces(n.consumer.(consumer.Traces)) case pipeline.SignalMetrics: n.Component, err = builder.CreateMetricsToLogs(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewMetrics(n.Component.(consumer.Metrics), consumedSettings) n.consumer = refconsumer.NewMetrics(n.consumer.(consumer.Metrics)) case xpipeline.SignalProfiles: n.Component, err = builder.CreateProfilesToLogs(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewProfiles(n.Component.(xconsumer.Profiles), consumedSettings) n.consumer = refconsumer.NewProfiles(n.consumer.(xconsumer.Profiles)) } return nil } func (n *connectorNode) buildProfiles( ctx context.Context, set connector.Settings, builder *builders.ConnectorBuilder, nexts []baseConsumer, ) error { tb, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return err } producedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorProducedItems, SizeCounter: tb.ConnectorProducedSize, Logger: set.Logger, } consumedSettings := obsconsumer.Settings{ ItemCounter: tb.ConnectorConsumedItems, SizeCounter: tb.ConnectorConsumedSize, Logger: set.Logger, } consumers := make(map[pipeline.ID]xconsumer.Profiles, len(nexts)) for _, next := range nexts { consumers[next.(*capabilitiesNode).pipelineID] = obsconsumer.NewProfiles( next.(xconsumer.Profiles), producedSettings, obsconsumer.WithStaticDataPointAttribute( otelattr.String( pipelineIDAttrKey, next.(*capabilitiesNode).pipelineID.String(), ), ), ) } next := xconnector.NewProfilesRouter(consumers) switch n.exprPipelineType { case xpipeline.SignalProfiles: n.Component, err = builder.CreateProfilesToProfiles(ctx, set, next) if err != nil { return err } // Connectors which might pass along data must inherit capabilities of all nexts n.consumer = obsconsumer.NewProfiles( capabilityconsumer.NewProfiles( n.Component.(xconsumer.Profiles), aggregateCap(n.Component.(xconsumer.Profiles), nexts), ), consumedSettings, ) n.consumer = refconsumer.NewProfiles(n.consumer.(xconsumer.Profiles)) case pipeline.SignalTraces: n.Component, err = builder.CreateTracesToProfiles(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewTraces(n.Component.(consumer.Traces), consumedSettings) n.consumer = refconsumer.NewTraces(n.consumer.(consumer.Traces)) case pipeline.SignalMetrics: n.Component, err = builder.CreateMetricsToProfiles(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewMetrics(n.Component.(consumer.Metrics), consumedSettings) n.consumer = refconsumer.NewMetrics(n.consumer.(consumer.Metrics)) case pipeline.SignalLogs: n.Component, err = builder.CreateLogsToProfiles(ctx, set, next) if err != nil { return err } n.consumer = obsconsumer.NewLogs(n.Component.(consumer.Logs), consumedSettings) n.consumer = refconsumer.NewLogs(n.consumer.(consumer.Logs)) } return nil } // When connecting pipelines of the same data type, the connector must // inherit the capabilities of pipelines in which it is acting as a receiver. // Since the incoming and outgoing data types are the same, we must also consider // that the connector itself may mutate the data and pass it along. func aggregateCap(base baseConsumer, nexts []baseConsumer) consumer.Capabilities { capabilities := base.Capabilities() for _, next := range nexts { capabilities.MutatesData = capabilities.MutatesData || next.Capabilities().MutatesData } return capabilities } opentelemetry-collector-0.141.0/service/internal/graph/consumer.go000066400000000000000000000007001511331344600252720ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "go.opentelemetry.io/collector/consumer" ) // baseConsumer redeclared here since not public in consumer package. May consider to make that public. type baseConsumer interface { Capabilities() consumer.Capabilities } type consumerNode interface { getConsumer() baseConsumer } opentelemetry-collector-0.141.0/service/internal/graph/exporter.go000066400000000000000000000071541511331344600253210ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/service/internal/attribute" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/componentattribute" "go.opentelemetry.io/collector/service/internal/metadata" "go.opentelemetry.io/collector/service/internal/obsconsumer" "go.opentelemetry.io/collector/service/internal/refconsumer" ) var _ consumerNode = (*exporterNode)(nil) // An exporter instance can be shared by multiple pipelines of the same type. // Therefore, nodeID is derived from "pipeline type" and "component ID". type exporterNode struct { attribute.Attributes componentID component.ID pipelineType pipeline.Signal component.Component consumer baseConsumer } func newExporterNode(pipelineType pipeline.Signal, exprID component.ID) *exporterNode { return &exporterNode{ Attributes: attribute.Exporter(pipelineType, exprID), componentID: exprID, pipelineType: pipelineType, } } func (n *exporterNode) getConsumer() baseConsumer { return n.consumer } func (n *exporterNode) buildComponent( ctx context.Context, tel component.TelemetrySettings, info component.BuildInfo, builder *builders.ExporterBuilder, ) error { set := exporter.Settings{ ID: n.componentID, TelemetrySettings: componentattribute.TelemetrySettingsWithAttributes(tel, *n.Set()), BuildInfo: info, } tb, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return err } consumedSettings := obsconsumer.Settings{ ItemCounter: tb.ExporterConsumedItems, SizeCounter: tb.ExporterConsumedSize, Logger: set.Logger, } switch n.pipelineType { case pipeline.SignalTraces: n.Component, err = builder.CreateTraces(ctx, set) if err != nil { return fmt.Errorf("failed to create %q exporter for data type %q: %w", set.ID, n.pipelineType, err) } n.consumer = obsconsumer.NewTraces(n.Component.(consumer.Traces), consumedSettings) n.consumer = refconsumer.NewTraces(n.consumer.(consumer.Traces)) case pipeline.SignalMetrics: n.Component, err = builder.CreateMetrics(ctx, set) if err != nil { return fmt.Errorf("failed to create %q exporter for data type %q: %w", set.ID, n.pipelineType, err) } n.consumer = obsconsumer.NewMetrics(n.Component.(consumer.Metrics), consumedSettings) n.consumer = refconsumer.NewMetrics(n.consumer.(consumer.Metrics)) case pipeline.SignalLogs: n.Component, err = builder.CreateLogs(ctx, set) if err != nil { return fmt.Errorf("failed to create %q exporter for data type %q: %w", set.ID, n.pipelineType, err) } n.consumer = obsconsumer.NewLogs(n.Component.(consumer.Logs), consumedSettings) n.consumer = refconsumer.NewLogs(n.consumer.(consumer.Logs)) case xpipeline.SignalProfiles: n.Component, err = builder.CreateProfiles(ctx, set) if err != nil { return fmt.Errorf("failed to create %q exporter for data type %q: %w", set.ID, n.pipelineType, err) } n.consumer = obsconsumer.NewProfiles(n.Component.(xconsumer.Profiles), consumedSettings) n.consumer = refconsumer.NewProfiles(n.consumer.(xconsumer.Profiles)) default: return fmt.Errorf("error creating exporter %q for data type %q is not supported", set.ID, n.pipelineType) } return nil } opentelemetry-collector-0.141.0/service/internal/graph/fanout.go000066400000000000000000000013431511331344600247370ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/internal/attribute" ) var _ consumerNode = (*fanOutNode)(nil) // Each pipeline has one fan-out node before exporters. // Therefore, nodeID is derived from "pipeline ID". type fanOutNode struct { attribute.Attributes pipelineID pipeline.ID baseConsumer } func newFanOutNode(pipelineID pipeline.ID) *fanOutNode { return &fanOutNode{ Attributes: attribute.Fanout(pipelineID), pipelineID: pipelineID, } } func (n *fanOutNode) getConsumer() baseConsumer { return n.baseConsumer } opentelemetry-collector-0.141.0/service/internal/graph/graph.go000066400000000000000000000535541511331344600245570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package graph contains the internal graph representation of the pipelines. // // [Build] is the constructor for a [Graph] object. The method calls out to helpers that transform the graph from a config // to a DAG of components. The configuration undergoes additional validation here as well, and is used to instantiate // the components of the pipeline. // // [Graph.StartAll] starts all components in each pipeline. // // [Graph.ShutdownAll] stops all components in each pipeline. package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "context" "errors" "fmt" "strings" "go.uber.org/multierr" "go.uber.org/zap" "gonum.org/v1/gonum/graph" "gonum.org/v1/gonum/graph/simple" "gonum.org/v1/gonum/graph/topo" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/fanoutconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/service/hostcapabilities" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/capabilityconsumer" "go.opentelemetry.io/collector/service/internal/status" "go.opentelemetry.io/collector/service/pipelines" ) // Settings holds configuration for building builtPipelines. type Settings struct { Telemetry component.TelemetrySettings BuildInfo component.BuildInfo ReceiverBuilder *builders.ReceiverBuilder ProcessorBuilder *builders.ProcessorBuilder ExporterBuilder *builders.ExporterBuilder ConnectorBuilder *builders.ConnectorBuilder // PipelineConfigs is a map of component.ID to PipelineConfig. PipelineConfigs pipelines.Config ReportStatus status.ServiceStatusFunc } type Graph struct { // All component instances represented as nodes, with directed edges indicating data flow. componentGraph *simple.DirectedGraph // Keep track of how nodes relate to pipelines, so we can declare edges in the graph. pipelines map[pipeline.ID]*pipelineNodes // Keep track of status source per node instanceIDs map[int64]*componentstatus.InstanceID telemetry component.TelemetrySettings } // Build builds a full pipeline graph. // Build also validates the configuration of the pipelines and does the actual initialization of each Component in the Graph. func Build(ctx context.Context, set Settings) (*Graph, error) { pipelines := &Graph{ componentGraph: simple.NewDirectedGraph(), pipelines: make(map[pipeline.ID]*pipelineNodes, len(set.PipelineConfigs)), instanceIDs: make(map[int64]*componentstatus.InstanceID), telemetry: set.Telemetry, } for pipelineID := range set.PipelineConfigs { pipelines.pipelines[pipelineID] = &pipelineNodes{ receivers: make(map[int64]graph.Node), exporters: make(map[int64]graph.Node), } } if err := pipelines.createNodes(set); err != nil { return nil, err } pipelines.createEdges() err := pipelines.buildComponents(ctx, set) return pipelines, err } // Creates a node for each instance of a component and adds it to the graph. // Validates that connectors are configured to export and receive correctly. func (g *Graph) createNodes(set Settings) error { // Build a list of all connectors for easy reference. connectors := make(map[component.ID]struct{}) // Keep track of connectors and where they are used. (map[connectorID][]pipelineID). connectorsAsExporter := make(map[component.ID][]pipeline.ID) connectorsAsReceiver := make(map[component.ID][]pipeline.ID) // Build each pipelineNodes struct for each pipeline by parsing the pipelineCfg. // Also populates the connectors, connectorsAsExporter and connectorsAsReceiver maps. for pipelineID, pipelineCfg := range set.PipelineConfigs { pipe := g.pipelines[pipelineID] for _, recvID := range pipelineCfg.Receivers { // Checks if this receiver is a connector or a regular receiver. if set.ConnectorBuilder.IsConfigured(recvID) { connectors[recvID] = struct{}{} connectorsAsReceiver[recvID] = append(connectorsAsReceiver[recvID], pipelineID) continue } rcvrNode := g.createReceiver(pipelineID, recvID) pipe.receivers[rcvrNode.ID()] = rcvrNode } pipe.capabilitiesNode = newCapabilitiesNode(pipelineID) for _, procID := range pipelineCfg.Processors { procNode := g.createProcessor(pipelineID, procID) pipe.processors = append(pipe.processors, procNode) } pipe.fanOutNode = newFanOutNode(pipelineID) for _, exprID := range pipelineCfg.Exporters { if set.ConnectorBuilder.IsConfigured(exprID) { connectors[exprID] = struct{}{} connectorsAsExporter[exprID] = append(connectorsAsExporter[exprID], pipelineID) continue } expNode := g.createExporter(pipelineID, exprID) pipe.exporters[expNode.ID()] = expNode } } for connID := range connectors { factory := set.ConnectorBuilder.Factory(connID.Type()) if factory == nil { return fmt.Errorf("connector factory not available for: %q", connID.Type()) } connFactory := factory.(connector.Factory) expTypes := make(map[pipeline.Signal]bool) for _, pipelineID := range connectorsAsExporter[connID] { // The presence of each key indicates how the connector is used as an exporter. // The value is initially set to false. Later we will set the value to true *if* we // confirm that there is a supported corresponding use as a receiver. expTypes[pipelineID.Signal()] = false } recTypes := make(map[pipeline.Signal]bool) for _, pipelineID := range connectorsAsReceiver[connID] { // The presence of each key indicates how the connector is used as a receiver. // The value is initially set to false. Later we will set the value to true *if* we // confirm that there is a supported corresponding use as an exporter. recTypes[pipelineID.Signal()] = false } for expType := range expTypes { for recType := range recTypes { // Typechecks the connector's receiving and exporting datatypes. if connectorStability(connFactory, expType, recType) != component.StabilityLevelUndefined { expTypes[expType] = true recTypes[recType] = true } } } for expType, supportedUse := range expTypes { if supportedUse { continue } return fmt.Errorf("connector %q used as exporter in %v pipeline but not used in any supported receiver pipeline", connID, formatPipelineNamesWithSignal(connectorsAsExporter[connID], expType)) } for recType, supportedUse := range recTypes { if supportedUse { continue } return fmt.Errorf("connector %q used as receiver in %v pipeline but not used in any supported exporter pipeline", connID, formatPipelineNamesWithSignal(connectorsAsReceiver[connID], recType)) } for _, eID := range connectorsAsExporter[connID] { for _, rID := range connectorsAsReceiver[connID] { if connectorStability(connFactory, eID.Signal(), rID.Signal()) == component.StabilityLevelUndefined { // Connector is not supported for this combination, but we know it is used correctly elsewhere continue } connNode := g.createConnector(eID, rID, connID) g.pipelines[eID].exporters[connNode.ID()] = connNode g.pipelines[rID].receivers[connNode.ID()] = connNode } } } return nil } // formatPipelineNamesWithSignal formats pipeline name with signal as "signal[/name]" format. func formatPipelineNamesWithSignal(pipelineIDs []pipeline.ID, signal pipeline.Signal) []string { var formatted []string for _, pid := range pipelineIDs { if pid.Signal() == signal { formatted = append(formatted, pid.String()) } } return formatted } func (g *Graph) createReceiver(pipelineID pipeline.ID, recvID component.ID) *receiverNode { rcvrNode := newReceiverNode(pipelineID.Signal(), recvID) if node := g.componentGraph.Node(rcvrNode.ID()); node != nil { instanceID := g.instanceIDs[node.ID()] g.instanceIDs[node.ID()] = instanceID.WithPipelines(pipelineID) return node.(*receiverNode) } g.componentGraph.AddNode(rcvrNode) g.instanceIDs[rcvrNode.ID()] = componentstatus.NewInstanceID( recvID, component.KindReceiver, pipelineID, ) return rcvrNode } func (g *Graph) createProcessor(pipelineID pipeline.ID, procID component.ID) *processorNode { procNode := newProcessorNode(pipelineID, procID) g.componentGraph.AddNode(procNode) g.instanceIDs[procNode.ID()] = componentstatus.NewInstanceID( procID, component.KindProcessor, pipelineID, ) return procNode } func (g *Graph) createExporter(pipelineID pipeline.ID, exprID component.ID) *exporterNode { expNode := newExporterNode(pipelineID.Signal(), exprID) if node := g.componentGraph.Node(expNode.ID()); node != nil { instanceID := g.instanceIDs[expNode.ID()] g.instanceIDs[expNode.ID()] = instanceID.WithPipelines(pipelineID) return node.(*exporterNode) } g.componentGraph.AddNode(expNode) g.instanceIDs[expNode.ID()] = componentstatus.NewInstanceID( expNode.componentID, component.KindExporter, pipelineID, ) return expNode } func (g *Graph) createConnector(exprPipelineID, rcvrPipelineID pipeline.ID, connID component.ID) *connectorNode { connNode := newConnectorNode(exprPipelineID.Signal(), rcvrPipelineID.Signal(), connID) if node := g.componentGraph.Node(connNode.ID()); node != nil { instanceID := g.instanceIDs[connNode.ID()] g.instanceIDs[connNode.ID()] = instanceID.WithPipelines(exprPipelineID, rcvrPipelineID) return node.(*connectorNode) } g.componentGraph.AddNode(connNode) g.instanceIDs[connNode.ID()] = componentstatus.NewInstanceID( connNode.componentID, component.KindConnector, exprPipelineID, rcvrPipelineID, ) return connNode } // Iterates through the pipelines and creates edges between components. func (g *Graph) createEdges() { for _, pg := range g.pipelines { // Draw edges from each receiver to the capability node. for _, receiver := range pg.receivers { g.componentGraph.SetEdge(g.componentGraph.NewEdge(receiver, pg.capabilitiesNode)) } // Iterates through processors, chaining them together. starts with the capabilities node. var from, to graph.Node from = pg.capabilitiesNode for _, processor := range pg.processors { to = processor g.componentGraph.SetEdge(g.componentGraph.NewEdge(from, to)) from = processor } // Always inserts a fanout node before any exporters. If there is only one // exporter, the fanout node is still created and acts as a noop. to = pg.fanOutNode g.componentGraph.SetEdge(g.componentGraph.NewEdge(from, to)) for _, exporter := range pg.exporters { g.componentGraph.SetEdge(g.componentGraph.NewEdge(pg.fanOutNode, exporter)) } } } // Uses the already built graph g to instantiate the actual components for each component of each pipeline. // Handles calling the factories for each component - and hooking up each component to the next. // Also calculates whether each pipeline mutates data so the receiver can know whether it needs to clone the data. func (g *Graph) buildComponents(ctx context.Context, set Settings) error { nodes, err := topo.Sort(g.componentGraph) if err != nil { return cycleErr(err, topo.DirectedCyclesIn(g.componentGraph)) } for i := len(nodes) - 1; i >= 0; i-- { node := nodes[i] switch n := node.(type) { case *receiverNode: err = n.buildComponent(ctx, set.Telemetry, set.BuildInfo, set.ReceiverBuilder, g.nextConsumers(n.ID())) case *processorNode: // nextConsumers is guaranteed to be length 1. Either it is the next processor or it is the fanout node for the exporters. err = n.buildComponent(ctx, set.Telemetry, set.BuildInfo, set.ProcessorBuilder, g.nextConsumers(n.ID())[0]) case *exporterNode: err = n.buildComponent(ctx, set.Telemetry, set.BuildInfo, set.ExporterBuilder) case *connectorNode: err = n.buildComponent(ctx, set.Telemetry, set.BuildInfo, set.ConnectorBuilder, g.nextConsumers(n.ID())) case *capabilitiesNode: capability := consumer.Capabilities{ // The fanOutNode represents the aggregate capabilities of the exporters in the pipeline. MutatesData: g.pipelines[n.pipelineID].fanOutNode.getConsumer().Capabilities().MutatesData, } for _, proc := range g.pipelines[n.pipelineID].processors { capability.MutatesData = capability.MutatesData || proc.(*processorNode).getConsumer().Capabilities().MutatesData } next := g.nextConsumers(n.ID())[0] switch n.pipelineID.Signal() { case pipeline.SignalTraces: cc := capabilityconsumer.NewTraces(next.(consumer.Traces), capability) n.baseConsumer = cc n.ConsumeTracesFunc = cc.ConsumeTraces case pipeline.SignalMetrics: cc := capabilityconsumer.NewMetrics(next.(consumer.Metrics), capability) n.baseConsumer = cc n.ConsumeMetricsFunc = cc.ConsumeMetrics case pipeline.SignalLogs: cc := capabilityconsumer.NewLogs(next.(consumer.Logs), capability) n.baseConsumer = cc n.ConsumeLogsFunc = cc.ConsumeLogs case xpipeline.SignalProfiles: cc := capabilityconsumer.NewProfiles(next.(xconsumer.Profiles), capability) n.baseConsumer = cc n.ConsumeProfilesFunc = cc.ConsumeProfiles } case *fanOutNode: nexts := g.nextConsumers(n.ID()) switch n.pipelineID.Signal() { case pipeline.SignalTraces: consumers := make([]consumer.Traces, 0, len(nexts)) for _, next := range nexts { consumers = append(consumers, next.(consumer.Traces)) } n.baseConsumer = fanoutconsumer.NewTraces(consumers) case pipeline.SignalMetrics: consumers := make([]consumer.Metrics, 0, len(nexts)) for _, next := range nexts { consumers = append(consumers, next.(consumer.Metrics)) } n.baseConsumer = fanoutconsumer.NewMetrics(consumers) case pipeline.SignalLogs: consumers := make([]consumer.Logs, 0, len(nexts)) for _, next := range nexts { consumers = append(consumers, next.(consumer.Logs)) } n.baseConsumer = fanoutconsumer.NewLogs(consumers) case xpipeline.SignalProfiles: consumers := make([]xconsumer.Profiles, 0, len(nexts)) for _, next := range nexts { consumers = append(consumers, next.(xconsumer.Profiles)) } n.baseConsumer = fanoutconsumer.NewProfiles(consumers) } } if err != nil { return err } } return nil } // Find all nodes func (g *Graph) nextConsumers(nodeID int64) []baseConsumer { nextNodes := g.componentGraph.From(nodeID) nexts := make([]baseConsumer, 0, nextNodes.Len()) for nextNodes.Next() { nexts = append(nexts, nextNodes.Node().(consumerNode).getConsumer()) } return nexts } // A node-based representation of a pipeline configuration. type pipelineNodes struct { // Use map to assist with deduplication of connector instances. receivers map[int64]graph.Node // The node to which receivers emit. Passes through to processors. // Easily accessible as the first node in a pipeline. *capabilitiesNode // The order of processors is very important. Therefore use a slice for processors. processors []graph.Node // Emits to exporters. *fanOutNode // Use map to assist with deduplication of connector instances. exporters map[int64]graph.Node } func (g *Graph) StartAll(ctx context.Context, host *Host) error { if host == nil { return errors.New("host cannot be nil") } nodes, err := topo.Sort(g.componentGraph) if err != nil { return err } // Start in reverse topological order so that downstream components // are started before upstream components. This ensures that each // component's consumer is ready to consume. for i := len(nodes) - 1; i >= 0; i-- { node := nodes[i] comp, ok := node.(component.Component) if !ok { // Skip capabilities/fanout nodes continue } instanceID := g.instanceIDs[node.ID()] host.Reporter.ReportStatus( instanceID, componentstatus.NewEvent(componentstatus.StatusStarting), ) if compErr := comp.Start(ctx, &HostWrapper{Host: host, InstanceID: instanceID}); compErr != nil { host.Reporter.ReportStatus( instanceID, componentstatus.NewPermanentErrorEvent(compErr), ) // We log with zap.AddStacktrace(zap.DPanicLevel) to avoid adding the stack trace to the error log g.telemetry.Logger.WithOptions(zap.AddStacktrace(zap.DPanicLevel)). Error("Failed to start component", zap.Error(compErr), zap.String("type", instanceID.Kind().String()), zap.String("id", instanceID.ComponentID().String()), ) return fmt.Errorf("failed to start %q %s: %w", instanceID.ComponentID().String(), strings.ToLower(instanceID.Kind().String()), compErr) } host.Reporter.ReportOKIfStarting(instanceID) } return nil } func (g *Graph) ShutdownAll(ctx context.Context, reporter status.Reporter) error { nodes, err := topo.Sort(g.componentGraph) if err != nil { return err } // Stop in topological order so that upstream components // are stopped before downstream components. This ensures // that each component has a chance to drain to its consumer // before the consumer is stopped. var errs error for i := range nodes { node := nodes[i] comp, ok := node.(component.Component) if !ok { // Skip capabilities/fanout nodes continue } instanceID := g.instanceIDs[node.ID()] reporter.ReportStatus( instanceID, componentstatus.NewEvent(componentstatus.StatusStopping), ) if compErr := comp.Shutdown(ctx); compErr != nil { errs = multierr.Append(errs, compErr) reporter.ReportStatus( instanceID, componentstatus.NewPermanentErrorEvent(compErr), ) continue } reporter.ReportStatus( instanceID, componentstatus.NewEvent(componentstatus.StatusStopped), ) } return errs } func (g *Graph) GetExporters() map[pipeline.Signal]map[component.ID]component.Component { exportersMap := make(map[pipeline.Signal]map[component.ID]component.Component) exportersMap[pipeline.SignalTraces] = make(map[component.ID]component.Component) exportersMap[pipeline.SignalMetrics] = make(map[component.ID]component.Component) exportersMap[pipeline.SignalLogs] = make(map[component.ID]component.Component) exportersMap[xpipeline.SignalProfiles] = make(map[component.ID]component.Component) for _, pg := range g.pipelines { for _, expNode := range pg.exporters { // Skip connectors, otherwise individual components can introduce cycles if expNode, ok := g.componentGraph.Node(expNode.ID()).(*exporterNode); ok { exportersMap[expNode.pipelineType][expNode.componentID] = expNode.Component } } } return exportersMap } func cycleErr(err error, cycles [][]graph.Node) error { var topoErr topo.Unorderable if !errors.As(err, &topoErr) || len(cycles) == 0 || len(cycles[0]) == 0 { return err } // There may be multiple cycles, but report only the first one. cycle := cycles[0] // The last node is a duplicate of the first node. // Remove it because we may start from a different node. cycle = cycle[:len(cycle)-1] // A cycle always contains a connector. For the sake of consistent // error messages report the cycle starting from a connector. for i := 0; i < len(cycle); i++ { if _, ok := cycle[i].(*connectorNode); ok { cycle = append(cycle[i:], cycle[:i]...) break } } // Repeat the first node at the end to clarify the cycle cycle = append(cycle, cycle[0]) // Build the error message componentDetails := make([]string, 0, len(cycle)) for _, node := range cycle { switch n := node.(type) { case *processorNode: componentDetails = append(componentDetails, fmt.Sprintf("processor %q in pipeline %q", n.componentID, n.pipelineID.String())) case *connectorNode: componentDetails = append(componentDetails, fmt.Sprintf("connector %q (%s to %s)", n.componentID, n.exprPipelineType, n.rcvrPipelineType)) default: continue // skip capabilities/fanout nodes } } return fmt.Errorf("cycle detected: %s", strings.Join(componentDetails, " -> ")) } func connectorStability(f connector.Factory, expType, recType pipeline.Signal) component.StabilityLevel { switch expType { case pipeline.SignalTraces: switch recType { case pipeline.SignalTraces: return f.TracesToTracesStability() case pipeline.SignalMetrics: return f.TracesToMetricsStability() case pipeline.SignalLogs: return f.TracesToLogsStability() case xpipeline.SignalProfiles: fprof, ok := f.(xconnector.Factory) if !ok { return component.StabilityLevelUndefined } return fprof.TracesToProfilesStability() } case pipeline.SignalMetrics: switch recType { case pipeline.SignalTraces: return f.MetricsToTracesStability() case pipeline.SignalMetrics: return f.MetricsToMetricsStability() case pipeline.SignalLogs: return f.MetricsToLogsStability() case xpipeline.SignalProfiles: fprof, ok := f.(xconnector.Factory) if !ok { return component.StabilityLevelUndefined } return fprof.MetricsToProfilesStability() } case pipeline.SignalLogs: switch recType { case pipeline.SignalTraces: return f.LogsToTracesStability() case pipeline.SignalMetrics: return f.LogsToMetricsStability() case pipeline.SignalLogs: return f.LogsToLogsStability() case xpipeline.SignalProfiles: fprof, ok := f.(xconnector.Factory) if !ok { return component.StabilityLevelUndefined } return fprof.LogsToProfilesStability() } case xpipeline.SignalProfiles: fprof, ok := f.(xconnector.Factory) if !ok { return component.StabilityLevelUndefined } switch recType { case pipeline.SignalTraces: return fprof.ProfilesToTracesStability() case pipeline.SignalMetrics: return fprof.ProfilesToMetricsStability() case pipeline.SignalLogs: return fprof.ProfilesToLogsStability() case xpipeline.SignalProfiles: return fprof.ProfilesToProfilesStability() } } return component.StabilityLevelUndefined } var ( _ component.Host = (*HostWrapper)(nil) _ componentstatus.Reporter = (*HostWrapper)(nil) _ hostcapabilities.ExposeExporters = (*HostWrapper)(nil) //nolint:staticcheck // SA1019 ) type HostWrapper struct { *Host InstanceID *componentstatus.InstanceID } func (host *HostWrapper) Report(event *componentstatus.Event) { host.Reporter.ReportStatus(host.InstanceID, event) } opentelemetry-collector-0.141.0/service/internal/graph/graph_test.go000066400000000000000000003511231511331344600256070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph import ( "context" "fmt" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pdata/xpdata/pref" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/status" "go.opentelemetry.io/collector/service/internal/testcomponents" "go.opentelemetry.io/collector/service/pipelines" ) func TestConnectorPipelinesGraph(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testConnectorPipelinesGraph(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testConnectorPipelinesGraph(t) }) } func testConnectorPipelinesGraph(t *testing.T) { tests := []struct { name string pipelineConfigs pipelines.Config expectedPerExporter int // requires symmetry in Pipelines }{ { name: "pipelines_simple.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_simple_mutate.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_simple_multi_proc.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor"), component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor"), component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor"), component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor"), component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_simple_no_proc.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_multi.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate"), component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate"), component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate"), component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate"), component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_multi_no_proc.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver"), component.MustNewIDWithName("examplereceiver", "1")}, Exporters: []component.ID{component.MustNewID("exampleexporter"), component.MustNewIDWithName("exampleexporter", "1")}, }, }, expectedPerExporter: 2, }, { name: "multi_pipeline_receivers_and_exporters.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_simple_traces.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_simple_metrics.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_simple_logs.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_simple_profiles.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_fork_merge_traces.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "type0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "type1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_fork_merge_metrics.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "type0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "type1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_fork_merge_logs.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "type0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "type1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_fork_merge_profiles.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "type0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "type1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "merge")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_translate_from_traces.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_translate_from_metrics.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_translate_from_logs.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_translate_from_profiles.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_matrix_immutable.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleconnector")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewID("exampleconnector")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 4, }, { name: "pipelines_conn_matrix_mutable.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewIDWithName("exampleprocessor", "mutate")}, // mutate propagates upstream to connector Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 4, }, { name: "pipelines_conn_lanes.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("mockforward")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("mockforward")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("mockforward")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewID("mockforward")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("mockforward")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewID("mockforward")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Exporters: []component.ID{component.MustNewID("mockforward")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewID("mockforward")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 1, }, { name: "pipelines_conn_mutate_traces.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "middle"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_mutate_metrics.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "middle"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_mutate_logs.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "middle"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, { name: "pipelines_conn_mutate_profiles.yaml", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out0"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "middle"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "inherit_mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out1"): { Receivers: []component.ID{component.MustNewIDWithName("exampleconnector", "mutate")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectedPerExporter: 2, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Build the pipeline set := Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), ReceiverBuilder: builders.NewReceiver( map[component.ID]component.Config{ component.MustNewID("examplereceiver"): testcomponents.ExampleReceiverFactory.CreateDefaultConfig(), component.MustNewIDWithName("examplereceiver", "1"): testcomponents.ExampleReceiverFactory.CreateDefaultConfig(), }, map[component.Type]receiver.Factory{ testcomponents.ExampleReceiverFactory.Type(): testcomponents.ExampleReceiverFactory, }, ), ProcessorBuilder: builders.NewProcessor( map[component.ID]component.Config{ component.MustNewID("exampleprocessor"): testcomponents.ExampleProcessorFactory.CreateDefaultConfig(), component.MustNewIDWithName("exampleprocessor", "mutate"): testcomponents.ExampleProcessorFactory.CreateDefaultConfig(), }, map[component.Type]processor.Factory{ testcomponents.ExampleProcessorFactory.Type(): testcomponents.ExampleProcessorFactory, }, ), ExporterBuilder: builders.NewExporter( map[component.ID]component.Config{ component.MustNewID("exampleexporter"): testcomponents.ExampleExporterFactory.CreateDefaultConfig(), component.MustNewIDWithName("exampleexporter", "1"): testcomponents.ExampleExporterFactory.CreateDefaultConfig(), }, map[component.Type]exporter.Factory{ testcomponents.ExampleExporterFactory.Type(): testcomponents.ExampleExporterFactory, }, ), ConnectorBuilder: builders.NewConnector( map[component.ID]component.Config{ component.MustNewID("exampleconnector"): testcomponents.ExampleConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("exampleconnector", "merge"): testcomponents.ExampleConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("exampleconnector", "mutate"): testcomponents.ExampleConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("exampleconnector", "inherit_mutate"): testcomponents.ExampleConnectorFactory.CreateDefaultConfig(), component.MustNewID("mockforward"): testcomponents.MockForwardConnectorFactory.CreateDefaultConfig(), }, map[component.Type]connector.Factory{ testcomponents.ExampleConnectorFactory.Type(): testcomponents.ExampleConnectorFactory, testcomponents.MockForwardConnectorFactory.Type(): testcomponents.MockForwardConnectorFactory, }, ), PipelineConfigs: tt.pipelineConfigs, } pg, err := Build(context.Background(), set) require.NoError(t, err) assert.Len(t, pg.pipelines, len(tt.pipelineConfigs)) require.NoError(t, pg.StartAll(context.Background(), &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})})) mutatingPipelines := make(map[pipeline.ID]bool, len(tt.pipelineConfigs)) // Check each pipeline individually, ensuring that all components are started // and that they have observed no signals yet. for pipelineID, pipelineCfg := range tt.pipelineConfigs { pl, ok := pg.pipelines[pipelineID] require.True(t, ok, "expected to find pipeline: %s", pipelineID.String()) // Determine independently if the capabilities node should report MutateData as true var expectMutatesData bool for _, expr := range pipelineCfg.Exporters { if strings.Contains(expr.Name(), "mutate") { expectMutatesData = true } } for _, proc := range pipelineCfg.Processors { if proc.Name() == "mutate" { expectMutatesData = true } } assert.Equal(t, expectMutatesData, pl.capabilitiesNode.getConsumer().Capabilities().MutatesData) mutatingPipelines[pipelineID] = expectMutatesData expectedReceivers, expectedExporters := expectedInstances(tt.pipelineConfigs, pipelineID) require.Len(t, pl.receivers, expectedReceivers) require.Len(t, pl.processors, len(pipelineCfg.Processors)) require.Len(t, pl.exporters, expectedExporters) for _, n := range pl.exporters { switch c := n.(type) { case *exporterNode: e := c.Component.(*testcomponents.ExampleExporter) require.True(t, e.Started()) require.Empty(t, e.Traces) require.Empty(t, e.Metrics) require.Empty(t, e.Logs) require.Empty(t, e.Profiles) case *connectorNode: require.True(t, c.Component.(*testcomponents.ExampleConnector).Started()) default: require.Fail(t, fmt.Sprintf("unexpected type %T", c)) } } for _, n := range pl.processors { require.True(t, n.(*processorNode).Component.(*testcomponents.ExampleProcessor).Started()) } for _, n := range pl.receivers { switch c := n.(type) { case *receiverNode: require.True(t, c.Component.(*testcomponents.ExampleReceiver).Started()) case *connectorNode: require.True(t, c.Component.(*testcomponents.ExampleConnector).Started()) default: require.Fail(t, fmt.Sprintf("unexpected type %T", c)) } } } // Check that Connectors are correctly inheriting mutability from downstream Pipelines for expPipelineID, expPipeline := range pg.pipelines { for _, exp := range expPipeline.exporters { expConn, ok := exp.(*connectorNode) if !ok { continue } if expConn.getConsumer().Capabilities().MutatesData { continue } // find all the Pipelines of the same type where this connector is a receiver var inheritMutatesData bool for recPipelineID, recPipeline := range pg.pipelines { if recPipelineID == expPipelineID || recPipelineID.Signal() != expPipelineID.Signal() { continue } for _, rec := range recPipeline.receivers { recConn, ok := rec.(*connectorNode) if !ok || recConn.ID() != expConn.ID() { continue } inheritMutatesData = inheritMutatesData || mutatingPipelines[recPipelineID] } } assert.Equal(t, inheritMutatesData, expConn.getConsumer().Capabilities().MutatesData) } } // Push data into the Pipelines. The list of Receivers is retrieved directly from the overall // component graph because we do not want to duplicate signal inputs to Receivers that are // shared between Pipelines. The `allReceivers` function also excludes Connectors, which we do // not want to directly inject with signals. allReceivers := pg.getReceivers() for _, c := range allReceivers[pipeline.SignalTraces] { tracesReceiver := c.(*testcomponents.ExampleReceiver) require.NoError(t, tracesReceiver.ConsumeTraces(context.Background(), testdata.GenerateTraces(1))) } for _, c := range allReceivers[pipeline.SignalMetrics] { metricsReceiver := c.(*testcomponents.ExampleReceiver) require.NoError(t, metricsReceiver.ConsumeMetrics(context.Background(), testdata.GenerateMetrics(1))) } for _, c := range allReceivers[pipeline.SignalLogs] { logsReceiver := c.(*testcomponents.ExampleReceiver) require.NoError(t, logsReceiver.ConsumeLogs(context.Background(), testdata.GenerateLogs(1))) } for _, c := range allReceivers[xpipeline.SignalProfiles] { profilesReceiver := c.(*testcomponents.ExampleReceiver) require.NoError(t, profilesReceiver.ConsumeProfiles(context.Background(), testdata.GenerateProfiles(1))) } // Shut down the entire component graph require.NoError(t, pg.ShutdownAll(context.Background(), status.NewNopStatusReporter())) // Check each pipeline individually, ensuring that all components are stopped. for pipelineID := range tt.pipelineConfigs { pl, ok := pg.pipelines[pipelineID] require.True(t, ok, "expected to find pipeline: %s", pipelineID.String()) for _, n := range pl.receivers { switch c := n.(type) { case *receiverNode: require.True(t, c.Component.(*testcomponents.ExampleReceiver).Stopped()) case *connectorNode: require.True(t, c.Component.(*testcomponents.ExampleConnector).Stopped()) default: require.Fail(t, fmt.Sprintf("unexpected type %T", c)) } } for _, n := range pl.processors { require.True(t, n.(*processorNode).Component.(*testcomponents.ExampleProcessor).Stopped()) } for _, n := range pl.exporters { switch c := n.(type) { case *exporterNode: require.True(t, c.Component.(*testcomponents.ExampleExporter).Stopped()) case *connectorNode: require.True(t, c.Component.(*testcomponents.ExampleConnector).Stopped()) default: require.Fail(t, fmt.Sprintf("unexpected type %T", c)) } } } // Get the list of Exporters directly from the overall component graph. Like Receivers, // exclude Connectors and validate each exporter once regardless of sharing between Pipelines. allExporters := pg.GetExporters() for _, e := range allExporters[pipeline.SignalTraces] { tracesExporter := e.(consumer.Traces).(*testcomponents.ExampleExporter) assert.Len(t, tracesExporter.Traces, tt.expectedPerExporter) expected := testdata.GenerateTraces(1) for i := 0; i < tt.expectedPerExporter; i++ { assert.True(t, pref.EqualTraces(expected, tracesExporter.Traces[i])) } } for _, e := range allExporters[pipeline.SignalMetrics] { metricsExporter := e.(consumer.Metrics).(*testcomponents.ExampleExporter) assert.Len(t, metricsExporter.Metrics, tt.expectedPerExporter) expected := testdata.GenerateMetrics(1) for i := 0; i < tt.expectedPerExporter; i++ { assert.True(t, pref.EqualMetrics(expected, metricsExporter.Metrics[i])) } } for _, e := range allExporters[pipeline.SignalLogs] { logsExporter := e.(consumer.Logs).(*testcomponents.ExampleExporter) assert.Len(t, logsExporter.Logs, tt.expectedPerExporter) expected := testdata.GenerateLogs(1) for i := 0; i < tt.expectedPerExporter; i++ { assert.True(t, pref.EqualLogs(expected, logsExporter.Logs[i])) } } for _, e := range allExporters[xpipeline.SignalProfiles] { profilesExporter := e.(xconsumer.Profiles).(*testcomponents.ExampleExporter) assert.Len(t, profilesExporter.Profiles, tt.expectedPerExporter) expected := testdata.GenerateProfiles(1) for i := 0; i < tt.expectedPerExporter; i++ { assert.True(t, pref.EqualProfiles(expected, profilesExporter.Profiles[i])) } } }) } } func TestInstances(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testInstances(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testInstances(t) }) } func testInstances(t *testing.T) { tests := []struct { name string pipelineConfigs pipelines.Config expectInstances map[component.ID]int }{ { name: "one_pipeline_each_signal", pipelineConfigs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectInstances: map[component.ID]int{ component.MustNewID("examplereceiver"): 4, // one per signal component.MustNewID("exampleprocessor"): 4, // one per pipeline component.MustNewID("exampleexporter"): 4, // one per signal }, }, { name: "shared_by_signals", pipelineConfigs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "2"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "2"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "2"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "1"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "2"): { Receivers: []component.ID{component.MustNewID("examplereceiver")}, Processors: []component.ID{component.MustNewID("exampleprocessor")}, Exporters: []component.ID{component.MustNewID("exampleexporter")}, }, }, expectInstances: map[component.ID]int{ component.MustNewID("examplereceiver"): 4, // one per signal component.MustNewID("exampleprocessor"): 8, // one per pipeline component.MustNewID("exampleexporter"): 4, // one per signal }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { set := Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), ReceiverBuilder: builders.NewReceiver( map[component.ID]component.Config{ component.MustNewID("examplereceiver"): testcomponents.ExampleReceiverFactory.CreateDefaultConfig(), }, map[component.Type]receiver.Factory{ testcomponents.ExampleReceiverFactory.Type(): testcomponents.ExampleReceiverFactory, }, ), ProcessorBuilder: builders.NewProcessor( map[component.ID]component.Config{ component.MustNewID("exampleprocessor"): testcomponents.ExampleProcessorFactory.CreateDefaultConfig(), }, map[component.Type]processor.Factory{ testcomponents.ExampleProcessorFactory.Type(): testcomponents.ExampleProcessorFactory, }, ), ExporterBuilder: builders.NewExporter( map[component.ID]component.Config{ component.MustNewID("exampleexporter"): testcomponents.ExampleExporterFactory.CreateDefaultConfig(), }, map[component.Type]exporter.Factory{ testcomponents.ExampleExporterFactory.Type(): testcomponents.ExampleExporterFactory, }, ), ConnectorBuilder: builders.NewConnector(map[component.ID]component.Config{}, map[component.Type]connector.Factory{}), PipelineConfigs: tt.pipelineConfigs, } pg, err := Build(context.Background(), set) require.NoError(t, err) require.Len(t, pg.pipelines, len(set.PipelineConfigs)) // For each component id, build a map of the instances of that component. // Use graph.Node.ID() as the key to determine uniqueness of instances. componentInstances := map[component.ID]map[int64]struct{}{} for _, pipeline := range pg.pipelines { for _, n := range pipeline.receivers { r := n.(*receiverNode) if _, ok := componentInstances[r.componentID]; !ok { componentInstances[r.componentID] = map[int64]struct{}{} } componentInstances[r.componentID][n.ID()] = struct{}{} } for _, n := range pipeline.processors { p := n.(*processorNode) if _, ok := componentInstances[p.componentID]; !ok { componentInstances[p.componentID] = map[int64]struct{}{} } componentInstances[p.componentID][n.ID()] = struct{}{} } for _, n := range pipeline.exporters { e := n.(*exporterNode) if _, ok := componentInstances[e.componentID]; !ok { componentInstances[e.componentID] = map[int64]struct{}{} } componentInstances[e.componentID][n.ID()] = struct{}{} } } var totalExpected int for id, instances := range componentInstances { totalExpected += tt.expectInstances[id] require.Len(t, instances, tt.expectInstances[id], id.String()) } totalExpected += len(tt.pipelineConfigs) * 2 // one fanout & one capabilities node per pipeline require.Equal(t, totalExpected, pg.componentGraph.Nodes().Len()) }) } } func TestConnectorRouter(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testConnectorRouter(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testConnectorRouter(t) }) } func testConnectorRouter(t *testing.T) { rcvrID := component.MustNewID("examplereceiver") routeTracesID := component.MustNewIDWithName("examplerouter", "traces") routeMetricsID := component.MustNewIDWithName("examplerouter", "metrics") routeLogsID := component.MustNewIDWithName("examplerouter", "logs") routeProfilesID := component.MustNewIDWithName("examplerouter", "profiles") expRightID := component.MustNewIDWithName("exampleexporter", "right") expLeftID := component.MustNewIDWithName("exampleexporter", "left") tracesInID := pipeline.NewIDWithName(pipeline.SignalTraces, "in") tracesRightID := pipeline.NewIDWithName(pipeline.SignalTraces, "right") tracesLeftID := pipeline.NewIDWithName(pipeline.SignalTraces, "left") metricsInID := pipeline.NewIDWithName(pipeline.SignalMetrics, "in") metricsRightID := pipeline.NewIDWithName(pipeline.SignalMetrics, "right") metricsLeftID := pipeline.NewIDWithName(pipeline.SignalMetrics, "left") logsInID := pipeline.NewIDWithName(pipeline.SignalLogs, "in") logsRightID := pipeline.NewIDWithName(pipeline.SignalLogs, "right") logsLeftID := pipeline.NewIDWithName(pipeline.SignalLogs, "left") profilesInID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "in") profilesRightID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "right") profilesLeftID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "left") ctx := context.Background() set := Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), ReceiverBuilder: builders.NewReceiver( map[component.ID]component.Config{ rcvrID: testcomponents.ExampleReceiverFactory.CreateDefaultConfig(), }, map[component.Type]receiver.Factory{ testcomponents.ExampleReceiverFactory.Type(): testcomponents.ExampleReceiverFactory, }, ), ExporterBuilder: builders.NewExporter( map[component.ID]component.Config{ expRightID: testcomponents.ExampleExporterFactory.CreateDefaultConfig(), expLeftID: testcomponents.ExampleExporterFactory.CreateDefaultConfig(), }, map[component.Type]exporter.Factory{ testcomponents.ExampleExporterFactory.Type(): testcomponents.ExampleExporterFactory, }, ), ConnectorBuilder: builders.NewConnector( map[component.ID]component.Config{ routeTracesID: testcomponents.ExampleRouterConfig{ Traces: &testcomponents.LeftRightConfig{ Right: tracesRightID, Left: tracesLeftID, }, }, routeMetricsID: testcomponents.ExampleRouterConfig{ Metrics: &testcomponents.LeftRightConfig{ Right: metricsRightID, Left: metricsLeftID, }, }, routeLogsID: testcomponents.ExampleRouterConfig{ Logs: &testcomponents.LeftRightConfig{ Right: logsRightID, Left: logsLeftID, }, }, routeProfilesID: testcomponents.ExampleRouterConfig{ Profiles: &testcomponents.LeftRightConfig{ Right: profilesRightID, Left: profilesLeftID, }, }, }, map[component.Type]connector.Factory{ testcomponents.ExampleRouterFactory.Type(): testcomponents.ExampleRouterFactory, }, ), PipelineConfigs: pipelines.Config{ tracesInID: { Receivers: []component.ID{rcvrID}, Exporters: []component.ID{routeTracesID}, }, tracesRightID: { Receivers: []component.ID{routeTracesID}, Exporters: []component.ID{expRightID}, }, tracesLeftID: { Receivers: []component.ID{routeTracesID}, Exporters: []component.ID{expLeftID}, }, metricsInID: { Receivers: []component.ID{rcvrID}, Exporters: []component.ID{routeMetricsID}, }, metricsRightID: { Receivers: []component.ID{routeMetricsID}, Exporters: []component.ID{expRightID}, }, metricsLeftID: { Receivers: []component.ID{routeMetricsID}, Exporters: []component.ID{expLeftID}, }, logsInID: { Receivers: []component.ID{rcvrID}, Exporters: []component.ID{routeLogsID}, }, logsRightID: { Receivers: []component.ID{routeLogsID}, Exporters: []component.ID{expRightID}, }, logsLeftID: { Receivers: []component.ID{routeLogsID}, Exporters: []component.ID{expLeftID}, }, profilesInID: { Receivers: []component.ID{rcvrID}, Exporters: []component.ID{routeProfilesID}, }, profilesRightID: { Receivers: []component.ID{routeProfilesID}, Exporters: []component.ID{expRightID}, }, profilesLeftID: { Receivers: []component.ID{routeProfilesID}, Exporters: []component.ID{expLeftID}, }, }, } pg, err := Build(ctx, set) require.NoError(t, err) allReceivers := pg.getReceivers() allExporters := pg.GetExporters() assert.Len(t, pg.pipelines, len(set.PipelineConfigs)) // Get a handle for the traces receiver and both Exporters tracesReceiver := allReceivers[pipeline.SignalTraces][rcvrID].(*testcomponents.ExampleReceiver) tracesRight := allExporters[pipeline.SignalTraces][expRightID].(*testcomponents.ExampleExporter) tracesLeft := allExporters[pipeline.SignalTraces][expLeftID].(*testcomponents.ExampleExporter) // Consume 1, validate it went right require.NoError(t, tracesReceiver.ConsumeTraces(ctx, testdata.GenerateTraces(1))) assert.Len(t, tracesRight.Traces, 1) assert.Empty(t, tracesLeft.Traces) // Consume 1, validate it went left require.NoError(t, tracesReceiver.ConsumeTraces(ctx, testdata.GenerateTraces(1))) assert.Len(t, tracesRight.Traces, 1) assert.Len(t, tracesLeft.Traces, 1) // Consume 3, validate 2 went right, 1 went left assert.NoError(t, tracesReceiver.ConsumeTraces(ctx, testdata.GenerateTraces(1))) assert.NoError(t, tracesReceiver.ConsumeTraces(ctx, testdata.GenerateTraces(1))) assert.NoError(t, tracesReceiver.ConsumeTraces(ctx, testdata.GenerateTraces(1))) assert.Len(t, tracesRight.Traces, 3) assert.Len(t, tracesLeft.Traces, 2) // Get a handle for the metrics receiver and both Exporters metricsReceiver := allReceivers[pipeline.SignalMetrics][rcvrID].(*testcomponents.ExampleReceiver) metricsRight := allExporters[pipeline.SignalMetrics][expRightID].(*testcomponents.ExampleExporter) metricsLeft := allExporters[pipeline.SignalMetrics][expLeftID].(*testcomponents.ExampleExporter) // Consume 1, validate it went right require.NoError(t, metricsReceiver.ConsumeMetrics(ctx, testdata.GenerateMetrics(1))) assert.Len(t, metricsRight.Metrics, 1) assert.Empty(t, metricsLeft.Metrics) // Consume 1, validate it went left require.NoError(t, metricsReceiver.ConsumeMetrics(ctx, testdata.GenerateMetrics(1))) assert.Len(t, metricsRight.Metrics, 1) assert.Len(t, metricsLeft.Metrics, 1) // Consume 3, validate 2 went right, 1 went left assert.NoError(t, metricsReceiver.ConsumeMetrics(ctx, testdata.GenerateMetrics(1))) assert.NoError(t, metricsReceiver.ConsumeMetrics(ctx, testdata.GenerateMetrics(1))) assert.NoError(t, metricsReceiver.ConsumeMetrics(ctx, testdata.GenerateMetrics(1))) assert.Len(t, metricsRight.Metrics, 3) assert.Len(t, metricsLeft.Metrics, 2) // Get a handle for the logs receiver and both Exporters logsReceiver := allReceivers[pipeline.SignalLogs][rcvrID].(*testcomponents.ExampleReceiver) logsRight := allExporters[pipeline.SignalLogs][expRightID].(*testcomponents.ExampleExporter) logsLeft := allExporters[pipeline.SignalLogs][expLeftID].(*testcomponents.ExampleExporter) // Consume 1, validate it went right require.NoError(t, logsReceiver.ConsumeLogs(ctx, testdata.GenerateLogs(1))) assert.Len(t, logsRight.Logs, 1) assert.Empty(t, logsLeft.Logs) // Consume 1, validate it went left require.NoError(t, logsReceiver.ConsumeLogs(ctx, testdata.GenerateLogs(1))) assert.Len(t, logsRight.Logs, 1) assert.Len(t, logsLeft.Logs, 1) // Consume 3, validate 2 went right, 1 went left assert.NoError(t, logsReceiver.ConsumeLogs(ctx, testdata.GenerateLogs(1))) assert.NoError(t, logsReceiver.ConsumeLogs(ctx, testdata.GenerateLogs(1))) assert.NoError(t, logsReceiver.ConsumeLogs(ctx, testdata.GenerateLogs(1))) assert.Len(t, logsRight.Logs, 3) assert.Len(t, logsLeft.Logs, 2) // Get a handle for the profiles receiver and both Exporters profilesReceiver := allReceivers[xpipeline.SignalProfiles][rcvrID].(*testcomponents.ExampleReceiver) profilesRight := allExporters[xpipeline.SignalProfiles][expRightID].(*testcomponents.ExampleExporter) profilesLeft := allExporters[xpipeline.SignalProfiles][expLeftID].(*testcomponents.ExampleExporter) // Consume 1, validate it went right require.NoError(t, profilesReceiver.ConsumeProfiles(ctx, testdata.GenerateProfiles(1))) assert.Len(t, profilesRight.Profiles, 1) assert.Empty(t, profilesLeft.Profiles) // Consume 1, validate it went left require.NoError(t, profilesReceiver.ConsumeProfiles(ctx, testdata.GenerateProfiles(1))) assert.Len(t, profilesRight.Profiles, 1) assert.Len(t, profilesLeft.Profiles, 1) // Consume 3, validate 2 went right, 1 went left assert.NoError(t, profilesReceiver.ConsumeProfiles(ctx, testdata.GenerateProfiles(1))) assert.NoError(t, profilesReceiver.ConsumeProfiles(ctx, testdata.GenerateProfiles(1))) assert.NoError(t, profilesReceiver.ConsumeProfiles(ctx, testdata.GenerateProfiles(1))) assert.Len(t, profilesRight.Profiles, 3) assert.Len(t, profilesLeft.Profiles, 2) } func TestGraphBuildErrors(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testGraphBuildErrors(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testGraphBuildErrors(t) }) } func testGraphBuildErrors(t *testing.T) { nopReceiverFactory := receivertest.NewNopFactory() nopProcessorFactory := processortest.NewNopFactory() nopExporterFactory := exportertest.NewNopFactory() nopConnectorFactory := connectortest.NewNopFactory() mfConnectorFactory := testcomponents.MockForwardConnectorFactory badReceiverFactory := newBadReceiverFactory() badProcessorFactory := newBadProcessorFactory() badExporterFactory := newBadExporterFactory() badConnectorFactory := newBadConnectorFactory() tests := []struct { name string receiverCfgs map[component.ID]component.Config processorCfgs map[component.ID]component.Config exporterCfgs map[component.ID]component.Config connectorCfgs map[component.ID]component.Config pipelineCfgs pipelines.Config expected string }{ { name: "not_supported_exporter_logs", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badExporterFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, }, expected: "failed to create \"bf\" exporter for data type \"logs\": telemetry type is not supported", }, { name: "not_supported_exporter_metrics", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badExporterFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, }, expected: "failed to create \"bf\" exporter for data type \"metrics\": telemetry type is not supported", }, { name: "not_supported_exporter_traces", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badExporterFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, }, expected: "failed to create \"bf\" exporter for data type \"traces\": telemetry type is not supported", }, { name: "not_supported_exporter_profiles", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badExporterFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, }, expected: "failed to create \"bf\" exporter for data type \"profiles\": telemetry type is not supported", }, { name: "not_supported_processor_logs", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" processor, in pipeline \"logs\": telemetry type is not supported", }, { name: "not_supported_processor_metrics", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" processor, in pipeline \"metrics\": telemetry type is not supported", }, { name: "not_supported_processor_traces", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" processor, in pipeline \"traces\": telemetry type is not supported", }, { name: "not_supported_processor_profiles", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" processor, in pipeline \"profiles\": telemetry type is not supported", }, { name: "not_supported_receiver_logs", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" receiver for data type \"logs\": telemetry type is not supported", }, { name: "not_supported_receiver_metrics", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" receiver for data type \"metrics\": telemetry type is not supported", }, { name: "not_supported_receiver_traces", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" receiver for data type \"traces\": telemetry type is not supported", }, { name: "not_supported_receiver_profiles", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): badReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"bf\" receiver for data type \"profiles\": telemetry type is not supported", }, { name: "not_supported_connector_traces_traces.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [traces/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_traces_metrics.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [traces/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_traces_logs.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [traces/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_traces_profiles.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [traces/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_metrics_traces.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [metrics/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_metrics_metrics.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [metrics/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_metrics_logs.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [metrics/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_metrics_profiles.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [metrics/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_logs_traces.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [logs/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_logs_metrics.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [logs/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_logs_logs.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [logs/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_logs_profiles.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [logs/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_profiles_traces.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [profiles/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_profiles_metrics.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [profiles/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_profiles_logs.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [profiles/in] pipeline but not used in any supported receiver pipeline", }, { name: "not_supported_connector_profiles_profiles.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("bf"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("bf")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewID("bf")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector \"bf\" used as exporter in [profiles/in] pipeline but not used in any supported receiver pipeline", }, { name: "orphaned-connector-use-as-exporter", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, }, expected: `connector "nop/conn" used as exporter in [metrics/in] pipeline but not used in any supported receiver pipeline`, }, { name: "orphaned-connector-use-as-receiver", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: `connector "nop/conn" used as receiver in [traces/out] pipeline but not used in any supported exporter pipeline`, }, { name: "partially-orphaned-connector-use-as-exporter", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("mockforward"): mfConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("mockforward")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("mockforward")}, Exporters: []component.ID{component.MustNewID("nop")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("mockforward")}, }, }, expected: `connector "mockforward" used as exporter in [metrics/in] pipeline but not used in any supported receiver pipeline`, }, { name: "partially-orphaned-connector-use-as-receiver", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("mockforward"): mfConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("mockforward")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewID("mockforward")}, Exporters: []component.ID{component.MustNewID("nop")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("mockforward")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: `connector "mockforward" used as receiver in [traces/out] pipeline but not used in any supported exporter pipeline`, }, { name: "not_allowed_simple_cycle_traces.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, }, expected: `cycle detected: ` + `connector "nop/conn" (traces to traces) -> ` + `processor "nop" in pipeline "traces" -> ` + `connector "nop/conn" (traces to traces)`, }, { name: "not_allowed_simple_cycle_metrics.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, }, expected: `cycle detected: ` + `connector "nop/conn" (metrics to metrics) -> ` + `processor "nop" in pipeline "metrics" -> ` + `connector "nop/conn" (metrics to metrics)`, }, { name: "not_allowed_simple_cycle_logs.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, }, expected: `cycle detected: ` + `connector "nop/conn" (logs to logs) -> ` + `processor "nop" in pipeline "logs" -> ` + `connector "nop/conn" (logs to logs)`, }, { name: "not_allowed_simple_cycle_profiles.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, }, expected: `cycle detected: ` + `connector "nop/conn" (profiles to profiles) -> ` + `processor "nop" in pipeline "profiles" -> ` + `connector "nop/conn" (profiles to profiles)`, }, { name: "not_allowed_deep_cycle_traces.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn1"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn2"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "1"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn1")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "2"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn1")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn2"), component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn2")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: `cycle detected: ` + `connector "nop/conn1" (traces to traces) -> ` + `processor "nop" in pipeline "traces/2" -> ` + `connector "nop/conn" (traces to traces) -> ` + `processor "nop" in pipeline "traces/1" -> ` + `connector "nop/conn1" (traces to traces)`, }, { name: "not_allowed_deep_cycle_metrics.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn1"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn2"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalMetrics, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "1"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn1")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "2"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn1")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn2"), component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "out"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn2")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: `cycle detected: ` + `connector "nop/conn1" (metrics to metrics) -> ` + `processor "nop" in pipeline "metrics/2" -> ` + `connector "nop/conn" (metrics to metrics) -> ` + `processor "nop" in pipeline "metrics/1" -> ` + `connector "nop/conn1" (metrics to metrics)`, }, { name: "not_allowed_deep_cycle_logs.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn1"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn2"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "1"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn1")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "2"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn1")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn2"), component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn2")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: `cycle detected: ` + `connector "nop/conn" (logs to logs) -> ` + `processor "nop" in pipeline "logs/1" -> ` + `connector "nop/conn1" (logs to logs) -> ` + `processor "nop" in pipeline "logs/2" -> ` + `connector "nop/conn" (logs to logs)`, }, { name: "not_allowed_deep_cycle_profiles.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "conn"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn1"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "conn2"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(xpipeline.SignalProfiles, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "1"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn1")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "2"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn1")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "conn2"), component.MustNewIDWithName("nop", "conn")}, }, pipeline.NewIDWithName(xpipeline.SignalProfiles, "out"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "conn2")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: `cycle detected: ` + `connector "nop/conn1" (profiles to profiles) -> ` + `processor "nop" in pipeline "profiles/2" -> ` + `connector "nop/conn" (profiles to profiles) -> ` + `processor "nop" in pipeline "profiles/1" -> ` + `connector "nop/conn1" (profiles to profiles)`, }, { name: "not_allowed_deep_cycle_multi_signal.yaml", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopExporterFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewIDWithName("nop", "fork"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "count"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "forkagain"): nopConnectorFactory.CreateDefaultConfig(), component.MustNewIDWithName("nop", "rawlog"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "fork")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "copy1"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "fork")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "count")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "copy2"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "fork")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "forkagain")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "copy2a"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "forkagain")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "count")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "copy2b"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "forkagain")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "rawlog")}, }, pipeline.NewIDWithName(pipeline.SignalMetrics, "count"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "count")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "raw"): { Receivers: []component.ID{component.MustNewIDWithName("nop", "rawlog")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewIDWithName("nop", "fork")}, // cannot loop back to "nop/fork" }, }, expected: `cycle detected: ` + `connector "nop/rawlog" (traces to logs) -> ` + `processor "nop" in pipeline "logs/raw" -> ` + `connector "nop/fork" (logs to traces) -> ` + `processor "nop" in pipeline "traces/copy2" -> ` + `connector "nop/forkagain" (traces to traces) -> ` + `processor "nop" in pipeline "traces/copy2b" -> ` + `connector "nop/rawlog" (traces to logs)`, }, { name: "unknown_exporter_config", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop"), component.MustNewIDWithName("nop", "1")}, }, }, expected: "failed to create \"nop/1\" exporter for data type \"traces\": exporter \"nop/1\" is not configured", }, { name: "unknown_exporter_factory", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("unknown"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("unknown")}, }, }, expected: "failed to create \"unknown\" exporter for data type \"traces\": exporter factory not available for: \"unknown\"", }, { name: "unknown_processor_config", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop"), component.MustNewIDWithName("nop", "1")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"nop/1\" processor, in pipeline \"metrics\": processor \"nop/1\" is not configured", }, { name: "unknown_processor_factory", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, processorCfgs: map[component.ID]component.Config{ component.MustNewID("unknown"): nopProcessorFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("unknown")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"unknown\" processor, in pipeline \"metrics\": processor factory not available for: \"unknown\"", }, { name: "unknown_receiver_config", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("nop"), component.MustNewIDWithName("nop", "1")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"nop/1\" receiver for data type \"logs\": receiver \"nop/1\" is not configured", }, { name: "unknown_receiver_factory", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("unknown"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.MustNewID("unknown")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "failed to create \"unknown\" receiver for data type \"logs\": receiver factory not available for: \"unknown\"", }, { name: "unknown_connector_factory", receiverCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, exporterCfgs: map[component.ID]component.Config{ component.MustNewID("nop"): nopReceiverFactory.CreateDefaultConfig(), }, connectorCfgs: map[component.ID]component.Config{ component.MustNewID("unknown"): nopConnectorFactory.CreateDefaultConfig(), }, pipelineCfgs: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("unknown")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.MustNewID("unknown")}, Exporters: []component.ID{component.MustNewID("nop")}, }, }, expected: "connector factory not available for: \"unknown\"", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { set := Settings{ BuildInfo: component.NewDefaultBuildInfo(), Telemetry: componenttest.NewNopTelemetrySettings(), ReceiverBuilder: builders.NewReceiver( tt.receiverCfgs, map[component.Type]receiver.Factory{ nopReceiverFactory.Type(): nopReceiverFactory, badReceiverFactory.Type(): badReceiverFactory, }), ProcessorBuilder: builders.NewProcessor( tt.processorCfgs, map[component.Type]processor.Factory{ nopProcessorFactory.Type(): nopProcessorFactory, badProcessorFactory.Type(): badProcessorFactory, }), ExporterBuilder: builders.NewExporter( tt.exporterCfgs, map[component.Type]exporter.Factory{ nopExporterFactory.Type(): nopExporterFactory, badExporterFactory.Type(): badExporterFactory, }), ConnectorBuilder: builders.NewConnector( tt.connectorCfgs, map[component.Type]connector.Factory{ nopConnectorFactory.Type(): nopConnectorFactory, badConnectorFactory.Type(): badConnectorFactory, mfConnectorFactory.Type(): mfConnectorFactory, }), PipelineConfigs: tt.pipelineCfgs, } _, err := Build(context.Background(), set) assert.EqualError(t, err, tt.expected) }) } } opentelemetry-collector-0.141.0/service/internal/graph/host.go000066400000000000000000000134511511331344600244230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "net/http" "path" "runtime" "time" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/hostcapabilities" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/moduleinfo" "go.opentelemetry.io/collector/service/internal/status" "go.opentelemetry.io/collector/service/internal/zpages" ) var ( _ component.Host = (*Host)(nil) _ hostcapabilities.ModuleInfo = (*Host)(nil) _ hostcapabilities.ExposeExporters = (*Host)(nil) //nolint:staticcheck // SA1019 _ hostcapabilities.ComponentFactory = (*Host)(nil) ) type Host struct { AsyncErrorChannel chan error Receivers *builders.ReceiverBuilder Processors *builders.ProcessorBuilder Exporters *builders.ExporterBuilder Connectors *builders.ConnectorBuilder Extensions *builders.ExtensionBuilder ModuleInfos moduleinfo.ModuleInfos BuildInfo component.BuildInfo Pipelines *Graph ServiceExtensions *extensions.Extensions Reporter status.Reporter } func (host *Host) GetFactory(kind component.Kind, componentType component.Type) component.Factory { switch kind { case component.KindReceiver: return host.Receivers.Factory(componentType) case component.KindProcessor: return host.Processors.Factory(componentType) case component.KindExporter: return host.Exporters.Factory(componentType) case component.KindConnector: return host.Connectors.Factory(componentType) case component.KindExtension: return host.Extensions.Factory(componentType) } return nil } func (host *Host) GetExtensions() map[component.ID]component.Component { return host.ServiceExtensions.GetExtensions() } func (host *Host) GetModuleInfos() moduleinfo.ModuleInfos { return host.ModuleInfos } // Deprecated: [0.79.0] This function will be removed in the future. // Several components in the contrib repository use this function so it cannot be removed // before those cases are removed. In most cases, use of this function can be replaced by a // connector. See https://github.com/open-telemetry/opentelemetry-collector/issues/7370 and // https://github.com/open-telemetry/opentelemetry-collector/pull/7390#issuecomment-1483710184 // for additional information. func (host *Host) GetExporters() map[pipeline.Signal]map[component.ID]component.Component { return host.Pipelines.GetExporters() } func (host *Host) NotifyComponentStatusChange(source *componentstatus.InstanceID, event *componentstatus.Event) { host.ServiceExtensions.NotifyComponentStatusChange(source, event) if event.Status() == componentstatus.StatusFatalError { host.AsyncErrorChannel <- event.Err() } } const ( // Paths zServicePath = "servicez" zPipelinePath = "pipelinez" zExtensionPath = "extensionz" zFeaturePath = "featurez" ) // InfoVar is a singleton instance of the Info struct. var runtimeInfoVar [][2]string func init() { runtimeInfoVar = [][2]string{ {"StartTimestamp", time.Now().String()}, {"Go", runtime.Version()}, {"OS", runtime.GOOS}, {"Arch", runtime.GOARCH}, // Add other valuable runtime information here. } } func (host *Host) RegisterZPages(mux *http.ServeMux, pathPrefix string) { mux.HandleFunc(path.Join(pathPrefix, zServicePath), host.zPagesRequest) mux.HandleFunc(path.Join(pathPrefix, zPipelinePath), host.Pipelines.HandleZPages) mux.HandleFunc(path.Join(pathPrefix, zExtensionPath), host.ServiceExtensions.HandleZPages) mux.HandleFunc(path.Join(pathPrefix, zFeaturePath), handleFeaturezRequest) } func (host *Host) zPagesRequest(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") zpages.WriteHTMLPageHeader(w, zpages.HeaderData{Title: "Service " + host.BuildInfo.Command}) zpages.WriteHTMLPropertiesTable(w, zpages.PropertiesTableData{Name: "Build Info", Properties: getBuildInfoProperties(host.BuildInfo)}) zpages.WriteHTMLPropertiesTable(w, zpages.PropertiesTableData{Name: "Runtime Info", Properties: runtimeInfoVar}) zpages.WriteHTMLComponentHeader(w, zpages.ComponentHeaderData{ Name: "Pipelines", ComponentEndpoint: zPipelinePath, Link: true, }) zpages.WriteHTMLComponentHeader(w, zpages.ComponentHeaderData{ Name: "Extensions", ComponentEndpoint: zExtensionPath, Link: true, }) zpages.WriteHTMLComponentHeader(w, zpages.ComponentHeaderData{ Name: "Features", ComponentEndpoint: zFeaturePath, Link: true, }) zpages.WriteHTMLPageFooter(w) } func handleFeaturezRequest(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "text/html; charset=utf-8") zpages.WriteHTMLPageHeader(w, zpages.HeaderData{Title: "Feature Gates"}) zpages.WriteHTMLFeaturesTable(w, getFeaturesTableData()) zpages.WriteHTMLPageFooter(w) } func getFeaturesTableData() zpages.FeatureGateTableData { data := zpages.FeatureGateTableData{} featuregate.GlobalRegistry().VisitAll(func(gate *featuregate.Gate) { data.Rows = append(data.Rows, zpages.FeatureGateTableRowData{ ID: gate.ID(), Enabled: gate.IsEnabled(), Description: gate.Description(), Stage: gate.Stage().String(), FromVersion: gate.FromVersion(), ToVersion: gate.ToVersion(), ReferenceURL: gate.ReferenceURL(), }) }) return data } func getBuildInfoProperties(buildInfo component.BuildInfo) [][2]string { return [][2]string{ {"Command", buildInfo.Command}, {"Description", buildInfo.Description}, {"Version", buildInfo.Version}, } } opentelemetry-collector-0.141.0/service/internal/graph/lifecycle_test.go000066400000000000000000000466561511331344600264610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gonum.org/v1/gonum/graph/simple" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/exportertest" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/processortest" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/receivertest" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/status" "go.opentelemetry.io/collector/service/pipelines" ) func TestGraphStartStop(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testGraphStartStop(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testGraphStartStop(t) }) } func testGraphStartStop(t *testing.T) { testCases := []struct { name string edges [][2]component.ID }{ { name: "single", edges: [][2]component.ID{ {component.MustNewIDWithName("r", "1"), component.MustNewIDWithName("p", "1")}, {component.MustNewIDWithName("r", "2"), component.MustNewIDWithName("p", "1")}, {component.MustNewIDWithName("p", "1"), component.MustNewIDWithName("p", "2")}, {component.MustNewIDWithName("p", "2"), component.MustNewIDWithName("e", "1")}, {component.MustNewIDWithName("p", "1"), component.MustNewIDWithName("e", "2")}, }, }, { name: "multi", edges: [][2]component.ID{ // Pipeline 1 {component.MustNewIDWithName("r", "1"), component.MustNewIDWithName("p", "1")}, {component.MustNewIDWithName("r", "2"), component.MustNewIDWithName("p", "1")}, {component.MustNewIDWithName("p", "1"), component.MustNewIDWithName("p", "2")}, {component.MustNewIDWithName("p", "2"), component.MustNewIDWithName("e", "1")}, {component.MustNewIDWithName("p", "1"), component.MustNewIDWithName("e", "2")}, // Pipeline 2, shares r1 and e2 {component.MustNewIDWithName("r", "1"), component.MustNewIDWithName("p", "3")}, {component.MustNewIDWithName("p", "3"), component.MustNewIDWithName("e", "2")}, }, }, { name: "connected", edges: [][2]component.ID{ // Pipeline 1 {component.MustNewIDWithName("r", "1"), component.MustNewIDWithName("p", "1")}, {component.MustNewIDWithName("r", "2"), component.MustNewIDWithName("p", "1")}, {component.MustNewIDWithName("p", "1"), component.MustNewIDWithName("p", "2")}, {component.MustNewIDWithName("p", "2"), component.MustNewIDWithName("e", "1")}, {component.MustNewIDWithName("p", "1"), component.MustNewIDWithName("c", "1")}, // Pipeline 2, shares r1 and c1 {component.MustNewIDWithName("r", "1"), component.MustNewIDWithName("p", "3")}, {component.MustNewIDWithName("p", "3"), component.MustNewIDWithName("c", "1")}, // Pipeline 3, emits to e2 and c2 {component.MustNewIDWithName("c", "1"), component.MustNewIDWithName("e", "2")}, {component.MustNewIDWithName("c", "1"), component.MustNewIDWithName("c", "2")}, // Pipeline 4, also emits to e2 {component.MustNewIDWithName("c", "2"), component.MustNewIDWithName("e", "2")}, }, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { ctx := &contextWithOrder{ Context: context.Background(), order: map[component.ID]int{}, } pg := &Graph{componentGraph: simple.NewDirectedGraph()} pg.telemetry = componenttest.NewNopTelemetrySettings() pg.instanceIDs = make(map[int64]*componentstatus.InstanceID) for _, edge := range tt.edges { f, t := &testNode{id: edge[0]}, &testNode{id: edge[1]} pg.instanceIDs[f.ID()] = &componentstatus.InstanceID{} pg.instanceIDs[t.ID()] = &componentstatus.InstanceID{} pg.componentGraph.SetEdge(simple.Edge{F: f, T: t}) } require.NoError(t, pg.StartAll(ctx, &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})})) for _, edge := range tt.edges { assert.Greater(t, ctx.order[edge[0]], ctx.order[edge[1]]) } ctx.order = map[component.ID]int{} require.NoError(t, pg.ShutdownAll(ctx, status.NewNopStatusReporter())) for _, edge := range tt.edges { assert.Less(t, ctx.order[edge[0]], ctx.order[edge[1]]) } }) } } func TestGraphStartStopCycle(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testGraphStartStopCycle(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testGraphStartStopCycle(t) }) } func testGraphStartStopCycle(t *testing.T) { pg := &Graph{componentGraph: simple.NewDirectedGraph()} r1 := &testNode{id: component.MustNewIDWithName("r", "1")} p1 := &testNode{id: component.MustNewIDWithName("p", "1")} c1 := &testNode{id: component.MustNewIDWithName("c", "1")} e1 := &testNode{id: component.MustNewIDWithName("e", "1")} pg.instanceIDs = map[int64]*componentstatus.InstanceID{ r1.ID(): {}, p1.ID(): {}, c1.ID(): {}, e1.ID(): {}, } pg.componentGraph.SetEdge(simple.Edge{F: r1, T: p1}) pg.componentGraph.SetEdge(simple.Edge{F: p1, T: c1}) pg.componentGraph.SetEdge(simple.Edge{F: c1, T: e1}) pg.componentGraph.SetEdge(simple.Edge{F: c1, T: p1}) // loop back err := pg.StartAll(context.Background(), &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})}) require.ErrorContains(t, err, `topo: no topological ordering: cyclic components`) err = pg.ShutdownAll(context.Background(), status.NewNopStatusReporter()) assert.ErrorContains(t, err, `topo: no topological ordering: cyclic components`) } func TestGraphStartStopComponentError(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testGraphStartStopComponentError(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testGraphStartStopComponentError(t) }) } func testGraphStartStopComponentError(t *testing.T) { pg := &Graph{componentGraph: simple.NewDirectedGraph()} pg.telemetry = componenttest.NewNopTelemetrySettings() r1 := &testNode{ id: component.MustNewIDWithName("r", "1"), startErr: errors.New("foo"), } e1 := &testNode{ id: component.MustNewIDWithName("e", "1"), shutdownErr: errors.New("bar"), } pg.instanceIDs = map[int64]*componentstatus.InstanceID{ r1.ID(): {}, e1.ID(): {}, } pg.componentGraph.SetEdge(simple.Edge{ F: r1, T: e1, }) require.ErrorIs(t, pg.StartAll(context.Background(), &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})}), r1.startErr) assert.EqualError(t, pg.ShutdownAll(context.Background(), status.NewNopStatusReporter()), "bar") } // This includes all tests from the previous implementation, plus a new one // relevant only to the new graph-based implementation. func TestGraphFailToStartAndShutdown(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testGraphFailToStartAndShutdown(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testGraphFailToStartAndShutdown(t) }) } func testGraphFailToStartAndShutdown(t *testing.T) { errReceiverFactory := newErrReceiverFactory() errProcessorFactory := newErrProcessorFactory() errExporterFactory := newErrExporterFactory() errConnectorFactory := newErrConnectorFactory() nopReceiverFactory := receivertest.NewNopFactory() nopProcessorFactory := processortest.NewNopFactory() nopExporterFactory := exportertest.NewNopFactory() nopConnectorFactory := connectortest.NewNopFactory() set := Settings{ Telemetry: componenttest.NewNopTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), ReceiverBuilder: builders.NewReceiver( map[component.ID]component.Config{ component.NewID(nopReceiverFactory.Type()): nopReceiverFactory.CreateDefaultConfig(), component.NewID(errReceiverFactory.Type()): errReceiverFactory.CreateDefaultConfig(), }, map[component.Type]receiver.Factory{ nopReceiverFactory.Type(): nopReceiverFactory, errReceiverFactory.Type(): errReceiverFactory, }), ProcessorBuilder: builders.NewProcessor( map[component.ID]component.Config{ component.NewID(nopProcessorFactory.Type()): nopProcessorFactory.CreateDefaultConfig(), component.NewID(errProcessorFactory.Type()): errProcessorFactory.CreateDefaultConfig(), }, map[component.Type]processor.Factory{ nopProcessorFactory.Type(): nopProcessorFactory, errProcessorFactory.Type(): errProcessorFactory, }), ExporterBuilder: builders.NewExporter( map[component.ID]component.Config{ component.NewID(nopExporterFactory.Type()): nopExporterFactory.CreateDefaultConfig(), component.NewID(errExporterFactory.Type()): errExporterFactory.CreateDefaultConfig(), }, map[component.Type]exporter.Factory{ nopExporterFactory.Type(): nopExporterFactory, errExporterFactory.Type(): errExporterFactory, }), ConnectorBuilder: builders.NewConnector( map[component.ID]component.Config{ component.NewIDWithName(nopConnectorFactory.Type(), "conn"): nopConnectorFactory.CreateDefaultConfig(), component.NewIDWithName(errConnectorFactory.Type(), "conn"): errConnectorFactory.CreateDefaultConfig(), }, map[component.Type]connector.Factory{ nopConnectorFactory.Type(): nopConnectorFactory, errConnectorFactory.Type(): errConnectorFactory, }), } dataTypes := []pipeline.Signal{pipeline.SignalTraces, pipeline.SignalMetrics, pipeline.SignalLogs} for _, dt := range dataTypes { t.Run(dt.String()+"/receiver", func(t *testing.T) { set.PipelineConfigs = pipelines.Config{ pipeline.NewID(dt): { Receivers: []component.ID{component.MustNewID("nop"), component.MustNewID("err")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, } pipelines, err := Build(context.Background(), set) require.NoError(t, err) require.Error(t, pipelines.StartAll(context.Background(), &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})})) assert.Error(t, pipelines.ShutdownAll(context.Background(), status.NewNopStatusReporter())) }) t.Run(dt.String()+"/processor", func(t *testing.T) { set.PipelineConfigs = pipelines.Config{ pipeline.NewID(dt): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop"), component.MustNewID("err")}, Exporters: []component.ID{component.MustNewID("nop")}, }, } pipelines, err := Build(context.Background(), set) require.NoError(t, err) require.Error(t, pipelines.StartAll(context.Background(), &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})})) assert.Error(t, pipelines.ShutdownAll(context.Background(), status.NewNopStatusReporter())) }) t.Run(dt.String()+"/exporter", func(t *testing.T) { set.PipelineConfigs = pipelines.Config{ pipeline.NewID(dt): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop"), component.MustNewID("err")}, }, } pipelines, err := Build(context.Background(), set) require.NoError(t, err) require.Error(t, pipelines.StartAll(context.Background(), &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})})) assert.Error(t, pipelines.ShutdownAll(context.Background(), status.NewNopStatusReporter())) }) for _, dt2 := range dataTypes { t.Run(dt.String()+"/"+dt2.String()+"/connector", func(t *testing.T) { set.PipelineConfigs = pipelines.Config{ pipeline.NewIDWithName(dt, "in"): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop"), component.MustNewIDWithName("err", "conn")}, }, pipeline.NewIDWithName(dt2, "out"): { Receivers: []component.ID{component.MustNewID("nop"), component.MustNewIDWithName("err", "conn")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, } pipelines, err := Build(context.Background(), set) require.NoError(t, err) require.Error(t, pipelines.StartAll(context.Background(), &Host{Reporter: status.NewReporter(func(*componentstatus.InstanceID, *componentstatus.Event) {}, func(error) {})})) assert.Error(t, pipelines.ShutdownAll(context.Background(), status.NewNopStatusReporter())) }) } } } func TestStatusReportedOnStartupShutdown(t *testing.T) { t.Run("with_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, true) testStatusReportedOnStartupShutdown(t) }) t.Run("without_internal_telemetry", func(t *testing.T) { setObsConsumerGateForTest(t, false) testStatusReportedOnStartupShutdown(t) }) } func testStatusReportedOnStartupShutdown(t *testing.T) { rNoErr := &testNode{id: component.MustNewIDWithName("r_no_err", "1")} rStErr := &testNode{id: component.MustNewIDWithName("r_st_err", "1"), startErr: assert.AnError} rSdErr := &testNode{id: component.MustNewIDWithName("r_sd_err", "1"), shutdownErr: assert.AnError} eNoErr := &testNode{id: component.MustNewIDWithName("e_no_err", "1")} eStErr := &testNode{id: component.MustNewIDWithName("e_st_err", "1"), startErr: assert.AnError} eSdErr := &testNode{id: component.MustNewIDWithName("e_sd_err", "1"), shutdownErr: assert.AnError} instanceIDs := map[*testNode]*componentstatus.InstanceID{ rNoErr: componentstatus.NewInstanceID(rNoErr.id, component.KindReceiver), rStErr: componentstatus.NewInstanceID(rStErr.id, component.KindReceiver), rSdErr: componentstatus.NewInstanceID(rSdErr.id, component.KindReceiver), eNoErr: componentstatus.NewInstanceID(eNoErr.id, component.KindExporter), eStErr: componentstatus.NewInstanceID(eStErr.id, component.KindExporter), eSdErr: componentstatus.NewInstanceID(eSdErr.id, component.KindExporter), } // compare two maps of status events ignoring timestamp assertEqualStatuses := func(t *testing.T, evMap1, evMap2 map[*componentstatus.InstanceID][]*componentstatus.Event) { assert.Len(t, evMap2, len(evMap1)) for id, evts1 := range evMap1 { evts2 := evMap2[id] assert.Len(t, evts2, len(evts1)) for i := range evts1 { ev1 := evts1[i] ev2 := evts2[i] assert.Equal(t, ev1.Status(), ev2.Status()) assert.Equal(t, ev1.Err(), ev2.Err()) } } } for _, tt := range []struct { name string edge [2]*testNode expectedStatuses map[*componentstatus.InstanceID][]*componentstatus.Event startupErr error shutdownErr error }{ { name: "successful startup/shutdown", edge: [2]*testNode{rNoErr, eNoErr}, expectedStatuses: map[*componentstatus.InstanceID][]*componentstatus.Event{ instanceIDs[rNoErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, instanceIDs[eNoErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, }, }, { name: "early startup error", edge: [2]*testNode{rNoErr, eStErr}, expectedStatuses: map[*componentstatus.InstanceID][]*componentstatus.Event{ instanceIDs[eStErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewPermanentErrorEvent(assert.AnError), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, }, startupErr: assert.AnError, }, { name: "late startup error", edge: [2]*testNode{rStErr, eNoErr}, expectedStatuses: map[*componentstatus.InstanceID][]*componentstatus.Event{ instanceIDs[rStErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewPermanentErrorEvent(assert.AnError), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, instanceIDs[eNoErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, }, startupErr: assert.AnError, }, { name: "early shutdown error", edge: [2]*testNode{rSdErr, eNoErr}, expectedStatuses: map[*componentstatus.InstanceID][]*componentstatus.Event{ instanceIDs[rSdErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewPermanentErrorEvent(assert.AnError), }, instanceIDs[eNoErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, }, shutdownErr: assert.AnError, }, { name: "late shutdown error", edge: [2]*testNode{rNoErr, eSdErr}, expectedStatuses: map[*componentstatus.InstanceID][]*componentstatus.Event{ instanceIDs[rNoErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewEvent(componentstatus.StatusStopped), }, instanceIDs[eSdErr]: { componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusStopping), componentstatus.NewPermanentErrorEvent(assert.AnError), }, }, shutdownErr: assert.AnError, }, } { t.Run(tt.name, func(t *testing.T) { pg := &Graph{componentGraph: simple.NewDirectedGraph()} pg.telemetry = componenttest.NewNopTelemetrySettings() actualStatuses := make(map[*componentstatus.InstanceID][]*componentstatus.Event) rep := status.NewReporter(func(id *componentstatus.InstanceID, ev *componentstatus.Event) { actualStatuses[id] = append(actualStatuses[id], ev) }, func(error) { }) e0, e1 := tt.edge[0], tt.edge[1] pg.instanceIDs = map[int64]*componentstatus.InstanceID{ e0.ID(): instanceIDs[e0], e1.ID(): instanceIDs[e1], } pg.componentGraph.SetEdge(simple.Edge{F: e0, T: e1}) require.ErrorIs(t, pg.StartAll(context.Background(), &Host{Reporter: rep}), tt.startupErr) assert.Equal(t, tt.shutdownErr, pg.ShutdownAll(context.Background(), rep)) assertEqualStatuses(t, tt.expectedStatuses, actualStatuses) }) } } opentelemetry-collector-0.141.0/service/internal/graph/metadata.yaml000066400000000000000000000002521511331344600255560ustar00rootroot00000000000000type: graph github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: service codeowners: emeritus: - djaglowski opentelemetry-collector-0.141.0/service/internal/graph/obs_test.go000066400000000000000000000575571511331344600253070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/obsconsumer" "go.opentelemetry.io/collector/service/internal/testcomponents" "go.opentelemetry.io/collector/service/pipelines" ) func TestComponentInstrumentation(t *testing.T) { setObsConsumerGateForTest(t, true) // All IDs have a name to ensure the "otelcol.component.id" attribute is not just the type rcvrID := component.MustNewIDWithName("examplereceiver", "foo") procID := component.MustNewIDWithName("exampleprocessor", "bar") routerID := component.MustNewIDWithName("examplerouter", "baz") expRightID := component.MustNewIDWithName("exampleexporter", "right") expLeftID := component.MustNewIDWithName("exampleexporter", "left") tracesInID := pipeline.NewIDWithName(pipeline.SignalTraces, "in") tracesRightID := pipeline.NewIDWithName(pipeline.SignalTraces, "right") tracesLeftID := pipeline.NewIDWithName(pipeline.SignalTraces, "left") metricsInID := pipeline.NewIDWithName(pipeline.SignalMetrics, "in") metricsRightID := pipeline.NewIDWithName(pipeline.SignalMetrics, "right") metricsLeftID := pipeline.NewIDWithName(pipeline.SignalMetrics, "left") logsInID := pipeline.NewIDWithName(pipeline.SignalLogs, "in") logsRightID := pipeline.NewIDWithName(pipeline.SignalLogs, "right") logsLeftID := pipeline.NewIDWithName(pipeline.SignalLogs, "left") profilesInID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "in") profilesRightID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "right") profilesLeftID := pipeline.NewIDWithName(xpipeline.SignalProfiles, "left") ctx := context.Background() testTel := componenttest.NewTelemetry() set := Settings{ Telemetry: testTel.NewTelemetrySettings(), BuildInfo: component.NewDefaultBuildInfo(), ReceiverBuilder: builders.NewReceiver( map[component.ID]component.Config{ rcvrID: testcomponents.ExampleReceiverFactory.CreateDefaultConfig(), }, map[component.Type]receiver.Factory{ testcomponents.ExampleReceiverFactory.Type(): testcomponents.ExampleReceiverFactory, }, ), ProcessorBuilder: builders.NewProcessor( map[component.ID]component.Config{ procID: testcomponents.ExampleProcessorFactory.CreateDefaultConfig(), }, map[component.Type]processor.Factory{ testcomponents.ExampleProcessorFactory.Type(): testcomponents.ExampleProcessorFactory, }, ), ExporterBuilder: builders.NewExporter( map[component.ID]component.Config{ expRightID: testcomponents.ExampleExporterFactory.CreateDefaultConfig(), expLeftID: testcomponents.ExampleExporterFactory.CreateDefaultConfig(), }, map[component.Type]exporter.Factory{ testcomponents.ExampleExporterFactory.Type(): testcomponents.ExampleExporterFactory, }, ), ConnectorBuilder: builders.NewConnector( map[component.ID]component.Config{ routerID: testcomponents.ExampleRouterConfig{ Traces: &testcomponents.LeftRightConfig{ Right: tracesRightID, Left: tracesLeftID, }, Metrics: &testcomponents.LeftRightConfig{ Right: metricsRightID, Left: metricsLeftID, }, Logs: &testcomponents.LeftRightConfig{ Right: logsRightID, Left: logsLeftID, }, Profiles: &testcomponents.LeftRightConfig{ Right: profilesRightID, Left: profilesLeftID, }, }, }, map[component.Type]connector.Factory{ testcomponents.ExampleRouterFactory.Type(): testcomponents.ExampleRouterFactory, }, ), PipelineConfigs: pipelines.Config{ tracesInID: { Receivers: []component.ID{rcvrID}, Processors: []component.ID{procID}, Exporters: []component.ID{routerID}, }, tracesRightID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expRightID}, }, tracesLeftID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expLeftID}, }, metricsInID: { Receivers: []component.ID{rcvrID}, Processors: []component.ID{procID}, Exporters: []component.ID{routerID}, }, metricsRightID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expRightID}, }, metricsLeftID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expLeftID}, }, logsInID: { Receivers: []component.ID{rcvrID}, Processors: []component.ID{procID}, Exporters: []component.ID{routerID}, }, logsRightID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expRightID}, }, logsLeftID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expLeftID}, }, profilesInID: { Receivers: []component.ID{rcvrID}, Processors: []component.ID{procID}, Exporters: []component.ID{routerID}, }, profilesRightID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expRightID}, }, profilesLeftID: { Receivers: []component.ID{routerID}, Exporters: []component.ID{expLeftID}, }, }, } pg, err := Build(ctx, set) require.NoError(t, err) allReceivers := pg.getReceivers() assert.Len(t, pg.pipelines, len(set.PipelineConfigs)) // First 3 right, next 2 left tracesReceiver := allReceivers[pipeline.SignalTraces][rcvrID].(*testcomponents.ExampleReceiver) require.NoError(t, tracesReceiver.ConsumeTraces(ctx, testdata.GenerateTraces(3))) require.NoError(t, tracesReceiver.ConsumeTraces(ctx, testdata.GenerateTraces(2))) // First 5 right, next 4 left metricsReceiver := allReceivers[pipeline.SignalMetrics][rcvrID].(*testcomponents.ExampleReceiver) require.NoError(t, metricsReceiver.ConsumeMetrics(ctx, testdata.GenerateMetrics(5))) require.NoError(t, metricsReceiver.ConsumeMetrics(ctx, testdata.GenerateMetrics(4))) // First 7 right, next 6 left logsReceiver := allReceivers[pipeline.SignalLogs][rcvrID].(*testcomponents.ExampleReceiver) require.NoError(t, logsReceiver.ConsumeLogs(ctx, testdata.GenerateLogs(7))) require.NoError(t, logsReceiver.ConsumeLogs(ctx, testdata.GenerateLogs(6))) // First 9 right, next 8 left profilesReceiver := allReceivers[xpipeline.SignalProfiles][rcvrID].(*testcomponents.ExampleReceiver) require.NoError(t, profilesReceiver.ConsumeProfiles(ctx, testdata.GenerateProfiles(9))) require.NoError(t, profilesReceiver.ConsumeProfiles(ctx, testdata.GenerateProfiles(8))) // TODO fix metric name prefix delimiter expectedScopeMetrics := simpleScopeMetrics{ // Traces attribute.NewSet( attribute.String("otelcol.component.kind", "receiver"), attribute.String("otelcol.component.id", "examplereceiver/foo"), attribute.String("otelcol.signal", "traces"), ): simpleMetricMap{ "otelcol.receiver.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 5, }, "otelcol.receiver.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 866, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "processor"), attribute.String("otelcol.component.id", "exampleprocessor/bar"), attribute.String("otelcol.pipeline.id", "traces/in"), attribute.String("otelcol.signal", "traces"), ): simpleMetricMap{ "otelcol.processor.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 5, }, "otelcol.processor.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 5, }, "otelcol.processor.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 866, }, "otelcol.processor.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 866, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "connector"), attribute.String("otelcol.component.id", "examplerouter/baz"), attribute.String("otelcol.signal", "traces"), attribute.String("otelcol.signal.output", "traces"), ): simpleMetricMap{ "otelcol.connector.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 5, }, "otelcol.connector.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "traces/right"), ): 3, attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "traces/left"), ): 2, }, "otelcol.connector.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 866, }, "otelcol.connector.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "traces/right"), ): 528, attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "traces/left"), ): 338, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/right"), attribute.String("otelcol.signal", "traces"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 3, }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 528, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/left"), attribute.String("otelcol.signal", "traces"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 2, }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 338, }, }, // Metrics attribute.NewSet( attribute.String("otelcol.component.kind", "receiver"), attribute.String("otelcol.component.id", "examplereceiver/foo"), attribute.String("otelcol.signal", "metrics"), ): simpleMetricMap{ "otelcol.receiver.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 18, // GenerateMetrics(9) produces 18 data points }, "otelcol.receiver.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1741, // GenerateMetrics(9) produces 18 data points }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "processor"), attribute.String("otelcol.component.id", "exampleprocessor/bar"), attribute.String("otelcol.pipeline.id", "metrics/in"), attribute.String("otelcol.signal", "metrics"), ): simpleMetricMap{ "otelcol.processor.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 18, // GenerateMetrics(9) produces 18 data points }, "otelcol.processor.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 18, // GenerateMetrics(9) produces 18 data points }, "otelcol.processor.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1741, // GenerateMetrics(9) produces 18 data points }, "otelcol.processor.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1741, // GenerateMetrics(9) produces 18 data points }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "connector"), attribute.String("otelcol.component.id", "examplerouter/baz"), attribute.String("otelcol.signal", "metrics"), attribute.String("otelcol.signal.output", "metrics"), ): simpleMetricMap{ "otelcol.connector.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 18, // GenerateMetrics(9) produces 18 data points }, "otelcol.connector.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "metrics/right"), ): 10, // GenerateMetrics(5) produces 10 data points attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "metrics/left"), ): 8, // GenerateMetrics(4) produces 8 data points }, "otelcol.connector.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1741, // GenerateMetrics(9) produces 18 data points }, "otelcol.connector.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "metrics/right"), ): 1035, // GenerateMetrics(5) produces 10 data points attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "metrics/left"), ): 706, // GenerateMetrics(4) produces 8 data points }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/right"), attribute.String("otelcol.signal", "metrics"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 10, // GenerateMetrics(5) produces 10 data points }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1035, // GenerateMetrics(9) produces 18 data points }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/left"), attribute.String("otelcol.signal", "metrics"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 8, // GenerateMetrics(4) produces 8 data points }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 706, // GenerateMetrics(9) produces 18 data points }, }, // Logs attribute.NewSet( attribute.String("otelcol.component.kind", "receiver"), attribute.String("otelcol.component.id", "examplereceiver/foo"), attribute.String("otelcol.signal", "logs"), ): simpleMetricMap{ "otelcol.receiver.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 13, }, "otelcol.receiver.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1363, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "processor"), attribute.String("otelcol.component.id", "exampleprocessor/bar"), attribute.String("otelcol.pipeline.id", "logs/in"), attribute.String("otelcol.signal", "logs"), ): simpleMetricMap{ "otelcol.processor.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 13, }, "otelcol.processor.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 13, }, "otelcol.processor.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1363, }, "otelcol.processor.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1363, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "connector"), attribute.String("otelcol.component.id", "examplerouter/baz"), attribute.String("otelcol.signal", "logs"), attribute.String("otelcol.signal.output", "logs"), ): simpleMetricMap{ "otelcol.connector.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 13, }, "otelcol.connector.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "logs/right"), ): 7, attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "logs/left"), ): 6, }, "otelcol.connector.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1363, }, "otelcol.connector.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "logs/right"), ): 737, attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "logs/left"), ): 626, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/right"), attribute.String("otelcol.signal", "logs"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 7, }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 737, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/left"), attribute.String("otelcol.signal", "logs"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 6, }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 626, }, }, // Profiles attribute.NewSet( attribute.String("otelcol.component.kind", "receiver"), attribute.String("otelcol.component.id", "examplereceiver/foo"), attribute.String("otelcol.signal", "profiles"), ): simpleMetricMap{ "otelcol.receiver.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 17, }, "otelcol.receiver.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1118, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "processor"), attribute.String("otelcol.component.id", "exampleprocessor/bar"), attribute.String("otelcol.pipeline.id", "profiles/in"), attribute.String("otelcol.signal", "profiles"), ): simpleMetricMap{ "otelcol.processor.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 17, }, "otelcol.processor.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 17, }, "otelcol.processor.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1118, }, "otelcol.processor.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1118, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "connector"), attribute.String("otelcol.component.id", "examplerouter/baz"), attribute.String("otelcol.signal", "profiles"), attribute.String("otelcol.signal.output", "profiles"), ): simpleMetricMap{ "otelcol.connector.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 17, }, "otelcol.connector.produced.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "profiles/right"), ): 9, attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "profiles/left"), ): 8, }, "otelcol.connector.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 1118, }, "otelcol.connector.produced.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "profiles/right"), ): 587, attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), attribute.String("otelcol.pipeline.id", "profiles/left"), ): 531, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/right"), attribute.String("otelcol.signal", "profiles"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 9, }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 587, }, }, attribute.NewSet( attribute.String("otelcol.component.kind", "exporter"), attribute.String("otelcol.component.id", "exampleexporter/left"), attribute.String("otelcol.signal", "profiles"), ): simpleMetricMap{ "otelcol.exporter.consumed.items": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 8, }, "otelcol.exporter.consumed.size": simpleMetric{ attribute.NewSet( attribute.String(obsconsumer.ComponentOutcome, "success"), ): 531, }, }, } // Verify telemetry was properly emitted by components var rm metricdata.ResourceMetrics require.NoError(t, testTel.Reader.Collect(ctx, &rm)) require.NotNil(t, rm) require.NotNil(t, rm.ScopeMetrics) assert.Len(t, rm.ScopeMetrics, len(expectedScopeMetrics)) for _, actualScopeMetrics := range rm.ScopeMetrics { expectedScopeMetrics, ok := expectedScopeMetrics[actualScopeMetrics.Scope.Attributes] require.True(t, ok) for _, actualMetric := range actualScopeMetrics.Metrics { expectedMetric, ok := expectedScopeMetrics[actualMetric.Name] require.True(t, ok) for _, actualPoint := range actualMetric.Data.(metricdata.Sum[int64]).DataPoints { expectedPoint, ok := expectedMetric[actualPoint.Attributes] require.True(t, ok) assert.Equal(t, int64(expectedPoint), actualPoint.Value) } } } assert.NoError(t, testTel.Shutdown(ctx)) } // map[dataPointAttrs]value type simpleMetric map[attribute.Set]int // map[metricName]simpleMetric type simpleMetricMap map[string]simpleMetric // map[scopeAttrs]simpleMetricMap type simpleScopeMetrics map[attribute.Set]simpleMetricMap opentelemetry-collector-0.141.0/service/internal/graph/package_test.go000066400000000000000000000003061511331344600260730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/internal/graph/processor.go000066400000000000000000000101401511331344600254550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/service/internal/attribute" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/componentattribute" "go.opentelemetry.io/collector/service/internal/metadata" "go.opentelemetry.io/collector/service/internal/obsconsumer" "go.opentelemetry.io/collector/service/internal/refconsumer" ) var _ consumerNode = (*processorNode)(nil) // Every processor instance is unique to one pipeline. // Therefore, nodeID is derived from "pipeline ID" and "component ID". type processorNode struct { attribute.Attributes componentID component.ID pipelineID pipeline.ID component.Component consumer baseConsumer } func newProcessorNode(pipelineID pipeline.ID, procID component.ID) *processorNode { return &processorNode{ Attributes: attribute.Processor(pipelineID, procID), componentID: procID, pipelineID: pipelineID, } } func (n *processorNode) getConsumer() baseConsumer { return n.consumer } func (n *processorNode) buildComponent(ctx context.Context, tel component.TelemetrySettings, info component.BuildInfo, builder *builders.ProcessorBuilder, next baseConsumer, ) error { set := processor.Settings{ ID: n.componentID, TelemetrySettings: componentattribute.TelemetrySettingsWithAttributes(tel, *n.Set()), BuildInfo: info, } tb, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return err } producedSettings := obsconsumer.Settings{ ItemCounter: tb.ProcessorProducedItems, SizeCounter: tb.ProcessorProducedSize, Logger: set.Logger, } consumedSettings := obsconsumer.Settings{ ItemCounter: tb.ProcessorConsumedItems, SizeCounter: tb.ProcessorConsumedSize, Logger: set.Logger, } switch n.pipelineID.Signal() { case pipeline.SignalTraces: n.Component, err = builder.CreateTraces(ctx, set, obsconsumer.NewTraces(next.(consumer.Traces), producedSettings), ) if err != nil { return fmt.Errorf("failed to create %q processor, in pipeline %q: %w", set.ID, n.pipelineID.String(), err) } n.consumer = obsconsumer.NewTraces(n.Component.(consumer.Traces), consumedSettings) n.consumer = refconsumer.NewTraces(n.consumer.(consumer.Traces)) case pipeline.SignalMetrics: n.Component, err = builder.CreateMetrics(ctx, set, obsconsumer.NewMetrics(next.(consumer.Metrics), producedSettings)) if err != nil { return fmt.Errorf("failed to create %q processor, in pipeline %q: %w", set.ID, n.pipelineID.String(), err) } n.consumer = obsconsumer.NewMetrics(n.Component.(consumer.Metrics), consumedSettings) n.consumer = refconsumer.NewMetrics(n.consumer.(consumer.Metrics)) case pipeline.SignalLogs: n.Component, err = builder.CreateLogs(ctx, set, obsconsumer.NewLogs(next.(consumer.Logs), producedSettings)) if err != nil { return fmt.Errorf("failed to create %q processor, in pipeline %q: %w", set.ID, n.pipelineID.String(), err) } n.consumer = obsconsumer.NewLogs(n.Component.(consumer.Logs), consumedSettings) n.consumer = refconsumer.NewLogs(n.consumer.(consumer.Logs)) case xpipeline.SignalProfiles: n.Component, err = builder.CreateProfiles(ctx, set, obsconsumer.NewProfiles(next.(xconsumer.Profiles), producedSettings)) if err != nil { return fmt.Errorf("failed to create %q processor, in pipeline %q: %w", set.ID, n.pipelineID.String(), err) } n.consumer = obsconsumer.NewProfiles(n.Component.(xconsumer.Profiles), consumedSettings) n.consumer = refconsumer.NewProfiles(n.consumer.(xconsumer.Profiles)) default: return fmt.Errorf("error creating processor %q in pipeline %q, data type %q is not supported", set.ID, n.pipelineID.String(), n.pipelineID.Signal()) } return nil } opentelemetry-collector-0.141.0/service/internal/graph/receiver.go000066400000000000000000000065211511331344600252520ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "context" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/fanoutconsumer" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service/internal/attribute" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/componentattribute" "go.opentelemetry.io/collector/service/internal/metadata" "go.opentelemetry.io/collector/service/internal/obsconsumer" ) // A receiver instance can be shared by multiple pipelines of the same type. // Therefore, nodeID is derived from "pipeline type" and "component ID". type receiverNode struct { attribute.Attributes componentID component.ID pipelineType pipeline.Signal component.Component } func newReceiverNode(pipelineType pipeline.Signal, recvID component.ID) *receiverNode { return &receiverNode{ Attributes: attribute.Receiver(pipelineType, recvID), componentID: recvID, pipelineType: pipelineType, } } func (n *receiverNode) buildComponent(ctx context.Context, tel component.TelemetrySettings, info component.BuildInfo, builder *builders.ReceiverBuilder, nexts []baseConsumer, ) error { set := receiver.Settings{ ID: n.componentID, TelemetrySettings: componentattribute.TelemetrySettingsWithAttributes(tel, *n.Set()), BuildInfo: info, } tb, err := metadata.NewTelemetryBuilder(set.TelemetrySettings) if err != nil { return err } producedSettings := obsconsumer.Settings{ ItemCounter: tb.ReceiverProducedItems, SizeCounter: tb.ReceiverProducedSize, Logger: set.Logger, } switch n.pipelineType { case pipeline.SignalTraces: var consumers []consumer.Traces for _, next := range nexts { consumers = append(consumers, next.(consumer.Traces)) } n.Component, err = builder.CreateTraces(ctx, set, obsconsumer.NewTraces(fanoutconsumer.NewTraces(consumers), producedSettings), ) case pipeline.SignalMetrics: var consumers []consumer.Metrics for _, next := range nexts { consumers = append(consumers, next.(consumer.Metrics)) } n.Component, err = builder.CreateMetrics(ctx, set, obsconsumer.NewMetrics(fanoutconsumer.NewMetrics(consumers), producedSettings)) case pipeline.SignalLogs: var consumers []consumer.Logs for _, next := range nexts { consumers = append(consumers, next.(consumer.Logs)) } n.Component, err = builder.CreateLogs(ctx, set, obsconsumer.NewLogs(fanoutconsumer.NewLogs(consumers), producedSettings)) case xpipeline.SignalProfiles: var consumers []xconsumer.Profiles for _, next := range nexts { consumers = append(consumers, next.(xconsumer.Profiles)) } n.Component, err = builder.CreateProfiles(ctx, set, obsconsumer.NewProfiles(fanoutconsumer.NewProfiles(consumers), producedSettings)) default: return fmt.Errorf("error creating receiver %q for data type %q is not supported", set.ID, n.pipelineType) } if err != nil { return fmt.Errorf("failed to create %q receiver for data type %q: %w", set.ID, n.pipelineType, err) } return nil } opentelemetry-collector-0.141.0/service/internal/graph/util_test.go000066400000000000000000000301301511331344600254530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph import ( "context" "errors" "hash/fnv" "sync" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/xprocessor" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/xreceiver" "go.opentelemetry.io/collector/service/pipelines" ) var _ component.Component = (*testNode)(nil) type testNode struct { id component.ID startErr error shutdownErr error } // ID satisfies the graph.Node interface, allowing // testNode to be used in a simple.DirectedGraph func (n *testNode) ID() int64 { h := fnv.New64a() h.Write([]byte(n.id.String())) // The graph identifies nodes by an int64 ID, but fnv gives us a uint64. // It is safe to cast because the meaning of the number is irrelevant. // We only care that each node has a unique 64 bit ID, which is unaltered by this cast. return int64(h.Sum64()) // #nosec G115 } func (n *testNode) Start(ctx context.Context, _ component.Host) error { if n.startErr != nil { return n.startErr } if cwo, ok := ctx.(*contextWithOrder); ok { cwo.record(n.id) } return nil } func (n *testNode) Shutdown(ctx context.Context) error { if n.shutdownErr != nil { return n.shutdownErr } if cwo, ok := ctx.(*contextWithOrder); ok { cwo.record(n.id) } return nil } type contextWithOrder struct { context.Context sync.Mutex next int order map[component.ID]int } func (c *contextWithOrder) record(id component.ID) { c.Lock() c.order[id] = c.next c.next++ c.Unlock() } func (g *Graph) getReceivers() map[pipeline.Signal]map[component.ID]component.Component { receiversMap := make(map[pipeline.Signal]map[component.ID]component.Component) receiversMap[pipeline.SignalTraces] = make(map[component.ID]component.Component) receiversMap[pipeline.SignalMetrics] = make(map[component.ID]component.Component) receiversMap[pipeline.SignalLogs] = make(map[component.ID]component.Component) receiversMap[xpipeline.SignalProfiles] = make(map[component.ID]component.Component) for _, pg := range g.pipelines { for _, rcvrNode := range pg.receivers { rcvrOrConnNode := g.componentGraph.Node(rcvrNode.ID()) rcvrNode, ok := rcvrOrConnNode.(*receiverNode) if !ok { continue } receiversMap[rcvrNode.pipelineType][rcvrNode.componentID] = rcvrNode.Component } } return receiversMap } // Calculates the expected number of receiver and exporter instances in the specified pipeline. // // Expect one instance of each receiver and exporter, unless it is a connector. // // For Connectors: // - Let E equal the number of pipeline types in which the connector is used as an exporter. // - Let R equal the number of pipeline types in which the connector is used as a receiver. // // Within the graph as a whole, we expect E*R instances, i.e. one per combination of data types. // // However, within an individual pipeline, we expect: // - E instances of the connector as a receiver. // - R instances of the connector as an exporter. func expectedInstances(m pipelines.Config, pID pipeline.ID) (int, int) { exConnectorType := component.MustNewType("exampleconnector") var r, e int for _, rID := range m[pID].Receivers { if rID.Type() != exConnectorType { r++ continue } // This is a connector. Count the pipeline types where it is an exporter. typeMap := map[pipeline.Signal]bool{} for pID, pCfg := range m { for _, eID := range pCfg.Exporters { if eID == rID { typeMap[pID.Signal()] = true } } } r += len(typeMap) } for _, eID := range m[pID].Exporters { if eID.Type() != exConnectorType { e++ continue } // This is a connector. Count the pipeline types where it is a receiver. typeMap := map[pipeline.Signal]bool{} for pID, pCfg := range m { for _, rID := range pCfg.Receivers { if rID == eID { typeMap[pID.Signal()] = true } } } e += len(typeMap) } return r, e } func newBadReceiverFactory() receiver.Factory { return receiver.NewFactory(component.MustNewType("bf"), func() component.Config { return &struct{}{} }) } func newBadProcessorFactory() processor.Factory { return processor.NewFactory(component.MustNewType("bf"), func() component.Config { return &struct{}{} }) } func newBadExporterFactory() exporter.Factory { return exporter.NewFactory(component.MustNewType("bf"), func() component.Config { return &struct{}{} }) } func newBadConnectorFactory() connector.Factory { return connector.NewFactory(component.MustNewType("bf"), func() component.Config { return &struct{}{} }) } func newErrReceiverFactory() receiver.Factory { return xreceiver.NewFactory(component.MustNewType("err"), func() component.Config { return &struct{}{} }, xreceiver.WithTraces(func(context.Context, receiver.Settings, component.Config, consumer.Traces) (receiver.Traces, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xreceiver.WithLogs(func(context.Context, receiver.Settings, component.Config, consumer.Logs) (receiver.Logs, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xreceiver.WithMetrics(func(context.Context, receiver.Settings, component.Config, consumer.Metrics) (receiver.Metrics, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xreceiver.WithProfiles(func(context.Context, receiver.Settings, component.Config, xconsumer.Profiles) (xreceiver.Profiles, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), ) } func newErrProcessorFactory() processor.Factory { return xprocessor.NewFactory(component.MustNewType("err"), func() component.Config { return &struct{}{} }, xprocessor.WithTraces(func(context.Context, processor.Settings, component.Config, consumer.Traces) (processor.Traces, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xprocessor.WithLogs(func(context.Context, processor.Settings, component.Config, consumer.Logs) (processor.Logs, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xprocessor.WithMetrics(func(context.Context, processor.Settings, component.Config, consumer.Metrics) (processor.Metrics, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xprocessor.WithProfiles(func(context.Context, processor.Settings, component.Config, xconsumer.Profiles) (xprocessor.Profiles, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), ) } func newErrExporterFactory() exporter.Factory { return xexporter.NewFactory(component.MustNewType("err"), func() component.Config { return &struct{}{} }, xexporter.WithTraces(func(context.Context, exporter.Settings, component.Config) (exporter.Traces, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xexporter.WithLogs(func(context.Context, exporter.Settings, component.Config) (exporter.Logs, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xexporter.WithMetrics(func(context.Context, exporter.Settings, component.Config) (exporter.Metrics, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), xexporter.WithProfiles(func(context.Context, exporter.Settings, component.Config) (xexporter.Profiles, error) { return &errComponent{}, nil }, component.StabilityLevelUndefined), ) } func newErrConnectorFactory() connector.Factory { return xconnector.NewFactory(component.MustNewType("err"), func() component.Config { return &struct{}{} }, xconnector.WithTracesToTraces(func(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Traces, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithTracesToMetrics(func(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Traces, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithTracesToLogs(func(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Traces, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithTracesToProfiles(func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Traces, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithMetricsToTraces(func(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Metrics, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithMetricsToMetrics(func(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Metrics, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithMetricsToLogs(func(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Metrics, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithMetricsToProfiles(func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Metrics, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithLogsToTraces(func(context.Context, connector.Settings, component.Config, consumer.Traces) (connector.Logs, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithLogsToMetrics(func(context.Context, connector.Settings, component.Config, consumer.Metrics) (connector.Logs, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithLogsToLogs(func(context.Context, connector.Settings, component.Config, consumer.Logs) (connector.Logs, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithLogsToProfiles(func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (connector.Logs, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithProfilesToTraces(func(context.Context, connector.Settings, component.Config, consumer.Traces) (xconnector.Profiles, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithProfilesToMetrics(func(context.Context, connector.Settings, component.Config, consumer.Metrics) (xconnector.Profiles, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithProfilesToLogs(func(context.Context, connector.Settings, component.Config, consumer.Logs) (xconnector.Profiles, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), xconnector.WithProfilesToProfiles(func(context.Context, connector.Settings, component.Config, xconsumer.Profiles) (xconnector.Profiles, error) { return &errComponent{}, nil }, component.StabilityLevelUnmaintained), ) } type errComponent struct { consumertest.Consumer } func (e errComponent) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: false} } func (e errComponent) Start(context.Context, component.Host) error { return errors.New("my error") } func (e errComponent) Shutdown(context.Context) error { return errors.New("my error") } func setObsConsumerGateForTest(t *testing.T, enabled bool) { initial := telemetry.NewPipelineTelemetryGate.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), enabled)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) } opentelemetry-collector-0.141.0/service/internal/graph/zpages.go000066400000000000000000000046651511331344600247460ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package graph // import "go.opentelemetry.io/collector/service/internal/graph" import ( "net/http" "sort" "go.opentelemetry.io/collector/service/internal/zpages" ) const ( // URL Params zPipelineName = "pipelinenamez" zComponentName = "componentnamez" zComponentKind = "componentkindz" ) func (g *Graph) HandleZPages(w http.ResponseWriter, r *http.Request) { qValues := r.URL.Query() pipelineName := qValues.Get(zPipelineName) componentName := qValues.Get(zComponentName) componentKind := qValues.Get(zComponentKind) w.Header().Set("Content-Type", "text/html; charset=utf-8") zpages.WriteHTMLPageHeader(w, zpages.HeaderData{Title: "builtPipelines"}) sumData := zpages.SummaryPipelinesTableData{} sumData.Rows = make([]zpages.SummaryPipelinesTableRowData, 0, len(g.pipelines)) for c, p := range g.pipelines { recvIDs := make([]string, 0, len(p.receivers)) for _, c := range p.receivers { switch n := c.(type) { case *receiverNode: recvIDs = append(recvIDs, n.componentID.String()) case *connectorNode: recvIDs = append(recvIDs, n.componentID.String()+" (connector)") } } procIDs := make([]string, 0, len(p.processors)) for _, c := range p.processors { procIDs = append(procIDs, c.(*processorNode).componentID.String()) } exprIDs := make([]string, 0, len(p.exporters)) for _, c := range p.exporters { switch n := c.(type) { case *exporterNode: exprIDs = append(exprIDs, n.componentID.String()) case *connectorNode: exprIDs = append(exprIDs, n.componentID.String()+" (connector)") } } sumData.Rows = append(sumData.Rows, zpages.SummaryPipelinesTableRowData{ FullName: c.String(), InputType: c.Signal().String(), MutatesData: p.capabilitiesNode.getConsumer().Capabilities().MutatesData, Receivers: recvIDs, Processors: procIDs, Exporters: exprIDs, }) } sort.Slice(sumData.Rows, func(i, j int) bool { return sumData.Rows[i].FullName < sumData.Rows[j].FullName }) zpages.WriteHTMLPipelinesSummaryTable(w, sumData) if pipelineName != "" && componentName != "" && componentKind != "" { fullName := componentName if componentKind == "processor" { fullName = pipelineName + "/" + componentName } zpages.WriteHTMLComponentHeader(w, zpages.ComponentHeaderData{ Name: componentKind + ": " + fullName, }) // TODO: Add config + status info. } zpages.WriteHTMLPageFooter(w) } opentelemetry-collector-0.141.0/service/internal/metadata/000077500000000000000000000000001511331344600235725ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/metadata/generated_telemetry.go000066400000000000000000000265251511331344600301630ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "context" "errors" "sync" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/metric/embedded" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/collector/component" ) func Meter(settings component.TelemetrySettings) metric.Meter { return settings.MeterProvider.Meter("go.opentelemetry.io/collector/service") } func Tracer(settings component.TelemetrySettings) trace.Tracer { return settings.TracerProvider.Tracer("go.opentelemetry.io/collector/service") } // TelemetryBuilder provides an interface for components to report telemetry // as defined in metadata and user config. type TelemetryBuilder struct { meter metric.Meter mu sync.Mutex registrations []metric.Registration ConnectorConsumedItems metric.Int64Counter ConnectorConsumedSize metric.Int64Counter ConnectorProducedItems metric.Int64Counter ConnectorProducedSize metric.Int64Counter ExporterConsumedItems metric.Int64Counter ExporterConsumedSize metric.Int64Counter ProcessCPUSeconds metric.Float64ObservableCounter ProcessMemoryRss metric.Int64ObservableGauge ProcessRuntimeHeapAllocBytes metric.Int64ObservableGauge ProcessRuntimeTotalAllocBytes metric.Int64ObservableCounter ProcessRuntimeTotalSysMemoryBytes metric.Int64ObservableGauge ProcessUptime metric.Float64ObservableCounter ProcessorConsumedItems metric.Int64Counter ProcessorConsumedSize metric.Int64Counter ProcessorProducedItems metric.Int64Counter ProcessorProducedSize metric.Int64Counter ReceiverProducedItems metric.Int64Counter ReceiverProducedSize metric.Int64Counter } // TelemetryBuilderOption applies changes to default builder. type TelemetryBuilderOption interface { apply(*TelemetryBuilder) } type telemetryBuilderOptionFunc func(mb *TelemetryBuilder) func (tbof telemetryBuilderOptionFunc) apply(mb *TelemetryBuilder) { tbof(mb) } // RegisterProcessCPUSecondsCallback sets callback for observable ProcessCPUSeconds metric. func (builder *TelemetryBuilder) RegisterProcessCPUSecondsCallback(cb metric.Float64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerFloat64{inst: builder.ProcessCPUSeconds, obs: o}) return nil }, builder.ProcessCPUSeconds) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterProcessMemoryRssCallback sets callback for observable ProcessMemoryRss metric. func (builder *TelemetryBuilder) RegisterProcessMemoryRssCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ProcessMemoryRss, obs: o}) return nil }, builder.ProcessMemoryRss) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterProcessRuntimeHeapAllocBytesCallback sets callback for observable ProcessRuntimeHeapAllocBytes metric. func (builder *TelemetryBuilder) RegisterProcessRuntimeHeapAllocBytesCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ProcessRuntimeHeapAllocBytes, obs: o}) return nil }, builder.ProcessRuntimeHeapAllocBytes) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterProcessRuntimeTotalAllocBytesCallback sets callback for observable ProcessRuntimeTotalAllocBytes metric. func (builder *TelemetryBuilder) RegisterProcessRuntimeTotalAllocBytesCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ProcessRuntimeTotalAllocBytes, obs: o}) return nil }, builder.ProcessRuntimeTotalAllocBytes) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterProcessRuntimeTotalSysMemoryBytesCallback sets callback for observable ProcessRuntimeTotalSysMemoryBytes metric. func (builder *TelemetryBuilder) RegisterProcessRuntimeTotalSysMemoryBytesCallback(cb metric.Int64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerInt64{inst: builder.ProcessRuntimeTotalSysMemoryBytes, obs: o}) return nil }, builder.ProcessRuntimeTotalSysMemoryBytes) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } // RegisterProcessUptimeCallback sets callback for observable ProcessUptime metric. func (builder *TelemetryBuilder) RegisterProcessUptimeCallback(cb metric.Float64Callback) error { reg, err := builder.meter.RegisterCallback(func(ctx context.Context, o metric.Observer) error { cb(ctx, &observerFloat64{inst: builder.ProcessUptime, obs: o}) return nil }, builder.ProcessUptime) if err != nil { return err } builder.mu.Lock() defer builder.mu.Unlock() builder.registrations = append(builder.registrations, reg) return nil } type observerInt64 struct { embedded.Int64Observer inst metric.Int64Observable obs metric.Observer } func (oi *observerInt64) Observe(value int64, opts ...metric.ObserveOption) { oi.obs.ObserveInt64(oi.inst, value, opts...) } type observerFloat64 struct { embedded.Float64Observer inst metric.Float64Observable obs metric.Observer } func (oi *observerFloat64) Observe(value float64, opts ...metric.ObserveOption) { oi.obs.ObserveFloat64(oi.inst, value, opts...) } // Shutdown unregister all registered callbacks for async instruments. func (builder *TelemetryBuilder) Shutdown() { builder.mu.Lock() defer builder.mu.Unlock() for _, reg := range builder.registrations { reg.Unregister() } } // NewTelemetryBuilder provides a struct with methods to update all internal telemetry // for a component func NewTelemetryBuilder(settings component.TelemetrySettings, options ...TelemetryBuilderOption) (*TelemetryBuilder, error) { builder := TelemetryBuilder{} for _, op := range options { op.apply(&builder) } builder.meter = Meter(settings) var err, errs error builder.ConnectorConsumedItems, err = builder.meter.Int64Counter( "otelcol.connector.consumed.items", metric.WithDescription("Number of items passed to the connector. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ConnectorConsumedSize, err = builder.meter.Int64Counter( "otelcol.connector.consumed.size", metric.WithDescription("Size of items passed to the connector, based on ProtoMarshaler.Sizer. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ConnectorProducedItems, err = builder.meter.Int64Counter( "otelcol.connector.produced.items", metric.WithDescription("Number of items emitted from the connector. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ConnectorProducedSize, err = builder.meter.Int64Counter( "otelcol.connector.produced.size", metric.WithDescription("Size of items emitted from the connector, based on ProtoMarshaler.Sizer. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ExporterConsumedItems, err = builder.meter.Int64Counter( "otelcol.exporter.consumed.items", metric.WithDescription("Number of items passed to the exporter. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ExporterConsumedSize, err = builder.meter.Int64Counter( "otelcol.exporter.consumed.size", metric.WithDescription("Size of items passed to the exporter, based on ProtoMarshaler.Sizer. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ProcessCPUSeconds, err = builder.meter.Float64ObservableCounter( "otelcol_process_cpu_seconds", metric.WithDescription("Total CPU user and system time in seconds [Alpha]"), metric.WithUnit("s"), ) errs = errors.Join(errs, err) builder.ProcessMemoryRss, err = builder.meter.Int64ObservableGauge( "otelcol_process_memory_rss", metric.WithDescription("Total physical memory (resident set size) [Alpha]"), metric.WithUnit("By"), ) errs = errors.Join(errs, err) builder.ProcessRuntimeHeapAllocBytes, err = builder.meter.Int64ObservableGauge( "otelcol_process_runtime_heap_alloc_bytes", metric.WithDescription("Bytes of allocated heap objects (see 'go doc runtime.MemStats.HeapAlloc') [Alpha]"), metric.WithUnit("By"), ) errs = errors.Join(errs, err) builder.ProcessRuntimeTotalAllocBytes, err = builder.meter.Int64ObservableCounter( "otelcol_process_runtime_total_alloc_bytes", metric.WithDescription("Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') [Alpha]"), metric.WithUnit("By"), ) errs = errors.Join(errs, err) builder.ProcessRuntimeTotalSysMemoryBytes, err = builder.meter.Int64ObservableGauge( "otelcol_process_runtime_total_sys_memory_bytes", metric.WithDescription("Total bytes of memory obtained from the OS (see 'go doc runtime.MemStats.Sys') [Alpha]"), metric.WithUnit("By"), ) errs = errors.Join(errs, err) builder.ProcessUptime, err = builder.meter.Float64ObservableCounter( "otelcol_process_uptime", metric.WithDescription("Uptime of the process [Alpha]"), metric.WithUnit("s"), ) errs = errors.Join(errs, err) builder.ProcessorConsumedItems, err = builder.meter.Int64Counter( "otelcol.processor.consumed.items", metric.WithDescription("Number of items passed to the processor. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ProcessorConsumedSize, err = builder.meter.Int64Counter( "otelcol.processor.consumed.size", metric.WithDescription("Size of items passed to the processor, based on ProtoMarshaler.Sizer. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ProcessorProducedItems, err = builder.meter.Int64Counter( "otelcol.processor.produced.items", metric.WithDescription("Number of items emitted from the processor. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ProcessorProducedSize, err = builder.meter.Int64Counter( "otelcol.processor.produced.size", metric.WithDescription("Size of items emitted from the processor, based on ProtoMarshaler.Sizer. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ReceiverProducedItems, err = builder.meter.Int64Counter( "otelcol.receiver.produced.items", metric.WithDescription("Number of items emitted from the receiver. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) builder.ReceiverProducedSize, err = builder.meter.Int64Counter( "otelcol.receiver.produced.size", metric.WithDescription("Size of items emitted from the receiver, based on ProtoMarshaler.Sizer. [Development]"), metric.WithUnit("{item}"), ) errs = errors.Join(errs, err) return &builder, errs } opentelemetry-collector-0.141.0/service/internal/metadata/generated_telemetry_test.go000066400000000000000000000034411511331344600312120ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadata import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" embeddedmetric "go.opentelemetry.io/otel/metric/embedded" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" embeddedtrace "go.opentelemetry.io/otel/trace/embedded" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" ) type mockMeter struct { noopmetric.Meter name string } type mockMeterProvider struct { embeddedmetric.MeterProvider } func (m mockMeterProvider) Meter(name string, opts ...metric.MeterOption) metric.Meter { return mockMeter{name: name} } type mockTracer struct { nooptrace.Tracer name string } type mockTracerProvider struct { embeddedtrace.TracerProvider } func (m mockTracerProvider) Tracer(name string, opts ...trace.TracerOption) trace.Tracer { return mockTracer{name: name} } func TestProviders(t *testing.T) { set := component.TelemetrySettings{ MeterProvider: mockMeterProvider{}, TracerProvider: mockTracerProvider{}, } meter := Meter(set) if m, ok := meter.(mockMeter); ok { require.Equal(t, "go.opentelemetry.io/collector/service", m.name) } else { require.Fail(t, "returned Meter not mockMeter") } tracer := Tracer(set) if m, ok := tracer.(mockTracer); ok { require.Equal(t, "go.opentelemetry.io/collector/service", m.name) } else { require.Fail(t, "returned Meter not mockTracer") } } func TestNewTelemetryBuilder(t *testing.T) { set := componenttest.NewNopTelemetrySettings() applied := false _, err := NewTelemetryBuilder(set, telemetryBuilderOptionFunc(func(b *TelemetryBuilder) { applied = true })) require.NoError(t, err) require.True(t, applied) } opentelemetry-collector-0.141.0/service/internal/metadatatest/000077500000000000000000000000001511331344600244725ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/metadatatest/generated_telemetrytest.go000066400000000000000000000255771511331344600317710ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" ) func AssertEqualConnectorConsumedItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.connector.consumed.items", Description: "Number of items passed to the connector. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.connector.consumed.items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualConnectorConsumedSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.connector.consumed.size", Description: "Size of items passed to the connector, based on ProtoMarshaler.Sizer. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.connector.consumed.size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualConnectorProducedItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.connector.produced.items", Description: "Number of items emitted from the connector. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.connector.produced.items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualConnectorProducedSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.connector.produced.size", Description: "Size of items emitted from the connector, based on ProtoMarshaler.Sizer. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.connector.produced.size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterConsumedItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.exporter.consumed.items", Description: "Number of items passed to the exporter. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.exporter.consumed.items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualExporterConsumedSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.exporter.consumed.size", Description: "Size of items passed to the exporter, based on ProtoMarshaler.Sizer. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.exporter.consumed.size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessCPUSeconds(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[float64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_process_cpu_seconds", Description: "Total CPU user and system time in seconds [Alpha]", Unit: "s", Data: metricdata.Sum[float64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_process_cpu_seconds") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessMemoryRss(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_process_memory_rss", Description: "Total physical memory (resident set size) [Alpha]", Unit: "By", Data: metricdata.Gauge[int64]{ DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_process_memory_rss") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessRuntimeHeapAllocBytes(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_process_runtime_heap_alloc_bytes", Description: "Bytes of allocated heap objects (see 'go doc runtime.MemStats.HeapAlloc') [Alpha]", Unit: "By", Data: metricdata.Gauge[int64]{ DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_process_runtime_heap_alloc_bytes") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessRuntimeTotalAllocBytes(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_process_runtime_total_alloc_bytes", Description: "Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') [Alpha]", Unit: "By", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_process_runtime_total_alloc_bytes") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessRuntimeTotalSysMemoryBytes(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_process_runtime_total_sys_memory_bytes", Description: "Total bytes of memory obtained from the OS (see 'go doc runtime.MemStats.Sys') [Alpha]", Unit: "By", Data: metricdata.Gauge[int64]{ DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_process_runtime_total_sys_memory_bytes") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessUptime(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[float64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol_process_uptime", Description: "Uptime of the process [Alpha]", Unit: "s", Data: metricdata.Sum[float64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol_process_uptime") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorConsumedItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.processor.consumed.items", Description: "Number of items passed to the processor. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.processor.consumed.items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorConsumedSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.processor.consumed.size", Description: "Size of items passed to the processor, based on ProtoMarshaler.Sizer. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.processor.consumed.size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorProducedItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.processor.produced.items", Description: "Number of items emitted from the processor. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.processor.produced.items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualProcessorProducedSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.processor.produced.size", Description: "Size of items emitted from the processor, based on ProtoMarshaler.Sizer. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.processor.produced.size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverProducedItems(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.receiver.produced.items", Description: "Number of items emitted from the receiver. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.receiver.produced.items") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } func AssertEqualReceiverProducedSize(t *testing.T, tt *componenttest.Telemetry, dps []metricdata.DataPoint[int64], opts ...metricdatatest.Option) { want := metricdata.Metrics{ Name: "otelcol.receiver.produced.size", Description: "Size of items emitted from the receiver, based on ProtoMarshaler.Sizer. [Development]", Unit: "{item}", Data: metricdata.Sum[int64]{ Temporality: metricdata.CumulativeTemporality, IsMonotonic: true, DataPoints: dps, }, } got, err := tt.GetMetric("otelcol.receiver.produced.size") require.NoError(t, err) metricdatatest.AssertEqual(t, want, got, opts...) } opentelemetry-collector-0.141.0/service/internal/metadatatest/generated_telemetrytest_test.go000066400000000000000000000110311511331344600330040ustar00rootroot00000000000000// Code generated by mdatagen. DO NOT EDIT. package metadatatest import ( "context" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/service/internal/metadata" ) func TestSetupTelemetry(t *testing.T) { testTel := componenttest.NewTelemetry() tb, err := metadata.NewTelemetryBuilder(testTel.NewTelemetrySettings()) require.NoError(t, err) defer tb.Shutdown() require.NoError(t, tb.RegisterProcessCPUSecondsCallback(func(_ context.Context, observer metric.Float64Observer) error { observer.Observe(1) return nil })) require.NoError(t, tb.RegisterProcessMemoryRssCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) require.NoError(t, tb.RegisterProcessRuntimeHeapAllocBytesCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) require.NoError(t, tb.RegisterProcessRuntimeTotalAllocBytesCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) require.NoError(t, tb.RegisterProcessRuntimeTotalSysMemoryBytesCallback(func(_ context.Context, observer metric.Int64Observer) error { observer.Observe(1) return nil })) require.NoError(t, tb.RegisterProcessUptimeCallback(func(_ context.Context, observer metric.Float64Observer) error { observer.Observe(1) return nil })) tb.ConnectorConsumedItems.Add(context.Background(), 1) tb.ConnectorConsumedSize.Add(context.Background(), 1) tb.ConnectorProducedItems.Add(context.Background(), 1) tb.ConnectorProducedSize.Add(context.Background(), 1) tb.ExporterConsumedItems.Add(context.Background(), 1) tb.ExporterConsumedSize.Add(context.Background(), 1) tb.ProcessorConsumedItems.Add(context.Background(), 1) tb.ProcessorConsumedSize.Add(context.Background(), 1) tb.ProcessorProducedItems.Add(context.Background(), 1) tb.ProcessorProducedSize.Add(context.Background(), 1) tb.ReceiverProducedItems.Add(context.Background(), 1) tb.ReceiverProducedSize.Add(context.Background(), 1) AssertEqualConnectorConsumedItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualConnectorConsumedSize(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualConnectorProducedItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualConnectorProducedSize(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterConsumedItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualExporterConsumedSize(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessCPUSeconds(t, testTel, []metricdata.DataPoint[float64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessMemoryRss(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessRuntimeHeapAllocBytes(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessRuntimeTotalAllocBytes(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessRuntimeTotalSysMemoryBytes(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessUptime(t, testTel, []metricdata.DataPoint[float64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorConsumedItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorConsumedSize(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorProducedItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualProcessorProducedSize(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverProducedItems(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) AssertEqualReceiverProducedSize(t, testTel, []metricdata.DataPoint[int64]{{Value: 1}}, metricdatatest.IgnoreTimestamp()) require.NoError(t, testTel.Shutdown(context.Background())) } opentelemetry-collector-0.141.0/service/internal/moduleinfo/000077500000000000000000000000001511331344600241535ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/moduleinfo/moduleinfo.go000066400000000000000000000012171511331344600266440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package moduleinfo // import "go.opentelemetry.io/collector/service/internal/moduleinfo" import "go.opentelemetry.io/collector/component" type ModuleInfo struct { // BuilderRef is the raw string passed in the builder configuration used to build this service. BuilderRef string } // ModuleInfos describes the go module for each component. type ModuleInfos struct { Receiver map[component.Type]ModuleInfo Processor map[component.Type]ModuleInfo Exporter map[component.Type]ModuleInfo Extension map[component.Type]ModuleInfo Connector map[component.Type]ModuleInfo } opentelemetry-collector-0.141.0/service/internal/obsconsumer/000077500000000000000000000000001511331344600243515ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/obsconsumer/consumer_test.go000066400000000000000000000152041511331344600275740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer_test import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.uber.org/zap" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/service/internal/obsconsumer" ) type failingConsumer struct { err error } var ( _ consumer.Metrics = (*failingConsumer)(nil) _ consumer.Logs = (*failingConsumer)(nil) _ consumer.Traces = (*failingConsumer)(nil) _ xconsumer.Profiles = (*failingConsumer)(nil) ) func (*failingConsumer) Capabilities() consumer.Capabilities { return consumer.Capabilities{} } func (fc *failingConsumer) ConsumeMetrics(_ context.Context, _ pmetric.Metrics) error { return fc.err } func (fc *failingConsumer) ConsumeLogs(_ context.Context, _ plog.Logs) error { return fc.err } func (fc *failingConsumer) ConsumeTraces(_ context.Context, _ ptrace.Traces) error { return fc.err } func (fc *failingConsumer) ConsumeProfiles(_ context.Context, _ pprofile.Profiles) error { return fc.err } func TestConsumeRefused(t *testing.T) { setGateForTest(t, true) ctx := context.Background() originalErr := errors.New("test error") expectedErr := consumererror.NewDownstream(originalErr) mockConsumer := &failingConsumer{err: originalErr} // Use delta temporality so sums don't accumulate across tests reader := sdkmetric.NewManualReader(sdkmetric.WithTemporalitySelector(func(_ sdkmetric.InstrumentKind) metricdata.Temporality { return metricdata.DeltaTemporality })) mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") receivedItemsCounter, err := meter.Int64Counter("received.items") require.NoError(t, err) receivedSizeCounter, err := meter.Int64Counter("received.size") require.NoError(t, err) producedItemsCounter, err := meter.Int64Counter("produced.items") require.NoError(t, err) producedSizeConter, err := meter.Int64Counter("produced.size") require.NoError(t, err) logger := zap.NewNop() receivedSettings := obsconsumer.Settings{ItemCounter: receivedItemsCounter, SizeCounter: receivedSizeCounter, Logger: logger} producedSettings := obsconsumer.Settings{ItemCounter: producedItemsCounter, SizeCounter: producedSizeConter, Logger: logger} type testCase struct { name string testConsumer func() error } testCases := []testCase{ { name: "metrics", testConsumer: func() error { consumer1 := obsconsumer.NewMetrics(mockConsumer, receivedSettings) consumer2 := obsconsumer.NewMetrics(consumer1, producedSettings) md := pmetric.NewMetrics() md.ResourceMetrics().AppendEmpty().ScopeMetrics().AppendEmpty().Metrics().AppendEmpty().SetEmptyGauge().DataPoints().AppendEmpty() return consumer2.ConsumeMetrics(ctx, md) }, }, { name: "logs", testConsumer: func() error { consumer1 := obsconsumer.NewLogs(mockConsumer, receivedSettings) consumer2 := obsconsumer.NewLogs(consumer1, producedSettings) ld := plog.NewLogs() ld.ResourceLogs().AppendEmpty().ScopeLogs().AppendEmpty().LogRecords().AppendEmpty() return consumer2.ConsumeLogs(ctx, ld) }, }, { name: "traces", testConsumer: func() error { consumer1 := obsconsumer.NewTraces(mockConsumer, receivedSettings) consumer2 := obsconsumer.NewTraces(consumer1, producedSettings) td := ptrace.NewTraces() td.ResourceSpans().AppendEmpty().ScopeSpans().AppendEmpty().Spans().AppendEmpty() return consumer2.ConsumeTraces(ctx, td) }, }, { name: "profiles", testConsumer: func() error { consumer1 := obsconsumer.NewProfiles(mockConsumer, receivedSettings) consumer2 := obsconsumer.NewProfiles(consumer1, producedSettings) pd := pprofile.NewProfiles() pd.ResourceProfiles().AppendEmpty().ScopeProfiles().AppendEmpty().Profiles().AppendEmpty().Samples().AppendEmpty() return consumer2.ConsumeProfiles(ctx, pd) }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { err := tc.testConsumer() assert.Equal(t, expectedErr, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 4) var receivedItemMetric, receivedSizeMetric metricdata.Metrics var producedItemMetric, producedSizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "received.items": receivedItemMetric = m case "received.size": receivedSizeMetric = m case "produced.items": producedItemMetric = m case "produced.size": producedSizeMetric = m } } require.NotNil(t, receivedItemMetric) require.NotNil(t, receivedSizeMetric) require.NotNil(t, producedItemMetric) require.NotNil(t, producedSizeMetric) data := receivedItemMetric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Equal(t, int64(1), data.DataPoints[0].Value) attrs := data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok := attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) data = receivedSizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Positive(t, data.DataPoints[0].Value) attrs = data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok = attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) data = producedItemMetric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Equal(t, int64(1), data.DataPoints[0].Value) attrs = data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok = attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "refused", val.Emit()) data = producedSizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Positive(t, data.DataPoints[0].Value) attrs = data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok = attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "refused", val.Emit()) }) } } opentelemetry-collector-0.141.0/service/internal/obsconsumer/enabled.go000066400000000000000000000006651511331344600263010ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer // import "go.opentelemetry.io/collector/service/internal/obsconsumer" import ( "context" "go.opentelemetry.io/otel/metric" ) type enabledInstrument interface { Enabled(context.Context) bool } func isEnabled(ctx context.Context, inst metric.Int64Counter) bool { ei, ok := inst.(enabledInstrument) return !ok || ei.Enabled(ctx) } opentelemetry-collector-0.141.0/service/internal/obsconsumer/enabled_test.go000066400000000000000000000010511511331344600273260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer_test import ( "context" "go.opentelemetry.io/otel/metric" ) type disabledCounter struct { metric.Int64Counter } func newDisabledCounter(embedded metric.Int64Counter) *disabledCounter { return &disabledCounter{Int64Counter: embedded} } func (m *disabledCounter) Enabled(context.Context) bool { return false } func (m *disabledCounter) Add(ctx context.Context, value int64, opts ...metric.AddOption) { m.Int64Counter.Add(ctx, value, opts...) } opentelemetry-collector-0.141.0/service/internal/obsconsumer/gate_test.go000066400000000000000000000011421511331344600266550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer_test import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/internal/telemetry" ) func setGateForTest(t *testing.T, enabled bool) { initial := telemetry.NewPipelineTelemetryGate.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), enabled)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) } opentelemetry-collector-0.141.0/service/internal/obsconsumer/logs.go000066400000000000000000000041621511331344600256470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer // import "go.opentelemetry.io/collector/service/internal/obsconsumer" import ( "context" "go.uber.org/zap" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/plog" ) var ( _ consumer.Logs = obsLogs{} logsMarshaler = &plog.ProtoMarshaler{} ) func NewLogs(cons consumer.Logs, set Settings, opts ...Option) consumer.Logs { if !telemetry.NewPipelineTelemetryGate.IsEnabled() { return cons } o := options{} for _, opt := range opts { opt(&o) } consumerSet := Settings{ ItemCounter: set.ItemCounter, SizeCounter: set.SizeCounter, Logger: set.Logger.With(telemetry.ToZapFields(o.staticDataPointAttributes)...), } return obsLogs{ consumer: cons, set: consumerSet, compiledOptions: o.compile(), } } type obsLogs struct { consumer consumer.Logs set Settings compiledOptions } // ConsumeLogs measures telemetry before calling ConsumeLogs because the data may be mutated downstream func (c obsLogs) ConsumeLogs(ctx context.Context, ld plog.Logs) error { // Use a pointer to so that deferred function can depend on the result of ConsumeLogs attrs := &c.withSuccessAttrs itemCount := ld.LogRecordCount() defer func() { c.set.ItemCounter.Add(ctx, int64(itemCount), *attrs) }() if isEnabled(ctx, c.set.SizeCounter) { byteCount := int64(logsMarshaler.LogsSize(ld)) defer func() { c.set.SizeCounter.Add(ctx, byteCount, *attrs) }() } err := c.consumer.ConsumeLogs(ctx, ld) if err != nil { if consumererror.IsDownstream(err) { attrs = &c.withRefusedAttrs } else { attrs = &c.withFailureAttrs err = consumererror.NewDownstream(err) } if c.set.Logger.Core().Enabled(zap.DebugLevel) { c.set.Logger.Debug("Logs pipeline component had an error", zap.Error(err), zap.Int("item count", itemCount)) } } return err } func (c obsLogs) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/obsconsumer/logs_test.go000066400000000000000000000335441511331344600267140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer_test import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/service/internal/obsconsumer" ) type mockLogsConsumer struct { err error capabilities consumer.Capabilities } func (m *mockLogsConsumer) ConsumeLogs(_ context.Context, _ plog.Logs) error { return m.err } func (m *mockLogsConsumer) Capabilities() consumer.Capabilities { return m.capabilities } func TestLogsNopWhenGateDisabled(t *testing.T) { setGateForTest(t, false) mp := sdkmetric.NewMeterProvider() meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) cons := consumertest.NewNop() require.Equal(t, cons, obsconsumer.NewLogs(cons, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()})) } func TestLogsItemsOnly(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockLogsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewLogs(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: logger}) ld := plog.NewLogs() r := ld.ResourceLogs().AppendEmpty() sl := r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() err = consumer.ConsumeLogs(ctx, ld) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 1) metric := rm.ScopeMetrics[0].Metrics[0] require.Equal(t, "item_counter", metric.Name) data := metric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Equal(t, int64(1), data.DataPoints[0].Value) attrs := data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok := attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestLogsConsumeSuccess(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockLogsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewLogs(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) ld := plog.NewLogs() r := ld.ResourceLogs().AppendEmpty() sl := r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() err = consumer.ConsumeLogs(ctx, ld) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestLogsConsumeFailure(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockLogsConsumer{err: expectedErr} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewLogs(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) ld := plog.NewLogs() r := ld.ResourceLogs().AppendEmpty() sl := r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() err = consumer.ConsumeLogs(ctx, ld) assert.Equal(t, downstreamErr, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) require.NotNil(t, sizeMetric) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) // Check that the logger was called with an error require.Len(t, logs.All(), 1) assert.Contains(t, logs.All()[0].Message, "Logs pipeline component had an error") } func TestLogsWithStaticAttributes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockLogsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) staticAttr := attribute.String("test", "value") core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewLogs(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}, obsconsumer.WithStaticDataPointAttribute(staticAttr)) ld := plog.NewLogs() r := ld.ResourceLogs().AppendEmpty() sl := r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() err = consumer.ConsumeLogs(ctx, ld) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 2, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 2, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestLogsMultipleItemsMixedOutcomes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockLogsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewLogs(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) // First batch: 2 successful items ld1 := plog.NewLogs() for range 2 { r := ld1.ResourceLogs().AppendEmpty() sl := r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() } err = consumer.ConsumeLogs(ctx, ld1) require.NoError(t, err) // Second batch: 1 failed item mockConsumer.err = expectedErr ld2 := plog.NewLogs() r := ld2.ResourceLogs().AppendEmpty() sl := r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() err = consumer.ConsumeLogs(ctx, ld2) assert.Equal(t, downstreamErr, err) // Third batch: 2 successful items mockConsumer.err = nil ld3 := plog.NewLogs() for range 2 { r = ld3.ResourceLogs().AppendEmpty() sl = r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() } err = consumer.ConsumeLogs(ctx, ld3) require.NoError(t, err) // Fourth batch: 1 failed item mockConsumer.err = expectedErr ld4 := plog.NewLogs() r = ld4.ResourceLogs().AppendEmpty() sl = r.ScopeLogs().AppendEmpty() sl.LogRecords().AppendEmpty() err = consumer.ConsumeLogs(ctx, ld4) assert.Equal(t, downstreamErr, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 2) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 2) var successDP, failureDP metricdata.DataPoint[int64] for _, dp := range itemData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successDP = dp } else { failureDP = dp } } require.Equal(t, int64(4), successDP.Value) require.Equal(t, int64(2), failureDP.Value) var successSizeDP, failureSizeDP metricdata.DataPoint[int64] for _, dp := range sizeData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successSizeDP = dp } else { failureSizeDP = dp } } require.Equal(t, int64(64), successSizeDP.Value) require.Equal(t, int64(32), failureSizeDP.Value) // Check that the logger was called for errors require.Len(t, logs.All(), 2) for _, log := range logs.All() { assert.Contains(t, log.Message, "Logs pipeline component had an error") } } func TestLogsCapabilities(t *testing.T) { setGateForTest(t, true) mockConsumer := &mockLogsConsumer{ capabilities: consumer.Capabilities{MutatesData: true}, } reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) // Test with item counter only consumer := obsconsumer.NewLogs(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) // Test with both counters consumer = obsconsumer.NewLogs(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) } opentelemetry-collector-0.141.0/service/internal/obsconsumer/metrics.go000066400000000000000000000042751511331344600263560ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer // import "go.opentelemetry.io/collector/service/internal/obsconsumer" import ( "context" "go.uber.org/zap" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/pmetric" ) var ( _ consumer.Metrics = obsMetrics{} metricsMarshaler = &pmetric.ProtoMarshaler{} ) func NewMetrics(cons consumer.Metrics, set Settings, opts ...Option) consumer.Metrics { if !telemetry.NewPipelineTelemetryGate.IsEnabled() { return cons } o := options{} for _, opt := range opts { opt(&o) } consumerSet := Settings{ ItemCounter: set.ItemCounter, SizeCounter: set.SizeCounter, Logger: set.Logger.With(telemetry.ToZapFields(o.staticDataPointAttributes)...), } return obsMetrics{ consumer: cons, set: consumerSet, compiledOptions: o.compile(), } } type obsMetrics struct { consumer consumer.Metrics set Settings compiledOptions } // ConsumeMetrics measures telemetry before calling ConsumeMetrics because the data may be mutated downstream func (c obsMetrics) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { // Use a pointer to so that deferred function can depend on the result of ConsumeMetrics attrs := &c.withSuccessAttrs itemCount := md.DataPointCount() defer func() { c.set.ItemCounter.Add(ctx, int64(itemCount), *attrs) }() if isEnabled(ctx, c.set.SizeCounter) { byteCount := int64(metricsMarshaler.MetricsSize(md)) defer func() { c.set.SizeCounter.Add(ctx, byteCount, *attrs) }() } err := c.consumer.ConsumeMetrics(ctx, md) if err != nil { if consumererror.IsDownstream(err) { attrs = &c.withRefusedAttrs } else { attrs = &c.withFailureAttrs err = consumererror.NewDownstream(err) } if c.set.Logger.Core().Enabled(zap.DebugLevel) { c.set.Logger.Debug("Metrics pipeline component had an error", zap.Error(err), zap.Int("item count", itemCount)) } } return err } func (c obsMetrics) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/obsconsumer/metrics_test.go000066400000000000000000000351301511331344600274070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer_test import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/service/internal/obsconsumer" ) type mockMetricsConsumer struct { err error capabilities consumer.Capabilities } func (m *mockMetricsConsumer) ConsumeMetrics(_ context.Context, _ pmetric.Metrics) error { return m.err } func (m *mockMetricsConsumer) Capabilities() consumer.Capabilities { return m.capabilities } func TestMetricsNopWhenGateDisabled(t *testing.T) { setGateForTest(t, false) mp := sdkmetric.NewMeterProvider() meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) cons := consumertest.NewNop() require.Equal(t, cons, obsconsumer.NewMetrics(cons, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()})) } func TestMetricsItemsOnly(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockMetricsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewMetrics(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: logger}) md := pmetric.NewMetrics() rm := md.ResourceMetrics().AppendEmpty() sm := rm.ScopeMetrics().AppendEmpty() m := sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() err = consumer.ConsumeMetrics(ctx, md) require.NoError(t, err) var metrics metricdata.ResourceMetrics err = reader.Collect(ctx, &metrics) require.NoError(t, err) require.Len(t, metrics.ScopeMetrics, 1) require.Len(t, metrics.ScopeMetrics[0].Metrics, 1) metric := metrics.ScopeMetrics[0].Metrics[0] require.Equal(t, "item_counter", metric.Name) data := metric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Equal(t, int64(1), data.DataPoints[0].Value) attrs := data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok := attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestMetricsConsumeSuccess(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockMetricsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewMetrics(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) md := pmetric.NewMetrics() r := md.ResourceMetrics().AppendEmpty() sm := r.ScopeMetrics().AppendEmpty() m := sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() err = consumer.ConsumeMetrics(ctx, md) require.NoError(t, err) var metrics metricdata.ResourceMetrics err = reader.Collect(ctx, &metrics) require.NoError(t, err) require.Len(t, metrics.ScopeMetrics, 1) require.Len(t, metrics.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range metrics.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) attrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok = attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestMetricsConsumeFailure(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockMetricsConsumer{err: expectedErr} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewMetrics(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) md := pmetric.NewMetrics() r := md.ResourceMetrics().AppendEmpty() sm := r.ScopeMetrics().AppendEmpty() m := sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() err = consumer.ConsumeMetrics(ctx, md) assert.Equal(t, downstreamErr, err) var metrics metricdata.ResourceMetrics err = reader.Collect(ctx, &metrics) require.NoError(t, err) require.Len(t, metrics.ScopeMetrics, 1) require.Len(t, metrics.ScopeMetrics[0].Metrics, 2) // Find the item counter and size counter metrics var itemMetric, sizeMetric metricdata.Metrics for _, m := range metrics.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) // Check that the logger was called with an error require.Len(t, logs.All(), 1) assert.Contains(t, logs.All()[0].Message, "Metrics pipeline component had an error") } func TestMetricsWithStaticAttributes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockMetricsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) staticAttr := attribute.String("test", "value") core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewMetrics(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}, obsconsumer.WithStaticDataPointAttribute(staticAttr)) md := pmetric.NewMetrics() rm := md.ResourceMetrics().AppendEmpty() rm.ScopeMetrics().AppendEmpty() sm := rm.ScopeMetrics().AppendEmpty() m := sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() err = consumer.ConsumeMetrics(ctx, md) require.NoError(t, err) var metrics metricdata.ResourceMetrics err = reader.Collect(ctx, &metrics) require.NoError(t, err) require.Len(t, metrics.ScopeMetrics, 1) require.Len(t, metrics.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range metrics.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 2, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 2, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestMetricsMultipleItemsMixedOutcomes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockMetricsConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewMetrics(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) // First batch: 2 successful items md1 := pmetric.NewMetrics() for range 2 { r := md1.ResourceMetrics().AppendEmpty() sm := r.ScopeMetrics().AppendEmpty() m := sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() } err = consumer.ConsumeMetrics(ctx, md1) require.NoError(t, err) // Second batch: 1 failed item mockConsumer.err = expectedErr md2 := pmetric.NewMetrics() r := md2.ResourceMetrics().AppendEmpty() sm := r.ScopeMetrics().AppendEmpty() m := sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() err = consumer.ConsumeMetrics(ctx, md2) assert.Equal(t, downstreamErr, err) // Third batch: 2 successful items mockConsumer.err = nil md3 := pmetric.NewMetrics() for range 2 { r = md3.ResourceMetrics().AppendEmpty() sm = r.ScopeMetrics().AppendEmpty() m = sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() } err = consumer.ConsumeMetrics(ctx, md3) require.NoError(t, err) // Fourth batch: 1 failed item mockConsumer.err = expectedErr md4 := pmetric.NewMetrics() r = md4.ResourceMetrics().AppendEmpty() sm = r.ScopeMetrics().AppendEmpty() m = sm.Metrics().AppendEmpty() m.SetEmptyGauge().DataPoints().AppendEmpty() err = consumer.ConsumeMetrics(ctx, md4) assert.Equal(t, downstreamErr, err) var metrics metricdata.ResourceMetrics err = reader.Collect(ctx, &metrics) require.NoError(t, err) require.Len(t, metrics.ScopeMetrics, 1) require.Len(t, metrics.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range metrics.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 2) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 2) // Find success and failure data points var successDP, failureDP metricdata.DataPoint[int64] for _, dp := range itemData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successDP = dp } else { failureDP = dp } } require.Equal(t, int64(4), successDP.Value) require.Equal(t, int64(2), failureDP.Value) for _, dp := range sizeData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successDP = dp } else { failureDP = dp } } require.Equal(t, int64(56), successDP.Value) require.Equal(t, int64(28), failureDP.Value) // Check that the logger was called for errors require.Len(t, logs.All(), 2) for _, log := range logs.All() { assert.Contains(t, log.Message, "Metrics pipeline component had an error") } } func TestMetricsCapabilities(t *testing.T) { setGateForTest(t, true) mockConsumer := &mockMetricsConsumer{ capabilities: consumer.Capabilities{MutatesData: true}, } reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) // Test with item counter only consumer := obsconsumer.NewMetrics(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) // Test with both counters consumer = obsconsumer.NewMetrics(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) } opentelemetry-collector-0.141.0/service/internal/obsconsumer/option.go000066400000000000000000000034621511331344600262150ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer // import "go.opentelemetry.io/collector/service/internal/obsconsumer" import ( "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" ) const ( ComponentOutcome = "otelcol.component.outcome" ) // Option modifies the consumer behavior. type Option func(*options) type options struct { staticDataPointAttributes []attribute.KeyValue } // WithStaticDataPointAttribute returns an Option that adds a static attribute to data points. func WithStaticDataPointAttribute(attr attribute.KeyValue) Option { return func(opts *options) { opts.staticDataPointAttributes = append(opts.staticDataPointAttributes, attr) } } type compiledOptions struct { withSuccessAttrs metric.AddOption withFailureAttrs metric.AddOption withRefusedAttrs metric.AddOption } func (o *options) compile() compiledOptions { successAttrs := make([]attribute.KeyValue, 0, 1+len(o.staticDataPointAttributes)) successAttrs = append(successAttrs, attribute.String(ComponentOutcome, "success")) successAttrs = append(successAttrs, o.staticDataPointAttributes...) failureAttrs := make([]attribute.KeyValue, 0, 1+len(o.staticDataPointAttributes)) failureAttrs = append(failureAttrs, attribute.String(ComponentOutcome, "failure")) failureAttrs = append(failureAttrs, o.staticDataPointAttributes...) refusedAttrs := make([]attribute.KeyValue, 0, 1+len(o.staticDataPointAttributes)) refusedAttrs = append(refusedAttrs, attribute.String(ComponentOutcome, "refused")) refusedAttrs = append(refusedAttrs, o.staticDataPointAttributes...) return compiledOptions{ withSuccessAttrs: metric.WithAttributes(successAttrs...), withFailureAttrs: metric.WithAttributes(failureAttrs...), withRefusedAttrs: metric.WithAttributes(refusedAttrs...), } } opentelemetry-collector-0.141.0/service/internal/obsconsumer/package_test.go000066400000000000000000000003141511331344600273300ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/internal/obsconsumer/profiles.go000066400000000000000000000044061511331344600265270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer // import "go.opentelemetry.io/collector/service/internal/obsconsumer" import ( "context" "go.uber.org/zap" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/pprofile" ) var ( _ xconsumer.Profiles = obsProfiles{} profilesMarshaler = pprofile.ProtoMarshaler{} ) func NewProfiles(cons xconsumer.Profiles, set Settings, opts ...Option) xconsumer.Profiles { if !telemetry.NewPipelineTelemetryGate.IsEnabled() { return cons } o := options{} for _, opt := range opts { opt(&o) } consumerSet := Settings{ ItemCounter: set.ItemCounter, SizeCounter: set.SizeCounter, Logger: set.Logger.With(telemetry.ToZapFields(o.staticDataPointAttributes)...), } return obsProfiles{ consumer: cons, set: consumerSet, compiledOptions: o.compile(), } } type obsProfiles struct { consumer xconsumer.Profiles set Settings compiledOptions } // ConsumeProfiles measures telemetry before calling ConsumeProfiles because the data may be mutated downstream func (c obsProfiles) ConsumeProfiles(ctx context.Context, pd pprofile.Profiles) error { // Measure before calling ConsumeProfiles because the data may be mutated downstream attrs := &c.withSuccessAttrs itemCount := pd.SampleCount() defer func() { c.set.ItemCounter.Add(ctx, int64(itemCount), *attrs) }() if isEnabled(ctx, c.set.SizeCounter) { byteCount := int64(profilesMarshaler.ProfilesSize(pd)) defer func() { c.set.SizeCounter.Add(ctx, byteCount, *attrs) }() } err := c.consumer.ConsumeProfiles(ctx, pd) if err != nil { if consumererror.IsDownstream(err) { attrs = &c.withRefusedAttrs } else { attrs = &c.withFailureAttrs err = consumererror.NewDownstream(err) } if c.set.Logger.Core().Enabled(zap.DebugLevel) { c.set.Logger.Debug("Profiles pipeline component had an error", zap.Error(err), zap.Int("item count", itemCount)) } } return err } func (c obsProfiles) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/obsconsumer/profiles_test.go000066400000000000000000000344551511331344600275750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer_test import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/service/internal/obsconsumer" ) type mockProfilesConsumer struct { err error capabilities consumer.Capabilities } func (m *mockProfilesConsumer) ConsumeProfiles(_ context.Context, _ pprofile.Profiles) error { return m.err } func (m *mockProfilesConsumer) Capabilities() consumer.Capabilities { return m.capabilities } func TestProfilesNopWhenGateDisabled(t *testing.T) { setGateForTest(t, false) mp := sdkmetric.NewMeterProvider() meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) cons := consumertest.NewNop() require.Equal(t, cons, obsconsumer.NewProfiles(cons, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()})) } func TestProfilesItemsOnly(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockProfilesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewProfiles(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: logger}) pd := pprofile.NewProfiles() r := pd.ResourceProfiles().AppendEmpty() sp := r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() err = consumer.ConsumeProfiles(ctx, pd) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 1) metric := rm.ScopeMetrics[0].Metrics[0] require.Equal(t, "item_counter", metric.Name) data := metric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Equal(t, int64(1), data.DataPoints[0].Value) attrs := data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok := attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestProfilesConsumeSuccess(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockProfilesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewProfiles(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) pd := pprofile.NewProfiles() r := pd.ResourceProfiles().AppendEmpty() sp := r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() err = consumer.ConsumeProfiles(ctx, pd) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestProfilesConsumeFailure(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockProfilesConsumer{err: expectedErr} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewProfiles(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) pd := pprofile.NewProfiles() r := pd.ResourceProfiles().AppendEmpty() sp := r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() err = consumer.ConsumeProfiles(ctx, pd) assert.Equal(t, downstreamErr, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) // Check that the logger was called with an error require.Len(t, logs.All(), 1) assert.Contains(t, logs.All()[0].Message, "Profiles pipeline component had an error") } func TestProfilesWithStaticAttributes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockProfilesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) staticAttr := attribute.String("test", "value") core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewProfiles(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}, obsconsumer.WithStaticDataPointAttribute(staticAttr)) pd := pprofile.NewProfiles() r := pd.ResourceProfiles().AppendEmpty() sp := r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() err = consumer.ConsumeProfiles(ctx, pd) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 2, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 2, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestProfilesMultipleItemsMixedOutcomes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockProfilesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewProfiles(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) // First batch: 2 successful items pd1 := pprofile.NewProfiles() for range 2 { r := pd1.ResourceProfiles().AppendEmpty() sp := r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() } err = consumer.ConsumeProfiles(ctx, pd1) require.NoError(t, err) // Second batch: 1 failed item mockConsumer.err = expectedErr pd2 := pprofile.NewProfiles() r := pd2.ResourceProfiles().AppendEmpty() sp := r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() err = consumer.ConsumeProfiles(ctx, pd2) assert.Equal(t, downstreamErr, err) // Third batch: 2 successful items mockConsumer.err = nil pd3 := pprofile.NewProfiles() for range 2 { r = pd3.ResourceProfiles().AppendEmpty() sp = r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() } err = consumer.ConsumeProfiles(ctx, pd3) require.NoError(t, err) // Fourth batch: 1 failed item mockConsumer.err = expectedErr pd4 := pprofile.NewProfiles() r = pd4.ResourceProfiles().AppendEmpty() sp = r.ScopeProfiles().AppendEmpty() sp.Profiles().AppendEmpty().Samples().AppendEmpty() err = consumer.ConsumeProfiles(ctx, pd4) assert.Equal(t, downstreamErr, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 2) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 2) var successDP, failureDP metricdata.DataPoint[int64] for _, dp := range itemData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successDP = dp } else { failureDP = dp } } require.Equal(t, int64(4), successDP.Value) require.Equal(t, int64(2), failureDP.Value) var successSizeDP, failureSizeDP metricdata.DataPoint[int64] for _, dp := range sizeData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successSizeDP = dp } else { failureSizeDP = dp } } require.Equal(t, int64(76), successSizeDP.Value) require.Equal(t, int64(40), failureSizeDP.Value) // Check that the logger was called for errors require.Len(t, logs.All(), 2) for _, log := range logs.All() { assert.Contains(t, log.Message, "Profiles pipeline component had an error") } } func TestProfilesCapabilities(t *testing.T) { setGateForTest(t, true) mockConsumer := &mockProfilesConsumer{ capabilities: consumer.Capabilities{MutatesData: true}, } reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) // Test with item counter only consumer := obsconsumer.NewProfiles(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) // Test with both counters consumer = obsconsumer.NewProfiles(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) } opentelemetry-collector-0.141.0/service/internal/obsconsumer/telemetry.go000066400000000000000000000011511511331344600267100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer // import "go.opentelemetry.io/collector/service/internal/obsconsumer" import ( "go.opentelemetry.io/otel/metric" "go.uber.org/zap" ) // Settings defines the settings for telemetry in the obsconsumer package. type Settings struct { // ItemCounter is the metric to count the number of items processed. ItemCounter metric.Int64Counter // SizeCounter is the metric to count the size of items processed. SizeCounter metric.Int64Counter // Logger is the logger for the obsconsumer package. Logger *zap.Logger } opentelemetry-collector-0.141.0/service/internal/obsconsumer/traces.go000066400000000000000000000042371511331344600261670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer // import "go.opentelemetry.io/collector/service/internal/obsconsumer" import ( "context" "go.uber.org/zap" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/ptrace" ) var ( _ consumer.Traces = obsTraces{} tracesMarshaler = &ptrace.ProtoMarshaler{} ) func NewTraces(cons consumer.Traces, set Settings, opts ...Option) consumer.Traces { if !telemetry.NewPipelineTelemetryGate.IsEnabled() { return cons } o := options{} for _, opt := range opts { opt(&o) } consumerSet := Settings{ ItemCounter: set.ItemCounter, SizeCounter: set.SizeCounter, Logger: set.Logger.With(telemetry.ToZapFields(o.staticDataPointAttributes)...), } return obsTraces{ consumer: cons, set: consumerSet, compiledOptions: o.compile(), } } type obsTraces struct { consumer consumer.Traces set Settings compiledOptions } // ConsumeTraces measures telemetry before calling ConsumeTraces because the data may be mutated downstream func (c obsTraces) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { // Use a pointer to so that deferred function can depend on the result of ConsumeTraces attrs := &c.withSuccessAttrs itemCount := td.SpanCount() defer func() { c.set.ItemCounter.Add(ctx, int64(itemCount), *attrs) }() if isEnabled(ctx, c.set.SizeCounter) { byteCount := int64(tracesMarshaler.TracesSize(td)) defer func() { c.set.SizeCounter.Add(ctx, byteCount, *attrs) }() } err := c.consumer.ConsumeTraces(ctx, td) if err != nil { if consumererror.IsDownstream(err) { attrs = &c.withRefusedAttrs } else { attrs = &c.withFailureAttrs err = consumererror.NewDownstream(err) } if c.set.Logger.Core().Enabled(zap.DebugLevel) { c.set.Logger.Debug("Traces pipeline component had an error", zap.Error(err), zap.Int("item count", itemCount)) } } return err } func (c obsTraces) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/obsconsumer/traces_test.go000066400000000000000000000337731511331344600272350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package obsconsumer_test import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/attribute" sdkmetric "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.uber.org/zap" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumererror" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/service/internal/obsconsumer" ) type mockTracesConsumer struct { err error capabilities consumer.Capabilities } func (m *mockTracesConsumer) ConsumeTraces(_ context.Context, _ ptrace.Traces) error { return m.err } func (m *mockTracesConsumer) Capabilities() consumer.Capabilities { return m.capabilities } func TestTracesNopWhenGateDisabled(t *testing.T) { setGateForTest(t, false) mp := sdkmetric.NewMeterProvider() meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) cons := consumertest.NewNop() require.Equal(t, cons, obsconsumer.NewTraces(cons, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()})) } func TestTracesItemsOnly(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockTracesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewTraces(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: logger}) td := ptrace.NewTraces() r := td.ResourceSpans().AppendEmpty() ss := r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() err = consumer.ConsumeTraces(ctx, td) require.NoError(t, err) var metrics metricdata.ResourceMetrics err = reader.Collect(ctx, &metrics) require.NoError(t, err) require.Len(t, metrics.ScopeMetrics, 1) require.Len(t, metrics.ScopeMetrics[0].Metrics, 1) metric := metrics.ScopeMetrics[0].Metrics[0] require.Equal(t, "item_counter", metric.Name) data := metric.Data.(metricdata.Sum[int64]) require.Len(t, data.DataPoints, 1) require.Equal(t, int64(1), data.DataPoints[0].Value) attrs := data.DataPoints[0].Attributes require.Equal(t, 1, attrs.Len()) val, ok := attrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestTracesConsumeSuccess(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockTracesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewTraces(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) td := ptrace.NewTraces() r := td.ResourceSpans().AppendEmpty() ss := r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() err = consumer.ConsumeTraces(ctx, td) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestTracesConsumeFailure(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockTracesConsumer{err: expectedErr} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewTraces(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) td := ptrace.NewTraces() r := td.ResourceSpans().AppendEmpty() ss := r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() err = consumer.ConsumeTraces(ctx, td) assert.Equal(t, downstreamErr, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 1, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 1, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "failure", val.Emit()) // Check that the logger was called with an error require.Len(t, logs.All(), 1) assert.Contains(t, logs.All()[0].Message, "Traces pipeline component had an error") } func TestTracesWithStaticAttributes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() mockConsumer := &mockTracesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) staticAttr := attribute.String("test", "value") core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewTraces(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}, obsconsumer.WithStaticDataPointAttribute(staticAttr)) td := ptrace.NewTraces() r := td.ResourceSpans().AppendEmpty() ss := r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() err = consumer.ConsumeTraces(ctx, td) require.NoError(t, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 1) require.Equal(t, int64(1), itemData.DataPoints[0].Value) itemAttrs := itemData.DataPoints[0].Attributes require.Equal(t, 2, itemAttrs.Len()) val, ok := itemAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = itemAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 1) require.Positive(t, sizeData.DataPoints[0].Value) sizeAttrs := sizeData.DataPoints[0].Attributes require.Equal(t, 2, sizeAttrs.Len()) val, ok = sizeAttrs.Value(attribute.Key("test")) require.True(t, ok) require.Equal(t, "value", val.Emit()) val, ok = sizeAttrs.Value(attribute.Key(obsconsumer.ComponentOutcome)) require.True(t, ok) require.Equal(t, "success", val.Emit()) // Check that the logger was not called assert.Empty(t, logs.All()) } func TestTracesMultipleItemsMixedOutcomes(t *testing.T) { setGateForTest(t, true) ctx := context.Background() expectedErr := errors.New("test error") downstreamErr := consumererror.NewDownstream(expectedErr) mockConsumer := &mockTracesConsumer{} reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) core, logs := observer.New(zap.DebugLevel) logger := zap.New(core) consumer := obsconsumer.NewTraces(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: logger}) // First batch: 2 successful items td1 := ptrace.NewTraces() for range 2 { r := td1.ResourceSpans().AppendEmpty() ss := r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() } err = consumer.ConsumeTraces(ctx, td1) require.NoError(t, err) // Second batch: 1 failed item mockConsumer.err = expectedErr td2 := ptrace.NewTraces() r := td2.ResourceSpans().AppendEmpty() ss := r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() err = consumer.ConsumeTraces(ctx, td2) assert.Equal(t, downstreamErr, err) // Third batch: 2 successful items mockConsumer.err = nil td3 := ptrace.NewTraces() for range 2 { r = td3.ResourceSpans().AppendEmpty() ss = r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() } err = consumer.ConsumeTraces(ctx, td3) require.NoError(t, err) // Fourth batch: 1 failed item mockConsumer.err = expectedErr td4 := ptrace.NewTraces() r = td4.ResourceSpans().AppendEmpty() ss = r.ScopeSpans().AppendEmpty() ss.Spans().AppendEmpty() err = consumer.ConsumeTraces(ctx, td4) assert.Equal(t, downstreamErr, err) var rm metricdata.ResourceMetrics err = reader.Collect(ctx, &rm) require.NoError(t, err) require.Len(t, rm.ScopeMetrics, 1) require.Len(t, rm.ScopeMetrics[0].Metrics, 2) var itemMetric, sizeMetric metricdata.Metrics for _, m := range rm.ScopeMetrics[0].Metrics { switch m.Name { case "item_counter": itemMetric = m case "size_counter": sizeMetric = m } } require.NotNil(t, itemMetric) require.NotNil(t, sizeMetric) itemData := itemMetric.Data.(metricdata.Sum[int64]) require.Len(t, itemData.DataPoints, 2) sizeData := sizeMetric.Data.(metricdata.Sum[int64]) require.Len(t, sizeData.DataPoints, 2) // Find success and failure data points var successDP, failureDP metricdata.DataPoint[int64] for _, dp := range itemData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successDP = dp } else { failureDP = dp } } require.Equal(t, int64(4), successDP.Value) require.Equal(t, int64(2), failureDP.Value) var successSizeDP, failureSizeDP metricdata.DataPoint[int64] for _, dp := range sizeData.DataPoints { val, ok := dp.Attributes.Value(attribute.Key(obsconsumer.ComponentOutcome)) if ok && val.Emit() == "success" { successSizeDP = dp } else { failureSizeDP = dp } } require.Equal(t, int64(72), successSizeDP.Value) require.Equal(t, int64(36), failureSizeDP.Value) // Check that the logger was called for errors require.Len(t, logs.All(), 2) for _, log := range logs.All() { assert.Contains(t, log.Message, "Traces pipeline component had an error") } } func TestTracesCapabilities(t *testing.T) { setGateForTest(t, true) mockConsumer := &mockTracesConsumer{ capabilities: consumer.Capabilities{MutatesData: true}, } reader := sdkmetric.NewManualReader() mp := sdkmetric.NewMeterProvider(sdkmetric.WithReader(reader)) meter := mp.Meter("test") itemCounter, err := meter.Int64Counter("item_counter") require.NoError(t, err) sizeCounter, err := meter.Int64Counter("size_counter") require.NoError(t, err) sizeCounterDisabled := newDisabledCounter(sizeCounter) // Test with item counter only consumer := obsconsumer.NewTraces(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounterDisabled, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) // Test with both counters consumer = obsconsumer.NewTraces(mockConsumer, obsconsumer.Settings{ItemCounter: itemCounter, SizeCounter: sizeCounter, Logger: zap.NewNop()}) require.Equal(t, consumer.Capabilities(), mockConsumer.capabilities) } opentelemetry-collector-0.141.0/service/internal/proctelemetry/000077500000000000000000000000001511331344600247105ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/proctelemetry/process_telemetry.go000066400000000000000000000100441511331344600310060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proctelemetry // import "go.opentelemetry.io/collector/service/internal/proctelemetry" import ( "context" "errors" "os" "runtime" "sync" "time" "github.com/shirou/gopsutil/v4/common" "github.com/shirou/gopsutil/v4/process" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/service/internal/metadata" ) // processMetrics is a struct that contains views related to process metrics (cpu, mem, etc) type processMetrics struct { startTimeUnixNano int64 proc *process.Process context context.Context // mu protects everything bellow. mu sync.Mutex lastMsRead time.Time ms *runtime.MemStats } type RegisterOption interface { apply(*registerOption) } type registerOption struct { hostProc string } type registerOptionFunc func(*registerOption) func (fn registerOptionFunc) apply(set *registerOption) { fn(set) } // WithHostProc overrides the /proc folder on Linux used by process telemetry. func WithHostProc(hostProc string) RegisterOption { return registerOptionFunc(func(uo *registerOption) { uo.hostProc = hostProc }) } // RegisterProcessMetrics creates a new set of processMetrics (mem, cpu) that can be used to measure // basic information about this process. func RegisterProcessMetrics(cfg component.TelemetrySettings, opts ...RegisterOption) error { set := registerOption{} for _, opt := range opts { opt.apply(&set) } var err error pm := &processMetrics{ startTimeUnixNano: time.Now().UnixNano(), ms: &runtime.MemStats{}, } ctx := context.Background() if set.hostProc != "" { ctx = context.WithValue(ctx, common.EnvKey, common.EnvMap{common.HostProcEnvKey: set.hostProc}) } pm.context = ctx pm.proc, err = process.NewProcessWithContext(pm.context, int32(os.Getpid())) if err != nil { return err } tb, err := metadata.NewTelemetryBuilder(cfg) if err != nil { return err } return errors.Join( tb.RegisterProcessUptimeCallback(pm.updateProcessUptime), tb.RegisterProcessRuntimeHeapAllocBytesCallback(pm.updateAllocMem), tb.RegisterProcessRuntimeTotalAllocBytesCallback(pm.updateTotalAllocMem), tb.RegisterProcessRuntimeTotalSysMemoryBytesCallback(pm.updateSysMem), tb.RegisterProcessCPUSecondsCallback(pm.updateCPUSeconds), tb.RegisterProcessMemoryRssCallback(pm.updateRSSMemory), ) } func (pm *processMetrics) updateProcessUptime(_ context.Context, obs metric.Float64Observer) error { now := time.Now().UnixNano() obs.Observe(float64(now-pm.startTimeUnixNano) / 1e9) return nil } func (pm *processMetrics) updateAllocMem(_ context.Context, obs metric.Int64Observer) error { pm.mu.Lock() defer pm.mu.Unlock() pm.readMemStatsIfNeeded() obs.Observe(int64(pm.ms.Alloc)) return nil } func (pm *processMetrics) updateTotalAllocMem(_ context.Context, obs metric.Int64Observer) error { pm.mu.Lock() defer pm.mu.Unlock() pm.readMemStatsIfNeeded() obs.Observe(int64(pm.ms.TotalAlloc)) return nil } func (pm *processMetrics) updateSysMem(_ context.Context, obs metric.Int64Observer) error { pm.mu.Lock() defer pm.mu.Unlock() pm.readMemStatsIfNeeded() obs.Observe(int64(pm.ms.Sys)) return nil } func (pm *processMetrics) updateCPUSeconds(_ context.Context, obs metric.Float64Observer) error { times, err := pm.proc.TimesWithContext(pm.context) //nolint:contextcheck if err != nil { return err } obs.Observe(times.User + times.System + times.Idle + times.Nice + times.Iowait + times.Irq + times.Softirq + times.Steal) return nil } func (pm *processMetrics) updateRSSMemory(_ context.Context, obs metric.Int64Observer) error { mem, err := pm.proc.MemoryInfoWithContext(pm.context) //nolint:contextcheck if err != nil { return err } obs.Observe(int64(mem.RSS)) return nil } func (pm *processMetrics) readMemStatsIfNeeded() { now := time.Now() // If last time we read was less than one second ago just reuse the values if now.Sub(pm.lastMsRead) < time.Second { return } pm.lastMsRead = now runtime.ReadMemStats(pm.ms) } opentelemetry-collector-0.141.0/service/internal/proctelemetry/process_telemetry_linux_test.go000066400000000000000000000031731511331344600332710ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:build linux package proctelemetry import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/service/internal/metadatatest" ) func TestProcessTelemetryWithHostProc(t *testing.T) { // Make the sure the environment variable value is not used. t.Setenv("HOST_PROC", "foo/bar") tel := componenttest.NewTelemetry() require.NoError(t, RegisterProcessMetrics(tel.NewTelemetrySettings(), WithHostProc("/proc"))) metadatatest.AssertEqualProcessUptime(t, tel, []metricdata.DataPoint[float64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessRuntimeHeapAllocBytes(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessRuntimeTotalAllocBytes(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessRuntimeTotalSysMemoryBytes(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessCPUSeconds(t, tel, []metricdata.DataPoint[float64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessMemoryRss(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) } opentelemetry-collector-0.141.0/service/internal/proctelemetry/process_telemetry_test.go000066400000000000000000000027461511331344600320570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package proctelemetry import ( "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/sdk/metric/metricdata" "go.opentelemetry.io/otel/sdk/metric/metricdata/metricdatatest" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/service/internal/metadatatest" ) func TestProcessTelemetry(t *testing.T) { tel := componenttest.NewTelemetry() require.NoError(t, RegisterProcessMetrics(tel.NewTelemetrySettings())) metadatatest.AssertEqualProcessUptime(t, tel, []metricdata.DataPoint[float64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessRuntimeHeapAllocBytes(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessRuntimeTotalAllocBytes(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessRuntimeTotalSysMemoryBytes(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessCPUSeconds(t, tel, []metricdata.DataPoint[float64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) metadatatest.AssertEqualProcessMemoryRss(t, tel, []metricdata.DataPoint[int64]{{}}, metricdatatest.IgnoreTimestamp(), metricdatatest.IgnoreValue()) } opentelemetry-collector-0.141.0/service/internal/promtest/000077500000000000000000000000001511331344600236675ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/promtest/server_util.go000066400000000000000000000022171511331344600265630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package promtest // import "go.opentelemetry.io/collector/service/internal/promtest" import ( "net" "strconv" "testing" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/collector/internal/testutil" ) func GetAvailableLocalIPv6AddressPrometheus(tb testing.TB) *config.Prometheus { return addrToPrometheus(testutil.GetAvailableLocalIPv6Address(tb)) } func GetAvailableLocalAddressPrometheus(tb testing.TB) *config.Prometheus { return addrToPrometheus(testutil.GetAvailableLocalAddress(tb)) } func addrToPrometheus(address string) *config.Prometheus { host, port, err := net.SplitHostPort(address) if host == "::1" { host = "[::1]" } if err != nil { return nil } portInt, err := strconv.Atoi(port) if err != nil { return nil } return &config.Prometheus{ Host: &host, Port: &portInt, WithoutScopeInfo: ptr(true), WithoutUnits: ptr(true), WithoutTypeSuffix: ptr(true), WithResourceConstantLabels: &config.IncludeExclude{ Included: []string{}, }, } } func ptr[T any](v T) *T { return &v } opentelemetry-collector-0.141.0/service/internal/refconsumer/000077500000000000000000000000001511331344600243425ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/refconsumer/logs.go000066400000000000000000000015211511331344600256340ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer // import "go.opentelemetry.io/collector/service/internal/refconsumer" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func NewLogs(cons consumer.Logs) consumer.Logs { return refLogs{ consumer: cons, } } type refLogs struct { consumer consumer.Logs } // ConsumeLogs measures telemetry before calling ConsumeLogs because the data may be mutated downstream func (c refLogs) ConsumeLogs(ctx context.Context, ld plog.Logs) error { if pref.MarkPipelineOwnedLogs(ld) { defer pref.UnrefLogs(ld) } return c.consumer.ConsumeLogs(ctx, ld) } func (c refLogs) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/refconsumer/logs_test.go000066400000000000000000000030011511331344600266660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func TestLogsNopWhenGateDisabled(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), false)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewLogs(consumertest.NewNop()) ld := testdata.GenerateLogs(10) assert.Equal(t, 10, ld.LogRecordCount()) require.NoError(t, refCons.ConsumeLogs(t.Context(), ld)) assert.Equal(t, 10, ld.LogRecordCount()) } func TestLogs(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), true)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewLogs(consumertest.NewNop()) ld := testdata.GenerateLogs(10) assert.Equal(t, 10, ld.LogRecordCount()) require.NoError(t, refCons.ConsumeLogs(t.Context(), ld)) // Data should be reset at this point. assert.Equal(t, 0, ld.LogRecordCount()) } opentelemetry-collector-0.141.0/service/internal/refconsumer/metrics.go000066400000000000000000000016041511331344600263400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer // import "go.opentelemetry.io/collector/service/internal/refconsumer" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func NewMetrics(cons consumer.Metrics) consumer.Metrics { return refMetrics{ consumer: cons, } } type refMetrics struct { consumer consumer.Metrics } // ConsumeMetrics measures telemetry before calling ConsumeMetrics because the data may be mutated downstream func (c refMetrics) ConsumeMetrics(ctx context.Context, ld pmetric.Metrics) error { if pref.MarkPipelineOwnedMetrics(ld) { defer pref.UnrefMetrics(ld) } return c.consumer.ConsumeMetrics(ctx, ld) } func (c refMetrics) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/refconsumer/metrics_test.go000066400000000000000000000030151511331344600273750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func TestMetricsNopWhenGateDisabled(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), false)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewMetrics(consumertest.NewNop()) md := testdata.GenerateMetrics(10) assert.Equal(t, 10, md.MetricCount()) require.NoError(t, refCons.ConsumeMetrics(t.Context(), md)) assert.Equal(t, 10, md.MetricCount()) } func TestMetrics(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), true)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewMetrics(consumertest.NewNop()) md := testdata.GenerateMetrics(10) assert.Equal(t, 10, md.MetricCount()) require.NoError(t, refCons.ConsumeMetrics(t.Context(), md)) // Data shoumd be reset at this point. assert.Equal(t, 0, md.MetricCount()) } opentelemetry-collector-0.141.0/service/internal/refconsumer/profiles.go000066400000000000000000000017141511331344600265170ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer // import "go.opentelemetry.io/collector/service/internal/refconsumer" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func NewProfiles(cons xconsumer.Profiles) xconsumer.Profiles { return refProfiles{ consumer: cons, } } type refProfiles struct { consumer xconsumer.Profiles } // ConsumeProfiles measures telemetry before calling ConsumeProfiles because the data may be mutated downstream func (c refProfiles) ConsumeProfiles(ctx context.Context, ld pprofile.Profiles) error { if pref.MarkPipelineOwnedProfiles(ld) { defer pref.UnrefProfiles(ld) } return c.consumer.ConsumeProfiles(ctx, ld) } func (c refProfiles) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/refconsumer/profiles_test.go000066400000000000000000000030251511331344600275530ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func TestProfilesNopWhenGateDisabled(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), false)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewProfiles(consumertest.NewNop()) pd := testdata.GenerateProfiles(10) assert.Equal(t, 10, pd.SampleCount()) require.NoError(t, refCons.ConsumeProfiles(t.Context(), pd)) assert.Equal(t, 10, pd.SampleCount()) } func TestProfiles(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), true)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewProfiles(consumertest.NewNop()) pd := testdata.GenerateProfiles(10) assert.Equal(t, 10, pd.SampleCount()) require.NoError(t, refCons.ConsumeProfiles(t.Context(), pd)) // Data shoupd be reset at this point. assert.Equal(t, 0, pd.SampleCount()) } opentelemetry-collector-0.141.0/service/internal/refconsumer/traces.go000066400000000000000000000015631511331344600261570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer // import "go.opentelemetry.io/collector/service/internal/refconsumer" import ( "context" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func NewTraces(cons consumer.Traces) consumer.Traces { return refTraces{ consumer: cons, } } type refTraces struct { consumer consumer.Traces } // ConsumeTraces measures telemetry before calling ConsumeTraces because the data may be mutated downstream func (c refTraces) ConsumeTraces(ctx context.Context, ld ptrace.Traces) error { if pref.MarkPipelineOwnedTraces(ld) { defer pref.UnrefTraces(ld) } return c.consumer.ConsumeTraces(ctx, ld) } func (c refTraces) Capabilities() consumer.Capabilities { return c.consumer.Capabilities() } opentelemetry-collector-0.141.0/service/internal/refconsumer/traces_test.go000066400000000000000000000027751511331344600272240ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package refconsumer import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) func TestTracesNopWhenGateDisabled(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), false)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewTraces(consumertest.NewNop()) td := testdata.GenerateTraces(10) assert.Equal(t, 10, td.SpanCount()) require.NoError(t, refCons.ConsumeTraces(t.Context(), td)) assert.Equal(t, 10, td.SpanCount()) } func TestTraces(t *testing.T) { initial := pref.UseProtoPooling.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(pref.UseProtoPooling.ID(), true)) t.Cleanup(func() { require.NoError(t, featuregate.GlobalRegistry().Set(telemetry.NewPipelineTelemetryGate.ID(), initial)) }) refCons := NewTraces(consumertest.NewNop()) td := testdata.GenerateTraces(10) assert.Equal(t, 10, td.SpanCount()) require.NoError(t, refCons.ConsumeTraces(t.Context(), td)) // Data shoutd be reset at this point. assert.Equal(t, 0, td.SpanCount()) } opentelemetry-collector-0.141.0/service/internal/resource/000077500000000000000000000000001511331344600236415ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/resource/config.go000066400000000000000000000031211511331344600254320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package resource // import "go.opentelemetry.io/collector/service/internal/resource" import ( "github.com/google/uuid" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/collector/component" ) // New resource from telemetry configuration. func New(buildInfo component.BuildInfo, resourceCfg map[string]*string) *resource.Resource { var telAttrs []attribute.KeyValue for k, v := range resourceCfg { // nil value indicates that the attribute should not be included in the telemetry. if v != nil { telAttrs = append(telAttrs, attribute.String(k, *v)) } } if _, ok := resourceCfg[string(semconv.ServiceNameKey)]; !ok { // AttributeServiceName is not specified in the config. Use the default service name. telAttrs = append(telAttrs, semconv.ServiceNameKey.String(buildInfo.Command)) } if _, ok := resourceCfg[string(semconv.ServiceInstanceIDKey)]; !ok { // AttributeServiceInstanceID is not specified in the config. Auto-generate one. instanceUUID, _ := uuid.NewRandom() instanceID := instanceUUID.String() telAttrs = append(telAttrs, semconv.ServiceInstanceIDKey.String(instanceID)) } if _, ok := resourceCfg[string(semconv.ServiceVersionKey)]; !ok { // AttributeServiceVersion is not specified in the config. Use the actual // build version. telAttrs = append(telAttrs, semconv.ServiceVersionKey.String(buildInfo.Version)) } return resource.NewWithAttributes(semconv.SchemaURL, telAttrs...) } opentelemetry-collector-0.141.0/service/internal/resource/config_test.go000066400000000000000000000110771511331344600265020ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package resource import ( "testing" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" sdkresource "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.37.0" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" ) const ( randomUUIDSpecialValue = "random-uuid" ) var buildInfo = component.BuildInfo{ Command: "otelcol", Version: "1.0.0", } func ptr[T any](v T) *T { return &v } func TestNew(t *testing.T) { tests := []struct { name string resourceCfg map[string]*string want map[string]string }{ { name: "empty", resourceCfg: map[string]*string{}, want: map[string]string{ "service.name": "otelcol", "service.version": "1.0.0", "service.instance.id": randomUUIDSpecialValue, }, }, { name: "overwrite", resourceCfg: map[string]*string{ "service.name": ptr("my-service"), "service.version": ptr("1.2.3"), "service.instance.id": ptr("123"), }, want: map[string]string{ "service.name": "my-service", "service.version": "1.2.3", "service.instance.id": "123", }, }, { name: "remove", resourceCfg: map[string]*string{ "service.name": nil, "service.version": nil, "service.instance.id": nil, }, want: map[string]string{}, }, { name: "add", resourceCfg: map[string]*string{ "host.name": ptr("my-host"), }, want: map[string]string{ "service.name": "otelcol", "service.version": "1.0.0", "service.instance.id": randomUUIDSpecialValue, "host.name": "my-host", }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { res := New(buildInfo, tt.resourceCfg) got := make(map[string]string) for _, attr := range res.Attributes() { got[string(attr.Key)] = attr.Value.Emit() } if tt.want["service.instance.id"] == randomUUIDSpecialValue { assert.Contains(t, got, "service.instance.id") // Check that the value is a valid UUID. _, err := uuid.Parse(got["service.instance.id"]) require.NoError(t, err) // Remove so that we can compare the rest of the map. delete(got, "service.instance.id") delete(tt.want, "service.instance.id") } assert.Equal(t, tt.want, got) }) } } func pdataFromSdk(res *sdkresource.Resource) pcommon.Resource { // pcommon.NewResource is the best way to generate a new resource currently and is safe to use outside of tests. // Because the resource is signal agnostic, and we need a net new resource, not an existing one, this is the only // method of creating it without exposing internal packages. pcommonRes := pcommon.NewResource() for _, keyValue := range res.Attributes() { pcommonRes.Attributes().PutStr(string(keyValue.Key), keyValue.Value.AsString()) } return pcommonRes } func TestBuildResource(t *testing.T) { buildInfo := component.NewDefaultBuildInfo() // Check default config var resMap map[string]*string otelRes := New(buildInfo, resMap) res := pdataFromSdk(otelRes) assert.Equal(t, 3, res.Attributes().Len()) value, ok := res.Attributes().Get("service.name") assert.True(t, ok) assert.Equal(t, buildInfo.Command, value.AsString()) value, ok = res.Attributes().Get("service.version") assert.True(t, ok) assert.Equal(t, buildInfo.Version, value.AsString()) _, ok = res.Attributes().Get("service.instance.id") assert.True(t, ok) // Check override by nil resMap = map[string]*string{ string(semconv.ServiceNameKey): nil, string(semconv.ServiceVersionKey): nil, string(semconv.ServiceInstanceIDKey): nil, } otelRes = New(buildInfo, resMap) res = pdataFromSdk(otelRes) // Attributes should not exist since we nil-ified all. assert.Equal(t, 0, res.Attributes().Len()) // Check override values strPtr := func(v string) *string { return &v } resMap = map[string]*string{ string(semconv.ServiceNameKey): strPtr("a"), string(semconv.ServiceVersionKey): strPtr("b"), string(semconv.ServiceInstanceIDKey): strPtr("c"), } otelRes = New(buildInfo, resMap) res = pdataFromSdk(otelRes) assert.Equal(t, 3, res.Attributes().Len()) value, ok = res.Attributes().Get("service.name") assert.True(t, ok) assert.Equal(t, "a", value.AsString()) value, ok = res.Attributes().Get("service.version") assert.True(t, ok) assert.Equal(t, "b", value.AsString()) value, ok = res.Attributes().Get("service.instance.id") assert.True(t, ok) assert.Equal(t, "c", value.AsString()) } opentelemetry-collector-0.141.0/service/internal/status/000077500000000000000000000000001511331344600233355ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/status/nop.go000066400000000000000000000010511511331344600244550ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package status // import "go.opentelemetry.io/collector/service/internal/status" import ( "go.opentelemetry.io/collector/component/componentstatus" ) func NewNopStatusReporter() Reporter { return &nopStatusReporter{} } type nopStatusReporter struct{} func (r *nopStatusReporter) Ready() {} func (r *nopStatusReporter) ReportStatus(*componentstatus.InstanceID, *componentstatus.Event) {} func (r *nopStatusReporter) ReportOKIfStarting(*componentstatus.InstanceID) {} opentelemetry-collector-0.141.0/service/internal/status/nop_test.go000066400000000000000000000004661511331344600255250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package status // import "go.opentelemetry.io/collector/service/internal/status" import "testing" func TestNopStatusReporter(*testing.T) { nop := NewNopStatusReporter() nop.ReportOKIfStarting(nil) nop.ReportStatus(nil, nil) } opentelemetry-collector-0.141.0/service/internal/status/package_test.go000066400000000000000000000003071511331344600263160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package status import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/internal/status/status.go000066400000000000000000000127001511331344600252070ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package status // import "go.opentelemetry.io/collector/service/internal/status" import ( "errors" "fmt" "sync" "go.opentelemetry.io/collector/component/componentstatus" ) // onTransitionFunc receives a componentstatus.Event on a successful state transition type onTransitionFunc func(*componentstatus.Event) // errInvalidStateTransition is returned for invalid state transitions var errInvalidStateTransition = errors.New("invalid state transition") // fsm is a finite state machine that models transitions for component status type fsm struct { current *componentstatus.Event transitions map[componentstatus.Status]map[componentstatus.Status]struct{} onTransition onTransitionFunc } // transition will attempt to execute a state transition. If it's successful, it calls the // onTransitionFunc with a Event representing the new state. Returns an error if the arguments // result in an invalid status, or if the state transition is not valid. func (m *fsm) transition(ev *componentstatus.Event) error { if _, ok := m.transitions[m.current.Status()][ev.Status()]; !ok { return fmt.Errorf( "cannot transition from %s to %s: %w", m.current.Status(), ev.Status(), errInvalidStateTransition, ) } m.current = ev m.onTransition(ev) return nil } // newFSM creates a state machine with all valid transitions for componentstatus.Status. // The initial state is set to componentstatus.StatusNone. func newFSM(onTransition onTransitionFunc) *fsm { return &fsm{ current: componentstatus.NewEvent(componentstatus.StatusNone), onTransition: onTransition, transitions: map[componentstatus.Status]map[componentstatus.Status]struct{}{ componentstatus.StatusNone: { componentstatus.StatusStarting: {}, }, componentstatus.StatusStarting: { componentstatus.StatusOK: {}, componentstatus.StatusRecoverableError: {}, componentstatus.StatusPermanentError: {}, componentstatus.StatusFatalError: {}, componentstatus.StatusStopping: {}, }, componentstatus.StatusOK: { componentstatus.StatusRecoverableError: {}, componentstatus.StatusPermanentError: {}, componentstatus.StatusFatalError: {}, componentstatus.StatusStopping: {}, }, componentstatus.StatusRecoverableError: { componentstatus.StatusOK: {}, componentstatus.StatusPermanentError: {}, componentstatus.StatusFatalError: {}, componentstatus.StatusStopping: {}, }, componentstatus.StatusPermanentError: { componentstatus.StatusStopping: {}, }, componentstatus.StatusFatalError: {}, componentstatus.StatusStopping: { componentstatus.StatusRecoverableError: {}, componentstatus.StatusPermanentError: {}, componentstatus.StatusFatalError: {}, componentstatus.StatusStopped: {}, }, componentstatus.StatusStopped: {}, }, } } // NotifyStatusFunc is the receiver of status events after successful state transitions type NotifyStatusFunc func(*componentstatus.InstanceID, *componentstatus.Event) // InvalidTransitionFunc is the receiver of invalid transition errors type InvalidTransitionFunc func(error) // ServiceStatusFunc is the expected type of ReportStatus type ServiceStatusFunc func(*componentstatus.InstanceID, *componentstatus.Event) // ErrStatusNotReady is returned when trying to report status before service start var ErrStatusNotReady = errors.New("report component status is not ready until service start") // Reporter handles component status reporting type Reporter interface { ReportStatus(id *componentstatus.InstanceID, ev *componentstatus.Event) ReportOKIfStarting(id *componentstatus.InstanceID) } type reporter struct { mu sync.Mutex fsmMap map[*componentstatus.InstanceID]*fsm onStatusChange NotifyStatusFunc onInvalidTransition InvalidTransitionFunc } // NewReporter returns a reporter that will invoke the NotifyStatusFunc when a component's status // has changed. func NewReporter(onStatusChange NotifyStatusFunc, onInvalidTransition InvalidTransitionFunc) Reporter { return &reporter{ fsmMap: make(map[*componentstatus.InstanceID]*fsm), onStatusChange: onStatusChange, onInvalidTransition: onInvalidTransition, } } // ReportStatus reports status for the given InstanceID func (r *reporter) ReportStatus( id *componentstatus.InstanceID, ev *componentstatus.Event, ) { r.mu.Lock() defer r.mu.Unlock() if err := r.componentFSM(id).transition(ev); err != nil { r.onInvalidTransition(err) } } func (r *reporter) ReportOKIfStarting(id *componentstatus.InstanceID) { r.mu.Lock() defer r.mu.Unlock() fsm := r.componentFSM(id) if fsm.current.Status() == componentstatus.StatusStarting { if err := fsm.transition(componentstatus.NewEvent(componentstatus.StatusOK)); err != nil { r.onInvalidTransition(err) } } } // Note: a lock must be acquired before calling this method. func (r *reporter) componentFSM(id *componentstatus.InstanceID) *fsm { fsm, ok := r.fsmMap[id] if !ok { fsm = newFSM(func(ev *componentstatus.Event) { r.onStatusChange(id, ev) }) r.fsmMap[id] = fsm } return fsm } // NewReportStatusFunc returns a function to be used as ReportStatus for componentstatus.TelemetrySettings func NewReportStatusFunc( id *componentstatus.InstanceID, srvStatus ServiceStatusFunc, ) func(*componentstatus.Event) { return func(ev *componentstatus.Event) { srvStatus(id, ev) } } opentelemetry-collector-0.141.0/service/internal/status/status_test.go000066400000000000000000000223101511331344600262440ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package status import ( "fmt" "sync" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componentstatus" ) func TestStatusFSM(t *testing.T) { for _, tt := range []struct { name string reportedStatuses []componentstatus.Status expectedStatuses []componentstatus.Status expectedErrorCount int }{ { name: "successful startup and shutdown", reportedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, }, { name: "component recovered", reportedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusRecoverableError, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusRecoverableError, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, }, { name: "repeated events are errors", reportedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusRecoverableError, componentstatus.StatusRecoverableError, componentstatus.StatusRecoverableError, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusRecoverableError, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, expectedErrorCount: 2, }, { name: "PermanentError is stoppable", reportedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusPermanentError, componentstatus.StatusOK, componentstatus.StatusStopping, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusPermanentError, componentstatus.StatusStopping, }, expectedErrorCount: 1, }, { name: "FatalError is terminal", reportedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusFatalError, componentstatus.StatusOK, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusFatalError, }, expectedErrorCount: 1, }, { name: "Stopped is terminal", reportedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, componentstatus.StatusOK, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, }, expectedErrorCount: 1, }, } { t.Run(tt.name, func(t *testing.T) { var receivedStatuses []componentstatus.Status fsm := newFSM( func(ev *componentstatus.Event) { receivedStatuses = append(receivedStatuses, ev.Status()) }, ) errorCount := 0 for _, status := range tt.reportedStatuses { if err := fsm.transition(componentstatus.NewEvent(status)); err != nil { errorCount++ require.ErrorIs(t, err, errInvalidStateTransition) } } require.Equal(t, tt.expectedErrorCount, errorCount) require.Equal(t, tt.expectedStatuses, receivedStatuses) }) } } func TestValidSeqsToStopped(t *testing.T) { events := []*componentstatus.Event{ componentstatus.NewEvent(componentstatus.StatusStarting), componentstatus.NewEvent(componentstatus.StatusOK), componentstatus.NewEvent(componentstatus.StatusRecoverableError), componentstatus.NewEvent(componentstatus.StatusPermanentError), componentstatus.NewEvent(componentstatus.StatusFatalError), } for _, ev := range events { name := fmt.Sprintf("transition from: %s to: %s", ev.Status(), componentstatus.StatusStopped) t.Run(name, func(t *testing.T) { fsm := newFSM(func(*componentstatus.Event) {}) if ev.Status() != componentstatus.StatusStarting { require.NoError(t, fsm.transition(componentstatus.NewEvent(componentstatus.StatusStarting))) } require.NoError(t, fsm.transition(ev)) // skipping to stopped is not allowed err := fsm.transition(componentstatus.NewEvent(componentstatus.StatusStopped)) require.ErrorIs(t, err, errInvalidStateTransition) // stopping -> stopped is allowed for non-fatal errors err = fsm.transition(componentstatus.NewEvent(componentstatus.StatusStopping)) if ev.Status() == componentstatus.StatusFatalError { require.ErrorIs(t, err, errInvalidStateTransition) } else { require.NoError(t, err) require.NoError(t, fsm.transition(componentstatus.NewEvent(componentstatus.StatusStopped))) } }) } } func TestStatusFuncs(t *testing.T) { id1 := &componentstatus.InstanceID{} id2 := &componentstatus.InstanceID{} actualStatuses := make(map[*componentstatus.InstanceID][]componentstatus.Status) statusFunc := func(id *componentstatus.InstanceID, ev *componentstatus.Event) { actualStatuses[id] = append(actualStatuses[id], ev.Status()) } statuses1 := []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, } statuses2 := []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, componentstatus.StatusRecoverableError, componentstatus.StatusOK, componentstatus.StatusStopping, componentstatus.StatusStopped, } expectedStatuses := map[*componentstatus.InstanceID][]componentstatus.Status{ id1: statuses1, id2: statuses2, } rep := NewReporter(statusFunc, func(err error) { require.NoError(t, err) }) comp1Func := NewReportStatusFunc(id1, rep.ReportStatus) comp2Func := NewReportStatusFunc(id2, rep.ReportStatus) for _, st := range statuses1 { comp1Func(componentstatus.NewEvent(st)) } for _, st := range statuses2 { comp2Func(componentstatus.NewEvent(st)) } require.Equal(t, expectedStatuses, actualStatuses) } func TestStatusFuncsConcurrent(t *testing.T) { ids := []*componentstatus.InstanceID{{}, {}, {}, {}} count := 0 statusFunc := func(*componentstatus.InstanceID, *componentstatus.Event) { count++ } rep := NewReporter(statusFunc, func(err error) { require.NoError(t, err) }) wg := sync.WaitGroup{} wg.Add(len(ids)) for _, id := range ids { go func() { compFn := NewReportStatusFunc(id, rep.ReportStatus) compFn(componentstatus.NewEvent(componentstatus.StatusStarting)) for range 1000 { compFn(componentstatus.NewEvent(componentstatus.StatusRecoverableError)) compFn(componentstatus.NewEvent(componentstatus.StatusOK)) } wg.Done() }() } wg.Wait() require.Equal(t, 8004, count) } func TestReportComponentOKIfStarting(t *testing.T) { for _, tt := range []struct { name string initialStatuses []componentstatus.Status expectedStatuses []componentstatus.Status }{ { name: "matching condition: StatusStarting", initialStatuses: []componentstatus.Status{ componentstatus.StatusStarting, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, }, }, { name: "non-matching condition StatusOK", initialStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusOK, }, }, { name: "non-matching condition RecoverableError", initialStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusRecoverableError, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusRecoverableError, }, }, { name: "non-matching condition PermanentError", initialStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusPermanentError, }, expectedStatuses: []componentstatus.Status{ componentstatus.StatusStarting, componentstatus.StatusPermanentError, }, }, } { t.Run(tt.name, func(t *testing.T) { var receivedStatuses []componentstatus.Status rep := NewReporter( func(_ *componentstatus.InstanceID, ev *componentstatus.Event) { receivedStatuses = append(receivedStatuses, ev.Status()) }, func(err error) { require.NoError(t, err) }, ) id := &componentstatus.InstanceID{} for _, status := range tt.initialStatuses { rep.ReportStatus(id, componentstatus.NewEvent(status)) } rep.ReportOKIfStarting(id) require.Equal(t, tt.expectedStatuses, receivedStatuses) }) } } opentelemetry-collector-0.141.0/service/internal/testcomponents/000077500000000000000000000000001511331344600250775ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/testcomponents/example_connector.go000066400000000000000000000216621511331344600311420ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents // import "go.opentelemetry.io/collector/service/internal/testcomponents" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/testdata" ) var connType = component.MustNewType("exampleconnector") // ExampleConnectorFactory is factory for ExampleConnector. var ExampleConnectorFactory = xconnector.NewFactory( connType, createExampleConnectorDefaultConfig, xconnector.WithTracesToTraces(createExampleTracesToTraces, component.StabilityLevelDevelopment), xconnector.WithTracesToMetrics(createExampleTracesToMetrics, component.StabilityLevelDevelopment), xconnector.WithTracesToLogs(createExampleTracesToLogs, component.StabilityLevelDevelopment), xconnector.WithTracesToProfiles(createExampleTracesToProfiles, component.StabilityLevelDevelopment), xconnector.WithMetricsToTraces(createExampleMetricsToTraces, component.StabilityLevelDevelopment), xconnector.WithMetricsToMetrics(createExampleMetricsToMetrics, component.StabilityLevelDevelopment), xconnector.WithMetricsToLogs(createExampleMetricsToLogs, component.StabilityLevelDevelopment), xconnector.WithMetricsToProfiles(createExampleMetricsToProfiles, component.StabilityLevelDevelopment), xconnector.WithLogsToTraces(createExampleLogsToTraces, component.StabilityLevelDevelopment), xconnector.WithLogsToMetrics(createExampleLogsToMetrics, component.StabilityLevelDevelopment), xconnector.WithLogsToLogs(createExampleLogsToLogs, component.StabilityLevelDevelopment), xconnector.WithLogsToProfiles(createExampleLogsToProfiles, component.StabilityLevelDevelopment), xconnector.WithProfilesToTraces(createExampleProfilesToTraces, component.StabilityLevelDevelopment), xconnector.WithProfilesToMetrics(createExampleProfilesToMetrics, component.StabilityLevelDevelopment), xconnector.WithProfilesToLogs(createExampleProfilesToLogs, component.StabilityLevelDevelopment), xconnector.WithProfilesToProfiles(createExampleProfilesToProfiles, component.StabilityLevelDevelopment), ) var MockForwardConnectorFactory = xconnector.NewFactory( component.MustNewType("mockforward"), createExampleConnectorDefaultConfig, xconnector.WithTracesToTraces(createExampleTracesToTraces, component.StabilityLevelDevelopment), xconnector.WithMetricsToMetrics(createExampleMetricsToMetrics, component.StabilityLevelDevelopment), xconnector.WithLogsToLogs(createExampleLogsToLogs, component.StabilityLevelDevelopment), xconnector.WithProfilesToProfiles(createExampleProfilesToProfiles, component.StabilityLevelDevelopment), ) func createExampleConnectorDefaultConfig() component.Config { return &struct{}{} } func createExampleTracesToTraces(_ context.Context, set connector.Settings, _ component.Config, traces consumer.Traces) (connector.Traces, error) { return &ExampleConnector{ ConsumeTracesFunc: traces.ConsumeTraces, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleTracesToMetrics(_ context.Context, set connector.Settings, _ component.Config, metrics consumer.Metrics) (connector.Traces, error) { return &ExampleConnector{ ConsumeTracesFunc: func(ctx context.Context, td ptrace.Traces) error { return metrics.ConsumeMetrics(ctx, testdata.GenerateMetrics(td.SpanCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleTracesToLogs(_ context.Context, set connector.Settings, _ component.Config, logs consumer.Logs) (connector.Traces, error) { return &ExampleConnector{ ConsumeTracesFunc: func(ctx context.Context, td ptrace.Traces) error { return logs.ConsumeLogs(ctx, testdata.GenerateLogs(td.SpanCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleTracesToProfiles(_ context.Context, set connector.Settings, _ component.Config, profiles xconsumer.Profiles) (connector.Traces, error) { return &ExampleConnector{ ConsumeTracesFunc: func(ctx context.Context, td ptrace.Traces) error { return profiles.ConsumeProfiles(ctx, testdata.GenerateProfiles(td.SpanCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleMetricsToTraces(_ context.Context, set connector.Settings, _ component.Config, traces consumer.Traces) (connector.Metrics, error) { return &ExampleConnector{ ConsumeMetricsFunc: func(ctx context.Context, md pmetric.Metrics) error { return traces.ConsumeTraces(ctx, testdata.GenerateTraces(md.MetricCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleMetricsToMetrics(_ context.Context, set connector.Settings, _ component.Config, metrics consumer.Metrics) (connector.Metrics, error) { return &ExampleConnector{ ConsumeMetricsFunc: metrics.ConsumeMetrics, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleMetricsToLogs(_ context.Context, set connector.Settings, _ component.Config, logs consumer.Logs) (connector.Metrics, error) { return &ExampleConnector{ ConsumeMetricsFunc: func(ctx context.Context, md pmetric.Metrics) error { return logs.ConsumeLogs(ctx, testdata.GenerateLogs(md.MetricCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleMetricsToProfiles(_ context.Context, set connector.Settings, _ component.Config, profiles xconsumer.Profiles) (connector.Metrics, error) { return &ExampleConnector{ ConsumeMetricsFunc: func(ctx context.Context, md pmetric.Metrics) error { return profiles.ConsumeProfiles(ctx, testdata.GenerateProfiles(md.MetricCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleLogsToTraces(_ context.Context, set connector.Settings, _ component.Config, traces consumer.Traces) (connector.Logs, error) { return &ExampleConnector{ ConsumeLogsFunc: func(ctx context.Context, ld plog.Logs) error { return traces.ConsumeTraces(ctx, testdata.GenerateTraces(ld.LogRecordCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleLogsToMetrics(_ context.Context, set connector.Settings, _ component.Config, metrics consumer.Metrics) (connector.Logs, error) { return &ExampleConnector{ ConsumeLogsFunc: func(ctx context.Context, ld plog.Logs) error { return metrics.ConsumeMetrics(ctx, testdata.GenerateMetrics(ld.LogRecordCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleLogsToLogs(_ context.Context, set connector.Settings, _ component.Config, logs consumer.Logs) (connector.Logs, error) { return &ExampleConnector{ ConsumeLogsFunc: logs.ConsumeLogs, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleLogsToProfiles(_ context.Context, set connector.Settings, _ component.Config, profiles xconsumer.Profiles) (connector.Logs, error) { return &ExampleConnector{ ConsumeLogsFunc: func(ctx context.Context, ld plog.Logs) error { return profiles.ConsumeProfiles(ctx, testdata.GenerateProfiles(ld.LogRecordCount())) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleProfilesToTraces(_ context.Context, set connector.Settings, _ component.Config, traces consumer.Traces) (xconnector.Profiles, error) { return &ExampleConnector{ ConsumeProfilesFunc: func(ctx context.Context, _ pprofile.Profiles) error { return traces.ConsumeTraces(ctx, testdata.GenerateTraces(1)) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleProfilesToMetrics(_ context.Context, set connector.Settings, _ component.Config, metrics consumer.Metrics) (xconnector.Profiles, error) { return &ExampleConnector{ ConsumeProfilesFunc: func(ctx context.Context, _ pprofile.Profiles) error { return metrics.ConsumeMetrics(ctx, testdata.GenerateMetrics(1)) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleProfilesToLogs(_ context.Context, set connector.Settings, _ component.Config, logs consumer.Logs) (xconnector.Profiles, error) { return &ExampleConnector{ ConsumeProfilesFunc: func(ctx context.Context, _ pprofile.Profiles) error { return logs.ConsumeLogs(ctx, testdata.GenerateLogs(1)) }, mutatesData: set.ID.Name() == "mutate", }, nil } func createExampleProfilesToProfiles(_ context.Context, set connector.Settings, _ component.Config, profiles xconsumer.Profiles) (xconnector.Profiles, error) { return &ExampleConnector{ ConsumeProfilesFunc: profiles.ConsumeProfiles, mutatesData: set.ID.Name() == "mutate", }, nil } type ExampleConnector struct { componentState consumer.ConsumeTracesFunc consumer.ConsumeMetricsFunc consumer.ConsumeLogsFunc xconsumer.ConsumeProfilesFunc mutatesData bool } func (c *ExampleConnector) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: c.mutatesData} } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_connector_test.go000066400000000000000000000011661511331344600321760ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" ) func TestExampleConnector(t *testing.T) { conn := &ExampleConnector{} host := componenttest.NewNopHost() assert.False(t, conn.Started()) require.NoError(t, conn.Start(context.Background(), host)) assert.True(t, conn.Started()) assert.False(t, conn.Stopped()) require.NoError(t, conn.Shutdown(context.Background())) assert.True(t, conn.Stopped()) } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_exporter.go000066400000000000000000000060631511331344600310160ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents // import "go.opentelemetry.io/collector/service/internal/testcomponents" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/exporter/xexporter" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/xpdata/pref" ) var exporterType = component.MustNewType("exampleexporter") // ExampleExporterFactory is factory for ExampleExporter. var ExampleExporterFactory = xexporter.NewFactory( exporterType, createExporterDefaultConfig, xexporter.WithTraces(createTracesExporter, component.StabilityLevelDevelopment), xexporter.WithMetrics(createMetricsExporter, component.StabilityLevelDevelopment), xexporter.WithLogs(createLogsExporter, component.StabilityLevelDevelopment), xexporter.WithProfiles(createProfilesExporter, component.StabilityLevelDevelopment), ) func createExporterDefaultConfig() component.Config { return &struct{}{} } func createTracesExporter(context.Context, exporter.Settings, component.Config) (exporter.Traces, error) { return &ExampleExporter{}, nil } func createMetricsExporter(context.Context, exporter.Settings, component.Config) (exporter.Metrics, error) { return &ExampleExporter{}, nil } func createLogsExporter(context.Context, exporter.Settings, component.Config) (exporter.Logs, error) { return &ExampleExporter{}, nil } func createProfilesExporter(context.Context, exporter.Settings, component.Config) (xexporter.Profiles, error) { return &ExampleExporter{}, nil } // ExampleExporter stores consumed traces, metrics, logs and profiles for testing purposes. type ExampleExporter struct { componentState Traces []ptrace.Traces Metrics []pmetric.Metrics Logs []plog.Logs Profiles []pprofile.Profiles } // ConsumeTraces receives ptrace.Traces for processing by the consumer.Traces. func (exp *ExampleExporter) ConsumeTraces(_ context.Context, td ptrace.Traces) error { pref.RefTraces(td) exp.Traces = append(exp.Traces, td) return nil } // ConsumeMetrics receives pmetric.Metrics for processing by the Metrics. func (exp *ExampleExporter) ConsumeMetrics(_ context.Context, md pmetric.Metrics) error { pref.RefMetrics(md) exp.Metrics = append(exp.Metrics, md) return nil } // ConsumeLogs receives plog.Logs for processing by the Logs. func (exp *ExampleExporter) ConsumeLogs(_ context.Context, ld plog.Logs) error { pref.RefLogs(ld) exp.Logs = append(exp.Logs, ld) return nil } // ConsumeProfiles receives pprofile.Profiles for processing by the xconsumer.Profiles. func (exp *ExampleExporter) ConsumeProfiles(_ context.Context, pd pprofile.Profiles) error { pref.RefProfiles(pd) exp.Profiles = append(exp.Profiles, pd) return nil } func (exp *ExampleExporter) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: false} } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_exporter_test.go000066400000000000000000000025371511331344600320570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" ) func TestExampleExporter(t *testing.T) { exp := &ExampleExporter{} host := componenttest.NewNopHost() assert.False(t, exp.Started()) require.NoError(t, exp.Start(context.Background(), host)) assert.True(t, exp.Started()) assert.Empty(t, exp.Traces) require.NoError(t, exp.ConsumeTraces(context.Background(), ptrace.NewTraces())) assert.Len(t, exp.Traces, 1) assert.Empty(t, exp.Metrics) require.NoError(t, exp.ConsumeMetrics(context.Background(), pmetric.NewMetrics())) assert.Len(t, exp.Metrics, 1) assert.Empty(t, exp.Logs) require.NoError(t, exp.ConsumeLogs(context.Background(), plog.NewLogs())) assert.Len(t, exp.Logs, 1) assert.Empty(t, exp.Profiles) require.NoError(t, exp.ConsumeProfiles(context.Background(), pprofile.NewProfiles())) assert.Len(t, exp.Profiles, 1) assert.False(t, exp.Stopped()) require.NoError(t, exp.Shutdown(context.Background())) assert.True(t, exp.Stopped()) } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_processor.go000066400000000000000000000050171511331344600311630ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents // import "go.opentelemetry.io/collector/service/internal/testcomponents" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/processor/xprocessor" ) var procType = component.MustNewType("exampleprocessor") // ExampleProcessorFactory is factory for ExampleProcessor. var ExampleProcessorFactory = xprocessor.NewFactory( procType, createDefaultConfig, xprocessor.WithTraces(createTracesProcessor, component.StabilityLevelDevelopment), xprocessor.WithMetrics(createMetricsProcessor, component.StabilityLevelDevelopment), xprocessor.WithLogs(createLogsProcessor, component.StabilityLevelDevelopment), xprocessor.WithProfiles(createProfilesProcessor, component.StabilityLevelDevelopment), ) // CreateDefaultConfig creates the default configuration for the Processor. func createDefaultConfig() component.Config { return &struct{}{} } func createTracesProcessor(_ context.Context, set processor.Settings, _ component.Config, nextConsumer consumer.Traces) (processor.Traces, error) { return &ExampleProcessor{ ConsumeTracesFunc: nextConsumer.ConsumeTraces, mutatesData: set.ID.Name() == "mutate", }, nil } func createMetricsProcessor(_ context.Context, set processor.Settings, _ component.Config, nextConsumer consumer.Metrics) (processor.Metrics, error) { return &ExampleProcessor{ ConsumeMetricsFunc: nextConsumer.ConsumeMetrics, mutatesData: set.ID.Name() == "mutate", }, nil } func createLogsProcessor(_ context.Context, set processor.Settings, _ component.Config, nextConsumer consumer.Logs) (processor.Logs, error) { return &ExampleProcessor{ ConsumeLogsFunc: nextConsumer.ConsumeLogs, mutatesData: set.ID.Name() == "mutate", }, nil } func createProfilesProcessor(_ context.Context, set processor.Settings, _ component.Config, nextConsumer xconsumer.Profiles) (xprocessor.Profiles, error) { return &ExampleProcessor{ ConsumeProfilesFunc: nextConsumer.ConsumeProfiles, mutatesData: set.ID.Name() == "mutate", }, nil } type ExampleProcessor struct { componentState consumer.ConsumeTracesFunc consumer.ConsumeMetricsFunc consumer.ConsumeLogsFunc xconsumer.ConsumeProfilesFunc mutatesData bool } func (ep *ExampleProcessor) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: ep.mutatesData} } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_processor_test.go000066400000000000000000000011571511331344600322230ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" ) func TestExampleProcessor(t *testing.T) { prc := &ExampleProcessor{} host := componenttest.NewNopHost() assert.False(t, prc.Started()) require.NoError(t, prc.Start(context.Background(), host)) assert.True(t, prc.Started()) assert.False(t, prc.Stopped()) require.NoError(t, prc.Shutdown(context.Background())) assert.True(t, prc.Stopped()) } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_receiver.go000066400000000000000000000064311511331344600307510ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents // import "go.opentelemetry.io/collector/service/internal/testcomponents" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/receiver/xreceiver" ) var receiverType = component.MustNewType("examplereceiver") // ExampleReceiverFactory is factory for ExampleReceiver. var ExampleReceiverFactory = xreceiver.NewFactory( receiverType, createReceiverDefaultConfig, xreceiver.WithTraces(createTracesReceiver, component.StabilityLevelDevelopment), xreceiver.WithMetrics(createMetricsReceiver, component.StabilityLevelDevelopment), xreceiver.WithLogs(createLogsReceiver, component.StabilityLevelDevelopment), xreceiver.WithProfiles(createProfilesReceiver, component.StabilityLevelDevelopment), ) func createReceiverDefaultConfig() component.Config { return &struct{}{} } // createTraces creates a receiver.Traces based on this config. func createTracesReceiver( _ context.Context, _ receiver.Settings, cfg component.Config, nextConsumer consumer.Traces, ) (receiver.Traces, error) { tr := createReceiver(cfg) tr.ConsumeTracesFunc = nextConsumer.ConsumeTraces return tr, nil } // createMetrics creates a receiver.Metrics based on this config. func createMetricsReceiver( _ context.Context, _ receiver.Settings, cfg component.Config, nextConsumer consumer.Metrics, ) (receiver.Metrics, error) { mr := createReceiver(cfg) mr.ConsumeMetricsFunc = nextConsumer.ConsumeMetrics return mr, nil } // createLogs creates a receiver.Logs based on this config. func createLogsReceiver( _ context.Context, _ receiver.Settings, cfg component.Config, nextConsumer consumer.Logs, ) (receiver.Logs, error) { lr := createReceiver(cfg) lr.ConsumeLogsFunc = nextConsumer.ConsumeLogs return lr, nil } // createProfiles creates a receiver.Profiles based on this config. func createProfilesReceiver( _ context.Context, _ receiver.Settings, cfg component.Config, nextConsumer xconsumer.Profiles, ) (xreceiver.Profiles, error) { tr := createReceiver(cfg) tr.ConsumeProfilesFunc = nextConsumer.ConsumeProfiles return tr, nil } func createReceiver(cfg component.Config) *ExampleReceiver { // There must be one receiver for all data types. We maintain a map of // receivers per config. // Check to see if there is already a receiver for this config. er, ok := exampleReceivers[cfg] if !ok { er = &ExampleReceiver{} // Remember the receiver in the map exampleReceivers[cfg] = er } return er } // ExampleReceiver allows producing traces, metrics, logs and profiles for testing purposes. type ExampleReceiver struct { componentState consumer.ConsumeTracesFunc consumer.ConsumeMetricsFunc consumer.ConsumeLogsFunc xconsumer.ConsumeProfilesFunc } // This is the map of already created example receivers for particular configurations. // We maintain this map because the receiver.Factory is asked trace and metric receivers separately // when it gets CreateTraces() and CreateMetrics() but they must not // create separate objects, they must use one Receiver object per configuration. var exampleReceivers = map[component.Config]*ExampleReceiver{} opentelemetry-collector-0.141.0/service/internal/testcomponents/example_receiver_test.go000066400000000000000000000011551511331344600320060ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" ) func TestExampleReceiver(t *testing.T) { rcv := &ExampleReceiver{} host := componenttest.NewNopHost() assert.False(t, rcv.Started()) require.NoError(t, rcv.Start(context.Background(), host)) assert.True(t, rcv.Started()) assert.False(t, rcv.Stopped()) require.NoError(t, rcv.Shutdown(context.Background())) assert.True(t, rcv.Stopped()) } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_router.go000066400000000000000000000110171511331344600304610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents // import "go.opentelemetry.io/collector/service/internal/testcomponents" import ( "context" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/plog" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pprofile" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pipeline" ) var routerType = component.MustNewType("examplerouter") // ExampleRouterFactory is factory for ExampleRouter. var ExampleRouterFactory = xconnector.NewFactory( routerType, createExampleRouterDefaultConfig, xconnector.WithTracesToTraces(createExampleTracesRouter, component.StabilityLevelDevelopment), xconnector.WithMetricsToMetrics(createExampleMetricsRouter, component.StabilityLevelDevelopment), xconnector.WithLogsToLogs(createExampleLogsRouter, component.StabilityLevelDevelopment), xconnector.WithProfilesToProfiles(createExampleProfilesRouter, component.StabilityLevelDevelopment), ) type LeftRightConfig struct { Left pipeline.ID `mapstructure:"left"` Right pipeline.ID `mapstructure:"right"` } type ExampleRouterConfig struct { Traces *LeftRightConfig `mapstructure:"traces"` Metrics *LeftRightConfig `mapstructure:"metrics"` Logs *LeftRightConfig `mapstructure:"logs"` Profiles *LeftRightConfig `mapstructure:"profiles"` } func createExampleRouterDefaultConfig() component.Config { return &ExampleRouterConfig{} } func createExampleTracesRouter(_ context.Context, _ connector.Settings, cfg component.Config, traces consumer.Traces) (connector.Traces, error) { c := cfg.(ExampleRouterConfig) r := traces.(connector.TracesRouterAndConsumer) left, _ := r.Consumer(c.Traces.Left) right, _ := r.Consumer(c.Traces.Right) return &ExampleRouter{ tracesRight: right, tracesLeft: left, }, nil } func createExampleMetricsRouter(_ context.Context, _ connector.Settings, cfg component.Config, metrics consumer.Metrics) (connector.Metrics, error) { c := cfg.(ExampleRouterConfig) r := metrics.(connector.MetricsRouterAndConsumer) left, _ := r.Consumer(c.Metrics.Left) right, _ := r.Consumer(c.Metrics.Right) return &ExampleRouter{ metricsRight: right, metricsLeft: left, }, nil } func createExampleLogsRouter(_ context.Context, _ connector.Settings, cfg component.Config, logs consumer.Logs) (connector.Logs, error) { c := cfg.(ExampleRouterConfig) r := logs.(connector.LogsRouterAndConsumer) left, _ := r.Consumer(c.Logs.Left) right, _ := r.Consumer(c.Logs.Right) return &ExampleRouter{ logsRight: right, logsLeft: left, }, nil } func createExampleProfilesRouter(_ context.Context, _ connector.Settings, cfg component.Config, profiles xconsumer.Profiles) (xconnector.Profiles, error) { c := cfg.(ExampleRouterConfig) r := profiles.(xconnector.ProfilesRouterAndConsumer) left, _ := r.Consumer(c.Profiles.Left) right, _ := r.Consumer(c.Profiles.Right) return &ExampleRouter{ profilesRight: right, profilesLeft: left, }, nil } type ExampleRouter struct { componentState tracesRight consumer.Traces tracesLeft consumer.Traces tracesNum int metricsRight consumer.Metrics metricsLeft consumer.Metrics metricsNum int logsRight consumer.Logs logsLeft consumer.Logs logsNum int profilesRight xconsumer.Profiles profilesLeft xconsumer.Profiles profilesNum int } func (r *ExampleRouter) ConsumeTraces(ctx context.Context, td ptrace.Traces) error { r.tracesNum++ if r.tracesNum%2 == 0 { return r.tracesLeft.ConsumeTraces(ctx, td) } return r.tracesRight.ConsumeTraces(ctx, td) } func (r *ExampleRouter) ConsumeMetrics(ctx context.Context, md pmetric.Metrics) error { r.metricsNum++ if r.metricsNum%2 == 0 { return r.metricsLeft.ConsumeMetrics(ctx, md) } return r.metricsRight.ConsumeMetrics(ctx, md) } func (r *ExampleRouter) ConsumeLogs(ctx context.Context, ld plog.Logs) error { r.logsNum++ if r.logsNum%2 == 0 { return r.logsLeft.ConsumeLogs(ctx, ld) } return r.logsRight.ConsumeLogs(ctx, ld) } func (r *ExampleRouter) ConsumeProfiles(ctx context.Context, td pprofile.Profiles) error { r.profilesNum++ if r.profilesNum%2 == 0 { return r.profilesLeft.ConsumeProfiles(ctx, td) } return r.profilesRight.ConsumeProfiles(ctx, td) } func (r *ExampleRouter) Capabilities() consumer.Capabilities { return consumer.Capabilities{MutatesData: false} } opentelemetry-collector-0.141.0/service/internal/testcomponents/example_router_test.go000066400000000000000000000154551511331344600315320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/connector/connectortest" "go.opentelemetry.io/collector/connector/xconnector" "go.opentelemetry.io/collector/consumer" "go.opentelemetry.io/collector/consumer/consumertest" "go.opentelemetry.io/collector/consumer/xconsumer" "go.opentelemetry.io/collector/pdata/testdata" "go.opentelemetry.io/collector/pipeline" ) func TestExampleRouter(t *testing.T) { conn := &ExampleRouter{} host := componenttest.NewNopHost() assert.False(t, conn.Started()) require.NoError(t, conn.Start(context.Background(), host)) assert.True(t, conn.Started()) assert.False(t, conn.Stopped()) require.NoError(t, conn.Shutdown(context.Background())) assert.True(t, conn.Stopped()) } func TestTracesRouter(t *testing.T) { leftID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_left") rightID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_right") sinkLeft := new(consumertest.TracesSink) sinkRight := new(consumertest.TracesSink) // The service will build a router to give to every connector. // Many connectors will just call router.ConsumeTraces, // but some implementation will call RouteTraces instead. router := connector.NewTracesRouter( map[pipeline.ID]consumer.Traces{ leftID: sinkLeft, rightID: sinkRight, }) cfg := ExampleRouterConfig{Traces: &LeftRightConfig{Left: leftID, Right: rightID}} tr, err := ExampleRouterFactory.CreateTracesToTraces( context.Background(), connectortest.NewNopSettings(ExampleRouterFactory.Type()), cfg, router) require.NoError(t, err) assert.False(t, tr.Capabilities().MutatesData) td := testdata.GenerateTraces(1) require.NoError(t, tr.ConsumeTraces(context.Background(), td)) assert.Len(t, sinkRight.AllTraces(), 1) assert.Empty(t, sinkLeft.AllTraces()) require.NoError(t, tr.ConsumeTraces(context.Background(), td)) assert.Len(t, sinkRight.AllTraces(), 1) assert.Len(t, sinkLeft.AllTraces(), 1) assert.NoError(t, tr.ConsumeTraces(context.Background(), td)) assert.NoError(t, tr.ConsumeTraces(context.Background(), td)) assert.NoError(t, tr.ConsumeTraces(context.Background(), td)) assert.Len(t, sinkRight.AllTraces(), 3) assert.Len(t, sinkLeft.AllTraces(), 2) } func TestMetricsRouter(t *testing.T) { leftID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_left") rightID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_right") sinkLeft := new(consumertest.MetricsSink) sinkRight := new(consumertest.MetricsSink) // The service will build a router to give to every connector. // Many connectors will just call router.ConsumeMetrics, // but some implementation will call RouteMetrics instead. router := connector.NewMetricsRouter( map[pipeline.ID]consumer.Metrics{ leftID: sinkLeft, rightID: sinkRight, }) cfg := ExampleRouterConfig{Metrics: &LeftRightConfig{Left: leftID, Right: rightID}} mr, err := ExampleRouterFactory.CreateMetricsToMetrics( context.Background(), connectortest.NewNopSettings(ExampleRouterFactory.Type()), cfg, router) require.NoError(t, err) assert.False(t, mr.Capabilities().MutatesData) md := testdata.GenerateMetrics(1) require.NoError(t, mr.ConsumeMetrics(context.Background(), md)) assert.Len(t, sinkRight.AllMetrics(), 1) assert.Empty(t, sinkLeft.AllMetrics()) require.NoError(t, mr.ConsumeMetrics(context.Background(), md)) assert.Len(t, sinkRight.AllMetrics(), 1) assert.Len(t, sinkLeft.AllMetrics(), 1) assert.NoError(t, mr.ConsumeMetrics(context.Background(), md)) assert.NoError(t, mr.ConsumeMetrics(context.Background(), md)) assert.NoError(t, mr.ConsumeMetrics(context.Background(), md)) assert.Len(t, sinkRight.AllMetrics(), 3) assert.Len(t, sinkLeft.AllMetrics(), 2) } func TestLogsRouter(t *testing.T) { leftID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_left") rightID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_right") sinkLeft := new(consumertest.LogsSink) sinkRight := new(consumertest.LogsSink) // The service will build a router to give to every connector. // Many connectors will just call router.ConsumeLogs, // but some implementation will call RouteLogs instead. router := connector.NewLogsRouter( map[pipeline.ID]consumer.Logs{ leftID: sinkLeft, rightID: sinkRight, }) cfg := ExampleRouterConfig{Logs: &LeftRightConfig{Left: leftID, Right: rightID}} lr, err := ExampleRouterFactory.CreateLogsToLogs( context.Background(), connectortest.NewNopSettings(ExampleRouterFactory.Type()), cfg, router) require.NoError(t, err) assert.False(t, lr.Capabilities().MutatesData) ld := testdata.GenerateLogs(1) require.NoError(t, lr.ConsumeLogs(context.Background(), ld)) assert.Len(t, sinkRight.AllLogs(), 1) assert.Empty(t, sinkLeft.AllLogs()) require.NoError(t, lr.ConsumeLogs(context.Background(), ld)) assert.Len(t, sinkRight.AllLogs(), 1) assert.Len(t, sinkLeft.AllLogs(), 1) assert.NoError(t, lr.ConsumeLogs(context.Background(), ld)) assert.NoError(t, lr.ConsumeLogs(context.Background(), ld)) assert.NoError(t, lr.ConsumeLogs(context.Background(), ld)) assert.Len(t, sinkRight.AllLogs(), 3) assert.Len(t, sinkLeft.AllLogs(), 2) } func TestProfilesRouter(t *testing.T) { leftID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_left") rightID := pipeline.NewIDWithName(pipeline.SignalTraces, "sink_right") sinkLeft := new(consumertest.ProfilesSink) sinkRight := new(consumertest.ProfilesSink) // The service will build a router to give to every connector. // Many connectors will just call router.ConsumeProfiles, // but some implementation will call RouteProfiles instead. router := xconnector.NewProfilesRouter( map[pipeline.ID]xconsumer.Profiles{ leftID: sinkLeft, rightID: sinkRight, }) cfg := ExampleRouterConfig{Profiles: &LeftRightConfig{Left: leftID, Right: rightID}} tr, err := ExampleRouterFactory.CreateProfilesToProfiles( context.Background(), connectortest.NewNopSettings(ExampleRouterFactory.Type()), cfg, router) require.NoError(t, err) assert.False(t, tr.Capabilities().MutatesData) td := testdata.GenerateProfiles(1) require.NoError(t, tr.ConsumeProfiles(context.Background(), td)) assert.Len(t, sinkRight.AllProfiles(), 1) assert.Empty(t, sinkLeft.AllProfiles()) require.NoError(t, tr.ConsumeProfiles(context.Background(), td)) assert.Len(t, sinkRight.AllProfiles(), 1) assert.Len(t, sinkLeft.AllProfiles(), 1) assert.NoError(t, tr.ConsumeProfiles(context.Background(), td)) assert.NoError(t, tr.ConsumeProfiles(context.Background(), td)) assert.NoError(t, tr.ConsumeProfiles(context.Background(), td)) assert.Len(t, sinkRight.AllProfiles(), 3) assert.Len(t, sinkLeft.AllProfiles(), 2) } opentelemetry-collector-0.141.0/service/internal/testcomponents/package_test.go000066400000000000000000000003171511331344600300610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/internal/testcomponents/stateful_component.go000066400000000000000000000011721511331344600313400ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package testcomponents // import "go.opentelemetry.io/collector/service/internal/testcomponents" import ( "context" "go.opentelemetry.io/collector/component" ) type componentState struct { started bool stopped bool } func (cs *componentState) Started() bool { return cs.started } func (cs *componentState) Stopped() bool { return cs.stopped } func (cs *componentState) Start(context.Context, component.Host) error { cs.started = true return nil } func (cs *componentState) Shutdown(context.Context) error { cs.stopped = true return nil } opentelemetry-collector-0.141.0/service/internal/zpages/000077500000000000000000000000001511331344600233035ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/zpages/package_test.go000066400000000000000000000003071511331344600262640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpages import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/internal/zpages/templates.go000066400000000000000000000121051511331344600256270ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpages // import "go.opentelemetry.io/collector/service/internal/zpages" import ( _ "embed" "html/template" "io" "log" ) var ( templateFunctions = template.FuncMap{ "even": even, "getKey": getKey, "getValue": getValue, } //go:embed templates/component_header.html componentHeaderBytes []byte componentHeaderTemplate = parseTemplate("component_header", componentHeaderBytes) //go:embed templates/extensions_table.html extensionsTableBytes []byte extensionsTableTemplate = parseTemplate("extensions_table", extensionsTableBytes) //go:embed templates/page_header.html headerBytes []byte headerTemplate = parseTemplate("header", headerBytes) //go:embed templates/page_footer.html footerBytes []byte footerTemplate = parseTemplate("footer", footerBytes) //go:embed templates/pipelines_table.html pipelinesTableBytes []byte pipelinesTableTemplate = parseTemplate("pipelines_table", pipelinesTableBytes) //go:embed templates/properties_table.html propertiesTableBytes []byte propertiesTableTemplate = parseTemplate("properties_table", propertiesTableBytes) //go:embed templates/features_table.html featuresTableBytes []byte featuresTableTemplate = parseTemplate("features_table", featuresTableBytes) ) func parseTemplate(name string, bytes []byte) *template.Template { return template.Must(template.New(name).Funcs(templateFunctions).Parse(string(bytes))) } // HeaderData contains data for the header template. type HeaderData struct { Title string } // WriteHTMLPageHeader writes the header. func WriteHTMLPageHeader(w io.Writer, hd HeaderData) { if err := headerTemplate.Execute(w, hd); err != nil { log.Printf("zpages: executing template: %v", err) } } // SummaryExtensionsTableData contains data for extensions summary table template. type SummaryExtensionsTableData struct { Rows []SummaryExtensionsTableRowData } // SummaryExtensionsTableRowData contains data for one row in extensions summary table template. type SummaryExtensionsTableRowData struct { FullName string Enabled bool } // WriteHTMLExtensionsSummaryTable writes the summary table for one component type (receivers, processors, exporters). // Id does not write the header or footer. func WriteHTMLExtensionsSummaryTable(w io.Writer, spd SummaryExtensionsTableData) { if err := extensionsTableTemplate.Execute(w, spd); err != nil { log.Printf("zpages: executing template: %v", err) } } // SummaryPipelinesTableData contains data for pipelines summary table template. type SummaryPipelinesTableData struct { Rows []SummaryPipelinesTableRowData } // SummaryPipelinesTableRowData contains data for one row in pipelines summary table template. type SummaryPipelinesTableRowData struct { FullName string InputType string MutatesData bool Receivers []string Processors []string Exporters []string } // WriteHTMLPipelinesSummaryTable writes the summary table for one component type (receivers, processors, exporters). // Id does not write the header or footer. func WriteHTMLPipelinesSummaryTable(w io.Writer, spd SummaryPipelinesTableData) { if err := pipelinesTableTemplate.Execute(w, spd); err != nil { log.Printf("zpages: executing template: %v", err) } } // ComponentHeaderData contains data for component header template. type ComponentHeaderData struct { Name string ComponentEndpoint string Link bool } // WriteHTMLComponentHeader writes the header for components. func WriteHTMLComponentHeader(w io.Writer, chd ComponentHeaderData) { if err := componentHeaderTemplate.Execute(w, chd); err != nil { log.Printf("zpages: executing template: %v", err) } } // PropertiesTableData contains data for properties table template. type PropertiesTableData struct { Name string Properties [][2]string } // WriteHTMLPropertiesTable writes the HTML for properties table. func WriteHTMLPropertiesTable(w io.Writer, chd PropertiesTableData) { if err := propertiesTableTemplate.Execute(w, chd); err != nil { log.Printf("zpages: executing template: %v", err) } } // WriteHTMLPageFooter writes the footer. func WriteHTMLPageFooter(w io.Writer) { if err := footerTemplate.Execute(w, nil); err != nil { log.Printf("zpages: executing template: %v", err) } } func even(x int) bool { return x%2 == 0 } func getKey(row [2]string) string { return row[0] } func getValue(row [2]string) string { return row[1] } // FeatureGateTableData contains data for feature gate table template. type FeatureGateTableData struct { Rows []FeatureGateTableRowData } // FeatureGateTableRowData contains data for one row in feature gate table template. type FeatureGateTableRowData struct { ID string Enabled bool Description string Stage string FromVersion string ToVersion string ReferenceURL string } // WriteHTMLFeaturesTable writes a table summarizing registered feature gates. func WriteHTMLFeaturesTable(w io.Writer, ftd FeatureGateTableData) { if err := featuresTableTemplate.Execute(w, ftd); err != nil { log.Printf("zpages: executing template: %v", err) } } opentelemetry-collector-0.141.0/service/internal/zpages/templates/000077500000000000000000000000001511331344600253015ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/internal/zpages/templates/component_header.html000066400000000000000000000002171511331344600315010ustar00rootroot00000000000000{{$link := .Link}} {{- if $link -}}
{{.Name}}
{{- else -}}
{{.Name}}
{{- end -}}opentelemetry-collector-0.141.0/service/internal/zpages/templates/extensions_table.html000066400000000000000000000005061511331344600315360ustar00rootroot00000000000000 {{range $rowindex, $row := .Rows}} {{- if even $rowindex}} {{else}} {{end -}} {{end}}
{{.FullName}}
opentelemetry-collector-0.141.0/service/internal/zpages/templates/features_table.html000066400000000000000000000027531511331344600311630ustar00rootroot00000000000000 {{range $rowindex, $row := .Rows}} {{- if even $rowindex}} {{else}} {{end -}} {{end}}
ID   |   Enabled   |   Description   |   Stage   |   From Version   |   To Version   |   Reference URL
{{$row.ID}}  |   {{$row.Enabled}}  |   {{$row.Description}}  |   {{$row.Stage}}  |   {{$row.FromVersion}}  |   {{$row.ToVersion}}  |   {{$row.ReferenceURL}}  |  
opentelemetry-collector-0.141.0/service/internal/zpages/templates/page_footer.html000066400000000000000000000000171511331344600304570ustar00rootroot00000000000000 opentelemetry-collector-0.141.0/service/internal/zpages/templates/page_header.html000066400000000000000000000007361511331344600304210ustar00rootroot00000000000000 {{.Title}}

{{.Title}}

opentelemetry-collector-0.141.0/service/internal/zpages/templates/pipelines_table.html000066400000000000000000000037171511331344600313360ustar00rootroot00000000000000 {{range $rowindex, $row := .Rows}} {{- if even $rowindex}} {{else}} {{end -}} {{end}}
FullName   |   InputType   |   MutatesData   |   Receivers   |   Processors   |   Exporters
{{$row.FullName}}  |   {{$row.InputType}}  |   {{$row.MutatesData}}  |   {{range $recindex, $rec := $row.Receivers}} {{$rec}}
{{end}}
  |   → {{range $proindex, $pro := $row.Processors}} {{$pro}} → {{end}}   |   {{range $expindex, $exp := $row.Exporters}} {{$exp}}
{{end}}
opentelemetry-collector-0.141.0/service/internal/zpages/templates/properties_table.html000066400000000000000000000007001511331344600315270ustar00rootroot00000000000000{{.Name}}: {{ $index := 0 }} {{range $index, $element := .Properties}} {{- if even $index}} {{else}} {{end -}} {{end}}
{{$element|getKey}}   |   {{$element|getValue}}
opentelemetry-collector-0.141.0/service/internal/zpages/templates_test.go000066400000000000000000000042031511331344600266660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package zpages import ( "bytes" "html/template" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) const tmplBody = `

{{.Index|even}}

{{.Element|getKey}}

{{.Element|getValue}}

` const want = `

true

key

value

` type testFuncsInput struct { Index int Element [2]string } var tmpl = template.Must(template.New("countTest").Funcs(templateFunctions).Parse(tmplBody)) func TestTemplateFuncs(t *testing.T) { buf := new(bytes.Buffer) input := testFuncsInput{ Index: 32, Element: [2]string{"key", "value"}, } require.NoError(t, tmpl.Execute(buf, input)) assert.Equal(t, want, buf.String()) } func TestNoCrash(t *testing.T) { buf := new(bytes.Buffer) assert.NotPanics(t, func() { WriteHTMLPageHeader(buf, HeaderData{Title: "Foo"}) }) assert.NotPanics(t, func() { WriteHTMLComponentHeader(buf, ComponentHeaderData{Name: "Bar"}) }) assert.NotPanics(t, func() { WriteHTMLComponentHeader(buf, ComponentHeaderData{Name: "Bar", ComponentEndpoint: "pagez", Link: true}) }) assert.NotPanics(t, func() { WriteHTMLPipelinesSummaryTable(buf, SummaryPipelinesTableData{ Rows: []SummaryPipelinesTableRowData{{ FullName: "test", InputType: "metrics", MutatesData: false, Receivers: []string{"oc"}, Processors: []string{"nop"}, Exporters: []string{"oc"}, }}, }) }) assert.NotPanics(t, func() { WriteHTMLExtensionsSummaryTable(buf, SummaryExtensionsTableData{ Rows: []SummaryExtensionsTableRowData{{ FullName: "test", }}, }) }) assert.NotPanics(t, func() { WriteHTMLPropertiesTable(buf, PropertiesTableData{Name: "Bar", Properties: [][2]string{{"key", "value"}}}) }) assert.NotPanics(t, func() { WriteHTMLFeaturesTable(buf, FeatureGateTableData{Rows: []FeatureGateTableRowData{ { ID: "test", Enabled: false, Description: "test gate", }, }}) }) assert.NotPanics(t, func() { WriteHTMLPageFooter(buf) }) assert.NotPanics(t, func() { WriteHTMLPageFooter(buf) }) } opentelemetry-collector-0.141.0/service/metadata.yaml000066400000000000000000000116301511331344600226430ustar00rootroot00000000000000type: service github_project: open-telemetry/opentelemetry-collector status: disable_codecov_badge: true class: pkg stability: development: [traces, metrics, logs] distributions: [core, contrib] telemetry: metrics: connector.consumed.items: prefix: otelcol. enabled: true stability: level: development description: Number of items passed to the connector. unit: "{item}" sum: value_type: int monotonic: true connector.consumed.size: prefix: otelcol. enabled: false stability: level: development description: Size of items passed to the connector, based on ProtoMarshaler.Sizer. unit: "{item}" sum: value_type: int monotonic: true connector.produced.items: prefix: otelcol. enabled: true stability: level: development description: Number of items emitted from the connector. unit: "{item}" sum: value_type: int monotonic: true connector.produced.size: prefix: otelcol. enabled: false stability: level: development description: Size of items emitted from the connector, based on ProtoMarshaler.Sizer. unit: "{item}" sum: value_type: int monotonic: true exporter.consumed.items: prefix: otelcol. enabled: true stability: level: development description: Number of items passed to the exporter. unit: "{item}" sum: value_type: int monotonic: true exporter.consumed.size: prefix: otelcol. enabled: false stability: level: development description: Size of items passed to the exporter, based on ProtoMarshaler.Sizer. unit: "{item}" sum: value_type: int monotonic: true process_cpu_seconds: enabled: true stability: level: alpha description: Total CPU user and system time in seconds unit: s sum: async: true value_type: double monotonic: true process_memory_rss: enabled: true stability: level: alpha description: Total physical memory (resident set size) unit: By gauge: async: true value_type: int process_runtime_heap_alloc_bytes: enabled: true stability: level: alpha description: Bytes of allocated heap objects (see 'go doc runtime.MemStats.HeapAlloc') unit: By gauge: async: true value_type: int process_runtime_total_alloc_bytes: enabled: true stability: level: alpha description: Cumulative bytes allocated for heap objects (see 'go doc runtime.MemStats.TotalAlloc') unit: By sum: async: true value_type: int monotonic: true process_runtime_total_sys_memory_bytes: enabled: true stability: level: alpha description: Total bytes of memory obtained from the OS (see 'go doc runtime.MemStats.Sys') unit: By gauge: async: true value_type: int process_uptime: enabled: true stability: level: alpha description: Uptime of the process unit: s sum: async: true value_type: double monotonic: true processor.consumed.items: prefix: otelcol. enabled: true stability: level: development description: Number of items passed to the processor. unit: "{item}" sum: value_type: int monotonic: true processor.consumed.size: prefix: otelcol. enabled: false stability: level: development description: Size of items passed to the processor, based on ProtoMarshaler.Sizer. unit: "{item}" sum: value_type: int monotonic: true processor.produced.items: prefix: otelcol. enabled: true stability: level: development description: Number of items emitted from the processor. unit: "{item}" sum: value_type: int monotonic: true processor.produced.size: prefix: otelcol. enabled: false stability: level: development description: Size of items emitted from the processor, based on ProtoMarshaler.Sizer. unit: "{item}" sum: value_type: int monotonic: true receiver.produced.items: prefix: otelcol. enabled: true stability: level: development description: Number of items emitted from the receiver. unit: "{item}" sum: value_type: int monotonic: true receiver.produced.size: prefix: otelcol. enabled: false stability: level: development description: Size of items emitted from the receiver, based on ProtoMarshaler.Sizer. unit: "{item}" sum: value_type: int monotonic: true opentelemetry-collector-0.141.0/service/pipelines/000077500000000000000000000000001511331344600221665ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/pipelines/config.go000066400000000000000000000056271511331344600237740ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pipelines // import "go.opentelemetry.io/collector/service/pipelines" import ( "errors" "fmt" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" ) var ( errMissingServicePipelines = errors.New("service must have at least one pipeline") errMissingServicePipelineReceivers = errors.New("must have at least one receiver") errMissingServicePipelineExporters = errors.New("must have at least one exporter") serviceProfileSupportGateID = "service.profilesSupport" serviceProfileSupportGate = featuregate.GlobalRegistry().MustRegister( serviceProfileSupportGateID, featuregate.StageAlpha, featuregate.WithRegisterFromVersion("v0.112.0"), featuregate.WithRegisterDescription("Controls whether profiles support can be enabled"), ) AllowNoPipelines = featuregate.GlobalRegistry().MustRegister( "service.AllowNoPipelines", featuregate.StageAlpha, featuregate.WithRegisterFromVersion("v0.122.0"), featuregate.WithRegisterDescription("Allow starting the Collector without starting any pipelines."), ) ) // Config defines the configurable settings for service telemetry. type Config map[pipeline.ID]*PipelineConfig func (cfg Config) Validate() error { // Must have at least one pipeline unless explicitly disabled. if !AllowNoPipelines.IsEnabled() && len(cfg) == 0 { return errMissingServicePipelines } if !serviceProfileSupportGate.IsEnabled() { // Check that all pipelines have at least one receiver and one exporter, and they reference // only configured components. for pipelineID := range cfg { if pipelineID.Signal() == xpipeline.SignalProfiles { return fmt.Errorf( "pipeline %q: profiling signal support is at alpha level, gated under the %q feature gate", pipelineID.String(), serviceProfileSupportGateID, ) } } } return nil } // PipelineConfig defines the configuration of a Pipeline. type PipelineConfig struct { Receivers []component.ID `mapstructure:"receivers"` Processors []component.ID `mapstructure:"processors"` Exporters []component.ID `mapstructure:"exporters"` } func (cfg *PipelineConfig) Validate() error { // Validate pipeline has at least one receiver. if len(cfg.Receivers) == 0 { return errMissingServicePipelineReceivers } // Validate pipeline has at least one exporter. if len(cfg.Exporters) == 0 { return errMissingServicePipelineExporters } // Validate no processors are duplicated within a pipeline. procSet := make(map[component.ID]struct{}, len(cfg.Processors)) for _, ref := range cfg.Processors { // Ensure no processors are duplicated within the pipeline if _, exists := procSet[ref]; exists { return fmt.Errorf("references processor %q multiple times", ref) } procSet[ref] = struct{}{} } return nil } opentelemetry-collector-0.141.0/service/pipelines/config_test.go000066400000000000000000000073131511331344600250250ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pipelines import ( "errors" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/confmap/xconfmap" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" ) func TestConfigValidate(t *testing.T) { testCases := []struct { name string // test case name (also file name containing config yaml) cfgFn func(*testing.T) Config expected error }{ { name: "valid", cfgFn: generateConfig, expected: nil, }, { name: "duplicate-processor-reference", cfgFn: func(*testing.T) Config { cfg := generateConfig(t) pipe := cfg[pipeline.NewID(pipeline.SignalTraces)] pipe.Processors = append(pipe.Processors, pipe.Processors...) return cfg }, expected: errors.New(`references processor "nop" multiple times`), }, { name: "missing-pipeline-receivers", cfgFn: func(*testing.T) Config { cfg := generateConfig(t) cfg[pipeline.NewID(pipeline.SignalTraces)].Receivers = nil return cfg }, expected: errMissingServicePipelineReceivers, }, { name: "missing-pipeline-exporters", cfgFn: func(*testing.T) Config { cfg := generateConfig(t) cfg[pipeline.NewID(pipeline.SignalTraces)].Exporters = nil return cfg }, expected: errMissingServicePipelineExporters, }, { name: "missing-pipelines", cfgFn: func(*testing.T) Config { return nil }, expected: errMissingServicePipelines, }, { name: "disabled-featuregate-profiles", cfgFn: func(*testing.T) Config { cfg := generateConfig(t) cfg[pipeline.NewID(xpipeline.SignalProfiles)] = &PipelineConfig{ Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, } return cfg }, expected: errors.New(`profiling signal support is at alpha level, gated under the "service.profilesSupport" feature gate`), }, { name: "enabled-featuregate-profiles", cfgFn: func(t *testing.T) Config { require.NoError(t, featuregate.GlobalRegistry().Set(serviceProfileSupportGateID, true)) cfg := generateConfig(t) cfg[pipeline.NewID(xpipeline.SignalProfiles)] = &PipelineConfig{ Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, } return cfg }, expected: nil, }, } for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { cfg := tt.cfgFn(t) if tt.expected != nil { require.ErrorContains(t, xconfmap.Validate(cfg), tt.expected.Error()) } else { require.NoError(t, xconfmap.Validate(cfg)) } // Clean up the profiles support gate, which may have been enabled in `cfgFn`. require.NoError(t, featuregate.GlobalRegistry().Set(serviceProfileSupportGateID, false)) }) } } func TestNoPipelinesFeatureGate(t *testing.T) { cfg := Config{} require.Error(t, xconfmap.Validate(cfg)) gate := AllowNoPipelines require.NoError(t, featuregate.GlobalRegistry().Set(gate.ID(), true)) defer func() { require.NoError(t, featuregate.GlobalRegistry().Set(gate.ID(), false)) }() require.NoError(t, xconfmap.Validate(cfg)) } func generateConfig(t *testing.T) Config { t.Helper() return map[pipeline.ID]*PipelineConfig{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.MustNewID("nop")}, Processors: []component.ID{component.MustNewID("nop")}, Exporters: []component.ID{component.MustNewID("nop")}, }, } } opentelemetry-collector-0.141.0/service/pipelines/package_test.go000066400000000000000000000003121511331344600251430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package pipelines import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/service.go000066400000000000000000000407431511331344600221750ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 //go:generate mdatagen metadata.yaml package service // import "go.opentelemetry.io/collector/service" import ( "context" "errors" "fmt" "runtime" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" noopmetric "go.opentelemetry.io/otel/metric/noop" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.uber.org/multierr" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/connector" "go.opentelemetry.io/collector/exporter" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/processor" "go.opentelemetry.io/collector/receiver" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/internal/graph" "go.opentelemetry.io/collector/service/internal/moduleinfo" "go.opentelemetry.io/collector/service/internal/proctelemetry" "go.opentelemetry.io/collector/service/internal/status" "go.opentelemetry.io/collector/service/telemetry" ) // This feature gate is deprecated and will be removed in 1.40.0. Views can now be configured. var _ = featuregate.GlobalRegistry().MustRegister( "telemetry.disableHighCardinalityMetrics", featuregate.StageDeprecated, featuregate.WithRegisterToVersion("0.133.0"), featuregate.WithRegisterDescription( "Controls whether the collector should enable potentially high "+ "cardinality metrics. Deprecated, configure service::telemetry::metrics::views instead.")) // ModuleInfo describes the Go module for a particular component. type ModuleInfo = moduleinfo.ModuleInfo // ModuleInfos describes the go module for all components. type ModuleInfos = moduleinfo.ModuleInfos // Settings holds configuration for building a new Service. type Settings struct { // BuildInfo provides collector start information. BuildInfo component.BuildInfo // CollectorConf contains the Collector's current configuration CollectorConf *confmap.Conf // Receivers configuration to its builder. ReceiversConfigs map[component.ID]component.Config ReceiversFactories map[component.Type]receiver.Factory // Processors configuration to its builder. ProcessorsConfigs map[component.ID]component.Config ProcessorsFactories map[component.Type]processor.Factory // exporters configuration to its builder. ExportersConfigs map[component.ID]component.Config ExportersFactories map[component.Type]exporter.Factory // Connectors configuration to its builder. ConnectorsConfigs map[component.ID]component.Config ConnectorsFactories map[component.Type]connector.Factory // Extensions builder for extensions. Extensions builders.Extension // Extensions configuration to its builder. ExtensionsConfigs map[component.ID]component.Config ExtensionsFactories map[component.Type]extension.Factory // ModuleInfo describes the go module for each component. ModuleInfos ModuleInfos // AsyncErrorChannel is the channel that is used to report fatal errors. AsyncErrorChannel chan error // LoggingOptions provides a way to change behavior of zap logging. LoggingOptions []zap.Option // TelemetryFactory is the factory for creating internal telemetry providers. TelemetryFactory telemetry.Factory } // Service represents the implementation of a component.Host. type Service struct { buildInfo component.BuildInfo telemetrySettings component.TelemetrySettings host *graph.Host collectorConf *confmap.Conf loggerShutdownFunc component.ShutdownFunc meterProvider telemetry.MeterProvider tracerProvider telemetry.TracerProvider } // New creates a new Service, its telemetry, and Components. func New(ctx context.Context, set Settings, cfg Config) (_ *Service, resultErr error) { srv := &Service{ buildInfo: set.BuildInfo, host: &graph.Host{ Receivers: builders.NewReceiver(set.ReceiversConfigs, set.ReceiversFactories), Processors: builders.NewProcessor(set.ProcessorsConfigs, set.ProcessorsFactories), Exporters: builders.NewExporter(set.ExportersConfigs, set.ExportersFactories), Connectors: builders.NewConnector(set.ConnectorsConfigs, set.ConnectorsFactories), Extensions: builders.NewExtension(set.ExtensionsConfigs, set.ExtensionsFactories), ModuleInfos: set.ModuleInfos, BuildInfo: set.BuildInfo, AsyncErrorChannel: set.AsyncErrorChannel, }, collectorConf: set.CollectorConf, } if set.TelemetryFactory == nil { return nil, errors.New("telemetry factory not provided") } // Create the resource first. This ensures all telemetry providers // (logger, meter, tracer) use the same resource with a consistent service.instance.id. telemetrySettings := telemetry.Settings{BuildInfo: set.BuildInfo} resource, err := set.TelemetryFactory.CreateResource(ctx, telemetrySettings, cfg.Telemetry) if err != nil { return nil, fmt.Errorf("failed to create resource: %w", err) } telemetrySettings.Resource = &resource loggerSettings := telemetry.LoggerSettings{ Settings: telemetrySettings, ZapOptions: set.LoggingOptions, } logger, loggerShutdownFunc, err := set.TelemetryFactory.CreateLogger(ctx, loggerSettings, cfg.Telemetry) if err != nil { return nil, fmt.Errorf("failed to create logger: %w", err) } defer func() { if resultErr != nil { logger.Error("error found during service initialization", zap.Error(resultErr)) resultErr = multierr.Append(resultErr, loggerShutdownFunc.Shutdown(ctx)) } }() srv.loggerShutdownFunc = loggerShutdownFunc meterSettings := telemetry.MeterSettings{ Settings: telemetrySettings, Logger: logger, DefaultViews: configureViews, } meterProvider, err := set.TelemetryFactory.CreateMeterProvider(ctx, meterSettings, cfg.Telemetry) if err != nil { return nil, fmt.Errorf("failed to create meter provider: %w", err) } defer func() { if resultErr != nil { resultErr = multierr.Append(resultErr, meterProvider.Shutdown(ctx)) } }() srv.meterProvider = meterProvider tracerSettings := telemetry.TracerSettings{ Settings: telemetrySettings, Logger: logger, } tracerProvider, err := set.TelemetryFactory.CreateTracerProvider(ctx, tracerSettings, cfg.Telemetry) if err != nil { return nil, fmt.Errorf("failed to create tracer provider: %w", err) } defer func() { if resultErr != nil { resultErr = multierr.Append(resultErr, tracerProvider.Shutdown(ctx)) } }() srv.tracerProvider = tracerProvider srv.telemetrySettings = component.TelemetrySettings{ Logger: logger, MeterProvider: meterProvider, TracerProvider: tracerProvider, Resource: resource, } srv.host.Reporter = status.NewReporter(srv.host.NotifyComponentStatusChange, func(err error) { if errors.Is(err, status.ErrStatusNotReady) { logger.Warn("Invalid transition", zap.Error(err)) } // ignore other errors as they represent invalid state transitions and are considered benign. }) err = srv.initGraph(ctx, cfg) if err != nil { return nil, err } // process the configuration and initialize the pipeline err = srv.initExtensions(ctx, cfg.Extensions) if err != nil { return nil, err } if err := proctelemetry.RegisterProcessMetrics(srv.telemetrySettings); err != nil { return nil, fmt.Errorf("failed to register process metrics: %w", err) } return srv, nil } // Start starts the extensions and pipelines. If Start fails Shutdown should be called to ensure a clean state. // Start does the following steps in order: // 1. Start all extensions. // 2. Notify extensions about Collector configuration // 3. Start all pipelines. // 4. Notify extensions that the pipeline is ready. func (srv *Service) Start(ctx context.Context) error { srv.telemetrySettings.Logger.Info("Starting "+srv.buildInfo.Command+"...", zap.String("Version", srv.buildInfo.Version), zap.Int("NumCPU", runtime.NumCPU()), ) if err := srv.host.ServiceExtensions.Start(ctx, srv.host); err != nil { return fmt.Errorf("failed to start extensions: %w", err) } if srv.collectorConf != nil { if err := srv.host.ServiceExtensions.NotifyConfig(ctx, srv.collectorConf); err != nil { return err } } if err := srv.host.Pipelines.StartAll(ctx, srv.host); err != nil { return fmt.Errorf("cannot start pipelines: %w", err) } if err := srv.host.ServiceExtensions.NotifyPipelineReady(); err != nil { return err } srv.telemetrySettings.Logger.Info("Everything is ready. Begin running and processing data.") return nil } // Shutdown the service. Shutdown will do the following steps in order: // 1. Notify extensions that the pipeline is shutting down. // 2. Shutdown all pipelines. // 3. Shutdown all extensions. // 4. Shutdown telemetry. func (srv *Service) Shutdown(ctx context.Context) error { // Accumulate errors and proceed with shutting down remaining components. var errs error // Begin shutdown sequence. srv.telemetrySettings.Logger.Info("Starting shutdown...") if err := srv.host.ServiceExtensions.NotifyPipelineNotReady(); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to notify that pipeline is not ready: %w", err)) } if err := srv.host.Pipelines.ShutdownAll(ctx, srv.host.Reporter); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to shutdown pipelines: %w", err)) } if err := srv.host.ServiceExtensions.Shutdown(ctx); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to shutdown extensions: %w", err)) } srv.telemetrySettings.Logger.Info("Shutdown complete.") // Shut down telemetry providers in the reverse order of creation, // since the tracer and meter providers may use the logger. if err := srv.tracerProvider.Shutdown(ctx); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to shutdown tracer provider: %w", err)) } if err := srv.meterProvider.Shutdown(ctx); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to shutdown meter provider: %w", err)) } if err := srv.loggerShutdownFunc.Shutdown(ctx); err != nil { errs = multierr.Append(errs, fmt.Errorf("failed to shutdown logger: %w", err)) } return errs } // Creates extensions. func (srv *Service) initExtensions(ctx context.Context, cfg extensions.Config) error { var err error extensionsSettings := extensions.Settings{ Telemetry: srv.telemetrySettings, BuildInfo: srv.buildInfo, Extensions: srv.host.Extensions, } if srv.host.ServiceExtensions, err = extensions.New(ctx, extensionsSettings, cfg, extensions.WithReporter(srv.host.Reporter)); err != nil { return fmt.Errorf("failed to build extensions: %w", err) } return nil } // Creates the pipeline graph. func (srv *Service) initGraph(ctx context.Context, cfg Config) error { var err error if srv.host.Pipelines, err = graph.Build(ctx, graph.Settings{ Telemetry: srv.telemetrySettings, BuildInfo: srv.buildInfo, ReceiverBuilder: srv.host.Receivers, ProcessorBuilder: srv.host.Processors, ExporterBuilder: srv.host.Exporters, ConnectorBuilder: srv.host.Connectors, PipelineConfigs: cfg.Pipelines, ReportStatus: srv.host.Reporter.ReportStatus, }); err != nil { return fmt.Errorf("failed to build pipelines: %w", err) } return nil } // Logger returns the logger created for this service. // This is a temporary API that may be removed soon after investigating how the collector should record different events. func (srv *Service) Logger() *zap.Logger { return srv.telemetrySettings.Logger } func dropViewOption(selector *config.ViewSelector) config.View { return config.View{ Selector: selector, Stream: &config.ViewStream{ Aggregation: &config.ViewStreamAggregation{ Drop: config.ViewStreamAggregationDrop{}, }, }, } } func configureViews(level configtelemetry.Level) []config.View { views := []config.View{} if level < configtelemetry.LevelDetailed { // Drop all otelhttp and otelgrpc metrics if the level is not detailed. views = append(views, dropViewOption(&config.ViewSelector{ MeterName: ptr("go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"), }), dropViewOption(&config.ViewSelector{ MeterName: ptr("go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"), }), // Drop duration metric if the level is not detailed dropViewOption(&config.ViewSelector{ MeterName: ptr("go.opentelemetry.io/collector/processor/processorhelper"), InstrumentName: ptr("otelcol_processor_internal_duration"), }), ) } // otel-arrow library metrics // See https://github.com/open-telemetry/otel-arrow/blob/c39257/pkg/otel/arrow_record/consumer.go#L174-L176 if level < configtelemetry.LevelNormal { scope := ptr("otel-arrow/pkg/otel/arrow_record") views = append(views, dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("arrow_batch_records"), }), dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("arrow_schema_resets"), }), dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("arrow_memory_inuse"), }), ) } // contrib's internal/otelarrow/netstats metrics // See // - https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/a25f05/internal/otelarrow/netstats/netstats.go#L130 // - https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/a25f05/internal/otelarrow/netstats/netstats.go#L165 if level < configtelemetry.LevelDetailed { scope := ptr("github.com/open-telemetry/opentelemetry-collector-contrib/internal/otelarrow/netstats") views = append(views, // Compressed size metrics. dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_*_compressed_size"), }), dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_*_compressed_size"), }), // makeRecvMetrics for exporters. dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_exporter_recv"), }), dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_exporter_recv_wire"), }), // makeSentMetrics for receivers. dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_receiver_sent"), }), dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_receiver_sent_wire"), }), ) } // Batch exporter metrics if level < configtelemetry.LevelDetailed { scope := ptr("go.opentelemetry.io/collector/exporter/exporterhelper") views = append(views, dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_exporter_queue_batch_send_size_bytes"), })) } // Batch processor metrics scope := ptr("go.opentelemetry.io/collector/processor/batchprocessor") if level < configtelemetry.LevelNormal { views = append(views, dropViewOption(&config.ViewSelector{ MeterName: scope, })) } else if level < configtelemetry.LevelDetailed { views = append(views, dropViewOption(&config.ViewSelector{ MeterName: scope, InstrumentName: ptr("otelcol_processor_batch_batch_send_size_bytes"), })) } // Internal graph metrics graphScope := ptr("go.opentelemetry.io/collector/service") if level < configtelemetry.LevelDetailed { views = append(views, dropViewOption(&config.ViewSelector{ MeterName: graphScope, InstrumentName: ptr("otelcol.*.consumed.size"), }), dropViewOption(&config.ViewSelector{ MeterName: graphScope, InstrumentName: ptr("otelcol.*.produced.size"), })) } return views } func ptr[T any](v T) *T { return &v } // Validate verifies the graph by calling the internal graph.Build. func Validate(ctx context.Context, set Settings, cfg Config) error { tel := component.TelemetrySettings{ Logger: zap.NewNop(), TracerProvider: nooptrace.NewTracerProvider(), MeterProvider: noopmetric.NewMeterProvider(), Resource: pcommon.NewResource(), } _, err := graph.Build(ctx, graph.Settings{ Telemetry: tel, BuildInfo: set.BuildInfo, ReceiverBuilder: builders.NewReceiver(set.ReceiversConfigs, set.ReceiversFactories), ProcessorBuilder: builders.NewProcessor(set.ProcessorsConfigs, set.ProcessorsFactories), ExporterBuilder: builders.NewExporter(set.ExportersConfigs, set.ExportersFactories), ConnectorBuilder: builders.NewConnector(set.ConnectorsConfigs, set.ConnectorsFactories), PipelineConfigs: cfg.Pipelines, }) if err != nil { return fmt.Errorf("failed to build pipelines: %w", err) } return nil } opentelemetry-collector-0.141.0/service/service_test.go000066400000000000000000000753461511331344600232430ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package service import ( "context" "errors" "net/http" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" otelconf "go.opentelemetry.io/contrib/otelconf/v0.3.0" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/sdk/metric" "go.opentelemetry.io/otel/sdk/metric/metricdata" sdktrace "go.opentelemetry.io/otel/sdk/trace" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componentstatus" "go.opentelemetry.io/collector/config/confighttp" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/extension" "go.opentelemetry.io/collector/extension/zpagesextension" "go.opentelemetry.io/collector/internal/testutil" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/pipeline" "go.opentelemetry.io/collector/pipeline/xpipeline" "go.opentelemetry.io/collector/service/extensions" "go.opentelemetry.io/collector/service/internal/builders" "go.opentelemetry.io/collector/service/pipelines" "go.opentelemetry.io/collector/service/telemetry" "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" "go.opentelemetry.io/collector/service/telemetry/telemetrytest" ) const ( otelCommand = "otelcoltest" ) var ( nopType = component.MustNewType("nop") wrongType = component.MustNewType("wrong") ) func TestServiceGetFactory(t *testing.T) { set := newNopSettings() srv, err := New(context.Background(), set, newNopConfig()) require.NoError(t, err) assert.NoError(t, srv.Start(context.Background())) t.Cleanup(func() { assert.NoError(t, srv.Shutdown(context.Background())) }) assert.Nil(t, srv.host.GetFactory(component.KindReceiver, wrongType)) assert.Equal(t, srv.host.Receivers.Factory(nopType), srv.host.GetFactory(component.KindReceiver, nopType)) assert.Nil(t, srv.host.GetFactory(component.KindProcessor, wrongType)) assert.Equal(t, srv.host.Processors.Factory(nopType), srv.host.GetFactory(component.KindProcessor, nopType)) assert.Nil(t, srv.host.GetFactory(component.KindExporter, wrongType)) assert.Equal(t, srv.host.Exporters.Factory(nopType), srv.host.GetFactory(component.KindExporter, nopType)) assert.Nil(t, srv.host.GetFactory(component.KindConnector, wrongType)) assert.Equal(t, srv.host.Connectors.Factory(nopType), srv.host.GetFactory(component.KindConnector, nopType)) assert.Nil(t, srv.host.GetFactory(component.KindExtension, wrongType)) assert.Equal(t, srv.host.Extensions.Factory(nopType), srv.host.GetFactory(component.KindExtension, nopType)) // Try retrieve non existing component.Kind. assert.Nil(t, srv.host.GetFactory(component.Kind{}, nopType)) } func TestServiceGetExtensions(t *testing.T) { srv, err := New(context.Background(), newNopSettings(), newNopConfig()) require.NoError(t, err) assert.NoError(t, srv.Start(context.Background())) t.Cleanup(func() { assert.NoError(t, srv.Shutdown(context.Background())) }) extMap := srv.host.GetExtensions() assert.Len(t, extMap, 1) assert.Contains(t, extMap, component.NewID(nopType)) } func TestServiceGetExporters(t *testing.T) { srv, err := New(context.Background(), newNopSettings(), newNopConfig()) require.NoError(t, err) assert.NoError(t, srv.Start(context.Background())) t.Cleanup(func() { assert.NoError(t, srv.Shutdown(context.Background())) }) //nolint:staticcheck expMap := srv.host.GetExporters() v, ok := expMap[pipeline.SignalTraces] assert.True(t, ok) assert.NotNil(t, v) assert.Len(t, expMap, 4) assert.Len(t, expMap[pipeline.SignalTraces], 1) assert.Contains(t, expMap[pipeline.SignalTraces], component.NewID(nopType)) assert.Len(t, expMap[pipeline.SignalMetrics], 1) assert.Contains(t, expMap[pipeline.SignalMetrics], component.NewID(nopType)) assert.Len(t, expMap[pipeline.SignalLogs], 1) assert.Contains(t, expMap[pipeline.SignalLogs], component.NewID(nopType)) assert.Len(t, expMap[xpipeline.SignalProfiles], 1) assert.Contains(t, expMap[xpipeline.SignalProfiles], component.NewID(nopType)) } // TestServiceTelemetryCleanupOnError tests that if newService errors due to an invalid config telemetry is cleaned up // and another service with a valid config can be started right after. func TestServiceTelemetryCleanupOnError(t *testing.T) { invalidCfg := newNopConfig() invalidCfg.Pipelines[pipeline.NewID(pipeline.SignalTraces)].Processors[0] = component.MustNewID("invalid") // Create a service with an invalid config and expect an error _, err := New(context.Background(), newNopSettings(), invalidCfg) require.Error(t, err) // Create a service with a valid config and expect no error srv, err := New(context.Background(), newNopSettings(), newNopConfig()) require.NoError(t, err) assert.NoError(t, srv.Shutdown(context.Background())) } func TestServiceTelemetryLogging(t *testing.T) { observerCore, observedLogs := observer.New(zapcore.WarnLevel) zapLogger := zap.New(observerCore) set := newNopSettings() set.BuildInfo = component.BuildInfo{Version: "test version", Command: otelCommand} set.TelemetryFactory = telemetry.NewFactory( func() component.Config { return nil }, telemetrytest.WithLogger(zapLogger, nil), ) cfg := newNopConfig() srv, err := New(context.Background(), set, cfg) require.NoError(t, err) require.NoError(t, srv.Start(context.Background())) defer func() { assert.NoError(t, srv.Shutdown(context.Background())) }() require.NotNil(t, srv.telemetrySettings.Logger) assert.Equal(t, srv.telemetrySettings.Logger, srv.Logger()) assert.Equal(t, zapcore.WarnLevel, srv.telemetrySettings.Logger.Level()) srv.telemetrySettings.Logger.Warn("warn_message") srv.telemetrySettings.Logger.Info("info_message") entries := observedLogs.All() require.Len(t, entries, 1) assert.Equal(t, "warn_message", entries[0].Message) } func TestServiceTelemetryMetrics(t *testing.T) { // Start a service and check that metrics are produced as expected. // We do this twice to ensure that the server is stopped cleanly. for range 2 { reader := metric.NewManualReader() set := newNopSettings() set.TelemetryFactory = telemetry.NewFactory( func() component.Config { return nil }, telemetrytest.WithMeterProvider( metric.NewMeterProvider( metric.WithReader(reader), ), ), ) srv, err := New(context.Background(), set, newNopConfig()) require.NoError(t, err) require.NoError(t, srv.Start(context.Background())) var rm metricdata.ResourceMetrics err = reader.Collect(context.Background(), &rm) require.NoError(t, err) assertMetrics(t, rm) require.NoError(t, srv.Shutdown(context.Background())) } } func assertMetrics(t *testing.T, rm metricdata.ResourceMetrics) { require.Len(t, rm.ScopeMetrics, 1) assert.Equal(t, "go.opentelemetry.io/collector/service", rm.ScopeMetrics[0].Scope.Name) actualNames := make([]string, len(rm.ScopeMetrics[0].Metrics)) for i, m := range rm.ScopeMetrics[0].Metrics { actualNames[i] = m.Name } assert.ElementsMatch(t, []string{ "otelcol_process_cpu_seconds", "otelcol_process_memory_rss", "otelcol_process_runtime_heap_alloc_bytes", "otelcol_process_runtime_total_alloc_bytes", "otelcol_process_runtime_total_sys_memory_bytes", "otelcol_process_uptime", }, actualNames) } func TestServiceTelemetryDefaultViews(t *testing.T) { var views []otelconf.View set := newNopSettings() set.TelemetryFactory = telemetry.NewFactory( func() component.Config { return nil }, telemetry.WithCreateMeterProvider( func(_ context.Context, set telemetry.MeterSettings, _ component.Config) (telemetry.MeterProvider, error) { views = set.DefaultViews(configtelemetry.LevelBasic) return telemetrytest.ShutdownMeterProvider{ MeterProvider: noopmetric.NewMeterProvider(), }, nil }, ), ) srv, err := New(context.Background(), set, newNopConfig()) require.NoError(t, err) require.NoError(t, srv.Start(context.Background())) defer func() { assert.NoError(t, srv.Shutdown(context.Background())) }() require.NotEmpty(t, views) } // TestServiceTelemetryZPages verifies that the zpages extension works correctly with servce telemetry. func TestServiceTelemetryZPages(t *testing.T) { t.Run("ipv4", func(t *testing.T) { testZPages(t, testutil.GetAvailableLocalAddress(t)) }) t.Run("ipv6", func(t *testing.T) { testZPages(t, testutil.GetAvailableLocalIPv6Address(t)) }) } func testZPages(t *testing.T, zpagesAddr string) { set := newNopSettings() set.BuildInfo = component.BuildInfo{Version: "test version", Command: otelCommand} set.ExtensionsConfigs = map[component.ID]component.Config{ component.MustNewID("zpages"): &zpagesextension.Config{ ServerConfig: confighttp.ServerConfig{Endpoint: zpagesAddr}, }, } set.ExtensionsFactories = map[component.Type]extension.Factory{ component.MustNewType("zpages"): zpagesextension.NewFactory(), } cfg := newNopConfig() cfg.Extensions = []component.ID{component.MustNewID("zpages")} // The zpages extension will register/unregister a span processor with // the tracer provider if it implements the RegisterSpanProcessor and // UnregisterSpanProcessor methods of the opentelemetry-go SDK implementation. // Hence we use sdktrace below, rather than the noop tracer provider. set.TelemetryFactory = telemetry.NewFactory( func() component.Config { return nil }, telemetrytest.WithTracerProvider(sdktrace.NewTracerProvider()), ) // Start a service and check that zpages is healthy. // We do this twice to ensure that the server is stopped cleanly. for range 2 { srv, err := New(context.Background(), set, cfg) require.NoError(t, err) require.NoError(t, srv.Start(context.Background())) assert.Eventually(t, func() bool { return zpagesHealthy(zpagesAddr) }, 10*time.Second, 100*time.Millisecond, "zpages endpoint is not healthy") require.NoError(t, srv.Shutdown(context.Background())) } } func zpagesHealthy(zpagesAddr string) bool { paths := []string{ "/debug/tracez", "/debug/pipelinez", "/debug/servicez", "/debug/extensionz", } for _, path := range paths { resp, err := http.Get("http://" + zpagesAddr + path) if err != nil { return false } if resp.Body.Close() != nil { return false } if resp.StatusCode != http.StatusOK { return false } } return true } // TestServiceTelemetryRestart tests that the service starts and shuts down telemetry as expected. func TestServiceTelemetryRestart(t *testing.T) { telemetryCreated := make(chan struct{}, 1) telemetryShutdown := make(chan struct{}, 1) set := newNopSettings() set.TelemetryFactory = telemetry.NewFactory( func() component.Config { return nil }, telemetry.WithCreateTracerProvider( func(context.Context, telemetry.TracerSettings, component.Config) (telemetry.TracerProvider, error) { telemetryCreated <- struct{}{} return telemetrytest.ShutdownTracerProvider{ TracerProvider: nooptrace.NewTracerProvider(), ShutdownFunc: func(context.Context) error { telemetryShutdown <- struct{}{} return nil }, }, nil }, ), ) for range 2 { // Create and start a service, telemetry should be created. srv, err := New(context.Background(), set, newNopConfig()) require.NoError(t, err) require.NoError(t, srv.Start(context.Background())) <-telemetryCreated // Shutdown the service, telemetry should be shutdown. require.NoError(t, srv.Shutdown(context.Background())) <-telemetryShutdown } } func TestServiceTelemetryShutdownError(t *testing.T) { set := newNopSettings() set.TelemetryFactory = telemetry.NewFactory( func() component.Config { return nil }, telemetry.WithCreateLogger( func(context.Context, telemetry.LoggerSettings, component.Config) (*zap.Logger, component.ShutdownFunc, error) { return zap.NewNop(), func(context.Context) error { return errors.New("an exception occurred") }, nil }, ), telemetry.WithCreateMeterProvider( func(context.Context, telemetry.MeterSettings, component.Config) (telemetry.MeterProvider, error) { return telemetrytest.ShutdownMeterProvider{ MeterProvider: noopmetric.NewMeterProvider(), ShutdownFunc: func(context.Context) error { return errors.New("an exception occurred") }, }, nil }, ), telemetry.WithCreateTracerProvider( func(context.Context, telemetry.TracerSettings, component.Config) (telemetry.TracerProvider, error) { return telemetrytest.ShutdownTracerProvider{ TracerProvider: nooptrace.NewTracerProvider(), ShutdownFunc: func(context.Context) error { return errors.New("an exception occurred") }, }, nil }, ), ) // Create and start a service cfg := newNopConfig() srv, err := New(context.Background(), set, cfg) require.NoError(t, err) require.NoError(t, srv.Start(context.Background())) // Shutdown the service err = srv.Shutdown(context.Background()) assert.EqualError(t, err, ""+ "failed to shutdown tracer provider: an exception occurred; "+ "failed to shutdown meter provider: an exception occurred; "+ "failed to shutdown logger: an exception occurred", ) } func TestExtensionNotificationFailure(t *testing.T) { set := newNopSettings() cfg := newNopConfig() extName := component.MustNewType("configWatcher") configWatcherExtensionFactory := newConfigWatcherExtensionFactory(extName) set.ExtensionsConfigs = map[component.ID]component.Config{component.NewID(extName): configWatcherExtensionFactory.CreateDefaultConfig()} set.ExtensionsFactories = map[component.Type]extension.Factory{extName: configWatcherExtensionFactory} cfg.Extensions = []component.ID{component.NewID(extName)} // Create a service srv, err := New(context.Background(), set, cfg) require.NoError(t, err) // Start the service require.Error(t, srv.Start(context.Background())) // Shut down the service require.NoError(t, srv.Shutdown(context.Background())) } func TestNilCollectorEffectiveConfig(t *testing.T) { set := newNopSettings() set.CollectorConf = nil cfg := newNopConfig() extName := component.MustNewType("configWatcher") configWatcherExtensionFactory := newConfigWatcherExtensionFactory(extName) set.ExtensionsConfigs = map[component.ID]component.Config{component.NewID(extName): configWatcherExtensionFactory.CreateDefaultConfig()} set.ExtensionsFactories = map[component.Type]extension.Factory{extName: configWatcherExtensionFactory} cfg.Extensions = []component.ID{component.NewID(extName)} // Create a service srv, err := New(context.Background(), set, cfg) require.NoError(t, err) // Start the service require.NoError(t, srv.Start(context.Background())) // Shut down the service require.NoError(t, srv.Shutdown(context.Background())) } func TestServiceTelemetryLogger(t *testing.T) { srv, err := New(context.Background(), newNopSettings(), newNopConfig()) require.NoError(t, err) assert.NoError(t, srv.Start(context.Background())) t.Cleanup(func() { assert.NoError(t, srv.Shutdown(context.Background())) }) assert.NotNil(t, srv.telemetrySettings.Logger) } func TestServiceFatalError(t *testing.T) { set := newNopSettings() set.AsyncErrorChannel = make(chan error) srv, err := New(context.Background(), set, newNopConfig()) require.NoError(t, err) assert.NoError(t, srv.Start(context.Background())) t.Cleanup(func() { assert.NoError(t, srv.Shutdown(context.Background())) }) go func() { ev := componentstatus.NewFatalErrorEvent(assert.AnError) srv.host.NotifyComponentStatusChange(&componentstatus.InstanceID{}, ev) }() err = <-srv.host.AsyncErrorChannel require.ErrorIs(t, err, assert.AnError) } func TestServiceTelemetryCreateProvidersError(t *testing.T) { loggerOpt := telemetry.WithCreateLogger( func(context.Context, telemetry.LoggerSettings, component.Config) (*zap.Logger, component.ShutdownFunc, error) { return nil, nil, errors.New("something went wrong") }, ) meterOpt := telemetry.WithCreateMeterProvider( func(context.Context, telemetry.MeterSettings, component.Config) (telemetry.MeterProvider, error) { return nil, errors.New("something went wrong") }, ) tracerOpt := telemetry.WithCreateTracerProvider( func(context.Context, telemetry.TracerSettings, component.Config) (telemetry.TracerProvider, error) { return nil, errors.New("something went wrong") }, ) resourceOpt := telemetry.WithCreateResource( func(context.Context, telemetry.Settings, component.Config) (pcommon.Resource, error) { return pcommon.Resource{}, errors.New("something went wrong") }, ) type testcase struct { opts []telemetry.FactoryOption expectedErr string } for name, tc := range map[string]testcase{ "CreateLogger": { opts: []telemetry.FactoryOption{loggerOpt, meterOpt, tracerOpt}, expectedErr: "failed to create logger: something went wrong", }, "CreateMeterProvider": { opts: []telemetry.FactoryOption{meterOpt, tracerOpt}, expectedErr: "failed to create meter provider: something went wrong", }, "CreateTracerProvider": { opts: []telemetry.FactoryOption{tracerOpt}, expectedErr: "failed to create tracer provider: something went wrong", }, "CreateResource": { opts: []telemetry.FactoryOption{resourceOpt}, expectedErr: "failed to create resource: something went wrong", }, } { t.Run(name, func(t *testing.T) { set := newNopSettings() set.TelemetryFactory = telemetry.NewFactory(func() component.Config { return nil }, tc.opts...) _, err := New(context.Background(), set, newNopConfig()) require.EqualError(t, err, tc.expectedErr) }) } } func TestNew_NilTelemetryProvider(t *testing.T) { set := newNopSettings() set.TelemetryFactory = nil _, err := New(context.Background(), set, newNopConfig()) require.EqualError(t, err, "telemetry factory not provided") } func TestServiceTelemetryConsistentInstanceID(t *testing.T) { var loggerResource, meterResource, tracerResource *pcommon.Resource createLoggerCalled := false createMeterCalled := false createTracerCalled := false baseFactory := otelconftelemetry.NewFactory() set := newNopSettings() set.TelemetryFactory = telemetry.NewFactory( baseFactory.CreateDefaultConfig, telemetry.WithCreateResource(baseFactory.CreateResource), telemetry.WithCreateLogger(func(ctx context.Context, settings telemetry.LoggerSettings, cfg component.Config) (*zap.Logger, component.ShutdownFunc, error) { createLoggerCalled = true loggerResource = settings.Resource return baseFactory.CreateLogger(ctx, settings, cfg) }), telemetry.WithCreateMeterProvider(func(ctx context.Context, settings telemetry.MeterSettings, cfg component.Config) (telemetry.MeterProvider, error) { createMeterCalled = true meterResource = settings.Resource return baseFactory.CreateMeterProvider(ctx, settings, cfg) }), telemetry.WithCreateTracerProvider(func(ctx context.Context, settings telemetry.TracerSettings, cfg component.Config) (telemetry.TracerProvider, error) { createTracerCalled = true tracerResource = settings.Resource return baseFactory.CreateTracerProvider(ctx, settings, cfg) }), ) cfg := newNopConfig() srv, err := New(context.Background(), set, cfg) require.NoError(t, err) require.True(t, createLoggerCalled, "logger should have been created") require.True(t, createMeterCalled, "meter provider should have been created") require.True(t, createTracerCalled, "tracer provider should have been created") var serviceInstanceID string if sid, ok := srv.telemetrySettings.Resource.Attributes().Get("service.instance.id"); ok { serviceInstanceID = sid.AsString() } require.NotEmpty(t, serviceInstanceID, "service.instance.id not found in service resource") require.NotNil(t, loggerResource, "logger should have received a resource") require.NotNil(t, meterResource, "meter provider should have received a resource") require.NotNil(t, tracerResource, "tracer provider should have received a resource") var loggerInstanceID, meterInstanceID, tracerInstanceID string if sid, ok := loggerResource.Attributes().Get("service.instance.id"); ok { loggerInstanceID = sid.AsString() } if sid, ok := meterResource.Attributes().Get("service.instance.id"); ok { meterInstanceID = sid.AsString() } if sid, ok := tracerResource.Attributes().Get("service.instance.id"); ok { tracerInstanceID = sid.AsString() } require.NotEmpty(t, loggerInstanceID, "logger resource should have service.instance.id") require.NotEmpty(t, meterInstanceID, "meter resource should have service.instance.id") require.NotEmpty(t, tracerInstanceID, "tracer resource should have service.instance.id") assert.Equal(t, serviceInstanceID, loggerInstanceID, "logger should use the same service.instance.id as the service resource") assert.Equal(t, serviceInstanceID, meterInstanceID, "meter provider should use the same service.instance.id as the service resource") assert.Equal(t, serviceInstanceID, tracerInstanceID, "tracer provider should use the same service.instance.id as the service resource") t.Logf("service.instance.id = %s (shared by logger, meter, and tracer)", serviceInstanceID) require.NoError(t, srv.Shutdown(context.Background())) } func newNopSettings() Settings { receiversConfigs, receiversFactories := builders.NewNopReceiverConfigsAndFactories() processorsConfigs, processorsFactories := builders.NewNopProcessorConfigsAndFactories() connectorsConfigs, connectorsFactories := builders.NewNopConnectorConfigsAndFactories() exportersConfigs, exportersFactories := builders.NewNopExporterConfigsAndFactories() extensionsConfigs, extensionsFactories := builders.NewNopExtensionConfigsAndFactories() telemetryFactory := telemetry.NewFactory(func() component.Config { return nil }) return Settings{ BuildInfo: component.NewDefaultBuildInfo(), CollectorConf: confmap.New(), ReceiversConfigs: receiversConfigs, ReceiversFactories: receiversFactories, ProcessorsConfigs: processorsConfigs, ProcessorsFactories: processorsFactories, ExportersConfigs: exportersConfigs, ExportersFactories: exportersFactories, ConnectorsConfigs: connectorsConfigs, ConnectorsFactories: connectorsFactories, ExtensionsConfigs: extensionsConfigs, ExtensionsFactories: extensionsFactories, AsyncErrorChannel: make(chan error), TelemetryFactory: telemetryFactory, } } func newNopConfig() Config { return newNopConfigPipelineConfigs(pipelines.Config{ pipeline.NewID(pipeline.SignalTraces): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{component.NewID(nopType)}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewID(pipeline.SignalMetrics): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{component.NewID(nopType)}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewID(pipeline.SignalLogs): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{component.NewID(nopType)}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewID(xpipeline.SignalProfiles): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{component.NewID(nopType)}, Exporters: []component.ID{component.NewID(nopType)}, }, }) } func newNopConfigPipelineConfigs(pipelineCfgs pipelines.Config) Config { return Config{ Extensions: extensions.Config{component.NewID(nopType)}, Pipelines: pipelineCfgs, Telemetry: &otelconftelemetry.Config{ Logs: otelconftelemetry.LogsConfig{ Level: zapcore.InfoLevel, Development: false, Encoding: "console", Sampling: &otelconftelemetry.LogsSamplingConfig{ Enabled: true, Tick: 10 * time.Second, Initial: 100, Thereafter: 100, }, OutputPaths: []string{"stderr"}, ErrorOutputPaths: []string{"stderr"}, DisableCaller: false, DisableStacktrace: false, InitialFields: map[string]any(nil), }, Metrics: otelconftelemetry.MetricsConfig{ Level: configtelemetry.LevelBasic, }, }, } } type configWatcherExtension struct{} func (comp *configWatcherExtension) Start(context.Context, component.Host) error { return nil } func (comp *configWatcherExtension) Shutdown(context.Context) error { return nil } func (comp *configWatcherExtension) NotifyConfig(context.Context, *confmap.Conf) error { return errors.New("Failed to resolve config") } func newConfigWatcherExtensionFactory(name component.Type) extension.Factory { return extension.NewFactory( name, func() component.Config { return &struct{}{} }, func(context.Context, extension.Settings, component.Config) (extension.Extension, error) { return &configWatcherExtension{}, nil }, component.StabilityLevelDevelopment, ) } func TestValidateGraph(t *testing.T) { testCases := map[string]struct { connectorCfg map[component.ID]component.Config receiverCfg map[component.ID]component.Config exporterCfg map[component.ID]component.Config pipelinesCfg pipelines.Config expectedError string }{ "Valid connector usage": { connectorCfg: map[component.ID]component.Config{ component.NewIDWithName(nopType, "connector1"): &struct{}{}, }, receiverCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, exporterCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, pipelinesCfg: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewIDWithName(nopType, "connector1")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.NewIDWithName(nopType, "connector1")}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, }, expectedError: "", }, "Valid without Connector": { receiverCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, exporterCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, pipelinesCfg: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, }, expectedError: "", }, "Connector used as exporter but not as receiver": { connectorCfg: map[component.ID]component.Config{ component.NewIDWithName(nopType, "connector1"): &struct{}{}, }, receiverCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, exporterCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, pipelinesCfg: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in1"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "in2"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewIDWithName(nopType, "connector1")}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, }, expectedError: `failed to build pipelines: connector "nop/connector1" used as exporter in [logs/in2] pipeline but not used in any supported receiver pipeline`, }, "Connector used as receiver but not as exporter": { connectorCfg: map[component.ID]component.Config{ component.NewIDWithName(nopType, "connector1"): &struct{}{}, }, receiverCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, exporterCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, pipelinesCfg: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalLogs, "in1"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "in2"): { Receivers: []component.ID{component.NewIDWithName(nopType, "connector1")}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, pipeline.NewIDWithName(pipeline.SignalLogs, "out"): { Receivers: []component.ID{component.NewID(nopType)}, Processors: []component.ID{}, Exporters: []component.ID{component.NewID(nopType)}, }, }, expectedError: `failed to build pipelines: connector "nop/connector1" used as receiver in [logs/in2] pipeline but not used in any supported exporter pipeline`, }, "Connector creates direct cycle between pipelines": { connectorCfg: map[component.ID]component.Config{ component.NewIDWithName(nopType, "forward"): &struct{}{}, }, receiverCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, exporterCfg: map[component.ID]component.Config{ component.NewID(nopType): &struct{}{}, }, pipelinesCfg: pipelines.Config{ pipeline.NewIDWithName(pipeline.SignalTraces, "in"): { Receivers: []component.ID{component.NewIDWithName(nopType, "forward")}, Processors: []component.ID{}, Exporters: []component.ID{component.NewIDWithName(nopType, "forward")}, }, pipeline.NewIDWithName(pipeline.SignalTraces, "out"): { Receivers: []component.ID{component.NewIDWithName(nopType, "forward")}, Processors: []component.ID{}, Exporters: []component.ID{component.NewIDWithName(nopType, "forward")}, }, }, expectedError: `failed to build pipelines: cycle detected: connector "nop/forward" (traces to traces) -> connector "nop/forward" (traces to traces)`, }, } _, connectorsFactories := builders.NewNopConnectorConfigsAndFactories() _, receiversFactories := builders.NewNopReceiverConfigsAndFactories() _, exportersFactories := builders.NewNopExporterConfigsAndFactories() for name, tc := range testCases { t.Run(name, func(t *testing.T) { settings := Settings{ ConnectorsConfigs: tc.connectorCfg, ConnectorsFactories: connectorsFactories, ReceiversConfigs: tc.receiverCfg, ReceiversFactories: receiversFactories, ExportersConfigs: tc.exporterCfg, ExportersFactories: exportersFactories, } cfg := Config{ Pipelines: tc.pipelinesCfg, } err := Validate(context.Background(), settings, cfg) if tc.expectedError == "" { require.NoError(t, err) } else { require.Error(t, err) assert.Equal(t, tc.expectedError, err.Error()) } }) } } opentelemetry-collector-0.141.0/service/telemetry/000077500000000000000000000000001511331344600222105ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/doc.go000066400000000000000000000003661511331344600233110ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 // Package telemetry provides an abstract interface for creating // telemetry providers. package telemetry // import "go.opentelemetry.io/collector/service/telemetry" opentelemetry-collector-0.141.0/service/telemetry/internal/000077500000000000000000000000001511331344600240245ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/internal/migration/000077500000000000000000000000001511331344600260155ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/internal/migration/normalize.go000066400000000000000000000007601511331344600303470ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package migration // import "go.opentelemetry.io/collector/service/telemetry/internal/migration" import "strings" func normalizeEndpoint(endpoint string, insecure *bool) *string { if !strings.HasPrefix(endpoint, "https://") && !strings.HasPrefix(endpoint, "http://") { if insecure != nil && *insecure { endpoint = "http://" + endpoint } else { endpoint = "https://" + endpoint } } return &endpoint } opentelemetry-collector-0.141.0/service/telemetry/internal/migration/testdata/000077500000000000000000000000001511331344600276265ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/internal/migration/testdata/v0.2.0_logs.yaml000066400000000000000000000006161511331344600323640ustar00rootroot00000000000000level: "info" processors: - batch: exporter: otlp: protocol: http/protobuf endpoint: 127.0.0.1:4317 headers: "key1": "value1" - simple: exporter: console: {} - simple: exporter: otlp: protocol: http/protobuf endpoint: http://127.0.0.1:4317 headers: "key1": "value1" opentelemetry-collector-0.141.0/service/telemetry/internal/migration/testdata/v0.2.0_metrics.yaml000066400000000000000000000004431511331344600330640ustar00rootroot00000000000000readers: - periodic: exporter: otlp: protocol: http/protobuf endpoint: 127.0.0.1:4317 headers: "key1": "value1" "key2": "value2" - pull: exporter: prometheus: host: 127.0.0.1 port: 8902opentelemetry-collector-0.141.0/service/telemetry/internal/migration/testdata/v0.2.0_traces.yaml000066400000000000000000000006001511331344600326720ustar00rootroot00000000000000processors: - batch: exporter: otlp: protocol: http/protobuf endpoint: 127.0.0.1:4317 headers: "key1": "value1" - simple: exporter: console: {} - simple: exporter: otlp: protocol: http/protobuf endpoint: http://127.0.0.1:4317 headers: "key1": "value1" opentelemetry-collector-0.141.0/service/telemetry/internal/migration/testdata/v0.3.0_logs.yaml000066400000000000000000000006761511331344600323730ustar00rootroot00000000000000level: "info" processors: - batch: exporter: otlp: protocol: http/protobuf endpoint: 127.0.0.1:4317 headers: - name: "key1" value: "value1" - simple: exporter: console: {} - simple: exporter: otlp: protocol: http/protobuf endpoint: http://127.0.0.1:4317 headers: - name: "key1" value: "value1" opentelemetry-collector-0.141.0/service/telemetry/internal/migration/testdata/v0.3.0_metrics.yaml000066400000000000000000000004561511331344600330710ustar00rootroot00000000000000level: detailed readers: - periodic: exporter: otlp: protocol: http/protobuf endpoint: 127.0.0.1:4317 headers: - name: "key1" value: "value1" - pull: exporter: prometheus: host: 127.0.0.1 port: 8902opentelemetry-collector-0.141.0/service/telemetry/internal/migration/testdata/v0.3.0_traces.yaml000066400000000000000000000010211511331344600326710ustar00rootroot00000000000000level: "none" processors: - batch: exporter: otlp: protocol: http/protobuf endpoint: 127.0.0.1:4317 headers: - name: "key1" value: "value1" - simple: exporter: console: {} - simple: exporter: otlp: protocol: http/protobuf endpoint: http://127.0.0.1:4317 headers: - name: "key1" value: "value1" sampler: parent_based: root: trace_id_ratio_based: ratio: 0.01 opentelemetry-collector-0.141.0/service/telemetry/internal/migration/v0.2.0.go000066400000000000000000000162271511331344600271770ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package migration // import "go.opentelemetry.io/collector/service/telemetry/internal/migration" import ( configv02 "go.opentelemetry.io/contrib/otelconf/v0.2.0" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/config/configtelemetry" ) type tracesConfigV020 struct { Level configtelemetry.Level `mapstructure:"level"` Propagators []string `mapstructure:"propagators"` Processors []configv02.SpanProcessor `mapstructure:"processors"` } type metricsConfigV020 struct { Level configtelemetry.Level `mapstructure:"level"` Readers []configv02.MetricReader `mapstructure:"readers"` } type logsConfigV020 struct { Level zapcore.Level `mapstructure:"level"` Development bool `mapstructure:"development"` Encoding string `mapstructure:"encoding"` DisableCaller bool `mapstructure:"disable_caller"` DisableStacktrace bool `mapstructure:"disable_stacktrace"` Sampling *LogsSamplingConfig `mapstructure:"sampling"` OutputPaths []string `mapstructure:"output_paths"` ErrorOutputPaths []string `mapstructure:"error_output_paths"` InitialFields map[string]any `mapstructure:"initial_fields"` Processors []configv02.LogRecordProcessor `mapstructure:"processors"` } func headersV02ToV03(in configv02.Headers) []config.NameStringValuePair { headers := make([]config.NameStringValuePair, 0, len(in)) for k, v := range in { headers = append(headers, config.NameStringValuePair{ Name: k, Value: &v, }) } return headers } func otlpV02ToV03(in *configv02.OTLP) *config.OTLP { if in == nil { return nil } return &config.OTLP{ Certificate: in.Certificate, ClientCertificate: in.ClientCertificate, ClientKey: in.ClientKey, Compression: in.Compression, Endpoint: normalizeEndpoint(in.Endpoint, in.Insecure), Insecure: in.Insecure, Protocol: &in.Protocol, Timeout: in.Timeout, Headers: headersV02ToV03(in.Headers), } } func otlpMetricV02ToV03(in *configv02.OTLPMetric) *config.OTLPMetric { if in == nil { return nil } return &config.OTLPMetric{ Certificate: in.Certificate, ClientCertificate: in.ClientCertificate, ClientKey: in.ClientKey, Compression: in.Compression, Endpoint: normalizeEndpoint(in.Endpoint, in.Insecure), Insecure: in.Insecure, Protocol: &in.Protocol, Timeout: in.Timeout, Headers: headersV02ToV03(in.Headers), } } func zipkinV02ToV03(in *configv02.Zipkin) *config.Zipkin { if in == nil { return nil } return &config.Zipkin{ Endpoint: &in.Endpoint, Timeout: in.Timeout, } } func tracesConfigV02ToV03(v2 tracesConfigV020, v3 *TracesConfigV030) error { processors := make([]config.SpanProcessor, len(v2.Processors)) for idx, p := range v2.Processors { processors[idx] = config.SpanProcessor{} if p.Batch != nil { processors[idx].Batch = &config.BatchSpanProcessor{ ExportTimeout: p.Batch.ExportTimeout, MaxExportBatchSize: p.Batch.MaxExportBatchSize, MaxQueueSize: p.Batch.MaxQueueSize, ScheduleDelay: p.Batch.ScheduleDelay, Exporter: config.SpanExporter{ Console: config.Console(p.Batch.Exporter.Console), OTLP: otlpV02ToV03(p.Batch.Exporter.OTLP), Zipkin: zipkinV02ToV03(p.Batch.Exporter.Zipkin), AdditionalProperties: p.Batch.Exporter.AdditionalProperties, }, } } if p.Simple != nil { processors[idx].Simple = &config.SimpleSpanProcessor{ Exporter: config.SpanExporter{ Console: config.Console(p.Simple.Exporter.Console), OTLP: otlpV02ToV03(p.Simple.Exporter.OTLP), Zipkin: zipkinV02ToV03(p.Simple.Exporter.Zipkin), AdditionalProperties: p.Simple.Exporter.AdditionalProperties, }, } } processors[idx].AdditionalProperties = p.AdditionalProperties } v3.Level = v2.Level v3.Propagators = v2.Propagators v3.Processors = processors return nil } func prometheusV02ToV03(in *configv02.Prometheus) *config.Prometheus { if in == nil { return nil } return &config.Prometheus{ Host: in.Host, Port: in.Port, WithoutScopeInfo: in.WithoutScopeInfo, WithoutUnits: in.WithoutUnits, WithoutTypeSuffix: in.WithoutTypeSuffix, WithResourceConstantLabels: (*config.IncludeExclude)(in.WithResourceConstantLabels), } } func metricsConfigV02ToV03(v2 metricsConfigV020, v3 *MetricsConfigV030) error { readers := make([]config.MetricReader, len(v2.Readers)) for idx, p := range v2.Readers { readers[idx] = config.MetricReader{} if p.Periodic != nil { readers[idx].Periodic = &config.PeriodicMetricReader{ Interval: p.Periodic.Interval, Timeout: p.Periodic.Timeout, Exporter: config.PushMetricExporter{ Console: config.Console(p.Periodic.Exporter.Console), OTLP: otlpMetricV02ToV03(p.Periodic.Exporter.OTLP), AdditionalProperties: p.Periodic.Exporter.AdditionalProperties, }, } } if p.Pull != nil { readers[idx].Pull = &config.PullMetricReader{ Exporter: config.PullMetricExporter{ Prometheus: prometheusV02ToV03(p.Pull.Exporter.Prometheus), AdditionalProperties: p.Pull.Exporter.AdditionalProperties, }, } } } v3.Level = v2.Level v3.Readers = readers return nil } func logsConfigV02ToV03(v2 logsConfigV020, v3 *LogsConfigV030) error { processors := make([]config.LogRecordProcessor, len(v2.Processors)) for idx, p := range v2.Processors { processors[idx] = config.LogRecordProcessor{} if p.Batch != nil { processors[idx].Batch = &config.BatchLogRecordProcessor{ ExportTimeout: p.Batch.ExportTimeout, MaxExportBatchSize: p.Batch.MaxExportBatchSize, MaxQueueSize: p.Batch.MaxQueueSize, ScheduleDelay: p.Batch.ScheduleDelay, Exporter: config.LogRecordExporter{ Console: config.Console(p.Batch.Exporter.Console), OTLP: otlpV02ToV03(p.Batch.Exporter.OTLP), AdditionalProperties: p.Batch.Exporter.AdditionalProperties, }, } } if p.Simple != nil { processors[idx].Simple = &config.SimpleLogRecordProcessor{ Exporter: config.LogRecordExporter{ Console: config.Console(p.Simple.Exporter.Console), OTLP: otlpV02ToV03(p.Simple.Exporter.OTLP), AdditionalProperties: p.Simple.Exporter.AdditionalProperties, }, } } processors[idx].AdditionalProperties = p.AdditionalProperties } v3.Level = v2.Level v3.Development = v2.Development v3.Encoding = v2.Encoding v3.DisableCaller = v2.DisableCaller v3.DisableStacktrace = v2.DisableStacktrace v3.Sampling = v2.Sampling v3.OutputPaths = v2.OutputPaths v3.ErrorOutputPaths = v2.ErrorOutputPaths v3.InitialFields = v2.InitialFields v3.Processors = processors return nil } opentelemetry-collector-0.141.0/service/telemetry/internal/migration/v0.2.0_test.go000066400000000000000000000046701511331344600302350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package migration import ( "path/filepath" "testing" "github.com/stretchr/testify/require" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestUnmarshalLogsConfigV020(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "v0.2.0_logs.yaml")) require.NoError(t, err) cfg := LogsConfigV030{ Encoding: "console", } require.NoError(t, cm.Unmarshal(&cfg)) require.Len(t, cfg.Processors, 3) // check the endpoint is prefixed w/ https require.Equal(t, "https://127.0.0.1:4317", *cfg.Processors[0].Batch.Exporter.OTLP.Endpoint) // check the endpoint is prefixed w/ http require.Equal(t, "http://127.0.0.1:4317", *cfg.Processors[2].Simple.Exporter.OTLP.Endpoint) // ensure defaults set in the original config object are not lost require.Equal(t, "console", cfg.Encoding) } func TestUnmarshalTracesConfigV020(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "v0.2.0_traces.yaml")) require.NoError(t, err) cfg := TracesConfigV030{ Level: configtelemetry.LevelNone, } require.NoError(t, cm.Unmarshal(&cfg)) require.Len(t, cfg.Processors, 3) // check the endpoint is prefixed w/ https require.Equal(t, "https://127.0.0.1:4317", *cfg.Processors[0].Batch.Exporter.OTLP.Endpoint) // check the endpoint is prefixed w/ http require.Equal(t, "http://127.0.0.1:4317", *cfg.Processors[2].Simple.Exporter.OTLP.Endpoint) // ensure defaults set in the original config object are not lost require.Equal(t, configtelemetry.LevelNone, cfg.Level) } func TestUnmarshalMetricsConfigV020(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "v0.2.0_metrics.yaml")) require.NoError(t, err) cfg := MetricsConfigV030{ Level: configtelemetry.LevelBasic, } require.NoError(t, cm.Unmarshal(&cfg)) require.Len(t, cfg.Readers, 2) // check the endpoint is prefixed w/ https require.Equal(t, "https://127.0.0.1:4317", *cfg.Readers[0].Periodic.Exporter.OTLP.Endpoint) require.ElementsMatch(t, []config.NameStringValuePair{{Name: "key1", Value: ptr("value1")}, {Name: "key2", Value: ptr("value2")}}, cfg.Readers[0].Periodic.Exporter.OTLP.Headers) // ensure defaults set in the original config object are not lost require.Equal(t, configtelemetry.LevelBasic, cfg.Level) } func ptr[T any](v T) *T { return &v } opentelemetry-collector-0.141.0/service/telemetry/internal/migration/v0.3.0.go000066400000000000000000000201731511331344600271730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package migration // import "go.opentelemetry.io/collector/service/telemetry/internal/migration" import ( "time" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" ) type TracesConfigV030 struct { // Level configures whether spans are emitted or not, the possible values are: // - "none" indicates that no tracing data should be collected; // - "basic" is the recommended and covers the basics of the service telemetry. Level configtelemetry.Level `mapstructure:"level"` // Propagators is a list of TextMapPropagators from the supported propagators list. Currently, // tracecontext and b3 are supported. By default, the value is set to empty list and // context propagation is disabled. Propagators []string `mapstructure:"propagators"` config.TracerProvider `mapstructure:",squash"` } func (c *TracesConfigV030) Unmarshal(conf *confmap.Conf) error { unmarshaled := *c if err := conf.Unmarshal(c); err != nil { v2TracesConfig := tracesConfigV020{ Level: unmarshaled.Level, Propagators: unmarshaled.Propagators, } // try unmarshaling using v0.2.0 struct if e := conf.Unmarshal(&v2TracesConfig); e != nil { // error could not be resolved through backwards // compatibility attempts return err } // TODO: add a warning log to tell users to migrate their config return tracesConfigV02ToV03(v2TracesConfig, c) } // ensure endpoint normalization occurs for _, r := range c.Processors { if r.Batch != nil { if r.Batch.Exporter.OTLP != nil { r.Batch.Exporter.OTLP.Endpoint = normalizeEndpoint(*r.Batch.Exporter.OTLP.Endpoint, r.Batch.Exporter.OTLP.Insecure) } } if r.Simple != nil { if r.Simple.Exporter.OTLP != nil && r.Simple.Exporter.OTLP.Endpoint != nil { r.Simple.Exporter.OTLP.Endpoint = normalizeEndpoint(*r.Simple.Exporter.OTLP.Endpoint, r.Simple.Exporter.OTLP.Insecure) } } } return nil } type MetricsConfigV030 struct { // Level is the level of telemetry metrics, the possible values are: // - "none" indicates that no telemetry data should be collected; // - "basic" is the recommended and covers the basics of the service telemetry. // - "normal" adds some other indicators on top of basic. // - "detailed" adds dimensions and views to the previous levels. Level configtelemetry.Level `mapstructure:"level"` config.MeterProvider `mapstructure:",squash"` } func (c *MetricsConfigV030) Unmarshal(conf *confmap.Conf) error { unmarshaled := *c if err := conf.Unmarshal(c); err != nil { v02 := metricsConfigV020{ Level: unmarshaled.Level, } // try unmarshaling using v0.2.0 struct if e := conf.Unmarshal(&v02); e != nil { // error could not be resolved through backwards // compatibility attempts return err } // TODO: add a warning log to tell users to migrate their config return metricsConfigV02ToV03(v02, c) } // ensure endpoint normalization occurs for _, r := range c.Readers { if r.Periodic != nil { if r.Periodic.Exporter.OTLP != nil && r.Periodic.Exporter.OTLP.Endpoint != nil { r.Periodic.Exporter.OTLP.Endpoint = normalizeEndpoint(*r.Periodic.Exporter.OTLP.Endpoint, r.Periodic.Exporter.OTLP.Insecure) } } } return nil } type LogsConfigV030 struct { // Level is the minimum enabled logging level. // (default = "INFO") Level zapcore.Level `mapstructure:"level"` // Development puts the logger in development mode, which changes the // behavior of DPanicLevel and takes stacktraces more liberally. // (default = false) Development bool `mapstructure:"development,omitempty"` // Encoding sets the logger's encoding. // Example values are "json", "console". Encoding string `mapstructure:"encoding"` // DisableCaller stops annotating logs with the calling function's file // name and line number. By default, all logs are annotated. // (default = false) DisableCaller bool `mapstructure:"disable_caller,omitempty"` // DisableStacktrace completely disables automatic stacktrace capturing. By // default, stacktraces are captured for WarnLevel and above logs in // development and ErrorLevel and above in production. // (default = false) DisableStacktrace bool `mapstructure:"disable_stacktrace,omitempty"` // Sampling sets a sampling policy. // Default: // sampling: // enabled: true // tick: 10s // initial: 10 // thereafter: 100 // Sampling can be disabled by setting 'enabled' to false Sampling *LogsSamplingConfig `mapstructure:"sampling"` // OutputPaths is a list of URLs or file paths to write logging output to. // The URLs could only be with "file" schema or without schema. // The URLs with "file" schema must be an absolute path. // The URLs without schema are treated as local file paths. // "stdout" and "stderr" are interpreted as os.Stdout and os.Stderr. // see details at Open in zap/writer.go. // (default = ["stderr"]) OutputPaths []string `mapstructure:"output_paths"` // ErrorOutputPaths is a list of URLs or file paths to write zap internal logger errors to. // The URLs could only be with "file" schema or without schema. // The URLs with "file" schema must use absolute paths. // The URLs without schema are treated as local file paths. // "stdout" and "stderr" are interpreted as os.Stdout and os.Stderr. // see details at Open in zap/writer.go. // // Note that this setting only affects the zap internal logger errors. // (default = ["stderr"]) ErrorOutputPaths []string `mapstructure:"error_output_paths"` // InitialFields is a collection of fields to add to the root logger. // Example: // // initial_fields: // foo: "bar" // // By default, there is no initial field. InitialFields map[string]any `mapstructure:"initial_fields,omitempty"` // Processors allow configuration of log record processors to emit logs to // any number of supported backends. Processors []config.LogRecordProcessor `mapstructure:"processors,omitempty"` } // LogsSamplingConfig sets a sampling strategy for the logger. Sampling caps the // global CPU and I/O load that logging puts on your process while attempting // to preserve a representative subset of your logs. type LogsSamplingConfig struct { // Enabled enable sampling logging Enabled bool `mapstructure:"enabled"` // Tick represents the interval in seconds that the logger apply each sampling. Tick time.Duration `mapstructure:"tick"` // Initial represents the first M messages logged each Tick. Initial int `mapstructure:"initial"` // Thereafter represents the sampling rate, every Nth message will be sampled after Initial messages are logged during each Tick. // If Thereafter is zero, the logger will drop all the messages after the Initial each Tick. Thereafter int `mapstructure:"thereafter"` } func (c *LogsConfigV030) Unmarshal(conf *confmap.Conf) error { unmarshaled := *c if err := conf.Unmarshal(c); err != nil { v02 := logsConfigV020{ Level: unmarshaled.Level, Development: unmarshaled.Development, Encoding: unmarshaled.Encoding, DisableCaller: unmarshaled.DisableCaller, DisableStacktrace: unmarshaled.DisableStacktrace, Sampling: unmarshaled.Sampling, OutputPaths: unmarshaled.OutputPaths, ErrorOutputPaths: unmarshaled.ErrorOutputPaths, InitialFields: unmarshaled.InitialFields, } // try unmarshaling using v0.2.0 struct if e := conf.Unmarshal(&v02); e != nil { // error could not be resolved through backwards // compatibility attempts return err } // TODO: add a warning log to tell users to migrate their config return logsConfigV02ToV03(v02, c) } // ensure endpoint normalization occurs for _, r := range c.Processors { if r.Batch != nil { if r.Batch.Exporter.OTLP != nil { r.Batch.Exporter.OTLP.Endpoint = normalizeEndpoint(*r.Batch.Exporter.OTLP.Endpoint, r.Batch.Exporter.OTLP.Insecure) } } if r.Simple != nil { if r.Simple.Exporter.OTLP != nil && r.Simple.Exporter.OTLP.Endpoint != nil { r.Simple.Exporter.OTLP.Endpoint = normalizeEndpoint(*r.Simple.Exporter.OTLP.Endpoint, r.Simple.Exporter.OTLP.Insecure) } } } return nil } opentelemetry-collector-0.141.0/service/telemetry/internal/migration/v0.3.0_test.go000066400000000000000000000032451511331344600302330ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package migration import ( "path/filepath" "testing" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/confmap/confmaptest" ) func TestUnmarshalLogsConfigV030(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "v0.3.0_logs.yaml")) require.NoError(t, err) cfg := LogsConfigV030{} require.NoError(t, cm.Unmarshal(&cfg)) require.Len(t, cfg.Processors, 3) // check the endpoint is prefixed w/ https require.Equal(t, "https://127.0.0.1:4317", *cfg.Processors[0].Batch.Exporter.OTLP.Endpoint) // check the endpoint is prefixed w/ http require.Equal(t, "http://127.0.0.1:4317", *cfg.Processors[2].Simple.Exporter.OTLP.Endpoint) } func TestUnmarshalTracesConfigV030(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "v0.3.0_traces.yaml")) require.NoError(t, err) cfg := TracesConfigV030{} require.NoError(t, cm.Unmarshal(&cfg)) require.Len(t, cfg.Processors, 3) // check the endpoint is prefixed w/ https require.Equal(t, "https://127.0.0.1:4317", *cfg.Processors[0].Batch.Exporter.OTLP.Endpoint) // check the endpoint is prefixed w/ http require.Equal(t, "http://127.0.0.1:4317", *cfg.Processors[2].Simple.Exporter.OTLP.Endpoint) } func TestUnmarshalMetricsConfigV030(t *testing.T) { cm, err := confmaptest.LoadConf(filepath.Join("testdata", "v0.3.0_metrics.yaml")) require.NoError(t, err) cfg := MetricsConfigV030{} require.NoError(t, cm.Unmarshal(&cfg)) require.Len(t, cfg.Readers, 2) // check the endpoint is prefixed w/ https require.Equal(t, "https://127.0.0.1:4317", *cfg.Readers[0].Periodic.Exporter.OTLP.Endpoint) } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/000077500000000000000000000000001511331344600257545ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/config.go000066400000000000000000000047621511331344600275610ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "errors" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/service/telemetry/internal/migration" ) // Config defines the configurable settings for service telemetry. type Config struct { Logs LogsConfig `mapstructure:"logs"` Metrics MetricsConfig `mapstructure:"metrics"` Traces TracesConfig `mapstructure:"traces,omitempty"` // Resource specifies user-defined attributes to include with all emitted telemetry. // Note that some attributes are added automatically (e.g. service.version) even // if they are not specified here. In order to suppress such attributes the // attribute must be specified in this map with null YAML value (nil string pointer). Resource map[string]*string `mapstructure:"resource,omitempty"` } // LogsConfig defines the configurable settings for service telemetry logs. // This MUST be compatible with zap.Config. Cannot use directly zap.Config because // the collector uses mapstructure and not yaml tags. type LogsConfig = migration.LogsConfigV030 // LogsSamplingConfig sets a sampling strategy for the logger. Sampling caps the // global CPU and I/O load that logging puts on your process while attempting // to preserve a representative subset of your logs. type LogsSamplingConfig = migration.LogsSamplingConfig // MetricsConfig exposes the common Telemetry configuration for one component. // Experimental: *NOTE* this structure is subject to change or removal in the future. type MetricsConfig = migration.MetricsConfigV030 // TracesConfig exposes the common Telemetry configuration for collector's internal spans. // Experimental: *NOTE* this structure is subject to change or removal in the future. type TracesConfig = migration.TracesConfigV030 // Validate checks whether the current configuration is valid func (c *Config) Validate() error { // Check when service telemetry metric level is not none, the metrics readers should not be empty if c.Metrics.Level != configtelemetry.LevelNone && len(c.Metrics.Readers) == 0 { return errors.New("collector telemetry metrics reader should exist when metric level is not none") } if c.Metrics.Views != nil && c.Metrics.Level != configtelemetry.LevelDetailed { return errors.New("service::telemetry::metrics::views can only be set when service::telemetry::metrics::level is detailed") } return nil } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/config_test.go000066400000000000000000000062031511331344600306100ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry import ( "path/filepath" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.uber.org/zap" "go.opentelemetry.io/collector/component/componenttest" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/confmap" "go.opentelemetry.io/collector/confmap/confmaptest" "go.opentelemetry.io/collector/confmap/xconfmap" ) func TestComponentConfigStruct(t *testing.T) { require.NoError(t, componenttest.CheckConfigStruct( NewFactory().CreateDefaultConfig(), )) } func TestUnmarshalDefaultConfig(t *testing.T) { factory := NewFactory() cfg := factory.CreateDefaultConfig() require.NoError(t, confmap.New().Unmarshal(&cfg)) assert.Equal(t, factory.CreateDefaultConfig(), cfg) } func TestConfig(t *testing.T) { t.Parallel() type testcase struct { setup func(*testing.T) // optional testcase setup config *Config unmarshalErr string validateErr string } tests := map[string]testcase{ "config_empty.yaml": { config: createDefaultConfig().(*Config), }, "config_logs.yaml": { config: func() *Config { cfg := createDefaultConfig().(*Config) cfg.Logs.Development = true cfg.Logs.DisableCaller = true cfg.Logs.DisableStacktrace = true cfg.Logs.InitialFields = map[string]any{"fieldKey": "fieldValue"} cfg.Logs.Level = zap.InfoLevel cfg.Logs.Sampling = &LogsSamplingConfig{ Enabled: false, Tick: 1 * time.Second, Initial: 234, Thereafter: 567, } cfg.Logs.Processors = []config.LogRecordProcessor{{ Batch: &config.BatchLogRecordProcessor{ Exporter: config.LogRecordExporter{ Console: config.Console{}, }, }, }} return cfg }(), }, "config_metrics_empty_readers.yaml": { config: func() *Config { cfg := createDefaultConfig().(*Config) cfg.Metrics.Level = configtelemetry.LevelNone cfg.Metrics.Readers = []config.MetricReader{} return cfg }(), }, "config_invalid_unknown_field.yaml": { unmarshalErr: `invalid keys: unknown`, }, "config_invalid_metrics_empty_readers.yaml": { validateErr: `collector telemetry metrics reader should exist when metric level is not none`, }, "config_invalid_metrics_views_level.yaml": { validateErr: `service::telemetry::metrics::views can only be set when service::telemetry::metrics::level is detailed`, }, } for filename, test := range tests { t.Run(filename, func(t *testing.T) { if test.setup != nil { test.setup(t) } cm, err := confmaptest.LoadConf(filepath.Join("testdata", filename)) require.NoError(t, err) cfg := createDefaultConfig().(*Config) err = cm.Unmarshal(cfg) if test.unmarshalErr != "" { assert.ErrorContains(t, err, test.unmarshalErr) return } require.NoError(t, err) err = xconfmap.Validate(cfg) if test.validateErr != "" { assert.ErrorContains(t, err, test.validateErr) return } require.NoError(t, err) assert.Equal(t, test.config, cfg) }) } } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/factory.go000066400000000000000000000047231511331344600277600ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "time" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/service/telemetry" ) var useLocalHostAsDefaultMetricsAddressFeatureGate = featuregate.GlobalRegistry().MustRegister( "telemetry.UseLocalHostAsDefaultMetricsAddress", featuregate.StageBeta, featuregate.WithRegisterFromVersion("v0.111.0"), featuregate.WithRegisterDescription("controls whether default Prometheus metrics server use localhost as the default host for their endpoints"), ) // NewFactory creates a new telemetry.Factory that uses otelconf // to configure opentelemetry-go SDK telemetry providers. func NewFactory() telemetry.Factory { return telemetry.NewFactory( createDefaultConfig, telemetry.WithCreateResource(createResource), telemetry.WithCreateLogger(createLogger), telemetry.WithCreateMeterProvider(createMeterProvider), telemetry.WithCreateTracerProvider(createTracerProvider), ) } func createDefaultConfig() component.Config { metricsHost := "localhost" if !useLocalHostAsDefaultMetricsAddressFeatureGate.IsEnabled() { metricsHost = "" } return &Config{ Logs: LogsConfig{ Level: zapcore.InfoLevel, Development: false, Encoding: "console", Sampling: &LogsSamplingConfig{ Enabled: true, Tick: 10 * time.Second, Initial: 10, Thereafter: 100, }, OutputPaths: []string{"stderr"}, ErrorOutputPaths: []string{"stderr"}, DisableCaller: false, DisableStacktrace: false, InitialFields: map[string]any(nil), }, Metrics: MetricsConfig{ Level: configtelemetry.LevelNormal, MeterProvider: config.MeterProvider{ Readers: []config.MetricReader{ { Pull: &config.PullMetricReader{Exporter: config.PullMetricExporter{Prometheus: &config.Prometheus{ WithoutScopeInfo: ptr(true), WithoutUnits: ptr(true), WithoutTypeSuffix: ptr(true), Host: &metricsHost, Port: ptr(8888), WithResourceConstantLabels: &config.IncludeExclude{ Included: []string{}, }, }}}, }, }, }, }, } } func ptr[T any](v T) *T { return &v } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/factory_test.go000066400000000000000000000023351511331344600310140ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry import ( "strconv" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/featuregate" ) func TestDefaultConfig(t *testing.T) { tests := []struct { expected string gate bool }{ { expected: "localhost", gate: true, }, { expected: "", gate: false, }, } for _, tt := range tests { t.Run("UseLocalHostAsDefaultMetricsAddress/"+strconv.FormatBool(tt.gate), func(t *testing.T) { prev := useLocalHostAsDefaultMetricsAddressFeatureGate.IsEnabled() require.NoError(t, featuregate.GlobalRegistry().Set(useLocalHostAsDefaultMetricsAddressFeatureGate.ID(), tt.gate)) defer func() { // Restore previous value. require.NoError(t, featuregate.GlobalRegistry().Set(useLocalHostAsDefaultMetricsAddressFeatureGate.ID(), prev)) }() cfg := NewFactory().CreateDefaultConfig() require.Len(t, cfg.(*Config).Metrics.Readers, 1) assert.Equal(t, tt.expected, *cfg.(*Config).Metrics.Readers[0].Pull.Exporter.Prometheus.Host) assert.Equal(t, 8888, *cfg.(*Config).Metrics.Readers[0].Pull.Exporter.Prometheus.Port) }) } } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/logger.go000066400000000000000000000066201511331344600275660ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "context" otelconf "go.opentelemetry.io/contrib/otelconf/v0.3.0" sdkresource "go.opentelemetry.io/otel/sdk/resource" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/service/telemetry" ) // createLogger creates a Logger and a LoggerProvider from Config. func createLogger( ctx context.Context, set telemetry.LoggerSettings, componentConfig component.Config, ) (*zap.Logger, component.ShutdownFunc, error) { cfg := componentConfig.(*Config) attrs := pcommonAttrsToOTelAttrs(set.Resource) res := sdkresource.NewWithAttributes("", attrs...) // Copied from NewProductionConfig. ec := zap.NewProductionEncoderConfig() ec.EncodeTime = zapcore.ISO8601TimeEncoder zapCfg := &zap.Config{ Level: zap.NewAtomicLevelAt(cfg.Logs.Level), Development: cfg.Logs.Development, Encoding: cfg.Logs.Encoding, EncoderConfig: ec, OutputPaths: cfg.Logs.OutputPaths, ErrorOutputPaths: cfg.Logs.ErrorOutputPaths, DisableCaller: cfg.Logs.DisableCaller, DisableStacktrace: cfg.Logs.DisableStacktrace, InitialFields: cfg.Logs.InitialFields, } if zapCfg.Encoding == "console" { // Human-readable timestamps for console format of logs. zapCfg.EncoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder } logger, err := zapCfg.Build(set.ZapOptions...) if err != nil { return nil, nil, err } // The attributes in res.Attributes(), which are generated in telemetry.go, // are added to logs exported through the LoggerProvider instantiated below. // To make sure they are also exposed in logs written to stdout, we add // them as fields to the Zap core created above using WrapCore. We do NOT // add them to the logger using With, because that would apply to all logs, // even ones exported through the core that wraps the LoggerProvider, // meaning that the attributes would be exported twice. if res != nil && len(res.Attributes()) > 0 { logger = logger.WithOptions(zap.WrapCore(func(c zapcore.Core) zapcore.Core { var fields []zap.Field for _, attr := range res.Attributes() { fields = append(fields, zap.String(string(attr.Key), attr.Value.Emit())) } r := zap.Dict("resource", fields...) return c.With([]zapcore.Field{r}) })) } if cfg.Logs.Sampling != nil && cfg.Logs.Sampling.Enabled { logger = logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { return zapcore.NewSamplerWithOptions( core, cfg.Logs.Sampling.Tick, cfg.Logs.Sampling.Initial, cfg.Logs.Sampling.Thereafter, ) })) } sdk, err := newSDK(ctx, res, otelconf.OpenTelemetryConfiguration{ LoggerProvider: &otelconf.LoggerProvider{ Processors: cfg.Logs.Processors, }, }) if err != nil { return nil, nil, err } // Wrap the zap.Logger with a special zap.Core so scope attributes // can be added and removed dynamically, and tee logs to the // LoggerProvider. loggerProvider := sdk.LoggerProvider() logger = logger.WithOptions(zap.WrapCore(func(core zapcore.Core) zapcore.Core { provider := zapCoreProvider{ sourceCore: core, lp: loggerProvider, scopeName: "go.opentelemetry.io/collector/service", } return provider.newCore() })) return logger, sdk.Shutdown, nil } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/logger_tee.go000066400000000000000000000057711511331344600304310ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "slices" "go.opentelemetry.io/contrib/bridges/otelzap" "go.opentelemetry.io/otel/log" "go.uber.org/multierr" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.opentelemetry.io/collector/service/internal/componentattribute" ) type zapCoreProvider struct { sourceCore zapcore.Core lp log.LoggerProvider scopeName string } func (zcp *zapCoreProvider) newCore() zapCore { return zapCore{ sourceCore: zcp.sourceCore, otelCore: otelzap.NewCore( zcp.scopeName, otelzap.WithLoggerProvider(zcp.lp), ), provider: zcp, } } // This struct wraps the original Zap core in order to copy logs to a [log.LoggerProvider] using [otelzap]. // For the copied logs, component attributes are injected as instrumentation scope attributes. // // Note that we intentionally do not use zapcore.NewTee here, because it will simply duplicate all log entries // to each core. The provided Zap core may have sampling or a minimum log level applied to it, so in order to // maintain consistency, we need to ensure that only the logs accepted by the provided core are copied to the // log.LoggerProvider. type zapCore struct { sourceCore zapcore.Core // regular Zap core (logs to stderr) otelCore zapcore.Core // otelzap core (forwards to OTel Logger) provider *zapCoreProvider withFields []zap.Field // additional fields injected by the user using .With } var _ zapcore.Core = zapCore{} func (zc zapCore) With(fields []zapcore.Field) zapcore.Core { zc.sourceCore = zc.sourceCore.With(fields) fields = slices.DeleteFunc(fields, func(field zapcore.Field) bool { scope, ok := componentattribute.ExtractLogScopeAttributes(field) if !ok { return false } // Set scope attributes zc.otelCore = otelzap.NewCore( zc.provider.scopeName, otelzap.WithLoggerProvider(zc.provider.lp), otelzap.WithAttributes(scope...), ).With(zc.withFields) return true }) zc.otelCore = zc.otelCore.With(fields) zc.withFields = append(slices.Clone(zc.withFields), fields...) return zc } func (zc zapCore) Enabled(level zapcore.Level) bool { return zc.sourceCore.Enabled(level) } func (zc zapCore) Check(entry zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry { ce = zc.sourceCore.Check(entry, ce) if ce != nil { // Only log to the otelzap core if the source core accepted the log entry. ce = ce.AddCore(entry, zc.otelCore) } return ce } // This function should never be called, since only the inner cores add themselves to the CheckedEntry. // But like zapcore.multiCore, we still implement it for compatibility with non-conforming users. func (zc zapCore) Write(entry zapcore.Entry, fields []zapcore.Field) error { return multierr.Append( zc.sourceCore.Write(entry, fields), zc.otelCore.Write(entry, fields), ) } func (zc zapCore) Sync() error { return multierr.Append( zc.sourceCore.Sync(), zc.otelCore.Sync(), ) } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/logger_test.go000066400000000000000000000324641511331344600306320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry" import ( "context" "encoding/json" "errors" "io" "net/http" "net/http/httptest" "strings" "testing" "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.37.0" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/component/componenttest" internalTelemetry "go.opentelemetry.io/collector/internal/telemetry" "go.opentelemetry.io/collector/pdata/plog/plogotlp" "go.opentelemetry.io/collector/service/internal/componentattribute" "go.opentelemetry.io/collector/service/telemetry" ) const ( version = "1.2.3" service = "test-service" testAttribute = "test-attribute" testValue = "test-value" ) func TestCreateLogger(t *testing.T) { tests := []struct { name string wantCoreType any wantErr error cfg Config }{ { name: "no log config", cfg: Config{}, wantErr: errors.New("no encoder name specified"), }, { name: "log config with invalid processors", cfg: Config{ Logs: LogsConfig{ Level: zapcore.DebugLevel, Development: true, Encoding: "console", DisableCaller: true, DisableStacktrace: true, InitialFields: map[string]any{"fieldKey": "filed-value"}, Processors: []config.LogRecordProcessor{ { Batch: &config.BatchLogRecordProcessor{ Exporter: config.LogRecordExporter{ OTLP: &config.OTLP{}, // missing required fields }, }, }, }, }, }, wantErr: errors.New("no valid log exporter"), }, { name: "log config with no processors", cfg: Config{ Logs: LogsConfig{ Level: zapcore.DebugLevel, Development: true, Encoding: "console", DisableCaller: true, DisableStacktrace: true, InitialFields: map[string]any{"fieldKey": "filed-value"}, }, }, }, { name: "log config with processors", cfg: Config{ Logs: LogsConfig{ Level: zapcore.DebugLevel, Development: true, Encoding: "console", DisableCaller: true, DisableStacktrace: true, InitialFields: map[string]any{"fieldKey": "filed-value"}, Processors: []config.LogRecordProcessor{ { Batch: &config.BatchLogRecordProcessor{ Exporter: config.LogRecordExporter{ Console: config.Console{}, }, }, }, }, }, }, }, { name: "log config with sampling", cfg: Config{ Logs: LogsConfig{ Level: zapcore.InfoLevel, Development: false, Encoding: "console", Sampling: &LogsSamplingConfig{ Enabled: true, Tick: 10 * time.Second, Initial: 10, Thereafter: 100, }, OutputPaths: []string{"stderr"}, ErrorOutputPaths: []string{"stderr"}, DisableCaller: false, DisableStacktrace: false, InitialFields: map[string]any(nil), }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { buildInfo := component.BuildInfo{} factory := NewFactory() resource, err := factory.CreateResource(context.Background(), telemetry.Settings{BuildInfo: buildInfo}, &tt.cfg) require.NoError(t, err) _, provider, err := factory.CreateLogger(context.Background(), telemetry.LoggerSettings{ Settings: telemetry.Settings{BuildInfo: buildInfo, Resource: &resource}, }, &tt.cfg) if tt.wantErr != nil { require.ErrorContains(t, err, tt.wantErr.Error()) } else { require.NoError(t, err) require.NoError(t, provider.Shutdown(context.Background())) } }) } } func TestCreateLoggerWithResource(t *testing.T) { tests := []struct { name string buildInfo component.BuildInfo resourceConfig map[string]*string wantFields map[string]string }{ { name: "auto-populated fields only", buildInfo: component.BuildInfo{ Command: "mycommand", Version: "1.0.0", }, resourceConfig: map[string]*string{}, wantFields: map[string]string{ string(semconv.ServiceNameKey): "mycommand", string(semconv.ServiceVersionKey): "1.0.0", string(semconv.ServiceInstanceIDKey): "", }, }, { name: "override service.name", buildInfo: component.BuildInfo{ Command: "mycommand", Version: "1.0.0", }, resourceConfig: map[string]*string{ string(semconv.ServiceNameKey): ptr("custom-service"), }, wantFields: map[string]string{ string(semconv.ServiceNameKey): "custom-service", string(semconv.ServiceVersionKey): "1.0.0", string(semconv.ServiceInstanceIDKey): "", }, }, { name: "override service.version", buildInfo: component.BuildInfo{ Command: "mycommand", Version: "1.0.0", }, resourceConfig: map[string]*string{ string(semconv.ServiceVersionKey): ptr("2.0.0"), }, wantFields: map[string]string{ string(semconv.ServiceNameKey): "mycommand", string(semconv.ServiceVersionKey): "2.0.0", string(semconv.ServiceInstanceIDKey): "", }, }, { name: "custom field with auto-populated", buildInfo: component.BuildInfo{ Command: "mycommand", Version: "1.0.0", }, resourceConfig: map[string]*string{ "custom.field": ptr("custom-value"), }, wantFields: map[string]string{ string(semconv.ServiceNameKey): "mycommand", string(semconv.ServiceVersionKey): "1.0.0", string(semconv.ServiceInstanceIDKey): "", // Just check presence "custom.field": "custom-value", }, }, { name: "resource with no attributes", buildInfo: component.BuildInfo{}, resourceConfig: nil, wantFields: map[string]string{ // A random UUID is injected for service.instance.id by default string(semconv.ServiceInstanceIDKey): "", // Just check presence }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { core, observedLogs := observer.New(zapcore.DebugLevel) cfg := &Config{ Logs: LogsConfig{ Level: zapcore.InfoLevel, Encoding: "json", }, Resource: tt.resourceConfig, } resource, err := createResource(t.Context(), telemetry.Settings{BuildInfo: tt.buildInfo}, cfg) require.NoError(t, err) set := telemetry.LoggerSettings{ Settings: telemetry.Settings{BuildInfo: tt.buildInfo, Resource: &resource}, ZapOptions: []zap.Option{ // Redirect logs to the observer core zap.WrapCore(func(zapcore.Core) zapcore.Core { return core }), }, } logger, loggerProvider, err := createLogger(t.Context(), set, cfg) require.NoError(t, err) defer func() { assert.NoError(t, loggerProvider.Shutdown(t.Context())) }() logger.Info("Test log message") require.Len(t, observedLogs.All(), 1) entry := observedLogs.All()[0] if tt.wantFields == nil { assert.Empty(t, entry.Context) return } assert.Equal(t, "resource", entry.Context[0].Key) dict := entry.Context[0].Interface.(zapcore.ObjectMarshaler) enc := zapcore.NewMapObjectEncoder() require.NoError(t, dict.MarshalLogObject(enc)) // Verify all expected fields for k, v := range tt.wantFields { if k == string(semconv.ServiceInstanceIDKey) { // For service.instance.id just verify it exists since it's auto-generated assert.Contains(t, enc.Fields, k) } else { assert.Equal(t, v, enc.Fields[k]) } } }) } } func TestLogger_OTLP(t *testing.T) { // Create a backend to receive the logs and assert the content receivedLogs := 0 logger := newOTLPLogger(t, zapcore.InfoLevel, func(req plogotlp.ExportRequest) { logs := req.Logs() rl := logs.ResourceLogs().At(0) resourceAttrs := rl.Resource().Attributes().AsRaw() assert.Equal(t, service, resourceAttrs[string(semconv.ServiceNameKey)]) assert.Equal(t, version, resourceAttrs[string(semconv.ServiceVersionKey)]) assert.Equal(t, testValue, resourceAttrs[testAttribute]) // Check that the resource attributes are not duplicated in the log records sl := rl.ScopeLogs().At(0) logRecord := sl.LogRecords().At(0) attrs := logRecord.Attributes().AsRaw() assert.NotContains(t, attrs, string(semconv.ServiceNameKey)) assert.NotContains(t, attrs, string(semconv.ServiceVersionKey)) assert.NotContains(t, attrs, testAttribute) receivedLogs++ }) const totalLogs = 10 for range totalLogs { logger.Info("Test log message") } // Ensure the correct number of logs were received require.Equal(t, totalLogs, receivedLogs) } func newOTLPLogger(t *testing.T, level zapcore.Level, handler func(plogotlp.ExportRequest)) *zap.Logger { srv := createLogsBackend(t, "/v1/logs", handler) t.Cleanup(srv.Close) processors := []config.LogRecordProcessor{{ Simple: &config.SimpleLogRecordProcessor{ Exporter: config.LogRecordExporter{ OTLP: &config.OTLP{ Endpoint: ptr(srv.URL), Protocol: ptr("http/protobuf"), Insecure: ptr(true), }, }, }, }} cfg := &Config{ Logs: LogsConfig{ Level: level, Encoding: "json", Processors: processors, // OutputPaths is empty, so logs are only // written to the OTLP processor }, Resource: map[string]*string{ string(semconv.ServiceNameKey): ptr(service), string(semconv.ServiceVersionKey): ptr(version), testAttribute: ptr(testValue), }, } resource, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) logger, shutdown, err := createLogger(t.Context(), telemetry.LoggerSettings{ Settings: telemetry.Settings{Resource: &resource}, }, cfg) require.NoError(t, err) t.Cleanup(func() { assert.NoError(t, shutdown.Shutdown(context.WithoutCancel(t.Context()))) }) return logger } func createLogsBackend(t *testing.T, endpoint string, handler func(plogotlp.ExportRequest)) *httptest.Server { mux := http.NewServeMux() mux.HandleFunc(endpoint, func(_ http.ResponseWriter, request *http.Request) { body, err := io.ReadAll(request.Body) assert.NoError(t, err) defer request.Body.Close() // Unmarshal the protobuf body into logs req := plogotlp.NewExportRequest() err = req.UnmarshalProto(body) assert.NoError(t, err) handler(req) }) return httptest.NewServer(mux) } func TestLogAttributeInjection(t *testing.T) { core, consoleLogs := observer.New(zapcore.DebugLevel) var otlpLogs []plogotlp.ExportRequest srv := createLogsBackend(t, "/v1/logs", func(req plogotlp.ExportRequest) { otlpLogs = append(otlpLogs, req) }) t.Cleanup(srv.Close) cfg := &Config{ Resource: map[string]*string{ "service.instance.id": nil, "service.name": nil, "service.version": nil, }, Logs: LogsConfig{ Encoding: "json", Processors: []config.LogRecordProcessor{{ Simple: &config.SimpleLogRecordProcessor{ Exporter: config.LogRecordExporter{ OTLP: &config.OTLP{ // Send OTLP logs to the mock backend Endpoint: ptr(srv.URL), Protocol: ptr("http/protobuf"), Insecure: ptr(true), }, }, }, }}, }, } resource, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) set := telemetry.LoggerSettings{ Settings: telemetry.Settings{Resource: &resource}, ZapOptions: []zap.Option{ // Redirect console logs to the observer core zap.WrapCore(func(zapcore.Core) zapcore.Core { return core }), }, } sourceLogger, loggerProvider, err := createLogger(t.Context(), set, cfg) require.NoError(t, err) defer func() { assert.NoError(t, loggerProvider.Shutdown(t.Context())) }() ts := componenttest.NewNopTelemetrySettings() ts.Logger = sourceLogger ts = componentattribute.TelemetrySettingsWithAttributes(ts, attribute.NewSet( attribute.String("injected1", "val"), attribute.String("injected2", "val"), )) ts.Logger = ts.Logger.With(zap.String("after", "val")) fields, scope := checkScopes(t, ts.Logger, consoleLogs, &otlpLogs) assert.JSONEq(t, `{"injected1":"val","injected2":"val","after":"val","manual":"val"}`, fields) assert.JSONEq(t, `{"injected1":"val","injected2":"val"}`, scope) ts = internalTelemetry.DropInjectedAttributes(ts, "injected1") fields, scope = checkScopes(t, ts.Logger, consoleLogs, &otlpLogs) assert.JSONEq(t, `{"injected2":"val","after":"val","manual":"val"}`, fields) assert.JSONEq(t, `{"injected2":"val"}`, scope) } func checkScopes(t *testing.T, logger *zap.Logger, consoleLogs *observer.ObservedLogs, otlpLogs *[]plogotlp.ExportRequest) (string, string) { logger.Info("Test log message", zap.String("manual", "val")) require.Len(t, consoleLogs.All(), 1) log := consoleLogs.TakeAll()[0] enc := zapcore.NewJSONEncoder(zapcore.EncoderConfig{}) fieldsBuf, err := enc.EncodeEntry(log.Entry, log.Context) require.NoError(t, err) fieldsStr := strings.TrimSuffix(fieldsBuf.String(), "\n") require.Len(t, *otlpLogs, 1) req := (*otlpLogs)[0] *otlpLogs = nil rls := req.Logs().ResourceLogs() require.Equal(t, 1, rls.Len()) sls := rls.At(0).ScopeLogs() require.Equal(t, 1, sls.Len()) attrs := sls.At(0).Scope().Attributes() scopeBuf, err := json.Marshal(attrs.AsRaw()) require.NoError(t, err) scopeStr := string(scopeBuf) return fieldsStr, scopeStr } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/metrics.go000066400000000000000000000027161511331344600277570ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "context" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" noopmetric "go.opentelemetry.io/otel/metric/noop" sdkresource "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/service/telemetry" ) func createMeterProvider( ctx context.Context, set telemetry.MeterSettings, componentConfig component.Config, ) (telemetry.MeterProvider, error) { cfg := componentConfig.(*Config) if cfg.Metrics.Level == configtelemetry.LevelNone { set.Logger.Info("Internal metrics telemetry disabled") return noopMeterProvider{MeterProvider: noopmetric.NewMeterProvider()}, nil } else if cfg.Metrics.Views == nil && set.DefaultViews != nil { cfg.Metrics.Views = set.DefaultViews(cfg.Metrics.Level) } attrs := pcommonAttrsToOTelAttrs(set.Resource) res := sdkresource.NewWithAttributes("", attrs...) mpConfig := cfg.Metrics.MeterProvider sdk, err := newSDK(ctx, res, config.OpenTelemetryConfiguration{ MeterProvider: &mpConfig, }) if err != nil { return nil, err } return sdk.MeterProvider().(telemetry.MeterProvider), nil } type noopMeterProvider struct { noopmetric.MeterProvider } func (noopMeterProvider) Shutdown(context.Context) error { return nil } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/metrics_test.go000066400000000000000000000313601511331344600310130ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry import ( "context" "fmt" "io" "net/http" "net/http/httptest" "testing" "time" io_prometheus_client "github.com/prometheus/client_model/go" "github.com/prometheus/common/expfmt" "github.com/prometheus/common/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/metric" semconv "go.opentelemetry.io/otel/semconv/v1.37.0" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/pdata/pmetric" "go.opentelemetry.io/collector/pdata/pmetric/pmetricotlp" "go.opentelemetry.io/collector/service/internal/promtest" "go.opentelemetry.io/collector/service/telemetry" ) const ( metricPrefix = "otelcol_" otelPrefix = "otel_sdk_" grpcPrefix = "grpc_" httpPrefix = "http_" counterName = "test_counter" ) var testInstanceID = "test_instance_id" func TestCreateMeterProvider(t *testing.T) { type metricValue struct { value float64 labels map[string]string } for _, tt := range []struct { name string expectedMetrics map[string]metricValue }{ { name: "UseOpenTelemetryForInternalMetrics", expectedMetrics: map[string]metricValue{ metricPrefix + otelPrefix + counterName: { value: 13, labels: map[string]string{ "service_name": "otelcol", "service_version": "latest", "service_instance_id": testInstanceID, }, }, metricPrefix + grpcPrefix + counterName: { value: 11, labels: map[string]string{ "rpc_system": "grpc", "service_name": "otelcol", "service_version": "latest", "service_instance_id": testInstanceID, }, }, metricPrefix + httpPrefix + counterName: { value: 10, labels: map[string]string{ "http_request_method": "GET", "service_name": "otelcol", "service_version": "latest", "service_instance_id": testInstanceID, }, }, "target_info": { value: 0, labels: map[string]string{ "service_name": "otelcol", "service_version": "latest", "service_instance_id": testInstanceID, }, }, "promhttp_metric_handler_errors_total": { value: 0, labels: map[string]string{ "cause": "encoding", }, }, }, }, } { prom := promtest.GetAvailableLocalAddressPrometheus(t) endpoint := fmt.Sprintf("http://%s:%d/metrics", *prom.Host, *prom.Port) cfg := createDefaultConfig().(*Config) cfg.Metrics = MetricsConfig{ Level: configtelemetry.LevelDetailed, MeterProvider: config.MeterProvider{ Readers: []config.MetricReader{{ Pull: &config.PullMetricReader{ Exporter: config.PullMetricExporter{Prometheus: prom}, }, }}, }, } cfg.Resource = map[string]*string{ string(semconv.ServiceNameKey): ptr("otelcol"), string(semconv.ServiceVersionKey): ptr("latest"), string(semconv.ServiceInstanceIDKey): ptr(testInstanceID), } t.Run(tt.name, func(t *testing.T) { resource, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) mp, err := createMeterProvider(t.Context(), telemetry.MeterSettings{ Settings: telemetry.Settings{Resource: &resource}, }, cfg) require.NoError(t, err) defer func() { assert.NoError(t, mp.Shutdown(t.Context())) }() createTestMetrics(t, mp) metrics := getMetricsFromPrometheus(t, endpoint) require.Len(t, metrics, len(tt.expectedMetrics)) for metricName, metricValue := range tt.expectedMetrics { mf, present := metrics[metricName] require.True(t, present, "expected metric %q was not present", metricName) if metricName == "promhttp_metric_handler_errors_total" { continue } require.Len(t, mf.Metric, 1, "only one measure should exist for metric %q", metricName) labels := make(map[string]string) for _, pair := range mf.Metric[0].Label { labels[pair.GetName()] = pair.GetValue() } require.Equal(t, metricValue.labels, labels, "labels for metric %q was different than expected", metricName) require.InDelta(t, metricValue.value, mf.Metric[0].Counter.GetValue(), 0.01, "value for metric %q was different than expected", metricName) } }) } } func createTestMetrics(t *testing.T, mp metric.MeterProvider) { // Creates a OTel Go counter counter, err := mp.Meter("collector_test").Int64Counter(metricPrefix+otelPrefix+counterName, metric.WithUnit("ms")) require.NoError(t, err) counter.Add(context.Background(), 13) grpcExampleCounter, err := mp.Meter("go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc").Int64Counter(metricPrefix + grpcPrefix + counterName) require.NoError(t, err) grpcExampleCounter.Add(context.Background(), 11, metric.WithAttributeSet(attribute.NewSet( attribute.String(string(semconv.RPCSystemKey), "grpc"), ))) httpExampleCounter, err := mp.Meter("go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp").Int64Counter(metricPrefix + httpPrefix + counterName) require.NoError(t, err) httpExampleCounter.Add(context.Background(), 10, metric.WithAttributeSet(attribute.NewSet( attribute.String(string(semconv.HTTPRequestMethodKey), "GET"), ))) } func getMetricsFromPrometheus(t *testing.T, endpoint string) map[string]*io_prometheus_client.MetricFamily { client := &http.Client{ Timeout: 10 * time.Second, } req, err := http.NewRequest(http.MethodGet, endpoint, http.NoBody) require.NoError(t, err) var rr *http.Response maxRetries := 5 for i := range maxRetries { rr, err = client.Do(req) if err == nil && rr.StatusCode == http.StatusOK { break } // skip sleep on last retry if i < maxRetries-1 { time.Sleep(2 * time.Second) // Wait before retrying } } require.NoError(t, err, "failed to get metrics from Prometheus after %d attempts", maxRetries) require.Equal(t, http.StatusOK, rr.StatusCode, "unexpected status code after %d attempts", maxRetries) defer rr.Body.Close() parser := expfmt.NewTextParser(model.UTF8Validation) parsed, err := parser.TextToMetricFamilies(rr.Body) require.NoError(t, err) return parsed } func TestCreateMeterProvider_Invalid(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.Logs.Level = zapcore.FatalLevel cfg.Traces.Level = configtelemetry.LevelNone cfg.Metrics.Readers = []config.MetricReader{{ // Invalid -- no OTLP protocol defined Periodic: &config.PeriodicMetricReader{Exporter: config.PushMetricExporter{OTLP: &config.OTLPMetric{}}}, }} resource, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) _, err = createMeterProvider(t.Context(), telemetry.MeterSettings{ Settings: telemetry.Settings{Resource: &resource}, }, cfg) require.EqualError(t, err, "no valid metric exporter") } func TestCreateMeterProvider_Disabled(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.Metrics.Readers = []config.MetricReader{{ // Invalid -- no OTLP protocol defined Periodic: &config.PeriodicMetricReader{Exporter: config.PushMetricExporter{OTLP: &config.OTLPMetric{}}}, }} core, observedLogs := observer.New(zapcore.DebugLevel) factory := NewFactory() resource, err := factory.CreateResource(context.Background(), telemetry.Settings{}, cfg) require.NoError(t, err) settings := telemetry.MeterSettings{ Settings: telemetry.Settings{Resource: &resource}, } settings.Logger = zap.New(core) _, err = factory.CreateMeterProvider(context.Background(), settings, cfg) require.EqualError(t, err, "no valid metric exporter") assert.Zero(t, observedLogs.Len()) // Setting Metrics.Level to LevelNone disables metrics, // so the invalid configuration should not cause an error. cfg.Metrics.Level = configtelemetry.LevelNone resource2, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) settings.Resource = &resource2 mp, err := createMeterProvider(t.Context(), settings, cfg) require.NoError(t, err) assert.NoError(t, mp.Shutdown(t.Context())) require.Equal(t, 1, observedLogs.Len()) assert.Equal(t, "Internal metrics telemetry disabled", observedLogs.All()[0].Message) } // Test that the MeterProvider implements the 'Enabled' functionality. // See https://pkg.go.dev/go.opentelemetry.io/otel/sdk/metric/internal/x#readme-instrument-enabled. func TestInstrumentEnabled(t *testing.T) { prom := promtest.GetAvailableLocalAddressPrometheus(t) cfg := createDefaultConfig().(*Config) cfg.Metrics.Readers = []config.MetricReader{{ Pull: &config.PullMetricReader{Exporter: config.PullMetricExporter{Prometheus: prom}}, }} resource, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) meterProvider, err := createMeterProvider(t.Context(), telemetry.MeterSettings{ Settings: telemetry.Settings{Resource: &resource}, }, cfg) require.NoError(t, err) defer func() { assert.NoError(t, meterProvider.Shutdown(t.Context())) }() meter := meterProvider.Meter("go.opentelemetry.io/collector/service/telemetry") type enabledInstrument interface{ Enabled(context.Context) bool } intCnt, err := meter.Int64Counter("int64.counter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), intCnt) intUpDownCnt, err := meter.Int64UpDownCounter("int64.updowncounter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), intUpDownCnt) intHist, err := meter.Int64Histogram("int64.updowncounter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), intHist) intGauge, err := meter.Int64Gauge("int64.updowncounter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), intGauge) floatCnt, err := meter.Float64Counter("int64.updowncounter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), floatCnt) floatUpDownCnt, err := meter.Float64UpDownCounter("int64.updowncounter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), floatUpDownCnt) floatHist, err := meter.Float64Histogram("int64.updowncounter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), floatHist) floatGauge, err := meter.Float64Gauge("int64.updowncounter") require.NoError(t, err) assert.Implements(t, new(enabledInstrument), floatGauge) } func TestTelemetryMetrics_DefaultViews(t *testing.T) { type testcase struct { configuredViews []config.View expectedMeterNames []string } defaultViews := func(level configtelemetry.Level) []config.View { assert.Equal(t, configtelemetry.LevelDetailed, level) return []config.View{{ Selector: &config.ViewSelector{ MeterName: ptr("a"), }, Stream: &config.ViewStream{ Aggregation: &config.ViewStreamAggregation{ Drop: config.ViewStreamAggregationDrop{}, }, }, }} } for name, tc := range map[string]testcase{ "no_configured_views": { expectedMeterNames: []string{"b", "c"}, }, "configured_views": { configuredViews: []config.View{{ Selector: &config.ViewSelector{ MeterName: ptr("b"), }, Stream: &config.ViewStream{ Aggregation: &config.ViewStreamAggregation{ Drop: config.ViewStreamAggregationDrop{}, }, }, }}, expectedMeterNames: []string{"a", "c"}, }, } { t.Run(name, func(t *testing.T) { var metrics pmetric.Metrics srv := httptest.NewServer(http.HandlerFunc(func(_ http.ResponseWriter, req *http.Request) { body, err := io.ReadAll(req.Body) assert.NoError(t, err) exportRequest := pmetricotlp.NewExportRequest() assert.NoError(t, exportRequest.UnmarshalProto(body)) metrics = exportRequest.Metrics() })) defer srv.Close() cfg := createDefaultConfig().(*Config) cfg.Metrics.Level = configtelemetry.LevelDetailed cfg.Metrics.Views = tc.configuredViews cfg.Metrics.Readers = []config.MetricReader{{ Periodic: &config.PeriodicMetricReader{ Exporter: config.PushMetricExporter{ OTLP: &config.OTLPMetric{ Endpoint: ptr(srv.URL), Protocol: ptr("http/protobuf"), Insecure: ptr(true), }, }, }, }} factory := NewFactory() settings := telemetry.MeterSettings{DefaultViews: defaultViews} provider, err := factory.CreateMeterProvider(t.Context(), settings, cfg) require.NoError(t, err) for _, meterName := range []string{"a", "b", "c"} { counter, _ := provider.Meter(meterName).Int64Counter(meterName + ".counter") counter.Add(t.Context(), 1) } require.NoError(t, provider.Shutdown(t.Context())) // should flush metrics var scopes []string for _, rm := range metrics.ResourceMetrics().All() { for _, sm := range rm.ScopeMetrics().All() { scopes = append(scopes, sm.Scope().Name()) } } assert.ElementsMatch(t, tc.expectedMeterNames, scopes) }) } } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/package_test.go000066400000000000000000000003221511331344600307320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry import ( "testing" "go.uber.org/goleak" ) func TestMain(m *testing.M) { goleak.VerifyTestMain(m) } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/resource.go000066400000000000000000000033251511331344600301350ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "context" "fmt" "go.opentelemetry.io/otel/attribute" sdkresource "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/service/internal/resource" "go.opentelemetry.io/collector/service/telemetry" ) func createResource( _ context.Context, set telemetry.Settings, componentConfig component.Config, ) (pcommon.Resource, error) { res := newResource(set, componentConfig.(*Config)) pcommonRes := pcommon.NewResource() for _, keyValue := range res.Attributes() { key := string(keyValue.Key) pcommonRes.Attributes().PutStr(key, mustAttributeValueString(key, keyValue.Value)) } return pcommonRes, nil } func newResource(set telemetry.Settings, cfg *Config) *sdkresource.Resource { return resource.New(set.BuildInfo, cfg.Resource) } func mustAttributeValueString(k string, v attribute.Value) string { if v.Type() != attribute.STRING { // We only support string-type resource attributes in the configuration. panic(fmt.Errorf("attribute %q: expected string, got %s", k, v.Type())) } return v.AsString() } // pcommonAttrsToOTelAttrs gets the Resource attributes to OpenTelemetry attribute.KeyValue slice. func pcommonAttrsToOTelAttrs(resource *pcommon.Resource) []attribute.KeyValue { var result []attribute.KeyValue if resource != nil { attrs := resource.Attributes() attrs.Range(func(k string, v pcommon.Value) bool { result = append(result, attribute.String(k, v.AsString())) return true }) } return result } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/resource_test.go000066400000000000000000000031101511331344600311640ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry" import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/service/telemetry" ) func TestCreateResource(t *testing.T) { t.Run("default", func(t *testing.T) { cfg := createDefaultConfig().(*Config) set := telemetry.Settings{BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}} res, err := createResource(t.Context(), set, cfg) require.NoError(t, err) raw := res.Attributes().AsRaw() assert.Contains(t, raw, "service.instance.id") delete(raw, "service.instance.id") // remove since it's random assert.Equal(t, map[string]any{ "service.name": "otelcol", "service.version": "latest", }, raw) }) t.Run("with resource attributes", func(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.Resource = map[string]*string{ "extra.attr": ptr("value"), "service.name": ptr("custom-service"), "service.version": ptr("0.1.0"), "service.instance.id": nil, // removes the attribute } set := telemetry.Settings{BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}} res, err := createResource(t.Context(), set, cfg) require.NoError(t, err) raw := res.Attributes().AsRaw() assert.Equal(t, map[string]any{ "extra.attr": "value", "service.name": "custom-service", "service.version": "0.1.0", }, raw) }) } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/sdk.go000066400000000000000000000016731511331344600270730ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "context" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" sdkresource "go.opentelemetry.io/otel/sdk/resource" semconv "go.opentelemetry.io/otel/semconv/v1.37.0" ) func newSDK(ctx context.Context, res *sdkresource.Resource, conf config.OpenTelemetryConfiguration) (config.SDK, error) { resourceAttrs := make([]config.AttributeNameValue, 0, res.Len()) for _, r := range res.Attributes() { key := string(r.Key) resourceAttrs = append(resourceAttrs, config.AttributeNameValue{ Name: key, Value: mustAttributeValueString(key, r.Value), }) } conf.Resource = &config.Resource{ SchemaUrl: ptr(semconv.SchemaURL), Attributes: resourceAttrs, } return config.NewSDK(config.WithContext(ctx), config.WithOpenTelemetryConfiguration(conf)) } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdata/000077500000000000000000000000001511331344600275655ustar00rootroot00000000000000config_deprecated_address.yaml000066400000000000000000000001141511331344600355200ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatalogs: level: "info" metrics: level: "basic" address: "localhost:6666" config_deprecated_address_and_readers.yaml000066400000000000000000000003021511331344600400460ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatalogs: level: "info" metrics: level: "basic" address: "192.168.0.1:6666" readers: - pull: exporter: prometheus: host: "localhost" port: 9999 opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdata/config_empty.yaml000066400000000000000000000000001511331344600331220ustar00rootroot00000000000000config_empty_readers.yaml000066400000000000000000000000501511331344600345550ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatametrics: level: "basic" readers: [] config_invalid_deprecated_address.yaml000066400000000000000000000001161511331344600372300ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatalogs: level: "info" metrics: level: "basic" address: "1212:212121:2121" config_invalid_metrics_empty_readers.yaml000066400000000000000000000000501511331344600400110ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatametrics: level: "basic" readers: [] config_invalid_metrics_views_feature_gate.yaml000066400000000000000000000001101511331344600410130ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatametrics: level: detailed views: - selector: {} stream: {} config_invalid_metrics_views_level.yaml000066400000000000000000000001051511331344600374730ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatametrics: level: basic views: - selector: {} stream: {} config_invalid_unknown_field.yaml000066400000000000000000000001071511331344600362650ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatametrics: unknown: basic views: - selector: {} stream: {} opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdata/config_logs.yaml000066400000000000000000000005451511331344600327460ustar00rootroot00000000000000logs: level: info development: true disable_caller: true disable_stacktrace: true encoding: console output_paths: [stderr] error_output_paths: [stderr] initial_fields: fieldKey: fieldValue sampling: enabled: false tick: 1s initial: 234 thereafter: 567 processors: - batch: exporter: console: {} config_metrics_empty_readers.yaml000066400000000000000000000000471511331344600363110ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/testdatametrics: level: "none" readers: [] opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/tracer.go000066400000000000000000000062341511331344600275700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry/otelconftelemetry" import ( "context" "errors" "fmt" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/contrib/propagators/b3" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" sdkresource "go.opentelemetry.io/otel/sdk/resource" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace/embedded" "go.opentelemetry.io/otel/trace/noop" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/featuregate" "go.opentelemetry.io/collector/service/telemetry" ) var _ = featuregate.GlobalRegistry().MustRegister("service.noopTracerProvider", featuregate.StageDeprecated, featuregate.WithRegisterFromVersion("v0.107.0"), featuregate.WithRegisterToVersion("v0.109.0"), featuregate.WithRegisterDescription("Sets a Noop OpenTelemetry TracerProvider to reduce memory allocations. This featuregate is incompatible with the zPages extension.")) const ( // supported trace propagators traceContextPropagator = "tracecontext" b3Propagator = "b3" ) func createTracerProvider( ctx context.Context, set telemetry.TracerSettings, componentConfig component.Config, ) (telemetry.TracerProvider, error) { cfg := componentConfig.(*Config) if cfg.Traces.Level == configtelemetry.LevelNone { set.Logger.Info("Internal trace telemetry disabled") return &noopNoContextTracerProvider{}, nil } propagator, err := textMapPropagatorFromConfig(cfg.Traces.Propagators) if err != nil { return nil, fmt.Errorf("error creating propagator: %w", err) } otel.SetTextMapPropagator(propagator) attrs := pcommonAttrsToOTelAttrs(set.Resource) res := sdkresource.NewWithAttributes("", attrs...) sdk, err := newSDK(ctx, res, config.OpenTelemetryConfiguration{ TracerProvider: &cfg.Traces.TracerProvider, }) if err != nil { return nil, err } return sdk.TracerProvider().(telemetry.TracerProvider), nil } var errUnsupportedPropagator = errors.New("unsupported trace propagator") type noopNoContextTracer struct { embedded.Tracer } var noopSpan = noop.Span{} func (n *noopNoContextTracer) Start(ctx context.Context, _ string, _ ...trace.SpanStartOption) (context.Context, trace.Span) { return ctx, noopSpan } type noopNoContextTracerProvider struct { embedded.TracerProvider } func (n *noopNoContextTracerProvider) Shutdown(_ context.Context) error { return nil } func (n *noopNoContextTracerProvider) Tracer(_ string, _ ...trace.TracerOption) trace.Tracer { return &noopNoContextTracer{} } func textMapPropagatorFromConfig(props []string) (propagation.TextMapPropagator, error) { var textMapPropagators []propagation.TextMapPropagator for _, prop := range props { switch prop { case traceContextPropagator: textMapPropagators = append(textMapPropagators, propagation.TraceContext{}) case b3Propagator: textMapPropagators = append(textMapPropagators, b3.New()) default: return nil, errUnsupportedPropagator } } return propagation.NewCompositeTextMapPropagator(textMapPropagators...), nil } opentelemetry-collector-0.141.0/service/telemetry/otelconftelemetry/tracer_test.go000066400000000000000000000140721511331344600306260ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package otelconftelemetry // import "go.opentelemetry.io/collector/service/telemetry" import ( "context" "io" "net/http" "net/http/httptest" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" config "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "go.uber.org/zap" "go.uber.org/zap/zapcore" "go.uber.org/zap/zaptest/observer" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/pdata/ptrace" "go.opentelemetry.io/collector/pdata/ptrace/ptraceotlp" "go.opentelemetry.io/collector/service/telemetry" ) func TestCreateTracerProvider(t *testing.T) { var received []ptrace.Traces mux := http.NewServeMux() mux.HandleFunc("/v1/traces", func(_ http.ResponseWriter, req *http.Request) { body, err := io.ReadAll(req.Body) assert.NoError(t, err) exportRequest := ptraceotlp.NewExportRequest() assert.NoError(t, exportRequest.UnmarshalProto(body)) received = append(received, exportRequest.Traces()) }) srv := httptest.NewServer(mux) defer srv.Close() cfg := createDefaultConfig().(*Config) cfg.Traces.Propagators = []string{"b3", "tracecontext"} cfg.Traces.Processors = []config.SpanProcessor{newOTLPSimpleSpanProcessor(srv)} resource, err := createResource(t.Context(), telemetry.Settings{ BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}, }, cfg) require.NoError(t, err) provider, err := createTracerProvider(t.Context(), telemetry.TracerSettings{ Settings: telemetry.Settings{ BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}, Resource: &resource, }, }, cfg) require.NoError(t, err) defer func() { assert.NoError(t, provider.Shutdown(t.Context())) }() tracer := provider.Tracer("test_tracer") _, span := tracer.Start(context.Background(), "test_span") span.End() require.Len(t, received, 1) traces := received[0] require.Equal(t, 1, traces.SpanCount()) assert.Equal(t, "test_span", traces.ResourceSpans().At(0).ScopeSpans().At(0).Spans().At(0).Name()) } func TestCreateTracerProvider_Invalid(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.Logs.Level = zapcore.FatalLevel cfg.Metrics.Level = configtelemetry.LevelNone cfg.Traces.Processors = []config.SpanProcessor{{ Simple: &config.SimpleSpanProcessor{ Exporter: config.SpanExporter{ OTLP: &config.OTLP{ /* missing endpoint, etc. */ }, }, }, }} resource, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) _, err = createTracerProvider(t.Context(), telemetry.TracerSettings{ Settings: telemetry.Settings{Resource: &resource}, }, cfg) require.EqualError(t, err, "no valid span exporter") } func TestCreateTracerProvider_Propagators(t *testing.T) { mux := http.NewServeMux() mux.HandleFunc("/v1/traces", func(http.ResponseWriter, *http.Request) {}) srv := httptest.NewServer(mux) defer srv.Close() cfg := createDefaultConfig().(*Config) cfg.Traces.Propagators = []string{"b3", "tracecontext"} cfg.Traces.Processors = []config.SpanProcessor{newOTLPSimpleSpanProcessor(srv)} resource, err := createResource(t.Context(), telemetry.Settings{ BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}, }, cfg) require.NoError(t, err) provider, err := createTracerProvider(t.Context(), telemetry.TracerSettings{ Settings: telemetry.Settings{ BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}, Resource: &resource, }, }, cfg) require.NoError(t, err) defer func() { assert.NoError(t, provider.Shutdown(t.Context())) }() propagator := otel.GetTextMapPropagator() require.NotNil(t, propagator) tracer := provider.Tracer("test_tracer") ctx, span := tracer.Start(context.Background(), "test_span") mapCarrier := make(propagation.MapCarrier) propagator.Inject(ctx, mapCarrier) span.End() assert.Contains(t, mapCarrier, "b3") assert.Contains(t, mapCarrier, "traceparent") } func TestCreateTracerProvider_InvalidPropagator(t *testing.T) { cfg := createDefaultConfig().(*Config) cfg.Traces.Propagators = []string{"invalid"} resource, err := createResource(t.Context(), telemetry.Settings{}, cfg) require.NoError(t, err) _, err = createTracerProvider(t.Context(), telemetry.TracerSettings{ Settings: telemetry.Settings{Resource: &resource}, }, cfg) assert.EqualError(t, err, "error creating propagator: unsupported trace propagator") } func TestCreateTracerProvider_Disabled(t *testing.T) { var received int mux := http.NewServeMux() mux.HandleFunc("/v1/traces", func(http.ResponseWriter, *http.Request) { received++ }) srv := httptest.NewServer(mux) defer srv.Close() cfg := createDefaultConfig().(*Config) cfg.Traces.Level = configtelemetry.LevelNone cfg.Traces.Processors = []config.SpanProcessor{newOTLPSimpleSpanProcessor(srv)} core, observedLogs := observer.New(zapcore.DebugLevel) resource, err := createResource(t.Context(), telemetry.Settings{ BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}, }, cfg) require.NoError(t, err) settings := telemetry.TracerSettings{ Settings: telemetry.Settings{ BuildInfo: component.BuildInfo{Command: "otelcol", Version: "latest"}, Resource: &resource, }, Logger: zap.New(core), } provider, err := createTracerProvider(t.Context(), settings, cfg) require.NoError(t, err) defer func() { assert.NoError(t, provider.Shutdown(t.Context())) }() require.Equal(t, 1, observedLogs.Len()) assert.Equal(t, "Internal trace telemetry disabled", observedLogs.All()[0].Message) tracer := provider.Tracer("test_tracer") _, span := tracer.Start(context.Background(), "test_span") span.End() assert.Equal(t, 0, received) } func newOTLPSimpleSpanProcessor(srv *httptest.Server) config.SpanProcessor { return config.SpanProcessor{ Simple: &config.SimpleSpanProcessor{ Exporter: config.SpanExporter{ OTLP: &config.OTLP{ Endpoint: ptr(srv.URL), Protocol: ptr("http/protobuf"), Insecure: ptr(true), }, }, }, } } opentelemetry-collector-0.141.0/service/telemetry/telemetry.go000066400000000000000000000177271511331344600245670ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetry // import "go.opentelemetry.io/collector/service/telemetry" import ( "context" otelconf "go.opentelemetry.io/contrib/otelconf/v0.3.0" "go.opentelemetry.io/otel/metric" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/config/configtelemetry" "go.opentelemetry.io/collector/pdata/pcommon" ) // LoggerSettings holds settings for building logger providers. type LoggerSettings struct { Settings // ZapOptions contains options for creating the zap logger. ZapOptions []zap.Option } // MeterSettings holds settings for building meter providers. type MeterSettings struct { Settings // Logger is a zap.Logger that may be used for logging details // of the MeterProvider's construction, and by the MeterProvider // for logging its internal operations. Logger *zap.Logger // DefaultViews holds a function that returns default metric // views for the given internal telemetry metrics level. // // The meter provider is expected to use this if no user-provided // view configuration is supplied. // // TODO we should not use otelconf.View directly here, change // to something independent of otelconf. DefaultViews func(configtelemetry.Level) []otelconf.View } // TracerSettings holds settings for building tracer providers. type TracerSettings struct { Settings // Logger is a zap.Logger that may be used for logging details // of the TracerProvider's construction, and by the TracerProvider // for logging its internal operations. Logger *zap.Logger } // Settings holds common settings for building telemetry providers. type Settings struct { // BuildInfo contains build information about the collector. BuildInfo component.BuildInfo // Resource is the telemetry resource that should be used by all telemetry providers. Resource *pcommon.Resource } // Factory is a factory interface for internal telemetry. // // This interface cannot be directly implemented. Implementations must // use the NewFactory to implement it. // // NOTE This API is experimental and will change soon - use at your own risk. // See https://github.com/open-telemetry/opentelemetry-collector/issues/4970 type Factory interface { // CreateDefaultConfig creates the default configuration for the telemetry. CreateDefaultConfig() component.Config // CreateResource creates a pcommon.Resource representing the collector. // This may be used by components in their internal telemetry. CreateResource(context.Context, Settings, component.Config) (pcommon.Resource, error) // CreateLogger creates a zap.Logger that may be used by components to // log their internal operations, along with a function that must be called // when the service is shutting down. CreateLogger(context.Context, LoggerSettings, component.Config) (*zap.Logger, component.ShutdownFunc, error) // CreateMeterProvider creates a metric.MeterProvider that may be used // by components to record metrics relating to their internal operations. CreateMeterProvider(context.Context, MeterSettings, component.Config) (MeterProvider, error) // CreateTracerProvider creates a trace.TracerProvider that may be used // by components to trace their internal operations. // // If the returned provider is a wrapper, consider implementing // the `Unwrap() trace.TracerProvider` method to grant components access to the underlying SDK. CreateTracerProvider(context.Context, TracerSettings, component.Config) (TracerProvider, error) // unexportedFactoryFunc is used to prevent external implementations of Factory. unexportedFactoryFunc() } // MeterProvider is a metric.MeterProvider that can be shutdown. type MeterProvider interface { metric.MeterProvider Shutdown(context.Context) error } // TracerProvider is a trace.TracerProvider that can be shutdown. type TracerProvider interface { trace.TracerProvider Shutdown(context.Context) error } type FactoryOption interface { applyOption(*factory) } // factoryOptionFunc is an FactoryOption created through a function. type factoryOptionFunc func(*factory) func (f factoryOptionFunc) applyOption(o *factory) { f(o) } type factory struct { component.CreateDefaultConfigFunc createResourceFunc CreateResourceFunc createLoggerFunc CreateLoggerFunc createMeterProviderFunc CreateMeterProviderFunc createTracerProviderFunc CreateTracerProviderFunc } // NewFactory returns a Factory. func NewFactory(createDefaultConfig component.CreateDefaultConfigFunc, opts ...FactoryOption) Factory { f := &factory{ CreateDefaultConfigFunc: createDefaultConfig, } for _, opt := range opts { opt.applyOption(f) } return f } // WithCreateResource overrides the default CreateResource implementation, // which creates an empty resource. func WithCreateResource(createResource CreateResourceFunc) FactoryOption { return factoryOptionFunc(func(f *factory) { f.createResourceFunc = createResource }) } // CreateResourceFunc is the equivalent of Factory.CreateResource. type CreateResourceFunc func(context.Context, Settings, component.Config) (pcommon.Resource, error) // WithCreateLogger overrides the default CreateLogger implementation, // which creates a noop logger and noop logger provider. func WithCreateLogger(createLogger CreateLoggerFunc) FactoryOption { return factoryOptionFunc(func(f *factory) { f.createLoggerFunc = createLogger }) } // WithCreateLogger is the equivalent of Factory.CreateLogger. type CreateLoggerFunc func(context.Context, LoggerSettings, component.Config) (*zap.Logger, component.ShutdownFunc, error) // WithCreateMeterProvider overrides the default CreateMeterProvider func WithCreateMeterProvider(createMeterProvider CreateMeterProviderFunc) FactoryOption { return factoryOptionFunc(func(f *factory) { f.createMeterProviderFunc = createMeterProvider }) } // CreateMeterProviderFunc is the equivalent of Factory.CreateMeterProvider. type CreateMeterProviderFunc func(context.Context, MeterSettings, component.Config) (MeterProvider, error) // WithCreateTracerProvider overrides the default CreateTracerProvider // implementation, which creates a noop tracer provider. func WithCreateTracerProvider(createTracerProvider CreateTracerProviderFunc) FactoryOption { return factoryOptionFunc(func(f *factory) { f.createTracerProviderFunc = createTracerProvider }) } // CreateTracerProviderFunc is the equivalent of Factory.CreateTracerProvider. type CreateTracerProviderFunc func(context.Context, TracerSettings, component.Config) (TracerProvider, error) func (*factory) unexportedFactoryFunc() {} func (f *factory) CreateResource(ctx context.Context, settings Settings, cfg component.Config) (pcommon.Resource, error) { if f.createResourceFunc == nil { return pcommon.NewResource(), nil } return f.createResourceFunc(ctx, settings, cfg) } func (f *factory) CreateLogger(ctx context.Context, settings LoggerSettings, cfg component.Config) (*zap.Logger, component.ShutdownFunc, error) { if f.createLoggerFunc == nil { logger := zap.NewNop() nopShutdown := component.ShutdownFunc(nil) return logger, nopShutdown, nil } return f.createLoggerFunc(ctx, settings, cfg) } func (f *factory) CreateMeterProvider(ctx context.Context, settings MeterSettings, cfg component.Config) (MeterProvider, error) { if f.createMeterProviderFunc == nil { return noopMeterProvider{MeterProvider: noopmetric.NewMeterProvider()}, nil } return f.createMeterProviderFunc(ctx, settings, cfg) } func (f *factory) CreateTracerProvider(ctx context.Context, settings TracerSettings, cfg component.Config) (TracerProvider, error) { if f.createTracerProviderFunc == nil { return noopTracerProvider{TracerProvider: nooptrace.NewTracerProvider()}, nil } return f.createTracerProviderFunc(ctx, settings, cfg) } type noopMeterProvider struct { noopmetric.MeterProvider component.ShutdownFunc } type noopTracerProvider struct { nooptrace.TracerProvider component.ShutdownFunc } opentelemetry-collector-0.141.0/service/telemetry/telemetry_test.go000066400000000000000000000130441511331344600256120ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetry // import "go.opentelemetry.io/collector/service/telemetry" import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" noopmetric "go.opentelemetry.io/otel/metric/noop" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" ) func TestNewFactory_CreateDefaultConfig(t *testing.T) { var config component.Config = new(struct{}) factory := NewFactory(func() component.Config { return config }) require.NotNil(t, factory) assert.Equal(t, config, factory.CreateDefaultConfig()) } func TestNewFactory_Defaults(t *testing.T) { factory := NewFactory(nil) require.NotNil(t, factory) res, err := factory.CreateResource(context.Background(), Settings{}, nil) require.NoError(t, err) assert.Equal(t, pcommon.NewResource(), res) logger, loggerShutdownFunc, err := factory.CreateLogger(context.Background(), LoggerSettings{}, nil) require.NoError(t, err) assert.Equal(t, zap.NewNop(), logger) assert.Nil(t, loggerShutdownFunc) meterProvider, err := factory.CreateMeterProvider(context.Background(), MeterSettings{}, nil) require.NoError(t, err) assert.Equal(t, noopMeterProvider{MeterProvider: noopmetric.NewMeterProvider()}, meterProvider) tracerProvider, err := factory.CreateTracerProvider(context.Background(), TracerSettings{}, nil) require.NoError(t, err) assert.Equal(t, noopTracerProvider{TracerProvider: nooptrace.NewTracerProvider()}, tracerProvider) } func TestNewFactory_Options(t *testing.T) { var called []string factory := NewFactory(nil, factoryOptionFunc(func(*factory) { called = append(called, "option1") }), factoryOptionFunc(func(*factory) { called = append(called, "option2") })) require.NotNil(t, factory) assert.Equal(t, []string{"option1", "option2"}, called) } func TestNewFactory_CreateResource(t *testing.T) { type contextKey struct{} var config component.Config = new(struct{}) settings := Settings{ BuildInfo: component.NewDefaultBuildInfo(), } ctx := context.WithValue(context.Background(), contextKey{}, 123) dummyResource := pcommon.NewResource() dummyResource.Attributes().PutStr("what", "ever") factory := NewFactory(nil, WithCreateResource( func(ctx context.Context, set Settings, cfg component.Config) (pcommon.Resource, error) { assert.Equal(t, 123, ctx.Value(contextKey{})) assert.Equal(t, settings, set) assert.Equal(t, config, cfg) return dummyResource, errors.New("not implemented") }, )) require.NotNil(t, factory) resource, err := factory.CreateResource(ctx, settings, config) require.EqualError(t, err, "not implemented") assert.Equal(t, dummyResource, resource) } func TestNewFactory_CreateLogger(t *testing.T) { type contextKey struct{} var config component.Config = new(struct{}) settings := LoggerSettings{ Settings: Settings{BuildInfo: component.NewDefaultBuildInfo()}, } ctx := context.WithValue(context.Background(), contextKey{}, 123) shutdownCalled := false dummyLogger := new(zap.Logger) factory := NewFactory(nil, WithCreateLogger( func(ctx context.Context, set LoggerSettings, cfg component.Config) (*zap.Logger, component.ShutdownFunc, error) { assert.Equal(t, 123, ctx.Value(contextKey{})) assert.Equal(t, settings, set) assert.Equal(t, config, cfg) shutdownFunc := func(context.Context) error { shutdownCalled = true return nil } return dummyLogger, shutdownFunc, errors.New("not implemented") }, )) require.NotNil(t, factory) logger, shutdownFunc, err := factory.CreateLogger(ctx, settings, config) require.EqualError(t, err, "not implemented") assert.Equal(t, dummyLogger, logger) require.NoError(t, shutdownFunc(context.Background())) assert.True(t, shutdownCalled) } func TestNewFactory_CreateMeterProvider(t *testing.T) { type contextKey struct{} var config component.Config = new(struct{}) settings := MeterSettings{ Settings: Settings{BuildInfo: component.NewDefaultBuildInfo()}, } ctx := context.WithValue(context.Background(), contextKey{}, 123) var dummyMeterProvider struct{ MeterProvider } factory := NewFactory(nil, WithCreateMeterProvider( func(ctx context.Context, set MeterSettings, cfg component.Config) (MeterProvider, error) { assert.Equal(t, 123, ctx.Value(contextKey{})) assert.Equal(t, settings, set) assert.Equal(t, config, cfg) return &dummyMeterProvider, errors.New("not implemented") }, )) require.NotNil(t, factory) meterProvider, err := factory.CreateMeterProvider(ctx, settings, config) require.EqualError(t, err, "not implemented") assert.Equal(t, &dummyMeterProvider, meterProvider) } func TestNewFactory_CreateTracerProvider(t *testing.T) { type contextKey struct{} var config component.Config = new(struct{}) settings := TracerSettings{ Settings: Settings{BuildInfo: component.NewDefaultBuildInfo()}, } ctx := context.WithValue(context.Background(), contextKey{}, 123) var dummyTracerProvider struct{ TracerProvider } factory := NewFactory(nil, WithCreateTracerProvider( func(ctx context.Context, set TracerSettings, cfg component.Config) (TracerProvider, error) { assert.Equal(t, 123, ctx.Value(contextKey{})) assert.Equal(t, settings, set) assert.Equal(t, config, cfg) return &dummyTracerProvider, errors.New("not implemented") }, )) require.NotNil(t, factory) tracerProvider, err := factory.CreateTracerProvider(ctx, settings, config) require.EqualError(t, err, "not implemented") assert.Equal(t, &dummyTracerProvider, tracerProvider) } opentelemetry-collector-0.141.0/service/telemetry/telemetrytest/000077500000000000000000000000001511331344600251225ustar00rootroot00000000000000opentelemetry-collector-0.141.0/service/telemetry/telemetrytest/Makefile000066400000000000000000000000411511331344600265550ustar00rootroot00000000000000include ../../../Makefile.Common opentelemetry-collector-0.141.0/service/telemetry/telemetrytest/go.mod000066400000000000000000000203141511331344600262300ustar00rootroot00000000000000module go.opentelemetry.io/collector/service/telemetry/telemetrytest go 1.24.0 require ( github.com/stretchr/testify v1.11.1 go.opentelemetry.io/collector/component v1.47.0 go.opentelemetry.io/collector/pdata v1.47.0 go.opentelemetry.io/collector/service v0.141.0 go.opentelemetry.io/otel/metric v1.38.0 go.opentelemetry.io/otel/trace v1.38.0 go.uber.org/zap v1.27.1 ) require ( github.com/beorn7/perks v1.0.1 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 // indirect github.com/hashicorp/go-version v1.7.0 // indirect github.com/json-iterator/go v1.1.12 // 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/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/client_golang v1.23.2 // indirect github.com/prometheus/client_model v0.6.2 // indirect github.com/prometheus/common v0.67.1 // indirect github.com/prometheus/otlptranslator v0.0.2 // indirect github.com/prometheus/procfs v0.17.0 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/collector/config/configtelemetry v0.141.0 // indirect go.opentelemetry.io/collector/featuregate v1.47.0 // indirect go.opentelemetry.io/contrib/otelconf v0.18.0 // indirect go.opentelemetry.io/otel v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 // indirect go.opentelemetry.io/otel/exporters/prometheus v0.60.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 // indirect go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 // indirect go.opentelemetry.io/otel/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk v1.38.0 // indirect go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/multierr v1.11.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/net v0.47.0 // indirect golang.org/x/sys v0.38.0 // indirect golang.org/x/text v0.31.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect google.golang.org/grpc v1.77.0 // indirect google.golang.org/protobuf v1.36.10 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) replace go.opentelemetry.io/collector/component => ../../../component replace go.opentelemetry.io/collector/internal/telemetry => ../../../internal/telemetry/ replace go.opentelemetry.io/collector/pdata => ../../../pdata replace go.opentelemetry.io/collector/confmap => ../../../confmap replace go.opentelemetry.io/collector/config/configtelemetry => ../../../config/configtelemetry replace go.opentelemetry.io/collector/featuregate => ../../../featuregate replace go.opentelemetry.io/collector/service => ../../ replace go.opentelemetry.io/collector/extension/extensionmiddleware => ../../../extension/extensionmiddleware replace go.opentelemetry.io/collector/config/configmiddleware => ../../../config/configmiddleware replace go.opentelemetry.io/collector/receiver => ../../../receiver replace go.opentelemetry.io/collector/processor/processortest => ../../../processor/processortest replace go.opentelemetry.io/collector/processor/xprocessor => ../../../processor/xprocessor replace go.opentelemetry.io/collector/processor => ../../../processor replace go.opentelemetry.io/collector/pdata/xpdata => ../../../pdata/xpdata replace go.opentelemetry.io/collector/pdata/pprofile => ../../../pdata/pprofile replace go.opentelemetry.io/collector/extension/extensiontest => ../../../extension/extensiontest replace go.opentelemetry.io/collector/exporter/xexporter => ../../../exporter/xexporter replace go.opentelemetry.io/collector/consumer/consumertest => ../../../consumer/consumertest replace go.opentelemetry.io/collector/pipeline => ../../../pipeline replace go.opentelemetry.io/collector/receiver/xreceiver => ../../../receiver/xreceiver replace go.opentelemetry.io/collector/pipeline/xpipeline => ../../../pipeline/xpipeline replace go.opentelemetry.io/collector/pdata/testdata => ../../../pdata/testdata replace go.opentelemetry.io/collector/otelcol => ../../../otelcol replace go.opentelemetry.io/collector/extension/extensioncapabilities => ../../../extension/extensioncapabilities replace go.opentelemetry.io/collector/extension/xextension => ../../../extension/xextension replace go.opentelemetry.io/collector/exporter => ../../../exporter replace go.opentelemetry.io/collector/config/configoptional => ../../../config/configoptional replace go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest => ../../../extension/extensionmiddleware/extensionmiddlewaretest replace go.opentelemetry.io/collector/config/configcompression => ../../../config/configcompression replace go.opentelemetry.io/collector/extension => ../../../extension replace go.opentelemetry.io/collector/exporter/exporterhelper => ../../../exporter/exporterhelper replace go.opentelemetry.io/collector/consumer => ../../../consumer replace go.opentelemetry.io/collector/consumer/xconsumer => ../../../consumer/xconsumer replace go.opentelemetry.io/collector/consumer/consumererror => ../../../consumer/consumererror replace go.opentelemetry.io/collector/connector => ../../../connector replace go.opentelemetry.io/collector/confmap/xconfmap => ../../../confmap/xconfmap replace go.opentelemetry.io/collector/config/configtls => ../../../config/configtls replace go.opentelemetry.io/collector/service/hostcapabilities => ../../hostcapabilities replace go.opentelemetry.io/collector/extension/zpagesextension => ../../../extension/zpagesextension replace go.opentelemetry.io/collector/config/configretry => ../../../config/configretry replace go.opentelemetry.io/collector/config/confighttp => ../../../config/confighttp replace go.opentelemetry.io/collector/config/configopaque => ../../../config/configopaque replace go.opentelemetry.io/collector/config/configauth => ../../../config/configauth replace go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest => ../../../extension/extensionauth/extensionauthtest replace go.opentelemetry.io/collector/client => ../../../client replace go.opentelemetry.io/collector/receiver/receivertest => ../../../receiver/receivertest replace go.opentelemetry.io/collector/confmap/provider/fileprovider => ../../../confmap/provider/fileprovider replace go.opentelemetry.io/collector/internal/fanoutconsumer => ../../../internal/fanoutconsumer replace go.opentelemetry.io/collector/exporter/exportertest => ../../../exporter/exportertest replace go.opentelemetry.io/collector/extension/extensionauth => ../../../extension/extensionauth replace go.opentelemetry.io/collector/connector/xconnector => ../../../connector/xconnector replace go.opentelemetry.io/collector/connector/connectortest => ../../../connector/connectortest replace go.opentelemetry.io/collector/component/componenttest => ../../../component/componenttest replace go.opentelemetry.io/collector/component/componentstatus => ../../../component/componentstatus replace go.opentelemetry.io/collector/internal/testutil => ../../../internal/testutil opentelemetry-collector-0.141.0/service/telemetry/telemetrytest/go.sum000066400000000000000000000327251511331344600262660ustar00rootroot00000000000000github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc h1:GN2Lv3MGO7AS6PrRoT6yV5+wkrOpcszoIsO4+4ds248= github.com/grafana/regexp v0.0.0-20240518133315-a468a5bfb3bc/go.mod h1:+JKpmjMGhpgPL+rXZ5nsZieVzvarn86asRlBg4uNGnk= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2 h1:8Tjv8EJ+pM1xP8mK6egEbD1OgnVTyacbefKhmbLhIhU= github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.2/go.mod h1:pkJQ2tZHJ0aFOVEEot6oZmaVEZcRme73eIFmhiVuRWs= github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY= github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/klauspost/compress v1.18.1 h1:bcSGx7UbpBqMChDtsF28Lw6v/G94LPrrbMbdC3JH2co= github.com/klauspost/compress v1.18.1/go.mod h1:ZQFFVG+MdnR0P+l6wpXgIL4NTtwiKIdBnrBd8Nrxr+0= 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= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/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= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8= github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v1.23.2 h1:Je96obch5RDVy3FDMndoUsjAhG5Edi49h0RJWRi/o0o= github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= github.com/prometheus/common v0.67.1 h1:OTSON1P4DNxzTg4hmKCc37o4ZAZDv0cfXLkOt0oEowI= github.com/prometheus/common v0.67.1/go.mod h1:RpmT9v35q2Y+lsieQsdOh5sXZ6ajUGC8NjZAmr8vb0Q= github.com/prometheus/otlptranslator v0.0.2 h1:+1CdeLVrRQ6Psmhnobldo0kTp96Rj80DRXRd5OSnMEQ= github.com/prometheus/otlptranslator v0.0.2/go.mod h1:P8AwMgdD7XEr6QRUJ2QWLpiAZTgTE2UYgjlu3svompI= github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0= github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw= github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/otelconf v0.18.0 h1:ciF2Gf00BWs0DnexKFZXcxg9kJ8r3SUW1LOzW3CsKA8= go.opentelemetry.io/contrib/otelconf v0.18.0/go.mod h1:FcP7k+JLwBLdOxS6qY6VQ/4b5VBntI6L6o80IMwhAeI= go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0 h1:QQqYw3lkrzwVsoEX0w//EhH/TCnpRdEenKBOOEIMjWc= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploghttp v0.14.0/go.mod h1:gSVQcr17jk2ig4jqJ2DX30IdWH251JcNAecvrqTxH1s= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 h1:Oe2z/BCg5q7k4iXC3cqJxKYg0ieRiOqF0cecFYdPTwk= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0/go.mod h1:ZQM5lAJpOsKnYagGg/zV2krVqTtaVdYdDkhMoX6Oalg= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0 h1:aTL7F04bJHUlztTsNGJ2l+6he8c+y/b//eR0jjjemT4= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.38.0/go.mod h1:kldtb7jDTeol0l3ewcmd8SDvx3EmIE7lyvqbasU3QC4= go.opentelemetry.io/otel/exporters/prometheus v0.60.0 h1:cGtQxGvZbnrWdC2GyjZi0PDKVSLWP/Jocix3QWfXtbo= go.opentelemetry.io/otel/exporters/prometheus v0.60.0/go.mod h1:hkd1EekxNo69PTV4OWFGZcKQiIqg0RfuWExcPKFvepk= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0 h1:B/g+qde6Mkzxbry5ZZag0l7QrQBCtVm7lVjaLgmpje8= go.opentelemetry.io/otel/exporters/stdout/stdoutlog v0.14.0/go.mod h1:mOJK8eMmgW6ocDJn6Bn11CcZ05gi3P8GylBXEkZtbgA= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0 h1:wm/Q0GAAykXv83wzcKzGGqAnnfLFyFe7RslekZuv+VI= go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.38.0/go.mod h1:ra3Pa40+oKjvYh+ZD3EdxFZZB0xdMfuileHAm4nNN7w= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0 h1:kJxSDN4SgWWTjG/hPp3O7LCGLcHXFlvS2/FFOrwL+SE= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.38.0/go.mod h1:mgIOzS7iZeKJdeB8/NYHrJ48fdGc71Llo5bJ1J4DWUE= go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= 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.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0= go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8= go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk= google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM= google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig= google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= opentelemetry-collector-0.141.0/service/telemetry/telemetrytest/providers.go000066400000000000000000000053041511331344600274700ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetrytest // import "go.opentelemetry.io/collector/service/telemetry/telemetrytest" import ( "context" "go.opentelemetry.io/otel/metric" "go.opentelemetry.io/otel/trace" "go.uber.org/zap" "go.opentelemetry.io/collector/component" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/service/telemetry" ) // WithResource returns a telemetry.FactoryOption that configures the // factory's CreateResource method to return res. func WithResource(res pcommon.Resource) telemetry.FactoryOption { return telemetry.WithCreateResource( func(context.Context, telemetry.Settings, component.Config) (pcommon.Resource, error) { return res, nil }, ) } // WithLogger returns a telemetry.FactoryOption that configures the // factory's CreateLogger method to return logger and shutdown func. func WithLogger(logger *zap.Logger, shutdownFunc component.ShutdownFunc) telemetry.FactoryOption { return telemetry.WithCreateLogger( func(context.Context, telemetry.LoggerSettings, component.Config) ( *zap.Logger, component.ShutdownFunc, error, ) { return logger, shutdownFunc, nil }, ) } // WithMeterProvider returns a telemetry.FactoryOption that configures the // factory's CreateMeterProvider method to return provider. If provider does // not implement the Shutdown method, it will be wrapped with // ShutdownMeterProvider with a no-op shutdown func. func WithMeterProvider(provider metric.MeterProvider) telemetry.FactoryOption { return telemetry.WithCreateMeterProvider( func(context.Context, telemetry.MeterSettings, component.Config) ( telemetry.MeterProvider, error, ) { withShutdown, ok := provider.(telemetry.MeterProvider) if !ok { withShutdown = ShutdownMeterProvider{MeterProvider: provider} } return withShutdown, nil }, ) } // WithTracerProvider returns a telemetry.FactoryOption that configures the // factory's CreateTracerProvider method to return provider. If provider does // not implement the Shutdown method, it will be wrapped with // ShutdownTracerProvider with a no-op shutdown func. func WithTracerProvider(provider trace.TracerProvider) telemetry.FactoryOption { return telemetry.WithCreateTracerProvider( func(context.Context, telemetry.TracerSettings, component.Config) ( telemetry.TracerProvider, error, ) { withShutdown, ok := provider.(telemetry.TracerProvider) if !ok { withShutdown = ShutdownTracerProvider{TracerProvider: provider} } return withShutdown, nil }, ) } type ShutdownMeterProvider struct { metric.MeterProvider component.ShutdownFunc } type ShutdownTracerProvider struct { trace.TracerProvider component.ShutdownFunc } opentelemetry-collector-0.141.0/service/telemetry/telemetrytest/providers_test.go000066400000000000000000000053701511331344600305320ustar00rootroot00000000000000// Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 package telemetrytest // import "go.opentelemetry.io/collector/service/telemetry/telemetrytest" import ( "context" "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.opentelemetry.io/otel/metric" noopmetric "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" nooptrace "go.opentelemetry.io/otel/trace/noop" "go.uber.org/zap" "go.opentelemetry.io/collector/pdata/pcommon" "go.opentelemetry.io/collector/service/telemetry" ) func TestWithResource(t *testing.T) { res := pcommon.NewResource() res.Attributes().PutStr("key", "value") factory := telemetry.NewFactory(nil, WithResource(res)) createdResource, err := factory.CreateResource(context.Background(), telemetry.Settings{}, nil) require.NoError(t, err) assert.Equal(t, res, createdResource) } func TestWithLogger(t *testing.T) { logger := zap.NewNop() shutdownErr := errors.New("shutdown error") shutdown := func(context.Context) error { return shutdownErr } factory := telemetry.NewFactory(nil, WithLogger(logger, shutdown)) createdLogger, createdShutdown, err := factory.CreateLogger(context.Background(), telemetry.LoggerSettings{}, nil) require.NoError(t, err) assert.Same(t, logger, createdLogger) assert.Same(t, shutdownErr, createdShutdown(t.Context())) } func TestWithMeterProvider(t *testing.T) { test := func(t *testing.T, provider metric.MeterProvider, expected telemetry.MeterProvider) { factory := telemetry.NewFactory(nil, WithMeterProvider(provider)) createdProvider, err := factory.CreateMeterProvider(context.Background(), telemetry.MeterSettings{}, nil) require.NoError(t, err) assert.Equal(t, expected, createdProvider) } t.Run("Without Shutdown method", func(t *testing.T) { provider := noopmetric.NewMeterProvider() test(t, provider, ShutdownMeterProvider{MeterProvider: provider}) }) t.Run("With Shutdown method", func(t *testing.T) { provider := new(struct{ telemetry.MeterProvider }) test(t, provider, provider) }) } func TestWithTracerProvider(t *testing.T) { test := func(t *testing.T, provider trace.TracerProvider, expected telemetry.TracerProvider) { factory := telemetry.NewFactory(nil, WithTracerProvider(provider)) createdProvider, err := factory.CreateTracerProvider(context.Background(), telemetry.TracerSettings{}, nil) require.NoError(t, err) assert.Equal(t, expected, createdProvider) } t.Run("Without Shutdown method", func(t *testing.T) { provider := nooptrace.NewTracerProvider() test(t, provider, ShutdownTracerProvider{TracerProvider: provider}) }) t.Run("With Shutdown method", func(t *testing.T) { provider := new(struct{ telemetry.TracerProvider }) test(t, provider, provider) }) } opentelemetry-collector-0.141.0/versions.yaml000066400000000000000000000131201511331344600212670ustar00rootroot00000000000000# Copyright The OpenTelemetry Authors # SPDX-License-Identifier: Apache-2.0 module-sets: stable: version: v1.47.0 modules: - go.opentelemetry.io/collector/client - go.opentelemetry.io/collector/featuregate - go.opentelemetry.io/collector/pdata - go.opentelemetry.io/collector/component - go.opentelemetry.io/collector/confmap - go.opentelemetry.io/collector/confmap/provider/envprovider - go.opentelemetry.io/collector/confmap/provider/fileprovider - go.opentelemetry.io/collector/confmap/provider/httpprovider - go.opentelemetry.io/collector/confmap/provider/httpsprovider - go.opentelemetry.io/collector/confmap/provider/yamlprovider - go.opentelemetry.io/collector/config/configauth - go.opentelemetry.io/collector/config/configopaque - go.opentelemetry.io/collector/config/configoptional - go.opentelemetry.io/collector/config/configcompression - go.opentelemetry.io/collector/config/configretry - go.opentelemetry.io/collector/config/configtls - go.opentelemetry.io/collector/config/confignet - go.opentelemetry.io/collector/config/configmiddleware - go.opentelemetry.io/collector/consumer - go.opentelemetry.io/collector/exporter - go.opentelemetry.io/collector/extension - go.opentelemetry.io/collector/extension/extensionauth - go.opentelemetry.io/collector/pipeline - go.opentelemetry.io/collector/processor - go.opentelemetry.io/collector/receiver beta: version: v0.141.0 modules: - go.opentelemetry.io/collector - go.opentelemetry.io/collector/internal/memorylimiter - go.opentelemetry.io/collector/internal/fanoutconsumer - go.opentelemetry.io/collector/internal/sharedcomponent - go.opentelemetry.io/collector/internal/telemetry - go.opentelemetry.io/collector/internal/testutil - go.opentelemetry.io/collector/cmd/builder - go.opentelemetry.io/collector/cmd/mdatagen - go.opentelemetry.io/collector/component/componentstatus - go.opentelemetry.io/collector/component/componenttest - go.opentelemetry.io/collector/confmap/xconfmap - go.opentelemetry.io/collector/config/configgrpc - go.opentelemetry.io/collector/config/confighttp - go.opentelemetry.io/collector/config/confighttp/xconfighttp - go.opentelemetry.io/collector/config/configtelemetry - go.opentelemetry.io/collector/connector - go.opentelemetry.io/collector/connector/connectortest - go.opentelemetry.io/collector/connector/forwardconnector - go.opentelemetry.io/collector/connector/xconnector - go.opentelemetry.io/collector/consumer/xconsumer - go.opentelemetry.io/collector/consumer/consumererror - go.opentelemetry.io/collector/consumer/consumererror/xconsumererror - go.opentelemetry.io/collector/consumer/consumertest - go.opentelemetry.io/collector/exporter/debugexporter - go.opentelemetry.io/collector/exporter/exporterhelper - go.opentelemetry.io/collector/exporter/exporterhelper/xexporterhelper - go.opentelemetry.io/collector/exporter/exportertest - go.opentelemetry.io/collector/exporter/nopexporter - go.opentelemetry.io/collector/exporter/otlpexporter - go.opentelemetry.io/collector/exporter/otlphttpexporter - go.opentelemetry.io/collector/exporter/xexporter - go.opentelemetry.io/collector/extension/extensionauth/extensionauthtest - go.opentelemetry.io/collector/extension/extensioncapabilities - go.opentelemetry.io/collector/extension/extensionmiddleware - go.opentelemetry.io/collector/extension/extensionmiddleware/extensionmiddlewaretest - go.opentelemetry.io/collector/extension/extensiontest - go.opentelemetry.io/collector/extension/zpagesextension - go.opentelemetry.io/collector/extension/memorylimiterextension - go.opentelemetry.io/collector/extension/xextension - go.opentelemetry.io/collector/otelcol - go.opentelemetry.io/collector/otelcol/otelcoltest - go.opentelemetry.io/collector/pdata/pprofile - go.opentelemetry.io/collector/pdata/testdata - go.opentelemetry.io/collector/pdata/xpdata - go.opentelemetry.io/collector/pipeline/xpipeline - go.opentelemetry.io/collector/processor/processortest - go.opentelemetry.io/collector/processor/processorhelper - go.opentelemetry.io/collector/processor/batchprocessor - go.opentelemetry.io/collector/processor/memorylimiterprocessor - go.opentelemetry.io/collector/processor/processorhelper/xprocessorhelper - go.opentelemetry.io/collector/processor/xprocessor - go.opentelemetry.io/collector/receiver/receiverhelper - go.opentelemetry.io/collector/receiver/nopreceiver - go.opentelemetry.io/collector/receiver/otlpreceiver - go.opentelemetry.io/collector/receiver/receivertest - go.opentelemetry.io/collector/receiver/xreceiver - go.opentelemetry.io/collector/scraper - go.opentelemetry.io/collector/scraper/scraperhelper - go.opentelemetry.io/collector/scraper/scrapertest - go.opentelemetry.io/collector/scraper/xscraper - go.opentelemetry.io/collector/service - go.opentelemetry.io/collector/service/hostcapabilities - go.opentelemetry.io/collector/service/telemetry/telemetrytest - go.opentelemetry.io/collector/filter excluded-modules: - go.opentelemetry.io/collector/cmd/otelcorecol - go.opentelemetry.io/collector/internal/cmd/pdatagen - go.opentelemetry.io/collector/internal/e2e - go.opentelemetry.io/collector/internal/tools - go.opentelemetry.io/collector/confmap/internal/e2e